Commit 570e04d8 by Jamie Madill Committed by Shannon Woods

Add support for passing nested structs in standard layout by value.

We add support for this by using global scratch values as storage for the structs in uniform blocks. Any structs in std140 layouts that are referenced by value are initialized in the shader scope, without any packing, so the type of the structs are equivalent with what a GLSL program would expect. TRAC #23327 Signed-off-by: Geoff Lang Signed-off-by: Shannon Woods Authored-by: Jamie Madill
parent e4075c9c
...@@ -208,6 +208,8 @@ ...@@ -208,6 +208,8 @@
'compiler/DetectDiscontinuity.cpp', 'compiler/DetectDiscontinuity.cpp',
'compiler/DetectDiscontinuity.h', 'compiler/DetectDiscontinuity.h',
'compiler/CodeGenHLSL.cpp', 'compiler/CodeGenHLSL.cpp',
'compiler/FlagStd140Structs.cpp',
'compiler/FlagStd140Structs.h',
'compiler/HLSLLayoutEncoder.cpp', 'compiler/HLSLLayoutEncoder.cpp',
'compiler/HLSLLayoutEncoder.h', 'compiler/HLSLLayoutEncoder.h',
'compiler/OutputHLSL.cpp', 'compiler/OutputHLSL.cpp',
......
//
// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/FlagStd140Structs.h"
namespace sh
{
bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode)
{
if (binaryNode->getRight()->getBasicType() == EbtStruct)
{
switch (binaryNode->getOp())
{
case EOpIndexDirectInterfaceBlock:
case EOpIndexDirectStruct:
if (isInStd140InterfaceBlock(binaryNode->getLeft()))
{
mFlaggedNodes.push_back(binaryNode);
}
break;
default: break;
}
return false;
}
if (binaryNode->getOp() == EOpIndexDirectStruct)
{
return false;
}
return visit == PreVisit;
}
void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol)
{
if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct)
{
mFlaggedNodes.push_back(symbol);
}
}
bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const
{
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
return isInStd140InterfaceBlock(binaryNode->getLeft());
}
const TType &type = node->getType();
if (type.isInterfaceBlockMember() || type.getBasicType() == EbtInterfaceBlock)
{
// determine if we are in the standard layout
const TType &interfaceBlockType = (type.isInterfaceBlockMember() ? *type.getInterfaceBlockType() : type);
return (interfaceBlockType.getLayoutQualifier().blockStorage == EbsStd140);
}
return false;
}
std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node)
{
FlagStd140Structs flaggingTraversal;
node->traverse(&flaggingTraversal);
return flaggingTraversal.getFlaggedNodes();
}
}
//
// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_FLAGSTD140STRUCTS_H_
#define COMPILER_FLAGSTD140STRUCTS_H_
#include "compiler/intermediate.h"
namespace sh
{
// This class finds references to nested structs of std140 blocks that access
// the nested struct "by value", where the padding added in the translator
// conflicts with the "natural" unpadded type.
class FlagStd140Structs : public TIntermTraverser
{
public:
const std::vector<TIntermTyped *> getFlaggedNodes() const { return mFlaggedNodes; }
protected:
virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode);
virtual void visitSymbol(TIntermSymbol *symbol);
private:
bool isInStd140InterfaceBlock(TIntermTyped *node) const;
std::vector<TIntermTyped *> mFlaggedNodes;
};
std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node);
}
#endif // COMPILER_FLAGSTD140STRUCTS_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "compiler/SearchSymbol.h" #include "compiler/SearchSymbol.h"
#include "compiler/UnfoldShortCircuit.h" #include "compiler/UnfoldShortCircuit.h"
#include "compiler/HLSLLayoutEncoder.h" #include "compiler/HLSLLayoutEncoder.h"
#include "compiler/FlagStd140Structs.h"
#include <algorithm> #include <algorithm>
#include <cfloat> #include <cfloat>
...@@ -174,6 +175,8 @@ OutputHLSL::~OutputHLSL() ...@@ -174,6 +175,8 @@ OutputHLSL::~OutputHLSL()
void OutputHLSL::output() void OutputHLSL::output()
{ {
mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
makeFlaggedStructMaps(flaggedStructs);
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
header(); header();
...@@ -182,6 +185,28 @@ void OutputHLSL::output() ...@@ -182,6 +185,28 @@ void OutputHLSL::output()
mContext.infoSink().obj << mBody.c_str(); mContext.infoSink().obj << mBody.c_str();
} }
void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
{
for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
{
TIntermTyped *flaggedNode = flaggedStructs[structIndex];
// This will mark the necessary block elements as referenced
flaggedNode->traverse(this);
TString structName(mBody.c_str());
mBody.erase();
mFlaggedStructOriginalNames[flaggedNode] = structName;
for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
{
structName.erase(pos, 1);
}
mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
}
}
TInfoSinkBase &OutputHLSL::getBodyStream() TInfoSinkBase &OutputHLSL::getBodyStream()
{ {
return mBody; return mBody;
...@@ -476,6 +501,46 @@ BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage) ...@@ -476,6 +501,46 @@ BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage)
} }
} }
TString OutputHLSL::structInitializerString(int indent, const TTypeList &structMembers, const TString &structName)
{
TString init;
TString preIndentString;
TString fullIndentString;
for (int spaces = 0; spaces < (indent * 4); spaces++)
{
preIndentString += ' ';
}
for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
{
fullIndentString += ' ';
}
init += preIndentString + "{\n";
for (unsigned int memberIndex = 0; memberIndex < structMembers.size(); memberIndex++)
{
const TType &memberType = *structMembers[memberIndex].type;
const TString &fieldName = decorate(memberType.getFieldName());
if (memberType.getBasicType() == EbtStruct)
{
const TTypeList &nestedStructMembers = *memberType.getStruct();
init += structInitializerString(indent + 1, nestedStructMembers, structName + "." + fieldName);
}
else
{
init += fullIndentString + structName + "." + fieldName + ",\n";
}
}
init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
return init;
}
void OutputHLSL::header() void OutputHLSL::header()
{ {
TInfoSinkBase &out = mHeader; TInfoSinkBase &out = mHeader;
...@@ -484,6 +549,7 @@ void OutputHLSL::header() ...@@ -484,6 +549,7 @@ void OutputHLSL::header()
TString interfaceBlocks; TString interfaceBlocks;
TString varyings; TString varyings;
TString attributes; TString attributes;
TString flaggedStructs;
for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++) for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++)
{ {
...@@ -547,6 +613,19 @@ void OutputHLSL::header() ...@@ -547,6 +613,19 @@ void OutputHLSL::header()
} }
} }
for (auto flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
{
TIntermTyped *structNode = flaggedStructIt->first;
const TString &mappedName = flaggedStructIt->second;
const TType &structType = structNode->getType();
const TTypeList &structMembers = *structType.getStruct();
const TString &originalName = mFlaggedStructOriginalNames[structNode];
flaggedStructs += "static " + decorate(structType.getTypeName()) + " " + mappedName + " =\n";
flaggedStructs += structInitializerString(0, structMembers, originalName);
flaggedStructs += "\n";
}
for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++) for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
{ {
const TType &type = varying->second->getType(); const TType &type = varying->second->getType();
...@@ -706,6 +785,14 @@ void OutputHLSL::header() ...@@ -706,6 +785,14 @@ void OutputHLSL::header()
{ {
out << interfaceBlocks; out << interfaceBlocks;
out << "\n"; out << "\n";
if (!flaggedStructs.empty())
{
out << "// Std140 Structures accessed by value\n";
out << "\n";
out << flaggedStructs;
out << "\n";
}
} }
if (usingMRTExtension && mNumRenderTargets > 1) if (usingMRTExtension && mNumRenderTargets > 1)
...@@ -786,6 +873,14 @@ void OutputHLSL::header() ...@@ -786,6 +873,14 @@ void OutputHLSL::header()
{ {
out << interfaceBlocks; out << interfaceBlocks;
out << "\n"; out << "\n";
if (!flaggedStructs.empty())
{
out << "// Std140 Structures accessed by value\n";
out << "\n";
out << flaggedStructs;
out << "\n";
}
} }
} }
...@@ -1337,6 +1432,13 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -1337,6 +1432,13 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
{ {
TInfoSinkBase &out = mBody; TInfoSinkBase &out = mBody;
// Handle accessing std140 structs by value
if (mFlaggedStructMappedNames.count(node) > 0)
{
out << mFlaggedStructMappedNames[node];
return;
}
TString name = node->getSymbol(); TString name = node->getSymbol();
if (name == "gl_DepthRange") if (name == "gl_DepthRange")
...@@ -1424,6 +1526,13 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1424,6 +1526,13 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
TInfoSinkBase &out = mBody; TInfoSinkBase &out = mBody;
// Handle accessing std140 structs by value
if (mFlaggedStructMappedNames.count(node) > 0)
{
out << mFlaggedStructMappedNames[node];
return false;
}
switch (node->getOp()) switch (node->getOp())
{ {
case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
......
...@@ -199,6 +199,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -199,6 +199,7 @@ class OutputHLSL : public TIntermTraverser
TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex); TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex);
TString std140PrePaddingString(const TType &type, int *elementIndex); TString std140PrePaddingString(const TType &type, int *elementIndex);
TString std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking); TString std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking);
TString structInitializerString(int indent, const TTypeList &structMembers, const TString &structName);
static GLenum glVariableType(const TType &type); static GLenum glVariableType(const TType &type);
static GLenum glVariablePrecision(const TType &type); static GLenum glVariablePrecision(const TType &type);
...@@ -211,6 +212,10 @@ class OutputHLSL : public TIntermTraverser ...@@ -211,6 +212,10 @@ class OutputHLSL : public TIntermTraverser
ActiveShaderVariables mActiveOutputVariables; ActiveShaderVariables mActiveOutputVariables;
ActiveShaderVariables mActiveAttributes; ActiveShaderVariables mActiveAttributes;
std::map<TString, int> mStd140StructElementIndexes; std::map<TString, int> mStd140StructElementIndexes;
std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
}; };
} }
......
...@@ -143,6 +143,7 @@ ...@@ -143,6 +143,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="CodeGenHLSL.cpp" /> <ClCompile Include="CodeGenHLSL.cpp" />
<ClCompile Include="FlagStd140Structs.cpp" />
<ClCompile Include="DetectDiscontinuity.cpp" /> <ClCompile Include="DetectDiscontinuity.cpp" />
<ClCompile Include="HLSLLayoutEncoder.cpp" /> <ClCompile Include="HLSLLayoutEncoder.cpp" />
<ClCompile Include="OutputHLSL.cpp" /> <ClCompile Include="OutputHLSL.cpp" />
...@@ -152,6 +153,7 @@ ...@@ -152,6 +153,7 @@
<ClCompile Include="Uniform.cpp" /> <ClCompile Include="Uniform.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="FlagStd140Structs.h" />
<ClInclude Include="DetectDiscontinuity.h" /> <ClInclude Include="DetectDiscontinuity.h" />
<ClInclude Include="HLSLLayoutEncoder.h" /> <ClInclude Include="HLSLLayoutEncoder.h" />
<ClInclude Include="OutputHLSL.h" /> <ClInclude Include="OutputHLSL.h" />
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
<ClCompile Include="HLSLLayoutEncoder.cpp"> <ClCompile Include="HLSLLayoutEncoder.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FlagStd140Structs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="DetectDiscontinuity.h"> <ClInclude Include="DetectDiscontinuity.h">
...@@ -58,5 +61,8 @@ ...@@ -58,5 +61,8 @@
<ClInclude Include="HLSLLayoutEncoder.h"> <ClInclude Include="HLSLLayoutEncoder.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FlagStd140Structs.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
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