Commit 48f63f90 by Qin Jiajia Committed by Commit Bot

ES31: add row major matrix support (part 2)

This patch implements read/write vector data in matrix or matrix data directly in a shader storage block with row_major qualifier. Bug: angleproject:1951 Change-Id: Id7847e2245b09414709361412a95c4dd84b9ee97 Reviewed-on: https://chromium-review.googlesource.com/c/1304019Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
parent 50bf0429
......@@ -16,38 +16,6 @@
namespace sh
{
namespace
{
unsigned int GetMatrixStride(const TType &type)
{
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (type.getLayoutQualifier().blockStorage == EbsStd140)
{
encoder = &std140Encoder;
}
else
{
// TODO(jiajia.qin@intel.com): add std430 support. http://anglebug.com/1951
encoder = &hlslEncoder;
}
const bool isRowMajorLayout = (type.getLayoutQualifier().matrixPacking == EmpRowMajor);
std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr)
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
}
const BlockMemberInfo &memberInfo =
encoder->encodeType(GLVariableType(type), arraySizes, isRowMajorLayout);
return memberInfo.matrixStride;
}
} // anonymous namespace
// static
void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
TInfoSinkBase &out,
......@@ -80,20 +48,47 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
}
else if (ssboFunction.type.isVector())
{
out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize()
<< "(loc));\n";
if (ssboFunction.rowMajor)
{
out << " = {";
for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
{
out << convertString << "buffer.Load(loc + " << index * ssboFunction.matrixStride
<< ")),";
}
out << "};\n";
}
else
{
out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize()
<< "(loc));\n";
}
}
else if (ssboFunction.type.isMatrix())
{
unsigned int matrixStride = GetMatrixStride(ssboFunction.type);
out << " = {";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
if (ssboFunction.rowMajor)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc +"
<< rowIndex * matrixStride << ")), ";
out << ";";
out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
<< " tmp_ = {";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + "
<< rowIndex * ssboFunction.matrixStride << ")), ";
}
out << "};\n";
out << " result = transpose(tmp_);\n";
}
else
{
out << " = {";
for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
{
out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + "
<< columnIndex * ssboFunction.matrixStride << ")), ";
}
out << "};\n";
}
out << "};\n";
}
else
{
......@@ -124,25 +119,51 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
}
else if (ssboFunction.type.isVector())
{
if (ssboFunction.type.getBasicType() == EbtBool)
if (ssboFunction.rowMajor)
{
out << " uint" << ssboFunction.type.getNominalSize() << " _tmp = uint"
<< ssboFunction.type.getNominalSize() << "(value);\n";
out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _tmp);\n";
for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
{
// Don't need to worry about bool value since there is no bool matrix.
out << "buffer.Store(loc + " << index * ssboFunction.matrixStride
<< ", asuint(value[" << index << "]));\n";
}
}
else
{
out << " buffer.Store" << ssboFunction.type.getNominalSize()
<< "(loc, asuint(value));\n";
if (ssboFunction.type.getBasicType() == EbtBool)
{
out << " uint" << ssboFunction.type.getNominalSize() << " _tmp = uint"
<< ssboFunction.type.getNominalSize() << "(value);\n";
out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _tmp);\n";
}
else
{
out << " buffer.Store" << ssboFunction.type.getNominalSize()
<< "(loc, asuint(value));\n";
}
}
}
else if (ssboFunction.type.isMatrix())
{
unsigned int matrixStride = GetMatrixStride(ssboFunction.type);
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
if (ssboFunction.rowMajor)
{
out << " buffer.Store" << ssboFunction.type.getCols() << "(loc +"
<< rowIndex * matrixStride << ", asuint(value[" << rowIndex << "]));\n";
out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
<< " tmp_ = transpose(value);\n";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{
out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + "
<< rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex
<< "]));\n";
}
}
else
{
for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
{
out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + "
<< columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex
<< "]));\n";
}
}
}
else
......@@ -158,26 +179,42 @@ bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
std::tie(rhs.functionName, rhs.typeString, rhs.method);
}
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(const TType &type,
SSBOMethod method)
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
const TType &type,
SSBOMethod method,
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride)
{
ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type);
ssboFunction.method = method;
ssboFunction.type = type;
ssboFunction.rowMajor = rowMajor;
ssboFunction.matrixStride = matrixStride;
ssboFunction.functionName =
TString(getBlockStorageString(storage)) + "_" + ssboFunction.typeString;
switch (method)
{
case SSBOMethod::LOAD:
ssboFunction.functionName = ssboFunction.typeString + "_Load";
ssboFunction.functionName += "_Load";
break;
case SSBOMethod::STORE:
ssboFunction.functionName = ssboFunction.typeString + "_Store";
ssboFunction.functionName += "_Store";
break;
default:
UNREACHABLE();
}
if (rowMajor)
{
ssboFunction.functionName += "_rm_";
}
else
{
ssboFunction.functionName += "_cm_";
}
mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
return ssboFunction.functionName;
}
......
......@@ -43,7 +43,11 @@ enum class SSBOMethod
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
{
public:
TString registerShaderStorageBlockFunction(const TType &type, SSBOMethod method);
TString registerShaderStorageBlockFunction(const TType &type,
SSBOMethod method,
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride);
void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
......@@ -55,6 +59,9 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TString typeString;
SSBOMethod method;
TType type;
TLayoutBlockStorage storage;
bool rowMajor;
int matrixStride;
};
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
......
......@@ -35,6 +35,85 @@ namespace sh
namespace
{
void GetBlockLayoutInfo(TIntermTyped *node,
bool rowMajorAlreadyAssigned,
TLayoutBlockStorage *storage,
bool *rowMajor)
{
TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
if (swizzleNode)
{
return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage,
rowMajor);
}
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
switch (binaryNode->getOp())
{
case EOpIndexDirectInterfaceBlock:
{
// The column_major/row_major qualifier of a field member overrides the interface
// block's row_major/column_major. So we can assign rowMajor here and don't need to
// assign it again. But we still need to call recursively to get the storage's
// value.
const TType &type = node->getType();
*rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor);
}
case EOpIndexIndirect:
case EOpIndexDirect:
case EOpIndexDirectStruct:
return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage,
rowMajor);
default:
UNREACHABLE();
return;
}
}
const TType &type = node->getType();
ASSERT(type.getQualifier() == EvqBuffer);
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
ASSERT(interfaceBlock);
*storage = interfaceBlock->blockStorage();
// If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In
// this situation, we still need to set rowMajor's value.
if (!rowMajorAlreadyAssigned)
{
*rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
}
}
// It's possible that the current type has lost the original layout information. So we should pass
// the right layout information to GetMatrixStride.
unsigned int GetMatrixStride(const TType &type, TLayoutBlockStorage storage, bool rowMajor)
{
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (storage == EbsStd140)
{
encoder = &std140Encoder;
}
else
{
encoder = &hlslEncoder;
}
std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr)
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
}
const BlockMemberInfo &memberInfo =
encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
return memberInfo.matrixStride;
}
const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
const ImmutableString &variableName)
{
......@@ -222,8 +301,40 @@ void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method)
{
const TString &functionName =
mSSBOFunctionHLSL->registerShaderStorageBlockFunction(node->getType(), method);
mMatrixStride = 0;
mRowMajor = false;
// Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current
// point. But we must use those information to generate the right function name. So here we have
// to calculate them again.
TLayoutBlockStorage storage;
bool rowMajor;
GetBlockLayoutInfo(node, false, &storage, &rowMajor);
// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL.
// It's because that if the current node's type is a vector which comes from a matrix, we will
// lost the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
if (node->getType().isVector())
{
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
const TType &leftType = binaryNode->getLeft()->getType();
if (leftType.isMatrix())
{
mMatrixStride = GetMatrixStride(leftType, storage, rowMajor);
mRowMajor = rowMajor;
}
}
}
else if (node->getType().isMatrix())
{
mMatrixStride = GetMatrixStride(node->getType(), storage, rowMajor);
mRowMajor = rowMajor;
}
const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
node->getType(), method, storage, mRowMajor, mMatrixStride);
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
out << functionName;
out << "(";
......
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