Commit 71e6afb1 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Set set/binding in SPIR-V

This change introduces a SPIR-V transformer that modifies shader interface variable decorations directly in SPIR-V instead of manipulating the input GLSL. Currently, descriptor set and binding indices are set by the transformer. The shader translator outputs arbitrary set and binding indices. Once compiled by glslang, the SPIR-V transformer modifies these decorations. The ultimate goal is to be able to modify the SPIR-V again when program pipeline objects decide a different set/binding is necessary. Bug: angleproject:3394 Change-Id: If358265a72bf1fe9f5676562b39a632cb2e05dc4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2001477Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 2bc9cc12
......@@ -613,6 +613,8 @@ if (angle_enable_vulkan || angle_enable_metal) {
":libANGLE_headers",
"${angle_glslang_dir}:glslang_default_resource_limits_sources",
"${angle_glslang_dir}:glslang_sources",
"${angle_spirv_headers_dir}:spv_headers",
"${angle_spirv_tools_dir}:spvtools_headers",
]
}
}
......
......@@ -15,4 +15,5 @@ angle_libjpeg_turbo_dir = "//third_party/libjpeg_turbo"
angle_jsoncpp_dir = "//third_party/jsoncpp"
angle_libpng_dir = "//third_party/libpng"
angle_spirv_cross_dir = "//third_party/spirv-cross/src"
angle_spirv_headers_dir = "//third_party/spirv-headers/src"
angle_spirv_tools_dir = "//third_party/spirv-tools/src"
......@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 223
#define ANGLE_SH_VERSION 224
enum ShShaderSpec
{
......@@ -733,6 +733,11 @@ inline bool IsDesktopGLSpec(ShShaderSpec spec)
return spec == SH_GL_CORE_SPEC || spec == SH_GL_COMPATIBILITY_SPEC;
}
// Can't prefix with just _ because then we might introduce a double underscore, which is not safe
// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for
// use by the underlying implementation). u is short for user-defined.
extern const char kUserDefinedNamePrefix[];
namespace vk
{
......@@ -745,6 +750,21 @@ enum class SpecializationConstantId : uint32_t
EnumCount = 1,
};
// Interface block name containing the aggregate default uniforms
extern const char kDefaultUniformsNameVS[];
extern const char kDefaultUniformsNameTCS[];
extern const char kDefaultUniformsNameTES[];
extern const char kDefaultUniformsNameGS[];
extern const char kDefaultUniformsNameFS[];
extern const char kDefaultUniformsNameCS[];
// Interface block and variable name containing driver uniforms
extern const char kDriverUniformsBlockName[];
extern const char kDriverUniformsVarName[];
// Interface block array variable name used for atomic counter emulation
extern const char kAtomicCountersVarName[];
} // namespace vk
} // namespace sh
......
......@@ -183,6 +183,13 @@ std::string ToString(const T &value)
return o.str();
}
inline bool IsLittleEndian()
{
constexpr uint32_t kEndiannessTest = 1;
const bool isLittleEndian = *reinterpret_cast<const uint8_t *>(&kEndiannessTest) == 1;
return isLittleEndian;
}
// snprintf is not defined with MSVC prior to to msvc14
#if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
......
......@@ -18,11 +18,6 @@ namespace
{
constexpr const ImmutableString kHashedNamePrefix("webgl_");
// Can't prefix with just _ because then we might introduce a double underscore, which is not safe
// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for
// use by the underlying implementation). u is short for user-defined.
constexpr const ImmutableString kUnhashedNamePrefix("_u");
ImmutableString HashName(const ImmutableString &name, ShHashFunction64 hashFunction)
{
ASSERT(!name.empty());
......@@ -47,6 +42,8 @@ ImmutableString HashName(const ImmutableString &name,
ShHashFunction64 hashFunction,
NameMap *nameMap)
{
const ImmutableString kUnhashedNamePrefix(kUserDefinedNamePrefix);
if (hashFunction == nullptr)
{
if (name.length() + kUnhashedNamePrefix.length() > kESSLMaxIdentifierLength)
......
......@@ -35,20 +35,21 @@ TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink,
shaderType,
shaderVersion,
output,
compileOptions)
compileOptions),
mNextUnusedBinding(0)
{}
// TODO(jmadill): This is not complete.
void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
{
const TType &type = variable->getType();
bool needsCustomLayout =
type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut ||
type.getQualifier() == EvqVertexIn || IsVarying(type.getQualifier()) ||
bool needsCustomLayout = type.getQualifier() == EvqAttribute ||
type.getQualifier() == EvqFragmentOut ||
type.getQualifier() == EvqVertexIn || IsVarying(type.getQualifier());
bool needsSetBinding =
IsSampler(type.getBasicType()) || type.isInterfaceBlock() || IsImage(type.getBasicType());
if (!NeedsToWriteLayoutQualifier(type) && !needsCustomLayout)
if (!NeedsToWriteLayoutQualifier(type) && !needsCustomLayout && !needsSetBinding)
{
return;
}
......@@ -96,6 +97,7 @@ void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
matrixPacking = getMatrixPackingString(layoutQualifier.matrixPacking);
}
const char *separator = "";
if (needsCustomLayout)
{
out << "@@ LAYOUT-" << name << "(";
......@@ -103,13 +105,20 @@ void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
else
{
out << "layout(";
// If the resource declaration requires set & binding layout qualifiers, specify arbitrary
// ones.
if (needsSetBinding)
{
out << "set=0, binding=" << nextUnusedBinding();
separator = ", ";
}
}
// Output the list of qualifiers already known at this stage, i.e. everything other than
// `location` and `set`/`binding`.
std::string otherQualifiers = getCommonLayoutQualifiers(variable);
const char *separator = "";
if (blockStorage)
{
out << separator << blockStorage;
......
......@@ -29,12 +29,19 @@ class TOutputVulkanGLSL : public TOutputGLSL
void writeStructType(const TStructure *structure);
uint32_t nextUnusedBinding() { return mNextUnusedBinding++; }
protected:
void writeLayoutQualifier(TIntermTyped *variable) override;
void writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol) override;
void writeVariableType(const TType &type,
const TSymbol *symbol,
bool isFunctionArgument) override;
// Every resource that requires set & binding layout qualifiers is assigned set 0 and an
// arbitrary binding when outputting GLSL. Glslang wrapper modifies set and binding decorations
// in SPIR-V directly.
uint32_t mNextUnusedBinding;
};
} // namespace sh
......@@ -698,4 +698,28 @@ unsigned int GetShaderSharedMemorySize(const ShHandle handle)
return sharedMemorySize;
}
// Can't prefix with just _ because then we might introduce a double underscore, which is not safe
// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for
// use by the underlying implementation). u is short for user-defined.
const char kUserDefinedNamePrefix[] = "_u";
namespace vk
{
// Interface block name containing the aggregate default uniforms
const char kDefaultUniformsNameVS[] = "defaultUniformsVS";
const char kDefaultUniformsNameTCS[] = "defaultUniformsTCS";
const char kDefaultUniformsNameTES[] = "defaultUniformsTES";
const char kDefaultUniformsNameGS[] = "defaultUniformsGS";
const char kDefaultUniformsNameFS[] = "defaultUniformsFS";
const char kDefaultUniformsNameCS[] = "defaultUniformsCS";
// Interface block and variable name containing driver uniforms
const char kDriverUniformsBlockName[] = "ANGLEUniformBlock";
const char kDriverUniformsVarName[] = "ANGLEUniforms";
// Interface block array variable name used for atomic counter emulation
const char kAtomicCountersVarName[] = "atomicCounters";
} // namespace vk
} // namespace sh
......@@ -12,6 +12,7 @@
#include "compiler/translator/TranslatorVulkan.h"
#include "angle_gl.h"
#include "common/PackedEnums.h"
#include "common/utilities.h"
#include "compiler/translator/BuiltinsWorkaroundGLSL.h"
#include "compiler/translator/ImmutableStringBuilder.h"
......@@ -158,8 +159,13 @@ class DeclareDefaultUniformsTraverser : public TIntermTraverser
constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPointCoord");
constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragCoord");
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
constexpr ImmutableString kUniformsBlockName = ImmutableString("ANGLEUniformBlock");
constexpr ImmutableString kUniformsVarName = ImmutableString("ANGLEUniforms");
constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
{gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
{gl::ShaderType::Geometry, vk::kDefaultUniformsNameGS},
{gl::ShaderType::Fragment, vk::kDefaultUniformsNameFS},
{gl::ShaderType::Compute, vk::kDefaultUniformsNameCS},
};
// Specialization constant names
constexpr ImmutableString kLineRasterEmulationSpecConstVarName =
......@@ -396,9 +402,9 @@ const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTa
}
// Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
return DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
TMemoryQualifier::Create(), 0, kUniformsBlockName,
kUniformsVarName);
return DeclareInterfaceBlock(
root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
}
const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
......@@ -420,9 +426,9 @@ const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTab
}
// Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
return DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
TMemoryQualifier::Create(), 0, kUniformsBlockName,
kUniformsVarName);
return DeclareInterfaceBlock(
root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
}
TIntermSymbol *GenerateLineRasterSpecConstRef(TSymbolTable *symbolTable)
......@@ -791,7 +797,9 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
if (defaultUniformCount > 0)
{
sink << "\n@@ LAYOUT-defaultUniforms(std140) @@ uniform defaultUniforms\n{\n";
gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
sink << "\nlayout(set=0, binding=" << outputGLSL->nextUnusedBinding()
<< ", std140) uniform " << kDefaultUniformNames[shaderType] << "\n{\n";
DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
root->traverse(&defaultTraverser);
......
......@@ -22,7 +22,6 @@ namespace
{
constexpr ImmutableString kAtomicCounterTypeName = ImmutableString("ANGLE_atomic_uint");
constexpr ImmutableString kAtomicCounterBlockName = ImmutableString("ANGLEAtomicCounters");
constexpr ImmutableString kAtomicCounterVarName = ImmutableString("atomicCounters");
constexpr ImmutableString kAtomicCounterFieldName = ImmutableString("counters");
// DeclareAtomicCountersBuffer adds a storage buffer array that's used with atomic counters.
......@@ -48,7 +47,7 @@ const TVariable *DeclareAtomicCountersBuffers(TIntermBlock *root, TSymbolTable *
// Define a storage block "ANGLEAtomicCounters" with instance name "atomicCounters".
return DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, coherentMemory,
kMaxAtomicCounterBuffers, kAtomicCounterBlockName,
kAtomicCounterVarName);
ImmutableString(vk::kAtomicCountersVarName));
}
TIntermConstantUnion *CreateUIntConstant(uint32_t value)
......
......@@ -360,7 +360,8 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
ASSERT(asSymbol);
const TVariable &variable = asSymbol->variable();
ASSERT(variable.symbolType() != SymbolType::Empty);
extractSampler(variable.name(), variable.getType(), newSequence, 0);
extractSampler(variable.name(), variable.symbolType(), variable.getType(), newSequence,
0);
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence);
}
......@@ -652,7 +653,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
if (fieldType.isSampler())
{
extractSampler(newPrefix, fieldType, newSequence, 0);
extractSampler(newPrefix, SymbolType::AngleInternal, fieldType, newSequence, 0);
}
else
{
......@@ -676,6 +677,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
// Extracts a sampler from a struct. Declares the new extracted sampler.
void extractSampler(const ImmutableString &newName,
SymbolType symbolType,
const TType &fieldType,
TIntermSequence *newSequence,
size_t arrayLevel)
......@@ -692,16 +694,27 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
newType->makeArray(static_cast<unsigned int>(mCumulativeArraySizeStack.back()));
}
newType->setQualifier(EvqUniform);
TVariable *newVariable =
new TVariable(mSymbolTable, newName, newType, SymbolType::AngleInternal);
TIntermSymbol *newRef = new TIntermSymbol(newVariable);
TVariable *newVariable = new TVariable(mSymbolTable, newName, newType, symbolType);
TIntermSymbol *newRef = new TIntermSymbol(newVariable);
TIntermDeclaration *samplerDecl = new TIntermDeclaration;
samplerDecl->appendDeclarator(newRef);
newSequence->push_back(samplerDecl);
mSymbolTable->declareInternal(newVariable);
// TODO(syoussefi): Use a SymbolType::Empty name instead of generating a name as currently
// done. There is no guarantee that these generated names cannot clash. Create a mapping
// from the previous name to the name assigned to the SymbolType::Empty variable so
// ShaderVariable::mappedName can be updated post-transformation.
// http://anglebug.com/4301
if (symbolType == SymbolType::AngleInternal)
{
mSymbolTable->declareInternal(newVariable);
}
else
{
mSymbolTable->declare(newVariable);
}
GenerateArrayStrides(mArraySizeStack, &mVariableExtraData.arrayStrideMap[newVariable]);
......
......@@ -18,6 +18,7 @@ namespace rx
enum class GlslangError
{
InvalidShader,
InvalidSpirv,
};
struct GlslangSourceOptions
......@@ -43,22 +44,49 @@ using SpirvBlob = std::vector<uint32_t>;
using GlslangErrorCallback = std::function<angle::Result(GlslangError)>;
// Information for each shader interface variable. Not all fields are relevant to each shader
// interface variable. For example opaque uniforms require a set and binding index, while vertex
// attributes require a location.
struct ShaderInterfaceVariableInfo
{
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
// Used for interface blocks and opaque uniforms.
uint32_t descriptorSet = kInvalid;
uint32_t binding = kInvalid;
// Used for vertex attributes, fragment shader outputs and varyings.
uint32_t location = kInvalid;
uint32_t component = kInvalid;
// Used for varyings.
gl::ShaderBitSet activeStages;
// Used for transform feedback extension to decorate vertex shader output.
uint32_t xfbBuffer = kInvalid;
uint32_t xfbOffset = kInvalid;
uint32_t xfbStride = kInvalid;
};
using ShaderInterfaceVariableInfoMap = std::unordered_map<std::string, ShaderInterfaceVariableInfo>;
void GlslangInitialize();
void GlslangRelease();
// Get the mapped sampler name after the soure is transformed by GlslangGetShaderSource()
std::string GlslangGetMappedSamplerName(const std::string &originalName);
// Transform the source to include actual binding points for various shader
// resources (textures, buffers, xfb, etc)
// Transform the source to include actual binding points for various shader resources (textures,
// buffers, xfb, etc). For some variables, these values are instead output to the variableInfoMap
// to be set during a SPIR-V transformation. This is a transitory step towards moving all variables
// to this map, at which point GlslangGetShaderSpirvCode will also be called by this function.
void GlslangGetShaderSource(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
angle::Result GlslangGetShaderSpirvCode(GlslangErrorCallback callback,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut);
} // namespace rx
......
......@@ -17,6 +17,7 @@
#include "common/Optional.h"
#include "common/utilities.h"
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_resources.h"
#include "libANGLE/renderer/metal/mtl_state_cache.h"
......@@ -162,6 +163,7 @@ class ProgramMtl : public ProgramImpl
// We keep the translated linked shader sources to use with shader draw call patching.
gl::ShaderMap<std::string> mShaderSource;
ShaderInterfaceVariableInfoMap mVariableInfoMap;
mtl::RenderPipelineCache mMetalRenderPipelineCache;
};
......
......@@ -295,7 +295,7 @@ std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
// assignment done in that function.
linkResources(resources);
mtl::GlslangGetShaderSource(mState, resources, &mShaderSource);
mtl::GlslangGetShaderSource(mState, resources, &mShaderSource, &mVariableInfoMap);
// NOTE(hqle): Parallelize linking.
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
......@@ -313,7 +313,7 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, gl::InfoLog &in
// Convert GLSL to spirv code
gl::ShaderMap<std::vector<uint32_t>> shaderCodes;
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, contextMtl->getCaps(), mShaderSource,
&shaderCodes));
mVariableInfoMap, &shaderCodes));
// Convert spirv code to MSL
ANGLE_TRY(convertToMsl(glContext, gl::ShaderType::Vertex, infoLog,
......
......@@ -12,6 +12,7 @@
#include "libANGLE/Caps.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/metal/mtl_common.h"
namespace rx
......@@ -20,11 +21,13 @@ namespace mtl
{
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
} // namespace mtl
} // namespace rx
......
......@@ -43,19 +43,22 @@ GlslangSourceOptions CreateSourceOptions()
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
rx::GlslangGetShaderSource(CreateSourceOptions(), programState, resources, shaderSourcesOut);
rx::GlslangGetShaderSource(CreateSourceOptions(), programState, resources, shaderSourcesOut,
variableInfoMapOut);
}
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
return rx::GlslangGetShaderSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, glCaps,
shaderSources, shaderCodeOut);
shaderSources, variableInfoMap, shaderCodeOut);
}
} // namespace mtl
} // namespace rx
......@@ -8,7 +8,6 @@
#include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
......@@ -42,20 +41,22 @@ GlslangSourceOptions CreateSourceOptions(const angle::FeaturesVk &features)
void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
GlslangGetShaderSource(CreateSourceOptions(features), programState, resources,
shaderSourcesOut);
GlslangGetShaderSource(CreateSourceOptions(features), programState, resources, shaderSourcesOut,
variableInfoMapOut);
}
// static
angle::Result GlslangWrapperVk::GetShaderCode(vk::Context *context,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
return GlslangGetShaderSpirvCode(
[context](GlslangError error) { return ErrorHandler(context, error); }, glCaps,
shaderSources, shaderCodeOut);
shaderSources, variableInfoMap, shaderCodeOut);
}
} // namespace rx
......@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_VULKAN_GLSLANG_WRAPPER_H_
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace angle
......@@ -27,11 +28,13 @@ class GlslangWrapperVk
static void GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
static angle::Result GetShaderCode(vk::Context *context,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
};
} // namespace rx
......
......@@ -364,14 +364,16 @@ ProgramVk::ShaderInfo::ShaderInfo() {}
ProgramVk::ShaderInfo::~ShaderInfo() = default;
angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
angle::Result ProgramVk::ShaderInfo::initShaders(
ContextVk *contextVk,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
{
ASSERT(!valid());
ANGLE_TRY(GlslangWrapperVk::GetShaderCode(contextVk, contextVk->getCaps(), shaderSources,
spirvBlobsOut));
variableInfoMap, spirvBlobsOut));
mIsInitialized = true;
return angle::Result::Continue;
......@@ -438,6 +440,25 @@ angle::Result ProgramVk::loadSpirvBlob(ContextVk *contextVk, gl::BinaryInputStre
// Read the shader source
mShaderSources[shaderType] = stream->readString();
// Read the expected bindings
size_t infoCount = stream->readInt<size_t>();
for (size_t i = 0; i < infoCount; ++i)
{
std::string varName = stream->readString();
ShaderInterfaceVariableInfo info;
info.descriptorSet = stream->readInt<uint32_t>();
info.binding = stream->readInt<uint32_t>();
info.location = stream->readInt<uint32_t>();
info.component = stream->readInt<uint32_t>();
info.activeStages = gl::ShaderBitSet(static_cast<uint8_t>(stream->readInt<uint32_t>()));
info.xfbBuffer = stream->readInt<uint32_t>();
info.xfbOffset = stream->readInt<uint32_t>();
info.xfbStride = stream->readInt<uint32_t>();
mVariableInfoMap[varName] = info;
}
SpirvBlob *spirvBlob = &mShaderInfo.getSpirvBlobs()[shaderType];
// Read the SPIR-V
......@@ -455,6 +476,21 @@ void ProgramVk::saveSpirvBlob(gl::BinaryOutputStream *stream)
// Write the shader source
stream->writeString(mShaderSources[shaderType]);
// Write the expected bindings
stream->writeInt(mVariableInfoMap.size());
for (const auto &nameInfo : mVariableInfoMap)
{
stream->writeString(nameInfo.first);
stream->writeIntOrNegOne(nameInfo.second.descriptorSet);
stream->writeIntOrNegOne(nameInfo.second.binding);
stream->writeIntOrNegOne(nameInfo.second.location);
stream->writeIntOrNegOne(nameInfo.second.component);
stream->writeIntOrNegOne(nameInfo.second.activeStages.bits());
stream->writeIntOrNegOne(nameInfo.second.xfbBuffer);
stream->writeIntOrNegOne(nameInfo.second.xfbOffset);
stream->writeIntOrNegOne(nameInfo.second.xfbStride);
}
const SpirvBlob &spirvBlob = mShaderInfo.getSpirvBlobs()[shaderType];
// Write the SPIR-V
......@@ -611,7 +647,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
linkResources(resources);
GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources,
&mShaderSources);
&mShaderSources, &mVariableInfoMap);
reset(contextVk);
......
......@@ -223,8 +223,8 @@ class ProgramVk : public ProgramImpl
// constants.
if (!mShaderInfo.valid())
{
ANGLE_TRY(
mShaderInfo.initShaders(contextVk, mShaderSources, &mShaderInfo.getSpirvBlobs()));
ANGLE_TRY(mShaderInfo.initShaders(contextVk, mShaderSources, mVariableInfoMap,
&mShaderInfo.getSpirvBlobs()));
}
ASSERT(mShaderInfo.valid());
......@@ -314,6 +314,7 @@ class ProgramVk : public ProgramImpl
angle::Result initShaders(ContextVk *contextVk,
const gl::ShaderMap<std::string> &shaderSources,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut);
void release(ContextVk *contextVk);
......@@ -350,10 +351,12 @@ class ProgramVk : public ProgramImpl
ProgramInfo mDefaultProgramInfo;
ProgramInfo mLineRasterProgramInfo;
// We keep the translated linked shader sources to use with shader draw call compilation.
// We keep the translated linked shader sources and the expected location/set/binding mapping to
// use with shader draw call compilation.
// TODO(syoussefi): Remove when shader compilation is done at link time.
// http://anglebug.com/3394
gl::ShaderMap<std::string> mShaderSources;
ShaderInterfaceVariableInfoMap mVariableInfoMap;
// We keep the SPIR-V code to use for draw call pipeline creation.
ShaderInfo mShaderInfo;
......
......@@ -563,6 +563,11 @@ RendererVk::RendererVk()
{
VkFormatProperties invalid = {0, 0, kInvalidFormatFeatureFlags};
mFormatProperties.fill(invalid);
// We currently don't have any big-endian devices in the list of supported platforms. There are
// a number of places in the Vulkan backend that make this assumption. This assertion is made
// early to fail immediately on big-endian platforms.
ASSERT(IsLittleEndian());
}
RendererVk::~RendererVk()
......
......@@ -108,9 +108,7 @@ uint32_t GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters &params)
// is not added to the build configuration file (to reduce binary size). If necessary, add
// IsBigEndian to ConvertVertex.comp.json and select the appropriate flag based on the
// endian-ness test here.
uint32_t endiannessTest = 0;
*reinterpret_cast<uint8_t *>(&endiannessTest) = 1;
ASSERT(endiannessTest == 1);
ASSERT(IsLittleEndian());
uint32_t flags = 0;
......
......@@ -102,7 +102,7 @@ TEST_F(EmulateGLBaseVertexBaseInstanceTest, EmulatesUniform)
#ifdef ANGLE_ENABLE_VULKAN
EXPECT_TRUE(foundInCode(
SH_GLSL_VULKAN_OUTPUT,
"uniform defaultUniforms\n{\n int angle_BaseInstance;\n int angle_BaseVertex;"));
"uniform defaultUniformsVS\n{\n int angle_BaseInstance;\n int angle_BaseVertex;"));
#endif
#ifdef ANGLE_ENABLE_HLSL
EXPECT_TRUE(foundInCode(SH_HLSL_3_0_OUTPUT, "uniform int angle_BaseVertex : register"));
......
......@@ -97,7 +97,7 @@ TEST_F(EmulateGLDrawIDTest, EmulatesUniform)
#ifdef ANGLE_ENABLE_VULKAN
EXPECT_TRUE(
foundInCode(SH_GLSL_VULKAN_OUTPUT, "uniform defaultUniforms\n{\n int angle_DrawID;"));
foundInCode(SH_GLSL_VULKAN_OUTPUT, "uniform defaultUniformsVS\n{\n int angle_DrawID;"));
#endif
#ifdef ANGLE_ENABLE_HLSL
EXPECT_TRUE(foundInCode(SH_HLSL_3_0_OUTPUT, "uniform int angle_DrawID : register"));
......
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