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 @@ ...@@ -16,38 +16,6 @@
namespace sh 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 // static
void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody( void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
TInfoSinkBase &out, TInfoSinkBase &out,
...@@ -80,20 +48,47 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody( ...@@ -80,20 +48,47 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
} }
else if (ssboFunction.type.isVector()) else if (ssboFunction.type.isVector())
{ {
out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize() if (ssboFunction.rowMajor)
<< "(loc));\n"; {
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()) else if (ssboFunction.type.isMatrix())
{ {
unsigned int matrixStride = GetMatrixStride(ssboFunction.type); if (ssboFunction.rowMajor)
out << " = {";
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{ {
out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc +" out << ";";
<< rowIndex * matrixStride << ")), "; 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 else
{ {
...@@ -124,25 +119,51 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody( ...@@ -124,25 +119,51 @@ void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
} }
else if (ssboFunction.type.isVector()) else if (ssboFunction.type.isVector())
{ {
if (ssboFunction.type.getBasicType() == EbtBool) if (ssboFunction.rowMajor)
{ {
out << " uint" << ssboFunction.type.getNominalSize() << " _tmp = uint" for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
<< ssboFunction.type.getNominalSize() << "(value);\n"; {
out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _tmp);\n"; // 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 else
{ {
out << " buffer.Store" << ssboFunction.type.getNominalSize() if (ssboFunction.type.getBasicType() == EbtBool)
<< "(loc, asuint(value));\n"; {
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()) else if (ssboFunction.type.isMatrix())
{ {
unsigned int matrixStride = GetMatrixStride(ssboFunction.type); if (ssboFunction.rowMajor)
for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
{ {
out << " buffer.Store" << ssboFunction.type.getCols() << "(loc +" out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
<< rowIndex * matrixStride << ", asuint(value[" << rowIndex << "]));\n"; << " 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 else
...@@ -158,26 +179,42 @@ bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<( ...@@ -158,26 +179,42 @@ bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
std::tie(rhs.functionName, rhs.typeString, rhs.method); std::tie(rhs.functionName, rhs.typeString, rhs.method);
} }
TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(const TType &type, TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
SSBOMethod method) const TType &type,
SSBOMethod method,
TLayoutBlockStorage storage,
bool rowMajor,
int matrixStride)
{ {
ShaderStorageBlockFunction ssboFunction; ShaderStorageBlockFunction ssboFunction;
ssboFunction.typeString = TypeString(type); ssboFunction.typeString = TypeString(type);
ssboFunction.method = method; ssboFunction.method = method;
ssboFunction.type = type; ssboFunction.type = type;
ssboFunction.rowMajor = rowMajor;
ssboFunction.matrixStride = matrixStride;
ssboFunction.functionName =
TString(getBlockStorageString(storage)) + "_" + ssboFunction.typeString;
switch (method) switch (method)
{ {
case SSBOMethod::LOAD: case SSBOMethod::LOAD:
ssboFunction.functionName = ssboFunction.typeString + "_Load"; ssboFunction.functionName += "_Load";
break; break;
case SSBOMethod::STORE: case SSBOMethod::STORE:
ssboFunction.functionName = ssboFunction.typeString + "_Store"; ssboFunction.functionName += "_Store";
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
if (rowMajor)
{
ssboFunction.functionName += "_rm_";
}
else
{
ssboFunction.functionName += "_cm_";
}
mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
return ssboFunction.functionName; return ssboFunction.functionName;
} }
......
...@@ -43,7 +43,11 @@ enum class SSBOMethod ...@@ -43,7 +43,11 @@ enum class SSBOMethod
class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
{ {
public: 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); void shaderStorageBlockFunctionHeader(TInfoSinkBase &out);
...@@ -55,6 +59,9 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable ...@@ -55,6 +59,9 @@ class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable
TString typeString; TString typeString;
SSBOMethod method; SSBOMethod method;
TType type; TType type;
TLayoutBlockStorage storage;
bool rowMajor;
int matrixStride;
}; };
static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out, static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out,
......
...@@ -35,6 +35,85 @@ namespace sh ...@@ -35,6 +35,85 @@ namespace sh
namespace 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 TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
const ImmutableString &variableName) const ImmutableString &variableName)
{ {
...@@ -222,8 +301,40 @@ void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node) ...@@ -222,8 +301,40 @@ void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method) void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method)
{ {
const TString &functionName = mMatrixStride = 0;
mSSBOFunctionHLSL->registerShaderStorageBlockFunction(node->getType(), method); 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(); TInfoSinkBase &out = mOutputHLSL->getInfoSink();
out << functionName; out << functionName;
out << "("; 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