Commit b36e46ab by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Line raster emulation through specialization constant

In preparation for compiling shaders early at link time, this change reworks line raster emulation such that it uses specialization constants instead of a preprocessor condition. This means drawing both triangles and lines with this program will still result in a one-time shader compilation. The compilation is still done at draw time in this change. Bug: angleproject:3394 Change-Id: I0bf91398868d7f7147456533b728906b505192b2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1992365 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 6d6b91a6
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 222 #define ANGLE_SH_VERSION 223
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -732,6 +732,20 @@ inline bool IsDesktopGLSpec(ShShaderSpec spec) ...@@ -732,6 +732,20 @@ inline bool IsDesktopGLSpec(ShShaderSpec spec)
{ {
return spec == SH_GL_CORE_SPEC || spec == SH_GL_COMPATIBILITY_SPEC; return spec == SH_GL_CORE_SPEC || spec == SH_GL_COMPATIBILITY_SPEC;
} }
namespace vk
{
// Specialization constant ids
enum class SpecializationConstantId : uint32_t
{
LineRasterEmulation = 0,
InvalidEnum = 1,
EnumCount = 1,
};
} // namespace vk
} // namespace sh } // namespace sh
#endif // GLSLANG_SHADERLANG_H_ #endif // GLSLANG_SHADERLANG_H_
...@@ -161,6 +161,10 @@ constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDept ...@@ -161,6 +161,10 @@ constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDept
constexpr ImmutableString kUniformsBlockName = ImmutableString("ANGLEUniformBlock"); constexpr ImmutableString kUniformsBlockName = ImmutableString("ANGLEUniformBlock");
constexpr ImmutableString kUniformsVarName = ImmutableString("ANGLEUniforms"); constexpr ImmutableString kUniformsVarName = ImmutableString("ANGLEUniforms");
// Specialization constant names
constexpr ImmutableString kLineRasterEmulationSpecConstVarName =
ImmutableString("ANGLELineRasterEmulation");
constexpr const char kViewport[] = "viewport"; constexpr const char kViewport[] = "viewport";
constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight"; constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char kViewportYScale[] = "viewportYScale"; constexpr const char kViewportYScale[] = "viewportYScale";
...@@ -421,25 +425,18 @@ const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTab ...@@ -421,25 +425,18 @@ const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTab
kUniformsVarName); kUniformsVarName);
} }
TIntermPreprocessorDirective *GenerateLineRasterIfDef() TIntermSymbol *GenerateLineRasterSpecConstRef(TSymbolTable *symbolTable)
{ {
return new TIntermPreprocessorDirective( TVariable *specConstVar =
PreprocessorDirective::Ifdef, ImmutableString("ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION")); new TVariable(symbolTable, kLineRasterEmulationSpecConstVarName,
} StaticType::GetBasic<EbtBool>(), SymbolType::AngleInternal);
return new TIntermSymbol(specConstVar);
TIntermPreprocessorDirective *GenerateEndIf()
{
return new TIntermPreprocessorDirective(PreprocessorDirective::Endif, kEmptyImmutableString);
} }
TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root, TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
TQualifier qualifier) TQualifier qualifier)
{ {
TIntermSequence *insertSequence = new TIntermSequence;
insertSequence->push_back(GenerateLineRasterIfDef());
// Define a driver varying vec2 "ANGLEPosition". // Define a driver varying vec2 "ANGLEPosition".
TType *varyingType = new TType(EbtFloat, EbpMedium, qualifier, 2); TType *varyingType = new TType(EbtFloat, EbpMedium, qualifier, 2);
TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEPosition"), TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEPosition"),
...@@ -447,9 +444,9 @@ TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root, ...@@ -447,9 +444,9 @@ TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
TIntermSymbol *varyingDeclarator = new TIntermSymbol(varyingVar); TIntermSymbol *varyingDeclarator = new TIntermSymbol(varyingVar);
TIntermDeclaration *varyingDecl = new TIntermDeclaration; TIntermDeclaration *varyingDecl = new TIntermDeclaration;
varyingDecl->appendDeclarator(varyingDeclarator); varyingDecl->appendDeclarator(varyingDeclarator);
insertSequence->push_back(varyingDecl);
insertSequence->push_back(GenerateEndIf()); TIntermSequence *insertSequence = new TIntermSequence;
insertSequence->push_back(varyingDecl);
// Insert the declarations before Main. // Insert the declarations before Main.
size_t mainIndex = FindMainIndex(root); size_t mainIndex = FindMainIndex(root);
...@@ -514,15 +511,18 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationVS(TCompiler *compiler, ...@@ -514,15 +511,18 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationVS(TCompiler *compiler,
TIntermSymbol *varyingRef = new TIntermSymbol(anglePosition); TIntermSymbol *varyingRef = new TIntermSymbol(anglePosition);
TIntermBinary *varyingAssign = new TIntermBinary(EOpAssign, varyingRef, clampedNDC); TIntermBinary *varyingAssign = new TIntermBinary(EOpAssign, varyingRef, clampedNDC);
TIntermBlock *emulationBlock = new TIntermBlock;
emulationBlock->appendStatement(ndcDecl);
emulationBlock->appendStatement(windowDecl);
emulationBlock->appendStatement(clampedDecl);
emulationBlock->appendStatement(varyingAssign);
TIntermIfElse *ifEmulation =
new TIntermIfElse(GenerateLineRasterSpecConstRef(symbolTable), emulationBlock, nullptr);
// Ensure the statements run at the end of the main() function. // Ensure the statements run at the end of the main() function.
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
TIntermBlock *mainBody = main->getBody(); TIntermBlock *mainBody = main->getBody();
mainBody->appendStatement(GenerateLineRasterIfDef()); mainBody->appendStatement(ifEmulation);
mainBody->appendStatement(ndcDecl);
mainBody->appendStatement(windowDecl);
mainBody->appendStatement(clampedDecl);
mainBody->appendStatement(varyingAssign);
mainBody->appendStatement(GenerateEndIf());
return compiler->validateAST(root); return compiler->validateAST(root);
} }
...@@ -538,9 +538,9 @@ ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler, ...@@ -538,9 +538,9 @@ ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler,
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot); BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
} }
// This block adds OpenGL line segment rasterization emulation behind #ifdef guards. // This block adds OpenGL line segment rasterization emulation behind a specialization constant
// OpenGL's simple rasterization algorithm is a strict subset of the pixels generated by the Vulkan // guard. OpenGL's simple rasterization algorithm is a strict subset of the pixels generated by the
// algorithm. Thus we can implement a shader patch that rejects pixels if they would not be // Vulkan algorithm. Thus we can implement a shader patch that rejects pixels if they would not be
// generated by the OpenGL algorithm. OpenGL's algorithm is similar to Bresenham's line algorithm. // generated by the OpenGL algorithm. OpenGL's algorithm is similar to Bresenham's line algorithm.
// It is implemented for each pixel by testing if the line segment crosses a small diamond inside // It is implemented for each pixel by testing if the line segment crosses a small diamond inside
// the pixel. See the OpenGL ES 2.0 spec section "3.4.1 Basic Line Segment Rasterization". Also // the pixel. See the OpenGL ES 2.0 spec section "3.4.1 Basic Line Segment Rasterization". Also
...@@ -652,25 +652,33 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationFS(TCompiler *compiler, ...@@ -652,25 +652,33 @@ ANGLE_NO_DISCARD bool AddBresenhamEmulationFS(TCompiler *compiler,
discardBlock->appendStatement(discard); discardBlock->appendStatement(discard);
TIntermIfElse *ifStatement = new TIntermIfElse(checkXY, discardBlock, nullptr); TIntermIfElse *ifStatement = new TIntermIfElse(checkXY, discardBlock, nullptr);
TIntermBlock *emulationBlock = new TIntermBlock;
TIntermSequence *emulationSequence = emulationBlock->getSequence();
std::array<TIntermNode *, 8> nodes = {
{pDecl, dDecl, fDecl, p_decl, d_decl, f_decl, iDecl, ifStatement}};
emulationSequence->insert(emulationSequence->begin(), nodes.begin(), nodes.end());
TIntermIfElse *ifEmulation =
new TIntermIfElse(GenerateLineRasterSpecConstRef(symbolTable), emulationBlock, nullptr);
// Ensure the line raster code runs at the beginning of main(). // Ensure the line raster code runs at the beginning of main().
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
TIntermSequence *mainSequence = main->getBody()->getSequence(); TIntermSequence *mainSequence = main->getBody()->getSequence();
ASSERT(mainSequence); ASSERT(mainSequence);
std::array<TIntermNode *, 9> nodes = { mainSequence->insert(mainSequence->begin(), ifEmulation);
{pDecl, dDecl, fDecl, p_decl, d_decl, f_decl, iDecl, ifStatement, GenerateEndIf()}};
mainSequence->insert(mainSequence->begin(), nodes.begin(), nodes.end());
// If the shader does not use frag coord, we should insert it inside the ifdef. // If the shader does not use frag coord, we should insert it inside the emulation if.
if (!usesFragCoord) if (!usesFragCoord)
{ {
if (!InsertFragCoordCorrection(compiler, root, mainSequence, symbolTable, driverUniforms)) if (!InsertFragCoordCorrection(compiler, root, emulationSequence, symbolTable,
driverUniforms))
{ {
return false; return false;
} }
} }
mainSequence->insert(mainSequence->begin(), GenerateLineRasterIfDef());
return compiler->validateAST(root); return compiler->validateAST(root);
} }
...@@ -819,6 +827,15 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -819,6 +827,15 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{ {
return false; return false;
} }
// Add specialization constant declarations. The default value of the specialization
// constant is irrelevant, as it will be set when creating the pipeline.
if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
{
sink << "layout(constant_id="
<< static_cast<uint32_t>(vk::SpecializationConstantId::LineRasterEmulation)
<< ") const bool " << kLineRasterEmulationSpecConstVarName << " = false;\n\n";
}
} }
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
......
...@@ -56,11 +56,6 @@ constexpr char kParamsEnd = ')'; ...@@ -56,11 +56,6 @@ constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform"; constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer"; constexpr char kSSBOQualifier[] = "buffer";
constexpr char kUnusedUniformSubstitution[] = "// "; constexpr char kUnusedUniformSubstitution[] = "// ";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
#define ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION
)";
constexpr uint32_t kANGLEPositionLocationOffset = 1; constexpr uint32_t kANGLEPositionLocationOffset = 1;
constexpr uint32_t kXfbANGLEPositionLocationOffset = 2; constexpr uint32_t kXfbANGLEPositionLocationOffset = 2;
...@@ -1082,7 +1077,7 @@ constexpr gl::ShaderMap<EShLanguage> kShLanguageMap = { ...@@ -1082,7 +1077,7 @@ constexpr gl::ShaderMap<EShLanguage> kShLanguageMap = {
angle::Result GetShaderSpirvCode(GlslangErrorCallback callback, angle::Result GetShaderSpirvCode(GlslangErrorCallback callback,
const gl::Caps &glCaps, const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
{ {
// Enable SPIR-V and Vulkan rules when parsing GLSL // Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules); EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
...@@ -1144,7 +1139,7 @@ angle::Result GetShaderSpirvCode(GlslangErrorCallback callback, ...@@ -1144,7 +1139,7 @@ angle::Result GetShaderSpirvCode(GlslangErrorCallback callback,
} }
glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]); glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
glslang::GlslangToSpv(*intermediate, (*shaderCodeOut)[shaderType]); glslang::GlslangToSpv(*intermediate, (*spirvBlobsOut)[shaderType]);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1270,33 +1265,9 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options, ...@@ -1270,33 +1265,9 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
angle::Result GlslangGetShaderSpirvCode(GlslangErrorCallback callback, angle::Result GlslangGetShaderSpirvCode(GlslangErrorCallback callback,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
{ {
if (enableLineRasterEmulation) return GetShaderSpirvCode(callback, glCaps, shaderSources, spirvBlobsOut);
{
ASSERT(shaderSources[gl::ShaderType::Compute].empty());
gl::ShaderMap<std::string> patchedSources = shaderSources;
for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
{
if (!shaderSources[shaderType].empty())
{
// #defines must come after the #version directive.
ANGLE_GLSLANG_CHECK(callback,
angle::ReplaceSubstring(&patchedSources[shaderType],
kVersionDefine, kLineRasterDefine),
GlslangError::InvalidShader);
}
}
return GetShaderSpirvCode(callback, glCaps, patchedSources, shaderCodeOut);
}
else
{
return GetShaderSpirvCode(callback, glCaps, shaderSources, shaderCodeOut);
}
} }
} // namespace rx } // namespace rx
...@@ -39,6 +39,8 @@ struct GlslangSourceOptions ...@@ -39,6 +39,8 @@ struct GlslangSourceOptions
bool emulateTransformFeedback = false; bool emulateTransformFeedback = false;
}; };
using SpirvBlob = std::vector<uint32_t>;
using GlslangErrorCallback = std::function<angle::Result(GlslangError)>; using GlslangErrorCallback = std::function<angle::Result(GlslangError)>;
void GlslangInitialize(); void GlslangInitialize();
...@@ -56,9 +58,8 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options, ...@@ -56,9 +58,8 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
angle::Result GlslangGetShaderSpirvCode(GlslangErrorCallback callback, angle::Result GlslangGetShaderSpirvCode(GlslangErrorCallback callback,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut); gl::ShaderMap<SpirvBlob> *spirvBlobsOut);
} // namespace rx } // namespace rx
......
...@@ -312,8 +312,8 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, gl::InfoLog &in ...@@ -312,8 +312,8 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, gl::InfoLog &in
// Convert GLSL to spirv code // Convert GLSL to spirv code
gl::ShaderMap<std::vector<uint32_t>> shaderCodes; gl::ShaderMap<std::vector<uint32_t>> shaderCodes;
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, contextMtl->getCaps(), false, ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, contextMtl->getCaps(), mShaderSource,
mShaderSource, &shaderCodes)); &shaderCodes));
// Convert spirv code to MSL // Convert spirv code to MSL
ANGLE_TRY(convertToMsl(glContext, gl::ShaderType::Vertex, infoLog, ANGLE_TRY(convertToMsl(glContext, gl::ShaderType::Vertex, infoLog,
......
...@@ -24,7 +24,6 @@ void GlslangGetShaderSource(const gl::ProgramState &programState, ...@@ -24,7 +24,6 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut); gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
} // namespace mtl } // namespace mtl
......
...@@ -50,13 +50,12 @@ void GlslangGetShaderSource(const gl::ProgramState &programState, ...@@ -50,13 +50,12 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{ {
return rx::GlslangGetShaderSpirvCode( return rx::GlslangGetShaderSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, glCaps, [context](GlslangError error) { return HandleError(context, error); }, glCaps,
enableLineRasterEmulation, shaderSources, shaderCodeOut); shaderSources, shaderCodeOut);
} }
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
...@@ -51,12 +51,11 @@ void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features, ...@@ -51,12 +51,11 @@ void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features,
// static // static
angle::Result GlslangWrapperVk::GetShaderCode(vk::Context *context, angle::Result GlslangWrapperVk::GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{ {
return GlslangGetShaderSpirvCode( return GlslangGetShaderSpirvCode(
[context](GlslangError error) { return ErrorHandler(context, error); }, glCaps, [context](GlslangError error) { return ErrorHandler(context, error); }, glCaps,
enableLineRasterEmulation, shaderSources, shaderCodeOut); shaderSources, shaderCodeOut);
} }
} // namespace rx } // namespace rx
...@@ -31,7 +31,6 @@ class GlslangWrapperVk ...@@ -31,7 +31,6 @@ class GlslangWrapperVk
static angle::Result GetShaderCode(vk::Context *context, static angle::Result GetShaderCode(vk::Context *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut); gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
}; };
......
...@@ -366,56 +366,99 @@ ProgramVk::ShaderInfo::~ShaderInfo() = default; ...@@ -366,56 +366,99 @@ ProgramVk::ShaderInfo::~ShaderInfo() = default;
angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk, angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
bool enableLineRasterEmulation) gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
{ {
ASSERT(!valid()); ASSERT(!valid());
gl::ShaderMap<std::vector<uint32_t>> shaderCodes; ANGLE_TRY(GlslangWrapperVk::GetShaderCode(contextVk, contextVk->getCaps(), shaderSources,
ANGLE_TRY(GlslangWrapperVk::GetShaderCode( spirvBlobsOut));
contextVk, contextVk->getCaps(), enableLineRasterEmulation, shaderSources, &shaderCodes));
mIsInitialized = true;
return angle::Result::Continue;
}
void ProgramVk::ShaderInfo::release(ContextVk *contextVk)
{
for (SpirvBlob &spirvBlob : mSpirvBlobs)
{
spirvBlob.clear();
}
mIsInitialized = false;
}
// ProgramVk::ProgramInfo implementation.
ProgramVk::ProgramInfo::ProgramInfo() {}
ProgramVk::ProgramInfo::~ProgramInfo() = default;
angle::Result ProgramVk::ProgramInfo::initProgram(ContextVk *contextVk,
const ShaderInfo &shaderInfo,
bool enableLineRasterEmulation)
{
const gl::ShaderMap<SpirvBlob> &spirvBlobs = shaderInfo.getSpirvBlobs();
for (const gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
if (!shaderSources[shaderType].empty()) const SpirvBlob &spirvBlob = spirvBlobs[shaderType];
if (!spirvBlob.empty())
{ {
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(), ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
shaderCodes[shaderType].data(), spirvBlob.data(),
shaderCodes[shaderType].size() * sizeof(uint32_t))); spirvBlob.size() * sizeof(uint32_t)));
mProgramHelper.setShader(shaderType, &mShaders[shaderType]); mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
} }
} }
if (enableLineRasterEmulation)
{
mProgramHelper.enableSpecializationConstant(
sh::vk::SpecializationConstantId::LineRasterEmulation);
}
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream) void ProgramVk::ProgramInfo::release(ContextVk *contextVk)
{
mProgramHelper.release(contextVk);
for (vk::RefCounted<vk::ShaderAndSerial> &shader : mShaders)
{
shader.get().destroy(contextVk->getDevice());
}
}
angle::Result ProgramVk::loadSpirvBlob(ContextVk *contextVk, gl::BinaryInputStream *stream)
{ {
// Read in shader sources for all shader types // Read in shader codes for all shader types
for (const gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
// Read the shader source
mShaderSources[shaderType] = stream->readString(); mShaderSources[shaderType] = stream->readString();
SpirvBlob *spirvBlob = &mShaderInfo.getSpirvBlobs()[shaderType];
// Read the SPIR-V
stream->readIntVector<uint32_t>(spirvBlob);
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream) void ProgramVk::saveSpirvBlob(gl::BinaryOutputStream *stream)
{ {
// Write out shader sources for all shader types // Write out shader codes for all shader types
for (const gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
// Write the shader source
stream->writeString(mShaderSources[shaderType]); stream->writeString(mShaderSources[shaderType]);
}
}
void ProgramVk::ShaderInfo::release(ContextVk *contextVk) const SpirvBlob &spirvBlob = mShaderInfo.getSpirvBlobs()[shaderType];
{
mProgramHelper.release(contextVk);
for (vk::RefCounted<vk::ShaderAndSerial> &shader : mShaders) // Write the SPIR-V
{ stream->writeIntVector(spirvBlob);
shader.get().destroy(contextVk->getDevice());
} }
} }
...@@ -455,8 +498,9 @@ void ProgramVk::reset(ContextVk *contextVk) ...@@ -455,8 +498,9 @@ void ProgramVk::reset(ContextVk *contextVk)
uniformBlock.storage.release(renderer); uniformBlock.storage.release(renderer);
} }
mDefaultShaderInfo.release(contextVk); mShaderInfo.release(contextVk);
mLineRasterShaderInfo.release(contextVk); mDefaultProgramInfo.release(contextVk);
mLineRasterProgramInfo.release(contextVk);
mEmptyBuffer.release(renderer); mEmptyBuffer.release(renderer);
...@@ -485,7 +529,7 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context, ...@@ -485,7 +529,7 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
gl::ShaderMap<size_t> requiredBufferSize; gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0); requiredBufferSize.fill(0);
angle::Result status = loadShaderSource(contextVk, stream); angle::Result status = loadSpirvBlob(contextVk, stream);
if (status != angle::Result::Continue) if (status != angle::Result::Continue)
{ {
return std::make_unique<LinkEventDone>(status); return std::make_unique<LinkEventDone>(status);
...@@ -525,7 +569,7 @@ void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream) ...@@ -525,7 +569,7 @@ void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
{ {
// (geofflang): Look into saving shader modules in ShaderInfo objects (keep in mind that we // (geofflang): Look into saving shader modules in ShaderInfo objects (keep in mind that we
// compile shaders lazily) // compile shaders lazily)
saveShaderSource(stream); saveSpirvBlob(stream);
// Serializes the uniformLayout data of mDefaultUniformBlocks // Serializes the uniformLayout data of mDefaultUniformBlocks
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (gl::ShaderType shaderType : gl::AllShaderTypes())
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h" #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
...@@ -140,7 +141,7 @@ class ProgramVk : public ProgramImpl ...@@ -140,7 +141,7 @@ class ProgramVk : public ProgramImpl
vk::PipelineHelper **pipelineOut) vk::PipelineHelper **pipelineOut)
{ {
vk::ShaderProgramHelper *shaderProgram; vk::ShaderProgramHelper *shaderProgram;
ANGLE_TRY(initGraphicsShaders(contextVk, mode, &shaderProgram)); ANGLE_TRY(initGraphicsProgram(contextVk, mode, &shaderProgram));
ASSERT(shaderProgram->isGraphicsProgram()); ASSERT(shaderProgram->isGraphicsProgram());
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
vk::PipelineCache *pipelineCache = nullptr; vk::PipelineCache *pipelineCache = nullptr;
...@@ -154,7 +155,7 @@ class ProgramVk : public ProgramImpl ...@@ -154,7 +155,7 @@ class ProgramVk : public ProgramImpl
angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut) angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut)
{ {
vk::ShaderProgramHelper *shaderProgram; vk::ShaderProgramHelper *shaderProgram;
ANGLE_TRY(initComputeShader(contextVk, &shaderProgram)); ANGLE_TRY(initComputeProgram(contextVk, &shaderProgram));
ASSERT(!shaderProgram->isGraphicsProgram()); ASSERT(!shaderProgram->isGraphicsProgram());
return shaderProgram->getComputePipeline(contextVk, mPipelineLayout.get(), pipelineOut); return shaderProgram->getComputePipeline(contextVk, mPipelineLayout.get(), pipelineOut);
} }
...@@ -212,45 +213,54 @@ class ProgramVk : public ProgramImpl ...@@ -212,45 +213,54 @@ class ProgramVk : public ProgramImpl
} }
uint32_t getImageBindingsOffset() const { return mImageBindingsOffset; } uint32_t getImageBindingsOffset() const { return mImageBindingsOffset; }
class ShaderInfo; class ProgramInfo;
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk, ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk,
bool enableLineRasterEmulation, bool enableLineRasterEmulation,
ShaderInfo *shaderInfo, ProgramInfo *programInfo,
vk::ShaderProgramHelper **shaderProgramOut) vk::ShaderProgramHelper **shaderProgramOut)
{ {
if (!shaderInfo->valid()) // Compile shaders if not already. This is done only once regardless of specialization
// constants.
if (!mShaderInfo.valid())
{ {
ANGLE_TRY( ANGLE_TRY(
shaderInfo->initShaders(contextVk, mShaderSources, enableLineRasterEmulation)); mShaderInfo.initShaders(contextVk, mShaderSources, &mShaderInfo.getSpirvBlobs()));
} }
ASSERT(mShaderInfo.valid());
ASSERT(shaderInfo->valid()); // Create the program pipeline. This is done lazily and once per combination of
*shaderProgramOut = &shaderInfo->getShaderProgram(); // specialization constants.
if (!programInfo->valid())
{
ANGLE_TRY(programInfo->initProgram(contextVk, mShaderInfo, enableLineRasterEmulation));
}
ASSERT(programInfo->valid());
*shaderProgramOut = programInfo->getShaderProgram();
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_INLINE angle::Result initGraphicsShaders(ContextVk *contextVk, ANGLE_INLINE angle::Result initGraphicsProgram(ContextVk *contextVk,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
vk::ShaderProgramHelper **shaderProgramOut) vk::ShaderProgramHelper **shaderProgramOut)
{ {
bool enableLineRasterEmulation = UseLineRaster(contextVk, mode); bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
ShaderInfo &shaderInfo = ProgramInfo &programInfo =
enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo; enableLineRasterEmulation ? mLineRasterProgramInfo : mDefaultProgramInfo;
return initShaders(contextVk, enableLineRasterEmulation, &shaderInfo, shaderProgramOut); return initProgram(contextVk, enableLineRasterEmulation, &programInfo, shaderProgramOut);
} }
ANGLE_INLINE angle::Result initComputeShader(ContextVk *contextVk, ANGLE_INLINE angle::Result initComputeProgram(ContextVk *contextVk,
vk::ShaderProgramHelper **shaderProgramOut) vk::ShaderProgramHelper **shaderProgramOut)
{ {
return initShaders(contextVk, false, &mDefaultShaderInfo, shaderProgramOut); return initProgram(contextVk, false, &mDefaultProgramInfo, shaderProgramOut);
} }
// Save and load implementation for GLES Program Binary support. // Save and load implementation for GLES Program Binary support.
angle::Result loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream); angle::Result loadSpirvBlob(ContextVk *contextVk, gl::BinaryInputStream *stream);
void saveShaderSource(gl::BinaryOutputStream *stream); void saveSpirvBlob(gl::BinaryOutputStream *stream);
// State for the default uniform blocks. // State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable struct DefaultUniformBlock final : private angle::NonCopyable
...@@ -304,27 +314,48 @@ class ProgramVk : public ProgramImpl ...@@ -304,27 +314,48 @@ class ProgramVk : public ProgramImpl
angle::Result initShaders(ContextVk *contextVk, angle::Result initShaders(ContextVk *contextVk,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut);
void release(ContextVk *contextVk);
ANGLE_INLINE bool valid() const { return mIsInitialized; }
gl::ShaderMap<SpirvBlob> &getSpirvBlobs() { return mSpirvBlobs; }
const gl::ShaderMap<SpirvBlob> &getSpirvBlobs() const { return mSpirvBlobs; }
private:
gl::ShaderMap<SpirvBlob> mSpirvBlobs;
bool mIsInitialized = false;
};
class ProgramInfo final : angle::NonCopyable
{
public:
ProgramInfo();
~ProgramInfo();
angle::Result initProgram(ContextVk *contextVk,
const ShaderInfo &shaderInfo,
bool enableLineRasterEmulation); bool enableLineRasterEmulation);
void release(ContextVk *contextVk); void release(ContextVk *contextVk);
ANGLE_INLINE bool valid() const ANGLE_INLINE bool valid() const { return mProgramHelper.valid(); }
{
return mShaders[gl::ShaderType::Vertex].get().valid() ||
mShaders[gl::ShaderType::Compute].get().valid();
}
vk::ShaderProgramHelper &getShaderProgram() { return mProgramHelper; } vk::ShaderProgramHelper *getShaderProgram() { return &mProgramHelper; }
private: private:
vk::ShaderProgramHelper mProgramHelper; vk::ShaderProgramHelper mProgramHelper;
gl::ShaderMap<vk::RefCounted<vk::ShaderAndSerial>> mShaders; gl::ShaderMap<vk::RefCounted<vk::ShaderAndSerial>> mShaders;
}; };
ShaderInfo mDefaultShaderInfo; ProgramInfo mDefaultProgramInfo;
ShaderInfo mLineRasterShaderInfo; ProgramInfo mLineRasterProgramInfo;
// We keep the translated linked shader sources to use with shader draw call patching. // We keep the translated linked shader sources 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; gl::ShaderMap<std::string> mShaderSources;
// We keep the SPIR-V code to use for draw call pipeline creation.
ShaderInfo mShaderInfo;
// In their descriptor set, uniform buffers are placed first, then storage buffers, then atomic // In their descriptor set, uniform buffers are placed first, then storage buffers, then atomic
// counter buffers and then images. These cached values contain the offsets where storage // counter buffers and then images. These cached values contain the offsets where storage
......
...@@ -7,23 +7,24 @@ of steps: ...@@ -7,23 +7,24 @@ of steps:
shader translator][translator]. The translator compiles application shaders into Vulkan-compatible shader translator][translator]. The translator compiles application shaders into Vulkan-compatible
GLSL. Vulkan-compatible GLSL matches the [GL_KHR_vulkan_glsl][GL_KHR_vulkan_glsl] extension spec GLSL. Vulkan-compatible GLSL matches the [GL_KHR_vulkan_glsl][GL_KHR_vulkan_glsl] extension spec
with some additional workarounds and emulation. We emulate OpenGL's different depth range, viewport with some additional workarounds and emulation. We emulate OpenGL's different depth range, viewport
y flipping, default uniforms, and OpenGL [line segment y flipping, default uniforms, and OpenGL
rasterization](OpenGLLineSegmentRasterization.md). For more info see [line segment rasterization](OpenGLLineSegmentRasterization.md). For more info see
[TranslatorVulkan.cpp][TranslatorVulkan.cpp]. After initial compilation the shaders are not [TranslatorVulkan.cpp][TranslatorVulkan.cpp]. After initial compilation the shaders are not
complete. They are templated with markers that are filled in later at link time. complete. They are templated with markers that are filled in later at link time.
1. **Link-Time Translation**: During a call to `glLinkProgram` the Vulkan back-end can know the 1. **Link-Time Translation**: During a call to `glLinkProgram` the Vulkan back-end can know the
necessary locations and properties to write to connect the shader stage interfaces. We get the necessary locations and properties to write to connect the shader stage interfaces. We get the
completed shader source using ANGLE's [GlslangWrapperVk][GlslangWrapperVk.cpp] helper class. We still completed shader source using ANGLE's [GlslangWrapperVk][GlslangWrapperVk.cpp] helper class. We still
cannot generate `VkShaderModules` since some ANGLE features like [OpenGL line cannot generate `VkShaderModules` since some ANGLE features like
rasterization](OpenGLLineSegmentRasterization.md) emulation depend on draw-time information. [OpenGL line rasterization](OpenGLLineSegmentRasterization.md) emulation depend on draw-time
information.
1. **Draw-time SPIR-V Generation**: Once the application records a draw call we use Khronos' 1. **Draw-time SPIR-V Generation**: Once the application records a draw call we use Khronos'
[glslang][glslang] to convert the Vulkan-compatible GLSL into SPIR-V with the correct draw-time [glslang][glslang] to convert the Vulkan-compatible GLSL into SPIR-V. The SPIR-V is then compiled
defines. The SPIR-V is then compiled into `VkShaderModules`. For details please see into `VkShaderModules`. For details please see [GlslangWrapperVk.cpp][GlslangWrapperVk.cpp]. The
[GlslangWrapperVk.cpp][GlslangWrapperVk.cpp]. The `VkShaderModules` are then used by `VkPipelines`. Note `VkShaderModules` are then used by `VkPipelines` with the appropriate specialization constant
that we currently don't use [SPIRV-Tools][SPIRV-Tools] to perform any SPIR-V optimization. This values. Note that we currently don't use [SPIRV-Tools][SPIRV-Tools] to perform any SPIR-V
could be something to improve on in the future. optimization. This could be something to improve on in the future.
See the below diagram for a high-level view of the shader translation flow: See the below diagram for a high-level view of the shader translation flow:
......
...@@ -186,6 +186,7 @@ void UnpackBlendAttachmentState(const vk::PackedColorBlendAttachmentState &packe ...@@ -186,6 +186,7 @@ void UnpackBlendAttachmentState(const vk::PackedColorBlendAttachmentState &packe
void SetPipelineShaderStageInfo(const VkStructureType type, void SetPipelineShaderStageInfo(const VkStructureType type,
const VkShaderStageFlagBits stage, const VkShaderStageFlagBits stage,
const VkShaderModule module, const VkShaderModule module,
const VkSpecializationInfo &specializationInfo,
VkPipelineShaderStageCreateInfo *shaderStage) VkPipelineShaderStageCreateInfo *shaderStage)
{ {
shaderStage->sType = type; shaderStage->sType = type;
...@@ -193,7 +194,7 @@ void SetPipelineShaderStageInfo(const VkStructureType type, ...@@ -193,7 +194,7 @@ void SetPipelineShaderStageInfo(const VkStructureType type,
shaderStage->stage = stage; shaderStage->stage = stage;
shaderStage->module = module; shaderStage->module = module;
shaderStage->pName = "main"; shaderStage->pName = "main";
shaderStage->pSpecializationInfo = nullptr; shaderStage->pSpecializationInfo = &specializationInfo;
} }
angle::Result InitializeRenderPassFromDesc(vk::Context *context, angle::Result InitializeRenderPassFromDesc(vk::Context *context,
...@@ -294,6 +295,29 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -294,6 +295,29 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
void InitializeSpecializationInfo(
vk::SpecializationConstantBitSet specConsts,
vk::SpecializationConstantMap<VkSpecializationMapEntry> *specializationEntriesOut,
vk::SpecializationConstantMap<VkBool32> *specializationValuesOut,
VkSpecializationInfo *specializationInfoOut)
{
// Collect specialization constants.
for (const sh::vk::SpecializationConstantId id :
angle::AllEnums<sh::vk::SpecializationConstantId>())
{
const uint32_t offset = static_cast<uint32_t>(id);
(*specializationValuesOut)[id] = specConsts.test(id);
(*specializationEntriesOut)[id].constantID = offset;
(*specializationEntriesOut)[id].offset = offset;
(*specializationEntriesOut)[id].size = sizeof(VkBool32);
}
specializationInfoOut->mapEntryCount = static_cast<uint32_t>(specializationEntriesOut->size());
specializationInfoOut->pMapEntries = specializationEntriesOut->data();
specializationInfoOut->dataSize = specializationEntriesOut->size() * sizeof(VkBool32);
specializationInfoOut->pData = specializationValuesOut->data();
}
// Utility for setting a value on a packed 4-bit integer array. // Utility for setting a value on a packed 4-bit integer array.
template <typename SrcT> template <typename SrcT>
void Int4Array_Set(uint8_t *arrayBytes, uint32_t arrayIndex, SrcT value) void Int4Array_Set(uint8_t *arrayBytes, uint32_t arrayIndex, SrcT value)
...@@ -617,6 +641,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -617,6 +641,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
const ShaderModule *vertexModule, const ShaderModule *vertexModule,
const ShaderModule *fragmentModule, const ShaderModule *fragmentModule,
const ShaderModule *geometryModule, const ShaderModule *geometryModule,
vk::SpecializationConstantBitSet specConsts,
Pipeline *pipelineOut) const Pipeline *pipelineOut) const
{ {
angle::FixedVector<VkPipelineShaderStageCreateInfo, 3> shaderStages; angle::FixedVector<VkPipelineShaderStageCreateInfo, 3> shaderStages;
...@@ -629,13 +654,20 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -629,13 +654,20 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
std::array<VkPipelineColorBlendAttachmentState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> std::array<VkPipelineColorBlendAttachmentState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
blendAttachmentState; blendAttachmentState;
VkPipelineColorBlendStateCreateInfo blendState = {}; VkPipelineColorBlendStateCreateInfo blendState = {};
VkSpecializationInfo specializationInfo = {};
VkGraphicsPipelineCreateInfo createInfo = {}; VkGraphicsPipelineCreateInfo createInfo = {};
vk::SpecializationConstantMap<VkSpecializationMapEntry> specializationEntries;
vk::SpecializationConstantMap<VkBool32> specializationValues;
InitializeSpecializationInfo(specConsts, &specializationEntries, &specializationValues,
&specializationInfo);
// Vertex shader is always expected to be present. // Vertex shader is always expected to be present.
ASSERT(vertexModule != nullptr); ASSERT(vertexModule != nullptr);
VkPipelineShaderStageCreateInfo vertexStage = {}; VkPipelineShaderStageCreateInfo vertexStage = {};
SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
VK_SHADER_STAGE_VERTEX_BIT, vertexModule->getHandle(), &vertexStage); VK_SHADER_STAGE_VERTEX_BIT, vertexModule->getHandle(),
specializationInfo, &vertexStage);
shaderStages.push_back(vertexStage); shaderStages.push_back(vertexStage);
if (geometryModule) if (geometryModule)
...@@ -643,7 +675,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -643,7 +675,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
VkPipelineShaderStageCreateInfo geometryStage = {}; VkPipelineShaderStageCreateInfo geometryStage = {};
SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
VK_SHADER_STAGE_GEOMETRY_BIT, geometryModule->getHandle(), VK_SHADER_STAGE_GEOMETRY_BIT, geometryModule->getHandle(),
&geometryStage); specializationInfo, &geometryStage);
shaderStages.push_back(geometryStage); shaderStages.push_back(geometryStage);
} }
...@@ -654,7 +686,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -654,7 +686,7 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
VkPipelineShaderStageCreateInfo fragmentStage = {}; VkPipelineShaderStageCreateInfo fragmentStage = {};
SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
VK_SHADER_STAGE_FRAGMENT_BIT, fragmentModule->getHandle(), VK_SHADER_STAGE_FRAGMENT_BIT, fragmentModule->getHandle(),
&fragmentStage); specializationInfo, &fragmentStage);
shaderStages.push_back(fragmentStage); shaderStages.push_back(fragmentStage);
} }
...@@ -1754,6 +1786,7 @@ angle::Result GraphicsPipelineCache::insertPipeline( ...@@ -1754,6 +1786,7 @@ angle::Result GraphicsPipelineCache::insertPipeline(
const vk::ShaderModule *vertexModule, const vk::ShaderModule *vertexModule,
const vk::ShaderModule *fragmentModule, const vk::ShaderModule *fragmentModule,
const vk::ShaderModule *geometryModule, const vk::ShaderModule *geometryModule,
vk::SpecializationConstantBitSet specConsts,
const vk::GraphicsPipelineDesc &desc, const vk::GraphicsPipelineDesc &desc,
const vk::GraphicsPipelineDesc **descPtrOut, const vk::GraphicsPipelineDesc **descPtrOut,
vk::PipelineHelper **pipelineOut) vk::PipelineHelper **pipelineOut)
...@@ -1767,7 +1800,7 @@ angle::Result GraphicsPipelineCache::insertPipeline( ...@@ -1767,7 +1800,7 @@ angle::Result GraphicsPipelineCache::insertPipeline(
ANGLE_TRY(desc.initializePipeline(contextVk, pipelineCacheVk, compatibleRenderPass, ANGLE_TRY(desc.initializePipeline(contextVk, pipelineCacheVk, compatibleRenderPass,
pipelineLayout, activeAttribLocationsMask, pipelineLayout, activeAttribLocationsMask,
programAttribsTypeMask, vertexModule, fragmentModule, programAttribsTypeMask, vertexModule, fragmentModule,
geometryModule, &newPipeline)); geometryModule, specConsts, &newPipeline));
} }
// The Serial will be updated outside of this query. // The Serial will be updated outside of this query.
......
...@@ -363,6 +363,7 @@ class GraphicsPipelineDesc final ...@@ -363,6 +363,7 @@ class GraphicsPipelineDesc final
const ShaderModule *vertexModule, const ShaderModule *vertexModule,
const ShaderModule *fragmentModule, const ShaderModule *fragmentModule,
const ShaderModule *geometryModule, const ShaderModule *geometryModule,
vk::SpecializationConstantBitSet specConsts,
Pipeline *pipelineOut) const; Pipeline *pipelineOut) const;
// Vertex input state. For ES 3.1 this should be separated into binding and attribute. // Vertex input state. For ES 3.1 this should be separated into binding and attribute.
...@@ -829,6 +830,7 @@ class GraphicsPipelineCache final : angle::NonCopyable ...@@ -829,6 +830,7 @@ class GraphicsPipelineCache final : angle::NonCopyable
const vk::ShaderModule *vertexModule, const vk::ShaderModule *vertexModule,
const vk::ShaderModule *fragmentModule, const vk::ShaderModule *fragmentModule,
const vk::ShaderModule *geometryModule, const vk::ShaderModule *geometryModule,
vk::SpecializationConstantBitSet specConsts,
const vk::GraphicsPipelineDesc &desc, const vk::GraphicsPipelineDesc &desc,
const vk::GraphicsPipelineDesc **descPtrOut, const vk::GraphicsPipelineDesc **descPtrOut,
vk::PipelineHelper **pipelineOut) vk::PipelineHelper **pipelineOut)
...@@ -843,7 +845,8 @@ class GraphicsPipelineCache final : angle::NonCopyable ...@@ -843,7 +845,8 @@ class GraphicsPipelineCache final : angle::NonCopyable
return insertPipeline(contextVk, pipelineCacheVk, compatibleRenderPass, pipelineLayout, return insertPipeline(contextVk, pipelineCacheVk, compatibleRenderPass, pipelineLayout,
activeAttribLocationsMask, programAttribsTypeMask, vertexModule, activeAttribLocationsMask, programAttribsTypeMask, vertexModule,
fragmentModule, geometryModule, desc, descPtrOut, pipelineOut); fragmentModule, geometryModule, specConsts, desc, descPtrOut,
pipelineOut);
} }
private: private:
...@@ -856,6 +859,7 @@ class GraphicsPipelineCache final : angle::NonCopyable ...@@ -856,6 +859,7 @@ class GraphicsPipelineCache final : angle::NonCopyable
const vk::ShaderModule *vertexModule, const vk::ShaderModule *vertexModule,
const vk::ShaderModule *fragmentModule, const vk::ShaderModule *fragmentModule,
const vk::ShaderModule *geometryModule, const vk::ShaderModule *geometryModule,
vk::SpecializationConstantBitSet specConsts,
const vk::GraphicsPipelineDesc &desc, const vk::GraphicsPipelineDesc &desc,
const vk::GraphicsPipelineDesc **descPtrOut, const vk::GraphicsPipelineDesc **descPtrOut,
vk::PipelineHelper **pipelineOut); vk::PipelineHelper **pipelineOut);
......
...@@ -3565,8 +3565,7 @@ ShaderProgramHelper::~ShaderProgramHelper() = default; ...@@ -3565,8 +3565,7 @@ ShaderProgramHelper::~ShaderProgramHelper() = default;
bool ShaderProgramHelper::valid() const bool ShaderProgramHelper::valid() const
{ {
// This will need to be extended for compute shader support. return mShaders[gl::ShaderType::Vertex].valid() || mShaders[gl::ShaderType::Compute].valid();
return mShaders[gl::ShaderType::Vertex].valid();
} }
void ShaderProgramHelper::destroy(VkDevice device) void ShaderProgramHelper::destroy(VkDevice device)
...@@ -3594,6 +3593,13 @@ void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<Shader ...@@ -3594,6 +3593,13 @@ void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<Shader
mShaders[shaderType].set(shader); mShaders[shaderType].set(shader);
} }
void ShaderProgramHelper::enableSpecializationConstant(sh::vk::SpecializationConstantId id)
{
ASSERT(id < sh::vk::SpecializationConstantId::EnumCount);
mSpecializationConstants.set(id);
}
angle::Result ShaderProgramHelper::getComputePipeline(Context *context, angle::Result ShaderProgramHelper::getComputePipeline(Context *context,
const PipelineLayout &pipelineLayout, const PipelineLayout &pipelineLayout,
PipelineAndSerial **pipelineOut) PipelineAndSerial **pipelineOut)
......
...@@ -1196,6 +1196,7 @@ class ShaderProgramHelper : angle::NonCopyable ...@@ -1196,6 +1196,7 @@ class ShaderProgramHelper : angle::NonCopyable
ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); } ShaderAndSerial &getShader(gl::ShaderType shaderType) { return mShaders[shaderType].get(); }
void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader); void setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader);
void enableSpecializationConstant(sh::vk::SpecializationConstantId id);
// For getting a Pipeline and from the pipeline cache. // For getting a Pipeline and from the pipeline cache.
ANGLE_INLINE angle::Result getGraphicsPipeline( ANGLE_INLINE angle::Result getGraphicsPipeline(
...@@ -1227,7 +1228,7 @@ class ShaderProgramHelper : angle::NonCopyable ...@@ -1227,7 +1228,7 @@ class ShaderProgramHelper : angle::NonCopyable
return mGraphicsPipelines.getPipeline( return mGraphicsPipelines.getPipeline(
contextVk, pipelineCache, *compatibleRenderPass, pipelineLayout, contextVk, pipelineCache, *compatibleRenderPass, pipelineLayout,
activeAttribLocationsMask, programAttribsTypeMask, vertexShader, fragmentShader, activeAttribLocationsMask, programAttribsTypeMask, vertexShader, fragmentShader,
geometryShader, pipelineDesc, descPtrOut, pipelineOut); geometryShader, mSpecializationConstants, pipelineDesc, descPtrOut, pipelineOut);
} }
angle::Result getComputePipeline(Context *context, angle::Result getComputePipeline(Context *context,
...@@ -1240,6 +1241,9 @@ class ShaderProgramHelper : angle::NonCopyable ...@@ -1240,6 +1241,9 @@ class ShaderProgramHelper : angle::NonCopyable
// We should probably use PipelineHelper here so we can remove PipelineAndSerial. // We should probably use PipelineHelper here so we can remove PipelineAndSerial.
PipelineAndSerial mComputePipeline; PipelineAndSerial mComputePipeline;
// Specialization constants, currently only used by the graphics queue.
vk::SpecializationConstantBitSet mSpecializationConstants;
}; };
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include "GLSLANG/ShaderLang.h"
#include "common/FixedVector.h" #include "common/FixedVector.h"
#include "common/Optional.h" #include "common/Optional.h"
#include "common/PackedEnums.h" #include "common/PackedEnums.h"
...@@ -605,6 +606,13 @@ class Recycler final : angle::NonCopyable ...@@ -605,6 +606,13 @@ class Recycler final : angle::NonCopyable
std::vector<T> mObjectFreeList; std::vector<T> mObjectFreeList;
}; };
using SpecializationConstantBitSet =
angle::PackedEnumBitSet<sh::vk::SpecializationConstantId, uint32_t>;
static_assert(sizeof(SpecializationConstantBitSet) == sizeof(uint32_t), "Unexpected size");
template <typename T>
using SpecializationConstantMap = angle::PackedEnumMap<sh::vk::SpecializationConstantId, T>;
} // namespace vk } // namespace vk
namespace gl_vk namespace gl_vk
......
...@@ -534,6 +534,11 @@ ...@@ -534,6 +534,11 @@
// General Vulkan failures // General Vulkan failures
// ANGLEPosition location assignment overlaps other varyings. This only affects platforms that
// don't support the bresenham line raster extension, which in turn also depends on the driver
// versions.
4251 VULKAN NVIDIA : dEQP-GLES3.functional.shaders.linkage.varying.struct.float_uvec2_vec3 = FAIL
// Tests failing due to the "flat" qualifier in the shader: // Tests failing due to the "flat" qualifier in the shader:
3677 VULKAN : dEQP-GLES3.functional.fragment_out.basic.int.* = FAIL 3677 VULKAN : dEQP-GLES3.functional.fragment_out.basic.int.* = FAIL
3677 VULKAN : dEQP-GLES3.functional.fragment_out.basic.uint.* = FAIL 3677 VULKAN : dEQP-GLES3.functional.fragment_out.basic.uint.* = FAIL
......
...@@ -88,12 +88,14 @@ void VulkanPipelineCachePerfTest::step() ...@@ -88,12 +88,14 @@ void VulkanPipelineCachePerfTest::step()
gl::AttributesMask am; gl::AttributesMask am;
gl::ComponentTypeMask ctm; gl::ComponentTypeMask ctm;
vk::SpecializationConstantBitSet defaultSpecConsts;
for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration) for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
{ {
for (const auto &hit : mCacheHits) for (const auto &hit : mCacheHits)
{ {
(void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, ctm, &sm, &sm, nullptr, hit, (void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, ctm, &sm, &sm, nullptr,
&desc, &result); defaultSpecConsts, hit, &desc, &result);
} }
} }
...@@ -101,8 +103,8 @@ void VulkanPipelineCachePerfTest::step() ...@@ -101,8 +103,8 @@ void VulkanPipelineCachePerfTest::step()
++missCount, ++mMissIndex) ++missCount, ++mMissIndex)
{ {
const auto &miss = mCacheMisses[mMissIndex]; const auto &miss = mCacheMisses[mMissIndex];
(void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, ctm, &sm, &sm, nullptr, miss, (void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, ctm, &sm, &sm, nullptr,
&desc, &result); defaultSpecConsts, miss, &desc, &result);
} }
} }
......
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