Add support for structures in interface and uniform blocks.

Also redesigns the uniform block layout computation to be more general. TRAC #23018 Signed-off-by: Geoff Lang Signed-off-by: Nicolas Capens Author: Jamie Madill git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2387 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 27125346
......@@ -194,6 +194,24 @@ TString OutputHLSL::interfaceBlockInstanceString(const TType& interfaceBlockType
}
}
TString OutputHLSL::interfaceBlockMemberTypeString(const TType &memberType)
{
// TODO: layout support
if (memberType.isMatrix())
{
return " row_major " + typeString(memberType);
}
else if (memberType.getBasicType() == EbtStruct)
{
return "rm" + typeString(memberType);
}
else
{
return typeString(memberType);
}
}
TString OutputHLSL::interfaceBlockMemberString(const TTypeList &typeList)
{
TString hlsl;
......@@ -203,7 +221,8 @@ TString OutputHLSL::interfaceBlockMemberString(const TTypeList &typeList)
for (unsigned int typeIndex = 0; typeIndex < typeList.size(); typeIndex++)
{
const TType &memberType = *typeList[typeIndex].type;
hlsl += " " + typeString(memberType) + " " + decorate(memberType.getFieldName()) + arrayString(memberType) + ";\n";
hlsl += " " + interfaceBlockMemberTypeString(memberType) +
" " + decorate(memberType.getFieldName()) + arrayString(memberType) + ";\n";
}
return hlsl;
......@@ -305,7 +324,7 @@ void OutputHLSL::header()
mInterfaceBlockRegister += std::max(1u, interfaceBlock.arraySize);
// TODO: handle other block layouts
interfaceBlock.setPackedBlockLayout();
interfaceBlock.setBlockLayout(BLOCKLAYOUT_SHARED);
mActiveInterfaceBlocks.push_back(interfaceBlock);
if (interfaceBlockType.hasInstanceName())
......@@ -2920,8 +2939,7 @@ void OutputHLSL::addConstructor(const TType &type, const TString &name, const TI
mStructNames.insert(decorate(name));
TString structure;
structure += "struct " + decorate(name) + "\n"
"{\n";
structure += "{\n";
const TTypeList &fields = *type.getStruct();
......@@ -2936,7 +2954,14 @@ void OutputHLSL::addConstructor(const TType &type, const TString &name, const TI
if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
{
mStructDeclarations.push_back(structure);
TString columnMajorString = "struct " + decorate(name) + "\n" + structure;
TString rowMajorString = "#pragma pack_matrix(row_major)\n"
"struct rm" + decorate(name) + "\n" +
structure +
"#pragma pack_matrix(column_major)\n";
mStructDeclarations.push_back(columnMajorString);
mStructDeclarations.push_back(rowMajorString);
}
for (unsigned int i = 0; i < fields.size(); i++)
......
......@@ -178,6 +178,7 @@ class OutputHLSL : public TIntermTraverser
TString decoratePrivate(const TString &privateText);
TString interfaceBlockStructName(const TType &interfaceBlockType);
TString interfaceBlockInstanceString(const TType& interfaceBlockType, unsigned int arrayIndex);
TString interfaceBlockMemberTypeString(const TType &memberType);
TString interfaceBlockMemberString(const TTypeList &typeList);
TString interfaceBlockStructString(const TType &interfaceBlockType);
TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex);
......
......@@ -33,151 +33,172 @@ const BlockMemberInfo BlockMemberInfo::defaultBlockInfo(-1, -1, -1, false);
InterfaceBlock::InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex)
: name(name),
arraySize(arraySize),
layout(BLOCKLAYOUT_SHARED),
registerIndex(registerIndex)
{
}
// Use the same layout for packed and shared
void InterfaceBlock::setSharedBlockLayout()
void InterfaceBlock::setBlockLayout(BlockLayoutType newLayout)
{
setPackedBlockLayout();
}
layout = newLayout;
// Block layout packed according to the default D3D11 register packing rules
// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
void InterfaceBlock::setPackedBlockLayout()
{
const size_t componentSize = 4;
const unsigned int registerSize = 4;
unsigned int currentOffset = 0;
blockInfo.clear();
getBlockLayoutInfo(activeUniforms, &currentOffset);
for (unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
{
const sh::Uniform &uniform = activeUniforms[uniformIndex];
dataSize = currentOffset * componentSize;
}
void InterfaceBlock::getBlockLayoutInfo(const sh::ActiveUniforms &fields, unsigned int *currentOffset)
{
const size_t componentSize = 4;
// TODO: structs
// TODO: row major matrices
bool isRowMajorMatrix = false;
// TODO: row major matrices
bool isRowMajorMatrix = false;
// We assume we are only dealing with 4 byte components (no doubles or half-words currently)
ASSERT(gl::UniformComponentSize(gl::UniformComponentType(uniform.type)) == componentSize);
for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
{
int arrayStride;
int matrixStride;
int arrayStride = 0;
int matrixStride = 0;
const sh::Uniform &uniform = fields[fieldIndex];
if (gl::IsMatrixType(uniform.type))
if (getBlockLayoutInfo(uniform, currentOffset, &arrayStride, &matrixStride))
{
currentOffset = rx::roundUp(currentOffset, 4u);
matrixStride = registerSize;
const BlockMemberInfo memberInfo(*currentOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix);
blockInfo.push_back(memberInfo);
if (uniform.arraySize > 0)
{
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
arrayStride = matrixStride * componentGroups;
*currentOffset += arrayStride * uniform.arraySize;
}
}
else if (uniform.arraySize > 0)
{
currentOffset = rx::roundUp(currentOffset, registerSize);
arrayStride = registerSize;
}
else
{
int numComponents = gl::UniformComponentCount(uniform.type);
if ((numComponents + (currentOffset % registerSize)) >= registerSize)
else if (gl::IsMatrixType(uniform.type))
{
const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
*currentOffset += matrixStride * componentGroups;
}
else
{
currentOffset = rx::roundUp(currentOffset, registerSize);
*currentOffset += gl::UniformComponentCount(uniform.type);
}
}
}
}
BlockMemberInfo memberInfo(currentOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix);
blockInfo.push_back(memberInfo);
// for arrays/matrices, the next element is in a multiple of register size
if (uniform.arraySize > 0)
{
currentOffset += arrayStride * uniform.arraySize;
}
else if (gl::IsMatrixType(uniform.type))
{
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
currentOffset += matrixStride * componentGroups;
}
else
{
currentOffset += gl::UniformComponentCount(uniform.type);
}
bool InterfaceBlock::getBlockLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut)
{
if (!uniform.fields.empty())
{
getBlockLayoutInfo(uniform.fields, currentOffset);
return false;
}
dataSize = currentOffset * componentSize;
switch (layout)
{
case BLOCKLAYOUT_SHARED:
case BLOCKLAYOUT_PACKED:
getD3DLayoutInfo(uniform, currentOffset, arrayStrideOut, matrixStrideOut);
return true;
case BLOCKLAYOUT_STANDARD:
getStandardLayoutInfo(uniform, currentOffset, arrayStrideOut, matrixStrideOut);
return true;
default:
UNREACHABLE();
return false;
}
}
void InterfaceBlock::setStandardBlockLayout()
// Block layout packed according to the default D3D11 register packing rules
// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
void InterfaceBlock::getD3DLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut)
{
ASSERT(uniform.fields.empty());
const unsigned int registerSize = 4;
const size_t componentSize = 4;
unsigned int currentOffset = 0;
blockInfo.clear();
// TODO: row major matrices
bool isRowMajorMatrix = false;
// We assume we are only dealing with 4 byte components (no doubles or half-words currently)
ASSERT(gl::UniformComponentSize(gl::UniformComponentType(uniform.type)) == componentSize);
int matrixStride = 0;
int arrayStride = 0;
for (unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
if (gl::IsMatrixType(uniform.type))
{
const sh::Uniform &uniform = activeUniforms[uniformIndex];
// TODO: structs
// TODO: row major matrices
bool isRowMajorMatrix = false;
// We assume we are only dealing with 4 byte components (no doubles or half-words currently)
ASSERT(gl::UniformComponentSize(gl::UniformComponentType(uniform.type)) == componentSize);
*currentOffset = rx::roundUp(*currentOffset, 4u);
matrixStride = registerSize;
int numComponents = gl::UniformComponentCount(uniform.type);
size_t baseAlignment = static_cast<size_t>(numComponents == 3 ? 4 : numComponents);
int arrayStride = 0;
int matrixStride = 0;
if (gl::IsMatrixType(uniform.type))
if (uniform.arraySize > 0)
{
numComponents = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
baseAlignment = rx::roundUp(baseAlignment, 4u);
matrixStride = baseAlignment;
if (uniform.arraySize > 0)
{
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
arrayStride = matrixStride * componentGroups;
}
const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
arrayStride = matrixStride * componentGroups;
}
else if (uniform.arraySize > 0)
}
else if (uniform.arraySize > 0)
{
*currentOffset = rx::roundUp(*currentOffset, registerSize);
arrayStride = registerSize;
}
else
{
int numComponents = gl::UniformComponentCount(uniform.type);
if ((numComponents + (*currentOffset % registerSize)) >= registerSize)
{
baseAlignment = rx::roundUp(baseAlignment, 4u);
arrayStride = baseAlignment;
*currentOffset = rx::roundUp(*currentOffset, registerSize);
}
}
const unsigned int alignedOffset = rx::roundUp(currentOffset, baseAlignment);
*matrixStrideOut = matrixStride;
*arrayStrideOut = arrayStride;
}
// Block layout according to the std140 block layout
// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
void InterfaceBlock::getStandardLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut)
{
ASSERT(uniform.fields.empty());
const size_t componentSize = 4;
BlockMemberInfo memberInfo(alignedOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix);
blockInfo.push_back(memberInfo);
// TODO: row major matrices
bool isRowMajorMatrix = false;
// We assume we are only dealing with 4 byte components (no doubles or half-words currently)
ASSERT(gl::UniformComponentSize(gl::UniformComponentType(uniform.type)) == componentSize);
int numComponents = gl::UniformComponentCount(uniform.type);
size_t baseAlignment = static_cast<size_t>(numComponents == 3 ? 4 : numComponents);
int matrixStride = 0;
int arrayStride = 0;
if (gl::IsMatrixType(uniform.type))
{
numComponents = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
baseAlignment = rx::roundUp(baseAlignment, 4u);
matrixStride = baseAlignment;
if (uniform.arraySize > 0)
{
currentOffset += arrayStride * uniform.arraySize;
currentOffset = rx::roundUp(currentOffset, baseAlignment);
}
else if (gl::IsMatrixType(uniform.type))
{
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
currentOffset += matrixStride * componentGroups;
currentOffset = rx::roundUp(currentOffset, baseAlignment);
}
else
{
currentOffset += gl::UniformComponentCount(uniform.type);
const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
arrayStride = matrixStride * componentGroups;
}
}
else if (uniform.arraySize > 0)
{
baseAlignment = rx::roundUp(baseAlignment, 4u);
arrayStride = baseAlignment;
}
dataSize = currentOffset * componentSize;
*currentOffset = rx::roundUp(*currentOffset, baseAlignment);
*matrixStrideOut = matrixStride;
*arrayStrideOut = arrayStride;
}
}
......@@ -45,6 +45,15 @@ struct BlockMemberInfo
static const BlockMemberInfo defaultBlockInfo;
};
typedef std::vector<BlockMemberInfo> BlockMemberInfoArray;
enum BlockLayoutType
{
BLOCKLAYOUT_STANDARD,
BLOCKLAYOUT_PACKED,
BLOCKLAYOUT_SHARED
};
struct InterfaceBlock
{
InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex);
......@@ -54,12 +63,17 @@ struct InterfaceBlock
ActiveUniforms activeUniforms;
size_t dataSize;
std::vector<BlockMemberInfo> blockInfo;
BlockLayoutType layout;
unsigned int registerIndex;
void setSharedBlockLayout();
void setPackedBlockLayout();
void setStandardBlockLayout();
void setBlockLayout(BlockLayoutType newLayout);
private:
void getBlockLayoutInfo(const sh::ActiveUniforms &fields, unsigned int *currentOffset);
bool getBlockLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut);
void getD3DLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut);
void getStandardLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut);
};
typedef std::vector<InterfaceBlock> ActiveInterfaceBlocks;
......
......@@ -2362,6 +2362,30 @@ bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfac
return true;
}
void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
{
for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
{
const sh::Uniform &uniform = uniforms[uniformIndex];
if (!uniform.fields.empty())
{
defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
}
else
{
const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
blockIndex, **blockInfoItr);
// add to uniform list, but not index, since uniform block uniforms have no location
blockUniformIndexes->push_back(mUniforms.size());
mUniforms.push_back(newUniform);
(*blockInfoItr)++;
}
}
}
bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
{
// create uniform block entries if they do not exist
......@@ -2371,16 +2395,8 @@ bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh
const unsigned int blockIndex = mUniformBlocks.size();
// define member uniforms
for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++)
{
const sh::Uniform &constant = interfaceBlock.activeUniforms[activeUniformIndex];
Uniform *uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize,
blockIndex, interfaceBlock.blockInfo[activeUniformIndex]);
// add to uniform list, but not index, since uniform block uniforms have no location
blockUniformIndexes.push_back(mUniforms.size());
mUniforms.push_back(uniform);
}
BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
// create all the uniform blocks
if (interfaceBlock.arraySize > 0)
......
......@@ -154,11 +154,14 @@ class ProgramBinary : public RefCountObject
bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
typedef sh::BlockMemberInfoArray::const_iterator BlockInfoItr;
bool areMatchingUniforms(InfoLog &infoLog, const std::string& uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
bool linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms);
bool defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog);
bool areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock);
bool linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexUniformBlocks, const sh::ActiveInterfaceBlocks &fragmentUniformBlocks);
void defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes);
bool defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock);
bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment