Commit 776c6015 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Call glslang at compile time

With this change, the ANGLE translator immediately compiles the generated GLSL into SPIR-V with glslang and discards the source. This is in preparation for generating SPIR-V directly, by making the frontend and backend already able to digest it. This change also allows the expensive glslang calls to be parallelized, improving the following perf test by about 20%: LinkProgramBenchmark.Run/vulkan_compile_and_link_multi_thread Previously, the test was run as such in the Vulkan backend: Main Thread 1 Thread 2 Compile1 ---> Compile2 ---------------------> Translator Translator <--- <--------------------- Link glslang for shader1 glslang for shader2 Done With this change, it is run as such: Main Thread 1 Thread 2 Compile1 ---> Compile2 ---------------------> Translator Translator glslang glslang <--- <--------------------- Link Done glslang_wrapper_utils no longer interacts with glslang! A rename will follow. Bug: angleproject:4889 Change-Id: If4303e8ba0ba43b1a2f47f8c0a9133d0bee1a19a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2721195 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent eac2397b
......@@ -499,7 +499,8 @@ angle_static_library("translator") {
defines = []
_needs_glsl_base = false
needs_glsl_and_vulkan_base = false
_needs_glsl_and_vulkan_base = false
_uses_spirv = false
if (angle_enable_essl || use_fuzzing_engine) {
_needs_glsl_base = true
......@@ -509,7 +510,7 @@ angle_static_library("translator") {
if (angle_enable_glsl || use_fuzzing_engine) {
_needs_glsl_base = true
needs_glsl_and_vulkan_base = true
_needs_glsl_and_vulkan_base = true
sources += angle_translator_glsl_sources
if (is_apple) {
sources += angle_translator_glsl_mac_sources
......@@ -524,7 +525,7 @@ angle_static_library("translator") {
if (angle_enable_vulkan || use_fuzzing_engine || angle_enable_metal) {
_needs_glsl_base = true
needs_glsl_and_vulkan_base = true
_needs_glsl_and_vulkan_base = true
# This translator is needed by metal backend also.
sources += angle_translator_lib_vulkan_sources
......@@ -533,8 +534,9 @@ angle_static_library("translator") {
if (_needs_glsl_base) {
sources += angle_translator_glsl_base_sources
}
if (needs_glsl_and_vulkan_base) {
if (_needs_glsl_and_vulkan_base) {
sources += angle_translator_glsl_and_vulkan_base_sources
_uses_spirv = true
}
if (angle_enable_vulkan || use_fuzzing_engine) {
......@@ -557,6 +559,16 @@ angle_static_library("translator") {
":preprocessor",
]
if (_uses_spirv) {
deps += [
"$angle_root/src/common/spirv:angle_spirv_base",
"${angle_glslang_dir}:glslang_default_resource_limits_sources",
"${angle_glslang_dir}:glslang_lib_sources",
"${angle_spirv_tools_dir}:spvtools_headers",
"${angle_spirv_tools_dir}:spvtools_val",
]
}
public_deps = [
":angle_common",
":angle_translator_headers",
......@@ -718,10 +730,7 @@ if (angle_enable_vulkan || angle_enable_metal) {
"$angle_root/src/common/spirv:angle_spirv_base",
"$angle_root/src/common/spirv:angle_spirv_builder",
"$angle_root/src/common/spirv:angle_spirv_parser",
"${angle_glslang_dir}:glslang_default_resource_limits_sources",
"${angle_glslang_dir}:glslang_lib_sources",
"${angle_spirv_headers_dir}:spv_headers",
"${angle_spirv_tools_dir}:spvtools_headers",
]
}
}
......@@ -1179,6 +1188,17 @@ angle_executable("angle_shader_translator") {
sources = [ "samples/shader_translator/shader_translator.cpp" ]
deps = [ ":translator" ]
defines = []
if (angle_enable_vulkan) {
deps += [
"${angle_spirv_tools_dir}:spvtools_headers",
"${angle_spirv_tools_dir}:spvtools_val",
]
defines += [ "ANGLE_ENABLE_VULKAN" ]
}
}
if (angle_standalone || build_with_chromium) {
......
......@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 254
#define ANGLE_SH_VERSION 255
enum ShShaderSpec
{
......@@ -616,6 +616,7 @@ using ShHandle = void *;
namespace sh
{
using BinaryBlob = std::vector<uint32_t>;
//
// Driver must call this first, once, before doing any other compiler operations.
......@@ -678,7 +679,7 @@ void Destruct(ShHandle handle);
// compiling for WebGL - it is implied.
// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
// Can be queried by calling sh::GetInfoLog().
// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader, or SPIR-V binary.
// Can be queried by calling sh::GetObjectCode().
// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
// Can be queried by calling ShGetVariableInfo().
......@@ -702,11 +703,18 @@ ShShaderOutput GetShaderOutputType(const ShHandle handle);
// handle: Specifies the compiler
const std::string &GetInfoLog(const ShHandle handle);
// Returns null-terminated object code for a compiled shader.
// Returns null-terminated object code for a compiled shader. Only valid for output types that
// generate human-readable code (GLSL, ESSL or HLSL).
// Parameters:
// handle: Specifies the compiler
const std::string &GetObjectCode(const ShHandle handle);
// Returns object binary blob for a compiled shader. Only valid for output types that
// generate binary blob (SPIR-V).
// Parameters:
// handle: Specifies the compiler
const BinaryBlob &GetObjectBinaryBlob(const ShHandle handle);
// Returns a (original_name, hash) map containing all the user defined names in the shader,
// including variable names, function names, struct names, and struct field names.
// Parameters:
......@@ -912,6 +920,13 @@ extern const char kCoverageMaskEnabledConstName[];
// Specialization constant to emulate rasterizer discard.
extern const char kRasterizerDiscardEnabledConstName[];
} // namespace mtl
// For backends that use glslang (the Vulkan shader compiler), i.e. Vulkan and Metal, call these to
// initialize and finalize glslang itself. This can be called independently from Initialize() and
// Finalize().
void InitializeGlslang();
void FinalizeGlslang();
} // namespace sh
#endif // GLSLANG_SHADERLANG_H_
......@@ -15,6 +15,11 @@
#include <vector>
#include "angle_gl.h"
#if defined(ANGLE_ENABLE_VULKAN)
// SPIR-V tools include for disassembly.
# include <spirv-tools/libspirv.hpp>
#endif
//
// Return codes from main.
//
......@@ -44,6 +49,8 @@ static void FreeShaderSource(ShaderSource &source);
static bool ParseGLSLOutputVersion(const std::string &, ShShaderOutput *outResult);
static bool ParseIntValue(const std::string &, int emptyDefault, int *outValue);
static void PrintSpirv(const sh::BinaryBlob &blob);
//
// Set up the per compile resources
//
......@@ -81,6 +88,9 @@ int main(int argc, char *argv[])
ShShaderSpec spec = SH_GLES2_SPEC;
ShShaderOutput output = SH_ESSL_OUTPUT;
#if defined(ANGLE_ENABLE_VULKAN)
sh::InitializeGlslang();
#endif
sh::Initialize();
ShBuiltInResources resources;
......@@ -332,8 +342,16 @@ int main(int argc, char *argv[])
if (compiled && (compileOptions & SH_OBJECT_CODE))
{
LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE");
std::string code = sh::GetObjectCode(compiler);
puts(code.c_str());
if (output != SH_SPIRV_VULKAN_OUTPUT)
{
const std::string &code = sh::GetObjectCode(compiler);
puts(code.c_str());
}
else
{
const sh::BinaryBlob &blob = sh::GetObjectBinaryBlob(compiler);
PrintSpirv(blob);
}
LogMsg("END", "COMPILER", numCompiles, "OBJ CODE");
printf("\n\n");
}
......@@ -371,6 +389,9 @@ int main(int argc, char *argv[])
sh::Destruct(geometryCompiler);
sh::Finalize();
#if defined(ANGLE_ENABLE_VULKAN)
sh::FinalizeGlslang();
#endif
return failCode;
}
......@@ -400,7 +421,7 @@ void usage()
" -b=g : output GLSL code (compatibility profile)\n"
" -b=g[NUM]: output GLSL code (NUM can be 130, 140, 150, 330, 400, 410, 420, 430, "
"440, 450)\n"
" -b=v : output Vulkan GLSL code\n"
" -b=v : output Vulkan SPIR-V code\n"
" -b=h9 : output HLSL9 code\n"
" -b=h11 : output HLSL11 code\n"
" -x=i : enable GL_OES_EGL_image_external\n"
......@@ -848,3 +869,15 @@ static bool ParseIntValue(const std::string &num, int emptyDefault, int *outValu
*outValue = value;
return true;
}
static void PrintSpirv(const sh::BinaryBlob &blob)
{
#if defined(ANGLE_ENABLE_VULKAN)
spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
std::string readableSpirv;
spirvTools.Disassemble(blob, &readableSpirv, 0);
puts(readableSpirv.c_str());
#endif
}
......@@ -312,6 +312,8 @@ angle_translator_lib_vulkan_sources = [
"src/compiler/translator/OutputVulkanGLSL.h",
"src/compiler/translator/TranslatorVulkan.cpp",
"src/compiler/translator/TranslatorVulkan.h",
"src/compiler/translator/glslang_wrapper.cpp",
"src/compiler/translator/glslang_wrapper.h",
"src/compiler/translator/tree_ops/vulkan/EarlyFragmentTestsOptimization.cpp",
"src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.cpp",
"src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h",
......
......@@ -184,6 +184,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
size -= kHeaderSize;
data += kHeaderSize;
sh::InitializeGlslang();
if (!sh::Initialize())
{
return 0;
......
......@@ -52,11 +52,10 @@ typedef std::basic_string<char, std::char_traits<char>, TStringAllocator> TStrin
typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
//
// Persistent string memory. Should only be used for strings that survive
// across compiles.
// Persistent memory. Should only be used for strings that survive across compiles.
//
#define TPersistString std::string
#define TPersistStringStream std::ostringstream
using TPersistString = std::string;
using TPersistStringStream = std::ostringstream;
//
// Pool allocator versions of vectors, lists, and maps
......
......@@ -9,6 +9,7 @@
#include <math.h>
#include <stdlib.h>
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/Common.h"
#include "compiler/translator/Severity.h"
......@@ -103,17 +104,39 @@ class TInfoSinkBase
return *this;
}
void erase() { sink.clear(); }
int size() { return static_cast<int>(sink.size()); }
void erase()
{
sink.clear();
binarySink.clear();
}
int size() { return static_cast<int>(isBinary() ? binarySink.size() : sink.size()); }
const TPersistString &str() const { return sink; }
const char *c_str() const { return sink.c_str(); }
const TPersistString &str() const
{
ASSERT(!isBinary());
return sink;
}
const char *c_str() const
{
ASSERT(!isBinary());
return sink.c_str();
}
void prefix(Severity severity);
void location(int file, int line);
bool isBinary() const { return !binarySink.empty(); }
void setBinary(BinaryBlob &&binary) { binarySink = std::move(binary); }
const BinaryBlob &getBinary() const
{
ASSERT(isBinary());
return binarySink;
}
private:
// The data in the info sink is either in human readable form (|sink|) or binary (|binarySink|).
TPersistString sink;
BinaryBlob binarySink;
};
class TInfoSink
......
......@@ -13,6 +13,7 @@
#include "compiler/translator/Compiler.h"
#include "compiler/translator/InitializeDll.h"
#include "compiler/translator/glslang_wrapper.h"
#include "compiler/translator/length_limits.h"
#ifdef ANGLE_ENABLE_HLSL
# include "compiler/translator/TranslatorHLSL.h"
......@@ -26,7 +27,8 @@ namespace sh
namespace
{
bool isInitialized = false;
bool isInitialized = false;
bool isGlslangInitialized = false;
//
// This is the platform independent interface between an OGL driver
......@@ -442,6 +444,18 @@ const std::string &GetObjectCode(const ShHandle handle)
return infoSink.obj.str();
}
//
// Return any object binary code.
//
const BinaryBlob &GetObjectBinaryBlob(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
ASSERT(compiler);
TInfoSink &infoSink = compiler->getInfoSink();
return infoSink.obj.getBinary();
}
const std::map<std::string, std::string> *GetNameHashingMap(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
......@@ -902,6 +916,24 @@ unsigned int GetShaderSharedMemorySize(const ShHandle handle)
return sharedMemorySize;
}
void InitializeGlslang()
{
if (!isGlslangInitialized)
{
GlslangInitialize();
}
isGlslangInitialized = true;
}
void FinalizeGlslang()
{
if (isGlslangInitialized)
{
GlslangFinalize();
}
isGlslangInitialized = false;
}
// 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.
......
......@@ -179,7 +179,7 @@ bool TranslatorMetal::translate(TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics)
{
TInfoSinkBase &sink = getInfoSink().obj;
TInfoSinkBase sink;
TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
getNameMap(), &getSymbolTable(), getShaderType(),
......@@ -187,7 +187,7 @@ bool TranslatorMetal::translate(TIntermBlock *root,
SpecConstMetal specConst(&getSymbolTable(), compileOptions, getShaderType());
DriverUniformMetal driverUniforms;
if (!TranslatorVulkan::translateImpl(root, compileOptions, perfDiagnostics, &specConst,
if (!TranslatorVulkan::translateImpl(sink, root, compileOptions, perfDiagnostics, &specConst,
&driverUniforms, &outputGLSL))
{
return false;
......@@ -210,14 +210,14 @@ bool TranslatorMetal::translate(TIntermBlock *root,
}
// Insert rasterizer discard logic
if (!insertRasterizerDiscardLogic(root))
if (!insertRasterizerDiscardLogic(sink, root))
{
return false;
}
}
else if (getShaderType() == GL_FRAGMENT_SHADER)
{
if (!insertSampleMaskWritingLogic(root, &driverUniforms))
if (!insertSampleMaskWritingLogic(sink, root, &driverUniforms))
{
return false;
}
......@@ -246,7 +246,7 @@ bool TranslatorMetal::translate(TIntermBlock *root,
// Write translated shader.
root->traverse(&outputGLSL);
return true;
return compileToSpirv(sink);
}
// Metal needs to inverse the depth if depthRange is is reverse order, i.e. depth near > depth far
......@@ -280,10 +280,10 @@ bool TranslatorMetal::transformDepthBeforeCorrection(TIntermBlock *root,
// Add sample_mask writing to main, guarded by the specialization constant
// kCoverageMaskEnabledConstName
ANGLE_NO_DISCARD bool TranslatorMetal::insertSampleMaskWritingLogic(
TInfoSinkBase &sink,
TIntermBlock *root,
const DriverUniformMetal *driverUniforms)
{
TInfoSinkBase &sink = getInfoSink().obj;
TSymbolTable *symbolTable = &getSymbolTable();
// Insert coverageMaskEnabled specialization constant and sample_mask writing function.
......@@ -334,9 +334,9 @@ ANGLE_NO_DISCARD bool TranslatorMetal::insertSampleMaskWritingLogic(
return RunAtTheEndOfShader(this, root, ifCall, symbolTable);
}
ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TIntermBlock *root)
ANGLE_NO_DISCARD bool TranslatorMetal::insertRasterizerDiscardLogic(TInfoSinkBase &sink,
TIntermBlock *root)
{
TInfoSinkBase &sink = getInfoSink().obj;
TSymbolTable *symbolTable = &getSymbolTable();
// Insert rasterizationDisabled specialization constant.
......
......@@ -65,9 +65,10 @@ class TranslatorMetal : public TranslatorVulkan
TIntermBlock *root,
const DriverUniform *driverUniforms) override;
ANGLE_NO_DISCARD bool insertSampleMaskWritingLogic(TIntermBlock *root,
ANGLE_NO_DISCARD bool insertSampleMaskWritingLogic(TInfoSinkBase &sink,
TIntermBlock *root,
const DriverUniformMetal *driverUniforms);
ANGLE_NO_DISCARD bool insertRasterizerDiscardLogic(TIntermBlock *root);
ANGLE_NO_DISCARD bool insertRasterizerDiscardLogic(TInfoSinkBase &sink, TIntermBlock *root);
};
} // namespace sh
......
......@@ -19,6 +19,7 @@
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/OutputVulkanGLSL.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/glslang_wrapper.h"
#include "compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h"
#include "compiler/translator/tree_ops/vulkan/MonomorphizeUnsupportedFunctionsInVulkanGLSL.h"
#include "compiler/translator/tree_ops/vulkan/NameEmbeddedUniformStructs.h"
......@@ -762,15 +763,14 @@ TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
{}
bool TranslatorVulkan::translateImpl(TIntermBlock *root,
bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink,
TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics * /*perfDiagnostics*/,
SpecConst *specConst,
DriverUniform *driverUniforms,
TOutputVulkanGLSL *outputGLSL)
{
TInfoSinkBase &sink = getInfoSink().obj;
if (getShaderType() == GL_VERTEX_SHADER)
{
if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
......@@ -1324,8 +1324,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics)
{
TInfoSinkBase &sink = getInfoSink().obj;
TInfoSinkBase sink;
bool precisionEmulation = false;
if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, SH_SPIRV_VULKAN_OUTPUT))
......@@ -1343,7 +1342,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
if ((compileOptions & SH_USE_SPECIALIZATION_CONSTANT) != 0)
{
DriverUniform driverUniforms;
if (!translateImpl(root, compileOptions, perfDiagnostics, &specConst, &driverUniforms,
if (!translateImpl(sink, root, compileOptions, perfDiagnostics, &specConst, &driverUniforms,
&outputGLSL))
{
return false;
......@@ -1352,8 +1351,8 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
else
{
DriverUniformExtended driverUniformsExt;
if (!translateImpl(root, compileOptions, perfDiagnostics, &specConst, &driverUniformsExt,
&outputGLSL))
if (!translateImpl(sink, root, compileOptions, perfDiagnostics, &specConst,
&driverUniformsExt, &outputGLSL))
{
return false;
}
......@@ -1362,7 +1361,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
// Write translated shader.
root->traverse(&outputGLSL);
return true;
return compileToSpirv(sink);
}
bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
......@@ -1370,4 +1369,16 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
// Not necessary.
return false;
}
bool TranslatorVulkan::compileToSpirv(const TInfoSinkBase &glsl)
{
angle::spirv::Blob spirvBlob;
if (!GlslangCompileToSpirv(getResources(), getShaderType(), glsl.str(), &spirvBlob))
{
return false;
}
getInfoSink().obj.setBinary(std::move(spirvBlob));
return true;
}
} // namespace sh
......@@ -34,7 +34,8 @@ class TranslatorVulkan : public TCompiler
// Subclass can call this method to transform the AST before writing the final output.
// See TranslatorMetal.cpp.
ANGLE_NO_DISCARD bool translateImpl(TIntermBlock *root,
ANGLE_NO_DISCARD bool translateImpl(TInfoSinkBase &sink,
TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics,
SpecConst *specConst,
......@@ -49,6 +50,9 @@ class TranslatorVulkan : public TCompiler
{
return true;
}
// Generate SPIR-V out of intermediate GLSL through glslang.
ANGLE_NO_DISCARD bool compileToSpirv(const TInfoSinkBase &glsl);
};
} // namespace sh
......
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// glslang_wrapper:
// A wrapper to compile GLSL strings to SPIR-V blobs. glslang here refers to the Khronos
// compiler.
//
// This file is separated as glslang's header contains conflicting macro definitions with ANGLE's.
//
#include "compiler/translator/glslang_wrapper.h"
// glslang has issues with some specific warnings.
ANGLE_DISABLE_SHADOWING_WARNING
ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
// glslang's version of ShaderLang.h, not to be confused with ANGLE's.
#include <glslang/Public/ShaderLang.h>
// Other glslang includes.
#include <SPIRV/GlslangToSpv.h>
#include <StandAlone/ResourceLimits.h>
// SPIR-V tools include for disassembly
#include <spirv-tools/libspirv.hpp>
// Enable this for debug logging of pre-transform SPIR-V:
#if !defined(ANGLE_DEBUG_SPIRV_TRANSFORMER)
# define ANGLE_DEBUG_SPIRV_TRANSFORMER 0
#endif // !defined(ANGLE_DEBUG_SPIRV_TRANSFORMER)
ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
ANGLE_REENABLE_SHADOWING_WARNING
namespace sh
{
namespace
{
// Run at startup to warm up glslang's internals to avoid hitches on first shader compile.
void Warmup()
{
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
const TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
glslang::TShader warmUpShader(EShLangVertex);
const char *kShaderString = R"(#version 450 core
void main(){}
)";
const int kShaderLength = static_cast<int>(strlen(kShaderString));
warmUpShader.setStringsWithLengths(&kShaderString, &kShaderLength, 1);
warmUpShader.setEntryPoint("main");
bool result = warmUpShader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
ASSERT(result);
}
// Generate glslang resources from ANGLE translator resources.
void GetBuiltInResources(const ShBuiltInResources &resources, TBuiltInResource *outResources)
{
outResources->maxDrawBuffers = resources.MaxDrawBuffers;
outResources->maxAtomicCounterBindings = resources.MaxAtomicCounterBindings;
outResources->maxAtomicCounterBufferSize = resources.MaxAtomicCounterBufferSize;
outResources->maxCombinedAtomicCounterBuffers = resources.MaxCombinedAtomicCounterBuffers;
outResources->maxCombinedAtomicCounters = resources.MaxCombinedAtomicCounters;
outResources->maxCombinedImageUniforms = resources.MaxCombinedImageUniforms;
outResources->maxCombinedTextureImageUnits = resources.MaxCombinedTextureImageUnits;
outResources->maxCombinedShaderOutputResources = resources.MaxCombinedShaderOutputResources;
outResources->maxComputeWorkGroupCountX = resources.MaxComputeWorkGroupCount[0];
outResources->maxComputeWorkGroupCountY = resources.MaxComputeWorkGroupCount[1];
outResources->maxComputeWorkGroupCountZ = resources.MaxComputeWorkGroupCount[2];
outResources->maxComputeWorkGroupSizeX = resources.MaxComputeWorkGroupSize[0];
outResources->maxComputeWorkGroupSizeY = resources.MaxComputeWorkGroupSize[1];
outResources->maxComputeWorkGroupSizeZ = resources.MaxComputeWorkGroupSize[2];
outResources->minProgramTexelOffset = resources.MinProgramTexelOffset;
outResources->maxFragmentUniformVectors = resources.MaxFragmentUniformVectors;
outResources->maxGeometryInputComponents = resources.MaxGeometryInputComponents;
outResources->maxGeometryOutputComponents = resources.MaxGeometryOutputComponents;
outResources->maxGeometryOutputVertices = resources.MaxGeometryOutputVertices;
outResources->maxGeometryTotalOutputComponents = resources.MaxGeometryTotalOutputComponents;
outResources->maxPatchVertices = resources.MaxPatchVertices;
outResources->maxProgramTexelOffset = resources.MaxProgramTexelOffset;
outResources->maxVaryingVectors = resources.MaxVaryingVectors;
outResources->maxVertexUniformVectors = resources.MaxVertexUniformVectors;
outResources->maxClipDistances = resources.MaxClipDistances;
outResources->maxSamples = resources.MaxSamples;
outResources->maxCullDistances = resources.MaxCullDistances;
outResources->maxCombinedClipAndCullDistances = resources.MaxCombinedClipAndCullDistances;
}
} // anonymous namespace
void GlslangInitialize()
{
int result = ShInitialize();
ASSERT(result != 0);
Warmup();
}
void GlslangFinalize()
{
int result = ShFinalize();
ASSERT(result != 0);
}
ANGLE_NO_DISCARD bool GlslangCompileToSpirv(const ShBuiltInResources &resources,
sh::GLenum shaderType,
const std::string &shaderSource,
angle::spirv::Blob *spirvBlobOut)
{
TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
GetBuiltInResources(resources, &builtInResources);
EShLanguage language = EShLangVertex;
switch (shaderType)
{
case GL_VERTEX_SHADER:
language = EShLangVertex;
break;
case GL_TESS_CONTROL_SHADER:
language = EShLangTessControl;
break;
case GL_TESS_EVALUATION_SHADER_EXT:
language = EShLangTessEvaluation;
break;
case GL_GEOMETRY_SHADER:
language = EShLangGeometry;
break;
case GL_FRAGMENT_SHADER:
language = EShLangFragment;
break;
case GL_COMPUTE_SHADER:
language = EShLangCompute;
break;
default:
UNREACHABLE();
}
glslang::TShader shader(language);
glslang::TProgram program;
// Enable SPIR-V and Vulkan rules when parsing GLSL
constexpr EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
const char *shaderString = shaderSource.c_str();
int shaderLength = static_cast<int>(shaderSource.size());
shader.setStringsWithLengths(&shaderString, &shaderLength, 1);
shader.setEntryPoint("main");
bool result = shader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!result)
{
WARN() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
<< shader.getInfoLog() << "\n"
<< shader.getInfoDebugLog() << "\n";
return false;
}
program.addShader(&shader);
bool linkResult = program.link(messages);
if (!linkResult)
{
WARN() << "Internal error linking Vulkan shader:\n" << program.getInfoLog() << "\n";
}
glslang::TIntermediate *intermediate = program.getIntermediate(language);
glslang::GlslangToSpv(*intermediate, *spirvBlobOut);
#if ANGLE_DEBUG_SPIRV_TRANSFORMER
spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
std::string readableSpirv;
spirvTools.Disassemble(*spirvBlobOut, &readableSpirv, 0);
fprintf(stderr, "%s\n%s\n", shaderString, readableSpirv.c_str());
#endif // ANGLE_DEBUG_SPIRV_TRANSFORMER
return true;
}
} // namespace sh
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// glslang_wrapper:
// A wrapper to compile GLSL strings to SPIR-V blobs. glslang here refers to the Khronos
// compiler.
//
#ifndef COMPILER_TRANSLATOR_GLSLANG_WRAPPER_H_
#define COMPILER_TRANSLATOR_GLSLANG_WRAPPER_H_
#include "GLSLANG/ShaderLang.h"
#include "common/PackedEnums.h"
#include "common/spirv/spirv_types.h"
#include <string>
#include <vector>
namespace sh
{
#if defined(ANGLE_ENABLE_VULKAN) || defined(ANGLE_ENABLE_METAL)
void GlslangInitialize();
void GlslangFinalize();
// Generate SPIR-V out of intermediate GLSL through glslang.
ANGLE_NO_DISCARD bool GlslangCompileToSpirv(const ShBuiltInResources &resources,
sh::GLenum shaderType,
const std::string &shaderSource,
angle::spirv::Blob *spirvBlobOut);
#else
ANGLE_INLINE void GlslangInitialize()
{
UNREACHABLE();
}
ANGLE_INLINE void GlslangFinalize()
{
UNREACHABLE();
}
#endif // defined(ANGLE_ENABLE_VULKAN) || defined(ANGLE_ENABLE_METAL)
} // namespace sh
#endif // COMPILER_TRANSLATOR_GLSLANG_WRAPPER_H_
......@@ -335,17 +335,13 @@ ImmutableString GetFunctionNameOfSubpassLoad(const InputType &inputType)
switch (inputType)
{
case InputType::SubpassInput:
case InputType::ISubpassInput:
case InputType::USubpassInput:
return ImmutableString("subpassLoad");
case InputType::SubpassInputMS:
return ImmutableString("subpassLoadMS");
case InputType::ISubpassInput:
return ImmutableString("isubpassLoad");
case InputType::ISubpassInputMS:
return ImmutableString("isubpassLoadMS");
case InputType::USubpassInput:
return ImmutableString("usubpassLoad");
case InputType::USubpassInputMS:
return ImmutableString("usubpassLoadMS");
return ImmutableString("subpassLoadMS");
default:
UNREACHABLE();
return kEmptyImmutableString;
......
......@@ -298,6 +298,12 @@ const std::string &Shader::getTranslatedSource()
return mState.mTranslatedSource;
}
const sh::BinaryBlob &Shader::getCompiledBinary()
{
resolveCompile();
return mState.mCompiledBinary;
}
void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer)
{
resolveCompile();
......@@ -310,6 +316,7 @@ void Shader::compile(const Context *context)
resolveCompile();
mState.mTranslatedSource.clear();
mState.mCompiledBinary.clear();
mInfoLog.clear();
mState.mShaderVersion = 100;
mState.mInputVaryings.clear();
......@@ -407,36 +414,47 @@ void Shader::resolveCompile()
return;
}
mState.mTranslatedSource = sh::GetObjectCode(compilerHandle);
const ShShaderOutput outputType = mCompilingState->shCompilerInstance.getShaderOutputType();
const bool isBinaryOutput =
outputType == SH_SPIRV_VULKAN_OUTPUT || outputType == SH_SPIRV_METAL_OUTPUT;
#if !defined(NDEBUG)
// Prefix translated shader with commented out un-translated shader.
// Useful in diagnostics tools which capture the shader source.
std::ostringstream shaderStream;
shaderStream << "// GLSL\n";
shaderStream << "//\n";
std::istringstream inputSourceStream(mState.mSource);
std::string line;
while (std::getline(inputSourceStream, line))
if (isBinaryOutput)
{
// Remove null characters from the source line
line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
shaderStream << "// " << line;
mState.mCompiledBinary = sh::GetObjectBinaryBlob(compilerHandle);
}
else
{
mState.mTranslatedSource = sh::GetObjectCode(compilerHandle);
// glslang complains if a comment ends with backslash
if (!line.empty() && line.back() == '\\')
#if !defined(NDEBUG)
// Prefix translated shader with commented out un-translated shader.
// Useful in diagnostics tools which capture the shader source.
std::ostringstream shaderStream;
shaderStream << "// GLSL\n";
shaderStream << "//\n";
std::istringstream inputSourceStream(mState.mSource);
std::string line;
while (std::getline(inputSourceStream, line))
{
shaderStream << "\\";
}
// Remove null characters from the source line
line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
shaderStream << std::endl;
}
shaderStream << "\n\n";
shaderStream << mState.mTranslatedSource;
mState.mTranslatedSource = shaderStream.str();
shaderStream << "// " << line;
// glslang complains if a comment ends with backslash
if (!line.empty() && line.back() == '\\')
{
shaderStream << "\\";
}
shaderStream << std::endl;
}
shaderStream << "\n\n";
shaderStream << mState.mTranslatedSource;
mState.mTranslatedSource = shaderStream.str();
#endif // !defined(NDEBUG)
}
// Gather the shader information
mState.mShaderVersion = sh::GetShaderVersion(compilerHandle);
......@@ -566,7 +584,7 @@ void Shader::resolveCompile()
UNREACHABLE();
}
ASSERT(!mState.mTranslatedSource.empty());
ASSERT(!mState.mTranslatedSource.empty() || !mState.mCompiledBinary.empty());
bool success = mCompilingState->compileEvent->postTranslate(&mInfoLog);
mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
......
......@@ -65,7 +65,9 @@ class ShaderState final : angle::NonCopyable
const std::string &getLabel() const { return mLabel; }
const std::string &getSource() const { return mSource; }
bool isCompiledToBinary() const { return !mCompiledBinary.empty(); }
const std::string &getTranslatedSource() const { return mTranslatedSource; }
const sh::BinaryBlob &getCompiledBinary() const { return mCompiledBinary; }
ShaderType getShaderType() const { return mShaderType; }
int getShaderVersion() const { return mShaderVersion; }
......@@ -118,6 +120,7 @@ class ShaderState final : angle::NonCopyable
ShaderType mShaderType;
int mShaderVersion;
std::string mTranslatedSource;
sh::BinaryBlob mCompiledBinary;
std::string mSource;
sh::WorkGroupSize mLocalSize;
......@@ -185,6 +188,7 @@ class Shader final : angle::NonCopyable, public LabeledObject
const std::string &getTranslatedSource();
void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer);
void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer);
const sh::BinaryBlob &getCompiledBinary();
void compile(const Context *context);
bool isCompiled();
......
......@@ -659,6 +659,7 @@ void SerializeShaderState(gl::BinaryOutputStream *bos, const gl::ShaderState &sh
bos->writeEnum(shaderState.getShaderType());
bos->writeInt(shaderState.getShaderVersion());
bos->writeString(shaderState.getTranslatedSource());
bos->writeIntVector(shaderState.getCompiledBinary());
bos->writeString(shaderState.getSource());
SerializeWorkGroupSize(bos, shaderState.getLocalSize());
SerializeShaderVariablesVector(bos, shaderState.getInputVaryings());
......
......@@ -17,12 +17,6 @@
namespace rx
{
enum class GlslangError
{
InvalidShader,
InvalidSpirv,
};
constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
{gl::ShaderType::Vertex, sh::vk::kDefaultUniformsNameVS},
{gl::ShaderType::TessControl, sh::vk::kDefaultUniformsNameTCS},
......@@ -69,8 +63,6 @@ struct GlslangSpirvOptions
bool isTransformFeedbackEmulated = false;
};
using GlslangErrorCallback = std::function<angle::Result(GlslangError)>;
struct ShaderInterfaceVariableXfbInfo
{
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
......@@ -170,12 +162,9 @@ class ShaderInterfaceVariableInfoMap final : angle::NonCopyable
gl::ShaderMap<VariableNameToInfoMap> mData;
};
void GlslangInitialize();
void GlslangRelease();
bool GetImageNameWithoutIndices(std::string *name);
// Get the mapped sampler name after the source is transformed by GlslangGetShaderSource()
// Get the mapped sampler name.
std::string GlslangGetMappedSamplerName(const std::string &originalName);
std::string GetXfbBufferName(const uint32_t bufferIndex);
......@@ -188,29 +177,19 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
GlslangProgramInterfaceInfo *programInterfaceInfo,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
// 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,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
// Retrieves the compiled SPIR-V code for each shader stage, and calls |GlslangAssignLocations|.
void GlslangGetShaderSpirvCode(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<const angle::spirv::Blob *> *spirvBlobsOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback,
const GlslangSpirvOptions &options,
angle::Result GlslangTransformSpirvCode(const GlslangSpirvOptions &options,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
const angle::spirv::Blob &initialSpirvBlob,
angle::spirv::Blob *spirvBlobOut);
angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<angle::spirv::Blob> *spirvBlobsOut);
} // namespace rx
#endif // LIBANGLE_RENDERER_GLSLANG_WRAPPER_UTILS_H_
......@@ -188,9 +188,6 @@ class DisplayMtl : public DisplayImpl
mutable gl::Limitations mNativeLimitations;
angle::FeaturesMtl mFeatures;
// track whether we initialized (or released) glslang
bool mGlslangInitialized;
};
} // namespace rx
......
......@@ -19,6 +19,7 @@
#include "libANGLE/renderer/metal/SyncMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc"
#include "libANGLE/trace.h"
#include "platform/Platform.h"
#include "EGL/eglext.h"
......@@ -56,9 +57,7 @@ struct DefaultShaderAsyncInfoMtl
bool compiled = false;
};
DisplayMtl::DisplayMtl(const egl::DisplayState &state)
: DisplayImpl(state), mUtils(this), mGlslangInitialized(false)
{}
DisplayMtl::DisplayMtl(const egl::DisplayState &state) : DisplayImpl(state), mUtils(this) {}
DisplayMtl::~DisplayMtl() {}
......@@ -90,10 +89,9 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display)
mCapsInitialized = false;
if (!mGlslangInitialized)
{
GlslangInitialize();
mGlslangInitialized = true;
ANGLE_TRACE_EVENT0("gpu.angle,startup", "GlslangWarmup");
sh::InitializeGlslang();
}
if (!mState.featuresAllDisabled)
......@@ -121,11 +119,7 @@ void DisplayMtl::terminate()
mMetalDeviceVendorId = 0;
if (mGlslangInitialized)
{
GlslangRelease();
mGlslangInitialized = false;
}
sh::FinalizeGlslang();
}
bool DisplayMtl::testDeviceLost()
......@@ -641,10 +635,9 @@ void DisplayMtl::initializeExtensions() const
// backend to be used in Chrome (http://anglebug.com/4946)
mNativeExtensions.debugMarker = true;
mNativeExtensions.robustness = true;
mNativeExtensions.textureBorderClampOES = false; // not implemented yet
mNativeExtensions.translatedShaderSource = true;
mNativeExtensions.discardFramebuffer = true;
mNativeExtensions.robustness = true;
mNativeExtensions.textureBorderClampOES = false; // not implemented yet
mNativeExtensions.discardFramebuffer = true;
// Enable EXT_blend_minmax
mNativeExtensions.blendMinMax = true;
......
......@@ -316,25 +316,23 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources;
gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
ShaderInterfaceVariableInfoMap variableInfoMap;
ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap;
mtl::GlslangGetShaderSource(mState, resources, &shaderSources, &variableInfoMap,
&xfbOnlyVariableInfoMap);
mtl::GlslangGetShaderSpirvCode(mState, resources, &spirvBlobs, &variableInfoMap,
&xfbOnlyVariableInfoMap);
// Convert GLSL to spirv code
gl::ShaderMap<angle::spirv::Blob> shaderCodes;
gl::ShaderMap<angle::spirv::Blob> xfbOnlyShaderCodes; // only vertex shader is needed.
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(
contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(),
shaderSources, false, variableInfoMap, &shaderCodes));
ANGLE_TRY(mtl::GlslangTransformSpirvCode(mState.getExecutable().getLinkedShaderStages(),
spirvBlobs, false, variableInfoMap, &shaderCodes));
if (!mState.getLinkedTransformFeedbackVaryings().empty())
{
gl::ShaderBitSet onlyVS;
onlyVS.set(gl::ShaderType::Vertex);
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, onlyVS, contextMtl->getCaps(),
shaderSources, true, xfbOnlyVariableInfoMap,
ANGLE_TRY(mtl::GlslangTransformSpirvCode(onlyVS, spirvBlobs, true, xfbOnlyVariableInfoMap,
&xfbOnlyShaderCodes));
}
......
......@@ -42,7 +42,7 @@ std::shared_ptr<WaitableCompileEvent> ShaderMtl::compile(const gl::Context *cont
std::string ShaderMtl::getDebugInfo() const
{
return mState.getTranslatedSource();
return mState.getCompiledBinary().empty() ? "" : "<binary blob>";
}
} // namespace rx
......@@ -41,17 +41,15 @@ struct TranslatedShaderInfo
bool hasUBOArgumentBuffer;
};
// shaderSourcesOut is result GLSL code per shader stage.
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut);
// spirvBlobsOut is the SPIR-V code per shader stage.
void GlslangGetShaderSpirvCode(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<const angle::spirv::Blob *> *spirvBlobsOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut);
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
angle::Result GlslangTransformSpirvCode(const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<angle::spirv::Blob> *shaderCodeOut);
......
......@@ -33,12 +33,6 @@ constexpr uint32_t kGlslangShaderResourceDescSet = 3;
using OriginalSamplerBindingMap =
angle::HashMap<std::string, std::vector<std::pair<uint32_t, uint32_t>>>;
angle::Result HandleError(ErrorHandler *context, GlslangError)
{
ANGLE_MTL_TRY(context, false);
return angle::Result::Stop;
}
void ResetGlslangProgramInterfaceInfo(GlslangProgramInterfaceInfo *programInterfaceInfo)
{
// These are binding options passed to glslang. The actual binding might be changed later
......@@ -403,11 +397,11 @@ void TranslatedShaderInfo::reset()
}
}
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut)
void GlslangGetShaderSpirvCode(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<const angle::spirv::Blob *> *spirvBlobsOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut)
{
GlslangSourceOptions options = CreateSourceOptions();
GlslangProgramInterfaceInfo programInterfaceInfo;
......@@ -416,8 +410,8 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
options.supportsTransformFeedbackEmulation = true;
// Get shader sources and fill variable info map with transform feedback disabled.
rx::GlslangGetShaderSource(options, programState, resources, &programInterfaceInfo,
shaderSourcesOut, variableInfoMapOut);
rx::GlslangGetShaderSpirvCode(options, programState, resources, &programInterfaceInfo,
spirvBlobsOut, variableInfoMapOut);
// Fill variable info map with transform feedback enabled.
if (!programState.getLinkedTransformFeedbackVaryings().empty())
......@@ -433,20 +427,12 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
}
}
angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
angle::Result GlslangTransformSpirvCode(const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<angle::spirv::Blob> *shaderCodeOut)
{
gl::ShaderMap<angle::spirv::Blob> initialSpirvBlobs;
ANGLE_TRY(rx::GlslangGetShaderSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, linkedShaderStages,
glCaps, shaderSources, &initialSpirvBlobs));
for (const gl::ShaderType shaderType : linkedShaderStages)
{
GlslangSpirvOptions options;
......@@ -457,8 +443,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
options.isTransformFeedbackEmulated = true;
angle::Result status = GlslangTransformSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, options,
variableInfoMap, initialSpirvBlobs[shaderType], &(*shaderCodeOut)[shaderType]);
options, variableInfoMap, *spirvBlobs[shaderType], &(*shaderCodeOut)[shaderType]);
if (status != angle::Result::Continue)
{
return status;
......
......@@ -13,16 +13,6 @@
namespace rx
{
namespace
{
angle::Result ErrorHandler(vk::Context *context, GlslangError)
{
ANGLE_VK_CHECK(context, false, VK_ERROR_INVALID_SHADER_NV);
return angle::Result::Stop;
}
} // namespace
// static
GlslangSourceOptions GlslangWrapperVk::CreateSourceOptions(const angle::FeaturesVk &features)
{
......@@ -57,40 +47,25 @@ void GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(
}
// static
void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
void GlslangWrapperVk::GetShaderCode(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<const angle::spirv::Blob *> *spirvBlobsOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
GlslangSourceOptions options = CreateSourceOptions(features);
GlslangGetShaderSource(options, programState, resources, programInterfaceInfo, shaderSourcesOut,
variableInfoMapOut);
}
// static
angle::Result GlslangWrapperVk::GetShaderCode(vk::Context *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
return GlslangGetShaderSpirvCode(
[context](GlslangError error) { return ErrorHandler(context, error); }, linkedShaderStages,
glCaps, shaderSources, shaderCodeOut);
GlslangGetShaderSpirvCode(options, programState, resources, programInterfaceInfo, spirvBlobsOut,
variableInfoMapOut);
}
// static
angle::Result GlslangWrapperVk::TransformSpirV(
vk::Context *context,
const GlslangSpirvOptions &options,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
const angle::spirv::Blob &initialSpirvBlob,
angle::spirv::Blob *shaderCodeOut)
{
return GlslangTransformSpirvCode(
[context](GlslangError error) { return ErrorHandler(context, error); }, options,
variableInfoMap, initialSpirvBlob, shaderCodeOut);
return GlslangTransformSpirvCode(options, variableInfoMap, initialSpirvBlob, shaderCodeOut);
}
} // namespace rx
......@@ -30,21 +30,14 @@ class GlslangWrapperVk
static void ResetGlslangProgramInterfaceInfo(
GlslangProgramInterfaceInfo *glslangProgramInterfaceInfo);
static void GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<std::string> *shaderSourcesOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
static angle::Result GetShaderCode(vk::Context *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
static angle::Result TransformSpirV(vk::Context *context,
const GlslangSpirvOptions &options,
static void GetShaderCode(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<const angle::spirv::Blob *> *spirvBlobsOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
static angle::Result TransformSpirV(const GlslangSpirvOptions &options,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
const angle::spirv::Blob &initialSpirvBlob,
angle::spirv::Blob *shaderCodeOut);
......
......@@ -60,8 +60,7 @@ void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xf
}
}
bool ValidateTransformedSpirV(ContextVk *contextVk,
const gl::ShaderBitSet &linkedShaderStages,
bool ValidateTransformedSpirV(const gl::ShaderBitSet &linkedShaderStages,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
const gl::ShaderMap<angle::spirv::Blob> &spirvBlobs)
{
......@@ -70,17 +69,15 @@ bool ValidateTransformedSpirV(ContextVk *contextVk,
for (gl::ShaderType shaderType : linkedShaderStages)
{
GlslangSpirvOptions options;
options.shaderType = shaderType;
options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
options.negativeViewportSupported =
contextVk->getFeatures().supportsNegativeViewport.enabled;
options.shaderType = shaderType;
options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
options.negativeViewportSupported = false;
options.transformPositionToVulkanClipSpace = true;
options.removeDebugInfo = true;
options.isTransformFeedbackStage = shaderType == lastPreFragmentStage;
angle::spirv::Blob transformed;
if (GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap,
spirvBlobs[shaderType],
if (GlslangWrapperVk::TransformSpirV(options, variableInfoMap, spirvBlobs[shaderType],
&transformed) != angle::Result::Continue)
{
return false;
......@@ -99,18 +96,22 @@ ShaderInfo::ShaderInfo() {}
ShaderInfo::~ShaderInfo() = default;
angle::Result ShaderInfo::initShaders(ContextVk *contextVk,
const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<std::string> &shaderSources,
angle::Result ShaderInfo::initShaders(const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
const ShaderInterfaceVariableInfoMap &variableInfoMap)
{
ASSERT(!valid());
ANGLE_TRY(GlslangWrapperVk::GetShaderCode(contextVk, linkedShaderStages, contextVk->getCaps(),
shaderSources, &mSpirvBlobs));
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (spirvBlobs[shaderType] != nullptr)
{
mSpirvBlobs[shaderType] = *spirvBlobs[shaderType];
}
}
// Assert that SPIR-V transformation is correct, even if the test never issues a draw call.
ASSERT(ValidateTransformedSpirV(contextVk, linkedShaderStages, variableInfoMap, mSpirvBlobs));
ASSERT(ValidateTransformedSpirV(linkedShaderStages, variableInfoMap, mSpirvBlobs));
mIsInitialized = true;
return angle::Result::Continue;
......@@ -186,8 +187,8 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.transformPositionToVulkanClipSpace = optionBits.enableDepthCorrection;
}
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, options, variableInfoMap,
originalSpirvBlob, &transformedSpirvBlob));
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(options, variableInfoMap, originalSpirvBlob,
&transformedSpirvBlob));
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
transformedSpirvBlob.data(),
transformedSpirvBlob.size() * sizeof(uint32_t)));
......
......@@ -29,9 +29,8 @@ class ShaderInfo final : angle::NonCopyable
ShaderInfo();
~ShaderInfo();
angle::Result initShaders(ContextVk *contextVk,
const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<std::string> &shaderSources,
angle::Result initShaders(const gl::ShaderBitSet &linkedShaderStages,
const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
const ShaderInterfaceVariableInfoMap &variableInfoMap);
void release(ContextVk *contextVk);
......
......@@ -267,16 +267,15 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
reset(contextVk);
mExecutable.clearVariableInfoMap();
// Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources;
GlslangWrapperVk::GetShaderSource(contextVk->getFeatures(), mState, resources,
&mGlslangProgramInterfaceInfo, &shaderSources,
&mExecutable.mVariableInfoMap);
// Gather variable info and compiled SPIR-V binaries.
gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
GlslangWrapperVk::GetShaderCode(contextVk->getFeatures(), mState, resources,
&mGlslangProgramInterfaceInfo, &spirvBlobs,
&mExecutable.mVariableInfoMap);
// Compile the shaders.
angle::Result status =
mOriginalShaderInfo.initShaders(contextVk, mState.getExecutable().getLinkedShaderStages(),
shaderSources, mExecutable.mVariableInfoMap);
angle::Result status = mOriginalShaderInfo.initShaders(
mState.getExecutable().getLinkedShaderStages(), spirvBlobs, mExecutable.mVariableInfoMap);
if (status != angle::Result::Continue)
{
return std::make_unique<LinkEventDone>(status);
......
......@@ -660,7 +660,6 @@ RendererVk::RendererVk()
mPipelineCacheDirty(false),
mPipelineCacheInitialized(false),
mCommandProcessor(this),
mGlslangInitialized(false),
mSupportedVulkanPipelineStageMask(0)
{
VkFormatProperties invalid = {0, 0, kInvalidFormatFeatureFlags};
......@@ -730,11 +729,7 @@ void RendererVk::onDestroy(vk::Context *context)
mAllocator.destroy();
if (mGlslangInitialized)
{
GlslangRelease();
mGlslangInitialized = false;
}
sh::FinalizeGlslang();
if (mDevice)
{
......@@ -1097,10 +1092,9 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
// Store the physical device memory properties so we can find the right memory pools.
mMemoryProperties.init(mPhysicalDevice);
if (!mGlslangInitialized)
{
GlslangInitialize();
mGlslangInitialized = true;
ANGLE_TRACE_EVENT0("gpu.angle,startup", "GlslangWarmup");
sh::InitializeGlslang();
}
// Initialize the format table.
......
......@@ -484,9 +484,6 @@ class RendererVk : angle::NonCopyable
// Async Command Queue
vk::CommandProcessor mCommandProcessor;
// track whether we initialized (or released) glslang
bool mGlslangInitialized;
vk::Allocator mAllocator;
SamplerCache mSamplerCache;
SamplerYcbcrConversionCache mYuvConversionCache;
......
......@@ -97,7 +97,7 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte
std::string ShaderVk::getDebugInfo() const
{
return mState.getTranslatedSource();
return mState.getCompiledBinary().empty() ? "" : "<binary blob>";
}
} // namespace rx
......@@ -343,9 +343,8 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.robustness =
!IsSwiftshader(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID) &&
!IsARM(mPhysicalDeviceProperties.vendorID);
mNativeExtensions.textureBorderClampOES = false; // not implemented yet
mNativeExtensions.translatedShaderSource = true;
mNativeExtensions.discardFramebuffer = true;
mNativeExtensions.textureBorderClampOES = false; // not implemented yet
mNativeExtensions.discardFramebuffer = true;
// Enable EXT_texture_type_2_10_10_10_REV
mNativeExtensions.textureFormat2101010REV = true;
......
......@@ -8,11 +8,24 @@
#include "gtest/gtest.h"
#include "test_utils/runner/TestSuite.h"
namespace
{
#if defined(ANGLE_ENABLE_VULKAN) || defined(ANGLE_ENABLE_METAL)
static constexpr bool kCanUseGlslang = true;
#else
static constexpr bool kCanUseGlslang = false;
#endif // defined(ANGLE_ENABLE_VULKAN) || defined(ANGLE_ENABLE_METAL)
} // anonymous namespace
class CompilerTestEnvironment : public testing::Environment
{
public:
void SetUp() override
{
if (kCanUseGlslang)
{
sh::InitializeGlslang();
}
if (!sh::Initialize())
{
FAIL() << "Failed to initialize the compiler.";
......@@ -21,6 +34,10 @@ class CompilerTestEnvironment : public testing::Environment
void TearDown() override
{
if (kCanUseGlslang)
{
sh::FinalizeGlslang();
}
if (!sh::Finalize())
{
FAIL() << "Failed to finalize the compiler.";
......
......@@ -350,7 +350,9 @@ TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileFailsWithExtensionWithou
#if defined(ANGLE_ENABLE_VULKAN)
// With extension flag and extension directive, compiling using TranslatorVulkan succeeds.
TEST_P(EXTClipCullDistanceForFragmentShaderTest, CompileSucceedsVulkan)
//
// Test is disabled due to translation bug. http://anglebug.com/5747
TEST_P(EXTClipCullDistanceForFragmentShaderTest, DISABLED_CompileSucceedsVulkan)
{
SetExtensionEnable(true);
......
......@@ -99,11 +99,6 @@ TEST_F(EmulateGLBaseVertexBaseInstanceTest, EmulatesUniform)
EXPECT_TRUE(foundInCode(SH_ESSL_OUTPUT, "uniform highp int angle_BaseVertex"));
EXPECT_TRUE(foundInCode(SH_ESSL_OUTPUT, "uniform highp int angle_BaseInstance"));
#ifdef ANGLE_ENABLE_VULKAN
EXPECT_TRUE(foundInCode(
SH_SPIRV_VULKAN_OUTPUT,
"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"));
EXPECT_TRUE(foundInCode(SH_HLSL_3_0_OUTPUT, "uniform int angle_BaseInstance : register"));
......
......@@ -95,10 +95,6 @@ TEST_F(EmulateGLDrawIDTest, EmulatesUniform)
EXPECT_TRUE(foundInCode(SH_GLSL_COMPATIBILITY_OUTPUT, "uniform int angle_DrawID"));
EXPECT_TRUE(foundInCode(SH_ESSL_OUTPUT, "uniform highp int angle_DrawID"));
#ifdef ANGLE_ENABLE_VULKAN
EXPECT_TRUE(
foundInCode(SH_SPIRV_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"));
EXPECT_TRUE(foundInCode(SH_HLSL_3_0_OUTPUT, "uniform int angle_DrawID : register"));
......
......@@ -18,6 +18,11 @@ namespace sh
namespace
{
constexpr char kBinaryBlob[] = "<binary blob>";
bool IsBinaryBlob(const std::string &code)
{
return code == kBinaryBlob;
}
ImmutableString GetSymbolTableMangledName(TIntermAggregate *node)
{
......@@ -86,9 +91,13 @@ bool compileTestShader(GLenum type,
translator->compile(shaderStrings, 1, SH_OBJECT_CODE | compileOptions);
TInfoSink &infoSink = translator->getInfoSink();
if (translatedCode)
*translatedCode = infoSink.obj.c_str();
{
*translatedCode = infoSink.obj.isBinary() ? kBinaryBlob : infoSink.obj.c_str();
}
if (infoLog)
{
*infoLog = infoSink.info.c_str();
}
SafeDelete(translator);
return compilationSuccess;
}
......@@ -167,6 +176,12 @@ bool MatchOutputCodeTest::foundInCodeRegex(ShShaderOutput output,
return std::string::npos;
}
// No meaningful check for binary blobs
if (IsBinaryBlob(code->second))
{
return true;
}
if (match)
{
return std::regex_search(code->second, *match, regexToFind);
......@@ -185,6 +200,13 @@ bool MatchOutputCodeTest::foundInCode(ShShaderOutput output, const char *stringT
{
return std::string::npos;
}
// No meaningful check for binary blobs
if (IsBinaryBlob(code->second))
{
return true;
}
return code->second.find(stringToFind) != std::string::npos;
}
......@@ -198,6 +220,12 @@ bool MatchOutputCodeTest::foundInCodeInOrder(ShShaderOutput output,
return false;
}
// No meaningful check for binary blobs
if (IsBinaryBlob(code->second))
{
return true;
}
size_t currentPos = 0;
for (const char *stringToFind : stringsToFind)
{
......@@ -222,6 +250,12 @@ bool MatchOutputCodeTest::foundInCode(ShShaderOutput output,
return false;
}
// No meaningful check for binary blobs
if (IsBinaryBlob(code->second))
{
return true;
}
size_t currentPos = 0;
int occurencesLeft = expectedOccurrences;
......@@ -293,6 +327,12 @@ bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
{
for (auto &code : mOutputCode)
{
// No meaningful check for binary blobs
if (IsBinaryBlob(code.second))
{
continue;
}
if (foundInCode(code.first, stringToFind))
{
return false;
......
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