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 ...@@ -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 OutputHLSL::interfaceBlockMemberString(const TTypeList &typeList)
{ {
TString hlsl; TString hlsl;
...@@ -203,7 +221,8 @@ TString OutputHLSL::interfaceBlockMemberString(const TTypeList &typeList) ...@@ -203,7 +221,8 @@ TString OutputHLSL::interfaceBlockMemberString(const TTypeList &typeList)
for (unsigned int typeIndex = 0; typeIndex < typeList.size(); typeIndex++) for (unsigned int typeIndex = 0; typeIndex < typeList.size(); typeIndex++)
{ {
const TType &memberType = *typeList[typeIndex].type; 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; return hlsl;
...@@ -305,7 +324,7 @@ void OutputHLSL::header() ...@@ -305,7 +324,7 @@ void OutputHLSL::header()
mInterfaceBlockRegister += std::max(1u, interfaceBlock.arraySize); mInterfaceBlockRegister += std::max(1u, interfaceBlock.arraySize);
// TODO: handle other block layouts // TODO: handle other block layouts
interfaceBlock.setPackedBlockLayout(); interfaceBlock.setBlockLayout(BLOCKLAYOUT_SHARED);
mActiveInterfaceBlocks.push_back(interfaceBlock); mActiveInterfaceBlocks.push_back(interfaceBlock);
if (interfaceBlockType.hasInstanceName()) if (interfaceBlockType.hasInstanceName())
...@@ -2920,8 +2939,7 @@ void OutputHLSL::addConstructor(const TType &type, const TString &name, const TI ...@@ -2920,8 +2939,7 @@ void OutputHLSL::addConstructor(const TType &type, const TString &name, const TI
mStructNames.insert(decorate(name)); mStructNames.insert(decorate(name));
TString structure; TString structure;
structure += "struct " + decorate(name) + "\n" structure += "{\n";
"{\n";
const TTypeList &fields = *type.getStruct(); const TTypeList &fields = *type.getStruct();
...@@ -2936,7 +2954,14 @@ void OutputHLSL::addConstructor(const TType &type, const TString &name, const TI ...@@ -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()) 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++) for (unsigned int i = 0; i < fields.size(); i++)
......
...@@ -178,6 +178,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -178,6 +178,7 @@ class OutputHLSL : public TIntermTraverser
TString decoratePrivate(const TString &privateText); TString decoratePrivate(const TString &privateText);
TString interfaceBlockStructName(const TType &interfaceBlockType); TString interfaceBlockStructName(const TType &interfaceBlockType);
TString interfaceBlockInstanceString(const TType& interfaceBlockType, unsigned int arrayIndex); TString interfaceBlockInstanceString(const TType& interfaceBlockType, unsigned int arrayIndex);
TString interfaceBlockMemberTypeString(const TType &memberType);
TString interfaceBlockMemberString(const TTypeList &typeList); TString interfaceBlockMemberString(const TTypeList &typeList);
TString interfaceBlockStructString(const TType &interfaceBlockType); TString interfaceBlockStructString(const TType &interfaceBlockType);
TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex); TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex);
......
...@@ -33,99 +33,139 @@ const BlockMemberInfo BlockMemberInfo::defaultBlockInfo(-1, -1, -1, false); ...@@ -33,99 +33,139 @@ const BlockMemberInfo BlockMemberInfo::defaultBlockInfo(-1, -1, -1, false);
InterfaceBlock::InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex) InterfaceBlock::InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex)
: name(name), : name(name),
arraySize(arraySize), arraySize(arraySize),
layout(BLOCKLAYOUT_SHARED),
registerIndex(registerIndex) registerIndex(registerIndex)
{ {
} }
// Use the same layout for packed and shared // 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 size_t componentSize = 4;
const unsigned int registerSize = 4;
unsigned int currentOffset = 0; unsigned int currentOffset = 0;
blockInfo.clear(); blockInfo.clear();
getBlockLayoutInfo(activeUniforms, &currentOffset);
for (unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++) dataSize = currentOffset * componentSize;
{ }
const sh::Uniform &uniform = activeUniforms[uniformIndex];
void InterfaceBlock::getBlockLayoutInfo(const sh::ActiveUniforms &fields, unsigned int *currentOffset)
{
const size_t componentSize = 4;
// TODO: structs
// TODO: row major matrices // TODO: row major matrices
bool isRowMajorMatrix = false; bool isRowMajorMatrix = false;
// We assume we are only dealing with 4 byte components (no doubles or half-words currently) for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
ASSERT(gl::UniformComponentSize(gl::UniformComponentType(uniform.type)) == componentSize); {
int arrayStride;
int matrixStride;
int arrayStride = 0; const sh::Uniform &uniform = fields[fieldIndex];
int matrixStride = 0;
if (gl::IsMatrixType(uniform.type)) if (getBlockLayoutInfo(uniform, currentOffset, &arrayStride, &matrixStride))
{ {
currentOffset = rx::roundUp(currentOffset, 4u); const BlockMemberInfo memberInfo(*currentOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix);
matrixStride = registerSize; blockInfo.push_back(memberInfo);
if (uniform.arraySize > 0) if (uniform.arraySize > 0)
{ {
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type)); *currentOffset += arrayStride * uniform.arraySize;
arrayStride = matrixStride * componentGroups;
}
} }
else if (uniform.arraySize > 0) else if (gl::IsMatrixType(uniform.type))
{ {
currentOffset = rx::roundUp(currentOffset, registerSize); const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
arrayStride = registerSize; *currentOffset += matrixStride * componentGroups;
} }
else else
{ {
int numComponents = gl::UniformComponentCount(uniform.type); *currentOffset += gl::UniformComponentCount(uniform.type);
if ((numComponents + (currentOffset % registerSize)) >= registerSize) }
}
}
}
bool InterfaceBlock::getBlockLayoutInfo(const sh::Uniform &uniform, unsigned int *currentOffset, int *arrayStrideOut, int *matrixStrideOut)
{
if (!uniform.fields.empty())
{ {
currentOffset = rx::roundUp(currentOffset, registerSize); getBlockLayoutInfo(uniform.fields, currentOffset);
return false;
} }
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;
} }
}
BlockMemberInfo memberInfo(currentOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix); // Block layout packed according to the default D3D11 register packing rules
blockInfo.push_back(memberInfo); // 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;
// 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;
if (gl::IsMatrixType(uniform.type))
{
*currentOffset = rx::roundUp(*currentOffset, 4u);
matrixStride = registerSize;
// for arrays/matrices, the next element is in a multiple of register size
if (uniform.arraySize > 0) if (uniform.arraySize > 0)
{ {
currentOffset += arrayStride * uniform.arraySize; const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
arrayStride = matrixStride * componentGroups;
} }
else if (gl::IsMatrixType(uniform.type)) }
else if (uniform.arraySize > 0)
{ {
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type)); *currentOffset = rx::roundUp(*currentOffset, registerSize);
currentOffset += matrixStride * componentGroups; arrayStride = registerSize;
} }
else else
{ {
currentOffset += gl::UniformComponentCount(uniform.type); int numComponents = gl::UniformComponentCount(uniform.type);
if ((numComponents + (*currentOffset % registerSize)) >= registerSize)
{
*currentOffset = rx::roundUp(*currentOffset, registerSize);
} }
} }
dataSize = currentOffset * componentSize; *matrixStrideOut = matrixStride;
*arrayStrideOut = arrayStride;
} }
void InterfaceBlock::setStandardBlockLayout() // 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)
{ {
const size_t componentSize = 4; ASSERT(uniform.fields.empty());
unsigned int currentOffset = 0;
blockInfo.clear();
for (unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++) const size_t componentSize = 4;
{
const sh::Uniform &uniform = activeUniforms[uniformIndex];
// TODO: structs
// TODO: row major matrices // TODO: row major matrices
bool isRowMajorMatrix = false; bool isRowMajorMatrix = false;
...@@ -134,18 +174,18 @@ void InterfaceBlock::setStandardBlockLayout() ...@@ -134,18 +174,18 @@ void InterfaceBlock::setStandardBlockLayout()
int numComponents = gl::UniformComponentCount(uniform.type); int numComponents = gl::UniformComponentCount(uniform.type);
size_t baseAlignment = static_cast<size_t>(numComponents == 3 ? 4 : numComponents); size_t baseAlignment = static_cast<size_t>(numComponents == 3 ? 4 : numComponents);
int arrayStride = 0;
int matrixStride = 0; int matrixStride = 0;
int arrayStride = 0;
if (gl::IsMatrixType(uniform.type)) if (gl::IsMatrixType(uniform.type))
{ {
numComponents = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type)); numComponents = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type));
baseAlignment = rx::roundUp(baseAlignment, 4u); baseAlignment = rx::roundUp(baseAlignment, 4u);
matrixStride = baseAlignment; matrixStride = baseAlignment;
if (uniform.arraySize > 0) if (uniform.arraySize > 0)
{ {
const int componentGroups = (isRowMajorMatrix ? gl::VariableColumnCount(uniform.type) : gl::VariableRowCount(uniform.type)); const int componentGroups = (isRowMajorMatrix ? gl::VariableRowCount(uniform.type) : gl::VariableColumnCount(uniform.type));
arrayStride = matrixStride * componentGroups; arrayStride = matrixStride * componentGroups;
} }
} }
...@@ -155,29 +195,10 @@ void InterfaceBlock::setStandardBlockLayout() ...@@ -155,29 +195,10 @@ void InterfaceBlock::setStandardBlockLayout()
arrayStride = baseAlignment; arrayStride = baseAlignment;
} }
const unsigned int alignedOffset = rx::roundUp(currentOffset, baseAlignment); *currentOffset = rx::roundUp(*currentOffset, baseAlignment);
BlockMemberInfo memberInfo(alignedOffset * componentSize, arrayStride * componentSize, matrixStride * componentSize, isRowMajorMatrix);
blockInfo.push_back(memberInfo);
if (uniform.arraySize > 0) *matrixStrideOut = matrixStride;
{ *arrayStrideOut = arrayStride;
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);
}
}
dataSize = currentOffset * componentSize;
} }
} }
...@@ -45,6 +45,15 @@ struct BlockMemberInfo ...@@ -45,6 +45,15 @@ struct BlockMemberInfo
static const BlockMemberInfo defaultBlockInfo; static const BlockMemberInfo defaultBlockInfo;
}; };
typedef std::vector<BlockMemberInfo> BlockMemberInfoArray;
enum BlockLayoutType
{
BLOCKLAYOUT_STANDARD,
BLOCKLAYOUT_PACKED,
BLOCKLAYOUT_SHARED
};
struct InterfaceBlock struct InterfaceBlock
{ {
InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex); InterfaceBlock(const char *name, unsigned int arraySize, unsigned int registerIndex);
...@@ -54,12 +63,17 @@ struct InterfaceBlock ...@@ -54,12 +63,17 @@ struct InterfaceBlock
ActiveUniforms activeUniforms; ActiveUniforms activeUniforms;
size_t dataSize; size_t dataSize;
std::vector<BlockMemberInfo> blockInfo; std::vector<BlockMemberInfo> blockInfo;
BlockLayoutType layout;
unsigned int registerIndex; unsigned int registerIndex;
void setSharedBlockLayout(); void setBlockLayout(BlockLayoutType newLayout);
void setPackedBlockLayout();
void setStandardBlockLayout(); 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; typedef std::vector<InterfaceBlock> ActiveInterfaceBlocks;
......
...@@ -2362,6 +2362,30 @@ bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfac ...@@ -2362,6 +2362,30 @@ bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfac
return true; 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) bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
{ {
// create uniform block entries if they do not exist // create uniform block entries if they do not exist
...@@ -2371,16 +2395,8 @@ bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh ...@@ -2371,16 +2395,8 @@ bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh
const unsigned int blockIndex = mUniformBlocks.size(); const unsigned int blockIndex = mUniformBlocks.size();
// define member uniforms // define member uniforms
for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++) BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
{ defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
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);
}
// create all the uniform blocks // create all the uniform blocks
if (interfaceBlock.arraySize > 0) if (interfaceBlock.arraySize > 0)
......
...@@ -154,11 +154,14 @@ class ProgramBinary : public RefCountObject ...@@ -154,11 +154,14 @@ class ProgramBinary : public RefCountObject
bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); 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 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 linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms);
bool defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog); bool defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog);
bool areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock); bool areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock);
bool linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexUniformBlocks, const sh::ActiveInterfaceBlocks &fragmentUniformBlocks); 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 defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock);
bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex); 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