Commit e033999e by Jamie Madill Committed by Commit Bot

Vulkan: Add struct sampler parsing.

Vulkan requires all uniforms to be declared in a block. Uniform blocks can't have store samplers. Thus we can't use structs in samplers with Vulkan GLSL. To work around this limitation we extract samplers from structs and move them into standalone types. The samplers are named according to the variable and struct fields. Arrays of structs and nested structs to come later. Bug: angleproject:2494 Change-Id: I83a94ab082c6ce7ee68ec1290751ecee18820683 Reviewed-on: https://chromium-review.googlesource.com/1101567Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 4da0d315
......@@ -84,6 +84,7 @@ TVariable::TVariable(TSymbolTable *symbolTable,
unionArray(nullptr)
{
ASSERT(mType);
ASSERT(name.empty() || symbolType != SymbolType::Empty);
}
TStructure::TStructure(TSymbolTable *symbolTable,
......
......@@ -13,20 +13,189 @@
#include "angle_gl.h"
#include "common/utilities.h"
#include "compiler/translator/ImmutableStringBuilder.h"
#include "compiler/translator/OutputVulkanGLSL.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/tree_util/BuiltIn_autogen.h"
#include "compiler/translator/tree_util/FindMain.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/ReplaceVariable.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
#include "compiler/translator/util.h"
#include "tree_util/FindMain.h"
#include "tree_util/ReplaceVariable.h"
namespace sh
{
namespace
{
// This traverser is designed to strip out samplers from structs. It moves them into
// separate uniform sampler declarations. This allows the struct to be stored in the
// default uniform block. It also requires that we rewrite any functions that take the
// struct as an argument. The struct is split into two arguments.
class RewriteStructSamplers final : public TIntermTraverser
{
public:
RewriteStructSamplers(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable), mRemovedUniformsCount(0)
{
}
int removedUniformsCount() const { return mRemovedUniformsCount; }
bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
{
ASSERT(visit == PreVisit);
if (!mInGlobalScope)
{
return true;
}
const TIntermSequence &sequence = *(decl->getSequence());
TIntermTyped *declarator = sequence.front()->getAsTyped();
const TType &type = declarator->getType();
if (type.isStructureContainingSamplers())
{
TIntermSequence *newSequence = new TIntermSequence;
if (type.isStructSpecifier())
{
stripStructSpecifierSamplers(type.getStruct(), newSequence);
}
else
{
TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
ASSERT(asSymbol);
const TVariable &variable = asSymbol->variable();
ASSERT(variable.symbolType() != SymbolType::Empty);
extractStructSamplerUniforms(decl, variable, type.getStruct(), newSequence);
}
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence);
}
return true;
}
bool visitBinary(Visit visit, TIntermBinary *node) override
{
if (node->getOp() == EOpIndexDirectStruct && node->getType().isSampler())
{
TIntermTyped *lhs = node->getLeft();
const ImmutableString &structName = lhs->getAsSymbolNode()->variable().name();
const TStructure *structure = lhs->getType().getStruct();
int index = node->getRight()->getAsConstantUnion()->getIConst(0);
const ImmutableString &fieldName = structure->fields()[index]->name();
ImmutableStringBuilder stringBuilder(structName.length() + fieldName.length() + 1);
stringBuilder << structName << "_" << fieldName;
TVariable *samplerReplacement = mExtractedSamplers[stringBuilder];
ASSERT(samplerReplacement);
TIntermSymbol *replacement = new TIntermSymbol(samplerReplacement);
queueReplacement(replacement, OriginalNode::IS_DROPPED);
return true;
}
return true;
}
private:
void stripStructSpecifierSamplers(const TStructure *structure,
TIntermSequence *newSequence) const
{
TFieldList *newFieldList = new TFieldList;
ASSERT(structure->containsSamplers());
for (const TField *field : structure->fields())
{
// TODO(jmadill): Nested struct samplers. http://anglebug.com/2494
ASSERT(!field->type()->isStructureContainingSamplers());
if (!field->type()->isSampler())
{
TType *newType = new TType(*field->type());
TField *newField =
new TField(newType, field->name(), field->line(), field->symbolType());
newFieldList->push_back(newField);
}
}
// Prune empty structs.
if (newFieldList->empty())
{
return;
}
TStructure *newStruct =
new TStructure(mSymbolTable, structure->name(), newFieldList, structure->symbolType());
TType *newStructType = new TType(newStruct, true);
TVariable *newStructVar =
new TVariable(mSymbolTable, ImmutableString(""), newStructType, SymbolType::Empty);
TIntermSymbol *newStructRef = new TIntermSymbol(newStructVar);
TIntermDeclaration *structDecl = new TIntermDeclaration;
structDecl->appendDeclarator(newStructRef);
newSequence->push_back(structDecl);
}
void extractStructSamplerUniforms(TIntermDeclaration *oldDeclaration,
const TVariable &variable,
const TStructure *structure,
TIntermSequence *newSequence)
{
ASSERT(structure->containsSamplers());
size_t nonSamplerCount = 0;
for (const TField *field : structure->fields())
{
// TODO(jmadill): Nested struct samplers. http://anglebug.com/2494
ASSERT(!field->type()->isStructureContainingSamplers());
if (field->type()->isSampler())
{
// Name the sampler internally as varName_fieldName
ImmutableStringBuilder stringBuilder(variable.name().length() +
field->name().length() + 1);
stringBuilder << variable.name() << "_" << field->name();
ImmutableString newName(stringBuilder);
TType *newType = new TType(*field->type());
newType->setQualifier(EvqUniform);
TVariable *newVariable =
new TVariable(mSymbolTable, newName, newType, SymbolType::AngleInternal);
TIntermSymbol *newRef = new TIntermSymbol(newVariable);
TIntermDeclaration *samplerDecl = new TIntermDeclaration;
samplerDecl->appendDeclarator(newRef);
newSequence->push_back(samplerDecl);
mExtractedSamplers[newName] = newVariable;
}
else
{
nonSamplerCount++;
}
}
if (nonSamplerCount > 0)
{
// Keep the old declaration around if it has other members.
newSequence->push_back(oldDeclaration);
}
else
{
mRemovedUniformsCount++;
}
}
int mRemovedUniformsCount;
std::map<ImmutableString, TVariable *> mExtractedSamplers;
};
// This traverser translates embedded uniform structs into a specifier and declaration.
// This makes the declarations easier to move into uniform blocks.
class NameEmbeddedUniformStructsTraverser : public TIntermTraverser
......@@ -372,6 +541,12 @@ void TranslatorVulkan::translate(TIntermBlock *root,
root->traverse(&nameStructs);
nameStructs.updateTree();
RewriteStructSamplers rewriteStructSamplers(&getSymbolTable());
root->traverse(&rewriteStructSamplers);
rewriteStructSamplers.updateTree();
defaultUniformCount -= rewriteStructSamplers.removedUniformsCount();
// We must declare the struct types before using them.
DeclareStructTypesTraverser structTypesTraverser(&outputGLSL);
root->traverse(&structTypesTraverser);
......
......@@ -330,6 +330,8 @@ class TType
// Initializes all lazily-initialized members.
void realize();
bool isSampler() const { return IsSampler(type); }
private:
void invalidateMangledName();
const char *buildMangledName() const;
......
......@@ -232,6 +232,9 @@ gl::LinkResult GlslangWrapper::linkProgram(const gl::Context *glContext,
std::string samplerName = gl::ParseResourceName(samplerUniform.name, nullptr);
// Samplers in structs are extracted.
std::replace(samplerName.begin(), samplerName.end(), '.', '_');
ASSERT(samplerUniform.isActive(gl::ShaderType::Vertex) ||
samplerUniform.isActive(gl::ShaderType::Fragment));
if (samplerUniform.isActive(gl::ShaderType::Vertex))
......
......@@ -235,9 +235,7 @@
2161 VULKAN : dEQP-GLES2.functional.vertex_arrays.* = SKIP
2598 VULKAN : dEQP-GLES2.functional.rasterization.primitives.line* = SKIP
2599 VULKAN : dEQP-GLES2.functional.rasterization.limits.points = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.basic_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.struct_in_array.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.array_in_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.multiple_nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.info_query.unused_uniforms.sampler2D_* = SKIP
......@@ -256,9 +254,7 @@
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_array_first_elem_without_brackets.sampler2D* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic.samplerCube* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic.sampler* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_array.sampler2D_* = SKIP
......@@ -268,9 +264,7 @@
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_array_first_elem_without_brackets.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic.samplerCube* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.struct_in_array.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.array_in_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.nested_structs_arrays.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_full.array_in_struct.sampler2D_* = SKIP
2161 VULKAN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_full.basic_array.sampler2D_* = SKIP
......
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