Commit a5a04ac0 by Le Quyen Committed by Commit Bot

Metal backend pt3: shader translator

Implementation of GLSL to MSL translator Bug: angleproject:2634 Change-Id: I66e2374b461548fac46163ea79790a488515e6b0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1887251 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 653ee5f1
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
/third_party/qemu-linux-x64 /third_party/qemu-linux-x64
/third_party/qemu-mac-x64 /third_party/qemu-mac-x64
/third_party/rapidjson/src /third_party/rapidjson/src
/third_party/spirv-cross/src
/third_party/spirv-headers/src /third_party/spirv-headers/src
/third_party/spirv-tools/src /third_party/spirv-tools/src
/third_party/SwiftShader /third_party/SwiftShader
......
...@@ -41,6 +41,9 @@ vars = { ...@@ -41,6 +41,9 @@ vars = {
# Note: this dep cannot be auto-rolled b/c of nesting. # Note: this dep cannot be auto-rolled b/c of nesting.
'patched_yasm_revision': '720b70524a4424b15fc57e82263568c8ba0496ad', 'patched_yasm_revision': '720b70524a4424b15fc57e82263568c8ba0496ad',
# Current revision of spirv-cross, the Khronos SPIRV cross compiler.
'spirv_cross_revision': 'd253f41e17e27285756d031d8ba43bf370264e1f',
# Current revision fo the SPIRV-Headers Vulkan support library. # Current revision fo the SPIRV-Headers Vulkan support library.
'spirv_headers_revision': 'af64a9e826bf5bb5fcd2434dd71be1e41e922563', 'spirv_headers_revision': 'af64a9e826bf5bb5fcd2434dd71be1e41e922563',
...@@ -160,6 +163,11 @@ deps = { ...@@ -160,6 +163,11 @@ deps = {
'url': '{chromium_git}/external/github.com/Tencent/rapidjson@7484e06c589873e1ed80382d262087e4fa80fb63', 'url': '{chromium_git}/external/github.com/Tencent/rapidjson@7484e06c589873e1ed80382d262087e4fa80fb63',
}, },
'third_party/spirv-cross/src': {
'url': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@{spirv_cross_revision}',
'condition': 'not build_with_chromium',
},
'third_party/spirv-headers/src': { 'third_party/spirv-headers/src': {
'url': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@{spirv_headers_revision}', 'url': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@{spirv_headers_revision}',
'condition': 'not build_with_chromium', 'condition': 'not build_with_chromium',
......
...@@ -14,4 +14,5 @@ angle_googletest_dir = "//third_party/googletest/src" ...@@ -14,4 +14,5 @@ angle_googletest_dir = "//third_party/googletest/src"
angle_libjpeg_turbo_dir = "//third_party/libjpeg_turbo" angle_libjpeg_turbo_dir = "//third_party/libjpeg_turbo"
angle_jsoncpp_dir = "//third_party/jsoncpp" angle_jsoncpp_dir = "//third_party/jsoncpp"
angle_libpng_dir = "//third_party/libpng" angle_libpng_dir = "//third_party/libpng"
angle_spirv_cross_dir = "//third_party/spirv-cross/src"
angle_spirv_tools_dir = "//third_party/spirv-tools/src" angle_spirv_tools_dir = "//third_party/spirv-tools/src"
...@@ -25,6 +25,12 @@ class TOutputVulkanGLSLForMetal : public TOutputVulkanGLSL ...@@ -25,6 +25,12 @@ class TOutputVulkanGLSLForMetal : public TOutputVulkanGLSL
int shaderVersion, int shaderVersion,
ShShaderOutput output, ShShaderOutput output,
ShCompileOptions compileOptions); ShCompileOptions compileOptions);
static void RemoveInvariantForTest(bool remove);
protected:
bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
void writeVariableType(const TType &type, const TSymbol *symbol) override;
}; };
} // namespace sh } // namespace sh
\ No newline at end of file
...@@ -10,11 +10,50 @@ ...@@ -10,11 +10,50 @@
#include "compiler/translator/OutputVulkanGLSLForMetal.h" #include "compiler/translator/OutputVulkanGLSLForMetal.h"
#include "common/debug.h" #include "common/apple_platform_utils.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/Symbol.h"
#include "compiler/translator/util.h"
namespace sh namespace sh
{ {
namespace
{
bool gOverrideRemoveInvariant = false;
bool ShoudRemoveInvariant(const TType &type)
{
if (gOverrideRemoveInvariant)
{
return true;
}
if (type.getQualifier() != EvqPosition)
{
// Metal only supports invariant for gl_Position
return true;
}
if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12))
{
return false;
}
else
{
// Metal 2.1 is not available, so we need to remove "invariant" keyword
return true;
}
}
}
// static
void TOutputVulkanGLSLForMetal::RemoveInvariantForTest(bool remove)
{
gOverrideRemoveInvariant = remove;
}
TOutputVulkanGLSLForMetal::TOutputVulkanGLSLForMetal(TInfoSinkBase &objSink, TOutputVulkanGLSLForMetal::TOutputVulkanGLSLForMetal(TInfoSinkBase &objSink,
ShArrayIndexClampingStrategy clampingStrategy, ShArrayIndexClampingStrategy clampingStrategy,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
...@@ -33,8 +72,32 @@ TOutputVulkanGLSLForMetal::TOutputVulkanGLSLForMetal(TInfoSinkBase &objSink, ...@@ -33,8 +72,32 @@ TOutputVulkanGLSLForMetal::TOutputVulkanGLSLForMetal(TInfoSinkBase &objSink,
shaderVersion, shaderVersion,
output, output,
compileOptions) compileOptions)
{}
void TOutputVulkanGLSLForMetal::writeVariableType(const TType &type, const TSymbol *symbol)
{ {
UNIMPLEMENTED(); TType overrideType(type);
// Remove invariant keyword if required.
if (type.isInvariant() && ShoudRemoveInvariant(type))
{
overrideType.setInvariant(false);
}
TOutputVulkanGLSL::writeVariableType(overrideType, symbol);
} }
bool TOutputVulkanGLSLForMetal::visitInvariantDeclaration(Visit visit,
TIntermInvariantDeclaration *node)
{
TInfoSinkBase &out = objSink();
ASSERT(visit == PreVisit);
const TIntermSymbol *symbol = node->getSymbol();
if (!ShoudRemoveInvariant(symbol->getType()))
{
out << "invariant ";
}
out << hashName(&symbol->variable());
return false;
}
} // namespace sh } // namespace sh
...@@ -4,40 +4,96 @@ ...@@ -4,40 +4,96 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// TranslatorMetal: // TranslatorMetal:
// Translator for Metal backend. // A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
// It takes into account some considerations for Metal backend also.
// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
//
// The SPIR-V will then be translated to Metal Shading Language later in Metal backend.
// //
#include "compiler/translator/TranslatorMetal.h" #include "compiler/translator/TranslatorMetal.h"
#include "common/debug.h" #include "angle_gl.h"
#include "common/utilities.h"
#include "compiler/translator/OutputVulkanGLSLForMetal.h" #include "compiler/translator/OutputVulkanGLSLForMetal.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/tree_util/BuiltIn.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
#include "compiler/translator/util.h"
namespace sh namespace sh
{ {
TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) namespace
: TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT) {
// Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
// manually.
// This operation performs flipping the gl_Position.y using this expression:
// gl_Position.y = gl_Position.y * negViewportScaleY
ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
TIntermBinary *negViewportYScale)
{
// Create a symbol reference to "gl_Position"
const TVariable *position = BuiltInVariable::gl_Position();
TIntermSymbol *positionRef = new TIntermSymbol(position);
// Create a swizzle to "gl_Position.y"
TVector<int> swizzleOffsetY;
swizzleOffsetY.push_back(1);
TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
// Create the expression "gl_Position.y * negViewportScaleY"
TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), negViewportYScale);
// Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
TIntermTyped *positionYLHS = positionY->deepCopy();
TIntermBinary *assignment = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
// Append the assignment as a statement at the end of the shader.
return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
}
} // anonymous namespace
TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) : TranslatorVulkan(type, spec)
{} {}
bool TranslatorMetal::translate(TIntermBlock *root, bool TranslatorMetal::translate(TIntermBlock *root,
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
PerformanceDiagnostics * /*perfDiagnostics*/) PerformanceDiagnostics *perfDiagnostics)
{ {
TInfoSinkBase &sink = getInfoSink().obj; TInfoSinkBase &sink = getInfoSink().obj;
TOutputVulkanGLSLForMetal outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
getNameMap(), &getSymbolTable(), getShaderType(), getNameMap(), &getSymbolTable(), getShaderType(),
getShaderVersion(), getOutputType(), compileOptions); getShaderVersion(), getOutputType(), compileOptions);
const TVariable *driverUniforms = nullptr;
if (!TranslatorVulkan::translateImpl(root, compileOptions, perfDiagnostics, &driverUniforms,
&outputGLSL))
{
return false;
}
UNIMPLEMENTED(); if (getShaderType() == GL_VERTEX_SHADER)
{
auto negViewportYScale = getDriverUniformNegViewportYScaleRef(driverUniforms);
// Append gl_Position.y correction to main
if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(),
negViewportYScale))
{
return false;
}
}
// Write translated shader.
root->traverse(&outputGLSL); root->traverse(&outputGLSL);
return false;
}
bool TranslatorMetal::shouldFlattenPragmaStdglInvariantAll() return true;
{
UNIMPLEMENTED();
return false;
} }
} // namespace sh } // namespace sh
...@@ -4,18 +4,23 @@ ...@@ -4,18 +4,23 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// TranslatorMetal: // TranslatorMetal:
// Translator for Metal backend. // A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
// It takes into account some considerations for Metal backend also.
// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
//
// The SPIR-V will then be translated to Metal Shading Language later in Metal backend.
// //
#ifndef LIBANGLE_RENDERER_METAL_TRANSLATORMETAL_H_ #ifndef LIBANGLE_RENDERER_METAL_TRANSLATORMETAL_H_
#define LIBANGLE_RENDERER_METAL_TRANSLATORMETAL_H_ #define LIBANGLE_RENDERER_METAL_TRANSLATORMETAL_H_
#include "compiler/translator/Compiler.h" #include "compiler/translator/TranslatorVulkan.h"
namespace sh namespace sh
{ {
class TranslatorMetal : public TCompiler class TranslatorMetal : public TranslatorVulkan
{ {
public: public:
TranslatorMetal(sh::GLenum type, ShShaderSpec spec); TranslatorMetal(sh::GLenum type, ShShaderSpec spec);
...@@ -24,8 +29,6 @@ class TranslatorMetal : public TCompiler ...@@ -24,8 +29,6 @@ class TranslatorMetal : public TCompiler
ANGLE_NO_DISCARD bool translate(TIntermBlock *root, ANGLE_NO_DISCARD bool translate(TIntermBlock *root,
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics) override; PerformanceDiagnostics *perfDiagnostics) override;
bool shouldFlattenPragmaStdglInvariantAll() override;
}; };
} // namespace sh } // namespace sh
......
...@@ -656,14 +656,13 @@ TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec) ...@@ -656,14 +656,13 @@ TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
: TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT) : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
{} {}
bool TranslatorVulkan::translate(TIntermBlock *root, bool TranslatorVulkan::translateImpl(TIntermBlock *root,
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
PerformanceDiagnostics * /*perfDiagnostics*/) PerformanceDiagnostics * /*perfDiagnostics*/,
const TVariable **driverUniformsOut,
TOutputVulkanGLSL *outputGLSL)
{ {
TInfoSinkBase &sink = getInfoSink().obj; TInfoSinkBase &sink = getInfoSink().obj;
TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
getNameMap(), &getSymbolTable(), getShaderType(),
getShaderVersion(), getOutputType(), compileOptions);
if (getShaderType() == GL_VERTEX_SHADER) if (getShaderType() == GL_VERTEX_SHADER)
{ {
...@@ -727,7 +726,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root, ...@@ -727,7 +726,7 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
defaultUniformCount -= removedUniformsCount; defaultUniformCount -= removedUniformsCount;
// We must declare the struct types before using them. // We must declare the struct types before using them.
DeclareStructTypesTraverser structTypesTraverser(&outputGLSL); DeclareStructTypesTraverser structTypesTraverser(outputGLSL);
root->traverse(&structTypesTraverser); root->traverse(&structTypesTraverser);
if (!structTypesTraverser.updateTree(this, root)) if (!structTypesTraverser.updateTree(this, root))
{ {
...@@ -939,6 +938,29 @@ bool TranslatorVulkan::translate(TIntermBlock *root, ...@@ -939,6 +938,29 @@ bool TranslatorVulkan::translate(TIntermBlock *root,
return false; return false;
} }
if (driverUniformsOut)
{
*driverUniformsOut = driverUniforms;
}
return true;
}
bool TranslatorVulkan::translate(TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics)
{
TInfoSinkBase &sink = getInfoSink().obj;
TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
getNameMap(), &getSymbolTable(), getShaderType(),
getShaderVersion(), getOutputType(), compileOptions);
if (!translateImpl(root, compileOptions, perfDiagnostics, nullptr, &outputGLSL))
{
return false;
}
// Write translated shader. // Write translated shader.
root->traverse(&outputGLSL); root->traverse(&outputGLSL);
...@@ -951,4 +973,10 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll() ...@@ -951,4 +973,10 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
return false; return false;
} }
TIntermBinary *TranslatorVulkan::getDriverUniformNegViewportYScaleRef(
const TVariable *driverUniforms) const
{
return CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
}
} // namespace sh } // namespace sh
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
namespace sh namespace sh
{ {
class TOutputVulkanGLSL;
class TranslatorVulkan : public TCompiler class TranslatorVulkan : public TCompiler
{ {
public: public:
...@@ -27,6 +29,15 @@ class TranslatorVulkan : public TCompiler ...@@ -27,6 +29,15 @@ class TranslatorVulkan : public TCompiler
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics) override; PerformanceDiagnostics *perfDiagnostics) override;
bool shouldFlattenPragmaStdglInvariantAll() override; bool shouldFlattenPragmaStdglInvariantAll() override;
TIntermBinary *getDriverUniformNegViewportYScaleRef(const TVariable *driverUniforms) const;
// Subclass can call this method to transform the AST before writing the final output.
// See TranslatorMetal.cpp.
ANGLE_NO_DISCARD bool translateImpl(TIntermBlock *root,
ShCompileOptions compileOptions,
PerformanceDiagnostics *perfDiagnostics,
const TVariable **driverUniformsOut,
TOutputVulkanGLSL *outputGLSL);
}; };
} // namespace sh } // namespace sh
......
...@@ -83,6 +83,10 @@ angle_source_set("angle_metal_backend") { ...@@ -83,6 +83,10 @@ angle_source_set("angle_metal_backend") {
"${angle_root}:libANGLE_headers", "${angle_root}:libANGLE_headers",
] ]
deps = [
"${angle_spirv_cross_dir}/gn:spirv_cross_sources",
]
objc_flags = [ objc_flags = [
"-Wno-nullability-completeness", "-Wno-nullability-completeness",
"-Wno-unguarded-availability", "-Wno-unguarded-availability",
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <sstream> #include <sstream>
#include <spirv_msl.hpp>
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/ProgramLinkedResources.h"
...@@ -31,6 +33,85 @@ namespace ...@@ -31,6 +33,85 @@ namespace
#define SHADER_ENTRY_NAME @"main0" #define SHADER_ENTRY_NAME @"main0"
spv::ExecutionModel ShaderTypeToSpvExecutionModel(gl::ShaderType shaderType)
{
switch (shaderType)
{
case gl::ShaderType::Vertex:
return spv::ExecutionModelVertex;
case gl::ShaderType::Fragment:
return spv::ExecutionModelFragment;
default:
UNREACHABLE();
return spv::ExecutionModelMax;
}
}
// Some GLSL variables need 2 binding points in metal. For example,
// glsl sampler will be converted to 2 metal objects: texture and sampler.
// Thus we need to set 2 binding points for one glsl sampler variable.
using BindingField = uint32_t spirv_cross::MSLResourceBinding::*;
template <BindingField bindingField1, BindingField bindingField2 = bindingField1>
angle::Result BindResources(spirv_cross::CompilerMSL *compiler,
const spirv_cross::SmallVector<spirv_cross::Resource> &resources,
gl::ShaderType shaderType)
{
auto &compilerMsl = *compiler;
for (const spirv_cross::Resource &resource : resources)
{
spirv_cross::MSLResourceBinding resBinding;
resBinding.stage = ShaderTypeToSpvExecutionModel(shaderType);
if (compilerMsl.has_decoration(resource.id, spv::DecorationDescriptorSet))
{
resBinding.desc_set =
compilerMsl.get_decoration(resource.id, spv::DecorationDescriptorSet);
}
if (!compilerMsl.has_decoration(resource.id, spv::DecorationBinding))
{
continue;
}
resBinding.binding = compilerMsl.get_decoration(resource.id, spv::DecorationBinding);
uint32_t bindingPoint;
// NOTE(hqle): We use separate discrete binding point for now, in future, we should use
// one argument buffer for each descriptor set.
switch (resBinding.desc_set)
{
case 0:
// Use resBinding.binding as binding point.
bindingPoint = resBinding.binding;
break;
case mtl::kDriverUniformsBindingIndex:
bindingPoint = mtl::kDriverUniformsBindingIndex;
break;
case mtl::kDefaultUniformsBindingIndex:
// NOTE(hqle): Properly handle transform feedbacks and UBO binding once ES 3.0 is
// implemented.
bindingPoint = mtl::kDefaultUniformsBindingIndex;
break;
default:
// We don't support this descriptor set.
continue;
}
// bindingField can be buffer or texture, which will be translated to [[buffer(d)]] or
// [[texture(d)]] or [[sampler(d)]]
resBinding.*bindingField1 = bindingPoint;
if (bindingField1 != bindingField2)
{
resBinding.*bindingField2 = bindingPoint;
}
compilerMsl.add_msl_resource_binding(resBinding);
}
return angle::Result::Continue;
}
void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
gl::Shader *shader, gl::Shader *shader,
sh::BlockLayoutMap *blockLayoutMapOut, sh::BlockLayoutMap *blockLayoutMapOut,
...@@ -214,7 +295,7 @@ std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context, ...@@ -214,7 +295,7 @@ std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
// assignment done in that function. // assignment done in that function.
linkResources(resources); linkResources(resources);
mtl::GlslangUtils::GetShaderSource(mState, resources, &mShaderSource); mtl::GlslangGetShaderSource(mState, resources, &mShaderSource);
// NOTE(hqle): Parallelize linking. // NOTE(hqle): Parallelize linking.
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog)); return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
...@@ -231,8 +312,8 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, gl::InfoLog &in ...@@ -231,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::GlslangUtils::GetShaderCode(contextMtl, contextMtl->getCaps(), false, ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, contextMtl->getCaps(), false,
mShaderSource, &shaderCodes)); mShaderSource, &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,
...@@ -339,9 +420,47 @@ angle::Result ProgramMtl::convertToMsl(const gl::Context *glContext, ...@@ -339,9 +420,47 @@ angle::Result ProgramMtl::convertToMsl(const gl::Context *glContext,
gl::InfoLog &infoLog, gl::InfoLog &infoLog,
std::vector<uint32_t> *sprivCode) std::vector<uint32_t> *sprivCode)
{ {
std::string translatedMsl = "TODO"; ContextMtl *contextMtl = mtl::GetImpl(glContext);
UNIMPLEMENTED(); spirv_cross::CompilerMSL compilerMsl(std::move(*sprivCode));
spirv_cross::CompilerMSL::Options compOpt;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
compOpt.platform = spirv_cross::CompilerMSL::Options::macOS;
#else
compOpt.platform = spirv_cross::CompilerMSL::Options::iOS;
#endif
if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12))
{
// Use Metal 2.1
compOpt.set_msl_version(2, 1);
}
else
{
// Always use at least Metal 2.0.
compOpt.set_msl_version(2);
}
compilerMsl.set_msl_options(compOpt);
// Tell spirv-cross to map default & driver uniform blocks & samplers as we want
spirv_cross::ShaderResources mslRes = compilerMsl.get_shader_resources();
ANGLE_TRY(BindResources<&spirv_cross::MSLResourceBinding::msl_buffer>(
&compilerMsl, mslRes.uniform_buffers, shaderType));
ANGLE_TRY((BindResources<&spirv_cross::MSLResourceBinding::msl_sampler,
&spirv_cross::MSLResourceBinding::msl_texture>(
&compilerMsl, mslRes.sampled_images, shaderType)));
// NOTE(hqle): spirv-cross uses exceptions to report error, what should we do here
// in case of error?
std::string translatedMsl = compilerMsl.compile();
if (translatedMsl.size() == 0)
{
ANGLE_MTL_CHECK(contextMtl, false, GL_INVALID_OPERATION);
}
// Create actual Metal shader // Create actual Metal shader
ANGLE_TRY(createMslShader(glContext, shaderType, infoLog, translatedMsl)); ANGLE_TRY(createMslShader(glContext, shaderType, infoLog, translatedMsl));
......
...@@ -18,19 +18,15 @@ namespace rx ...@@ -18,19 +18,15 @@ namespace rx
{ {
namespace mtl namespace mtl
{ {
class GlslangUtils void GlslangGetShaderSource(const gl::ProgramState &programState,
{ const gl::ProgramLinkedResources &resources,
public: gl::ShaderMap<std::string> *shaderSourcesOut);
static void GetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
static angle::Result GetShaderCode(ErrorHandler *context, angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::Caps &glCaps, const gl::Caps &glCaps,
bool enableLineRasterEmulation, 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
} // namespace rx } // namespace rx
......
...@@ -14,24 +14,50 @@ namespace rx ...@@ -14,24 +14,50 @@ namespace rx
{ {
namespace mtl namespace mtl
{ {
namespace
{
angle::Result HandleError(ErrorHandler *context, GlslangError)
{
ANGLE_MTL_TRY(context, false);
return angle::Result::Stop;
}
GlslangSourceOptions CreateSourceOptions()
{
GlslangSourceOptions options;
// We don't actually use descriptor set for now, the actual binding will be done inside
// ProgramMtl using spirv-cross.
options.uniformsAndXfbDescriptorSetIndex = kDefaultUniformsBindingIndex;
options.textureDescriptorSetIndex = 0;
options.driverUniformsDescriptorSetIndex = kDriverUniformsBindingIndex;
// NOTE(hqle): Unused for now, until we support ES 3.0
options.shaderResourceDescriptorSetIndex = -1;
options.xfbBindingIndexStart = -1;
static_assert(kDefaultUniformsBindingIndex != 0, "kDefaultUniformsBindingIndex must not be 0");
static_assert(kDriverUniformsBindingIndex != 0, "kDriverUniformsBindingIndex must not be 0");
// static return options;
void GlslangUtils::GetShaderSource(const gl::ProgramState &programState, }
const gl::ProgramLinkedResources &resources, } // namespace
gl::ShaderMap<std::string> *shaderSourcesOut)
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
{ {
UNIMPLEMENTED(); rx::GlslangGetShaderSource(CreateSourceOptions(), false, programState, resources,
shaderSourcesOut);
} }
// static angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
angle::Result GlslangUtils::GetShaderCode(ErrorHandler *context, const gl::Caps &glCaps,
const gl::Caps &glCaps, bool enableLineRasterEmulation,
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)
{ {
UNIMPLEMENTED(); return rx::GlslangGetShaderSpirvCode(
return angle::Result::Stop; [context](GlslangError error) { return HandleError(context, error); }, glCaps,
enableLineRasterEmulation, shaderSources, shaderCodeOut);
} }
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
Name: Khronos SPIRV-Cross
Short Name: spirv-cross
URL: https://github.com/KhronosGroup/SPIRV-Cross
Version: N/A
Security Critical: yes
License: Apache 2.0
License File: LICENSE
Description:
A tool designed for parsing and converting SPIR-V to other shader languages.
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment