| // |
| // Copyright (c) 2019 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. |
| // |
| // TranslatorMetal: |
| // 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 "angle_gl.h" |
| #include "common/utilities.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 |
| { |
| |
| // 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, |
| ShCompileOptions compileOptions, |
| PerformanceDiagnostics *perfDiagnostics) |
| { |
| TInfoSinkBase &sink = getInfoSink().obj; |
| TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), |
| getNameMap(), &getSymbolTable(), getShaderType(), |
| getShaderVersion(), getOutputType(), compileOptions); |
| |
| const TVariable *driverUniforms = nullptr; |
| if (!TranslatorVulkan::translateImpl(root, compileOptions, perfDiagnostics, &driverUniforms, |
| &outputGLSL)) |
| { |
| return false; |
| } |
| |
| 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); |
| |
| return true; |
| } |
| |
| // Metal needs to inverse the depth if depthRange is is reverse order, i.e. depth near > depth far |
| // This is achieved by multiply the depth value with scale value stored in |
| // driver uniform's depthRange.reserved |
| bool TranslatorMetal::transformDepthBeforeCorrection(TIntermBlock *root, |
| const TVariable *driverUniforms) |
| { |
| // Create a symbol reference to "gl_Position" |
| const TVariable *position = BuiltInVariable::gl_Position(); |
| TIntermSymbol *positionRef = new TIntermSymbol(position); |
| |
| // Create a swizzle to "gl_Position.z" |
| TVector<int> swizzleOffsetZ = {2}; |
| TIntermSwizzle *positionZ = new TIntermSwizzle(positionRef, swizzleOffsetZ); |
| |
| // Create a ref to "depthRange.reserved" |
| TIntermBinary *viewportZScale = getDriverUniformDepthRangeReservedFieldRef(driverUniforms); |
| |
| // Create the expression "gl_Position.z * depthRange.reserved". |
| TIntermBinary *zScale = new TIntermBinary(EOpMul, positionZ->deepCopy(), viewportZScale); |
| |
| // Create the assignment "gl_Position.z = gl_Position.z * depthRange.reserved" |
| TIntermTyped *positionZLHS = positionZ->deepCopy(); |
| TIntermBinary *assignment = new TIntermBinary(TOperator::EOpAssign, positionZLHS, zScale); |
| |
| // Append the assignment as a statement at the end of the shader. |
| return RunAtTheEndOfShader(this, root, assignment, &getSymbolTable()); |
| } |
| |
| } // namespace sh |