• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TranslatorMetal:
7 //   A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
8 //   It takes into account some considerations for Metal backend also.
9 //   The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
10 //   See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
11 //
12 //   The SPIR-V will then be translated to Metal Shading Language later in Metal backend.
13 //
14 
15 #include "compiler/translator/TranslatorMetal.h"
16 
17 #include "angle_gl.h"
18 #include "common/utilities.h"
19 #include "compiler/translator/OutputVulkanGLSLForMetal.h"
20 #include "compiler/translator/StaticType.h"
21 #include "compiler/translator/tree_util/BuiltIn.h"
22 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
23 #include "compiler/translator/util.h"
24 
25 namespace sh
26 {
27 
28 namespace
29 {
30 
31 // Unlike Vulkan having auto viewport flipping extension, in Metal we have to flip gl_Position.y
32 // manually.
33 // This operation performs flipping the gl_Position.y using this expression:
34 // gl_Position.y = gl_Position.y * negViewportScaleY
AppendVertexShaderPositionYCorrectionToMain(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,TIntermBinary * negViewportYScale)35 ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *compiler,
36                                                                   TIntermBlock *root,
37                                                                   TSymbolTable *symbolTable,
38                                                                   TIntermBinary *negViewportYScale)
39 {
40     // Create a symbol reference to "gl_Position"
41     const TVariable *position  = BuiltInVariable::gl_Position();
42     TIntermSymbol *positionRef = new TIntermSymbol(position);
43 
44     // Create a swizzle to "gl_Position.y"
45     TVector<int> swizzleOffsetY;
46     swizzleOffsetY.push_back(1);
47     TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
48 
49     // Create the expression "gl_Position.y * negViewportScaleY"
50     TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), negViewportYScale);
51 
52     // Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
53     TIntermTyped *positionYLHS = positionY->deepCopy();
54     TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionYLHS, inverseY);
55 
56     // Append the assignment as a statement at the end of the shader.
57     return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
58 }
59 
60 }  // anonymous namespace
61 
TranslatorMetal(sh::GLenum type,ShShaderSpec spec)62 TranslatorMetal::TranslatorMetal(sh::GLenum type, ShShaderSpec spec) : TranslatorVulkan(type, spec)
63 {}
64 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics * perfDiagnostics)65 bool TranslatorMetal::translate(TIntermBlock *root,
66                                 ShCompileOptions compileOptions,
67                                 PerformanceDiagnostics *perfDiagnostics)
68 {
69     TInfoSinkBase &sink = getInfoSink().obj;
70 
71     TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
72                                  getNameMap(), &getSymbolTable(), getShaderType(),
73                                  getShaderVersion(), getOutputType(), false, true, compileOptions);
74 
75     const TVariable *driverUniforms = nullptr;
76     if (!TranslatorVulkan::translateImpl(root, compileOptions, perfDiagnostics, &driverUniforms,
77                                          &outputGLSL))
78     {
79         return false;
80     }
81 
82     if (getShaderType() == GL_VERTEX_SHADER)
83     {
84         auto negViewportYScale = getDriverUniformNegViewportYScaleRef(driverUniforms);
85 
86         // Append gl_Position.y correction to main
87         if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(),
88                                                          negViewportYScale))
89         {
90             return false;
91         }
92     }
93 
94     // Write translated shader.
95     root->traverse(&outputGLSL);
96 
97     return true;
98 }
99 
100 // Metal needs to inverse the depth if depthRange is is reverse order, i.e. depth near > depth far
101 // This is achieved by multiply the depth value with scale value stored in
102 // driver uniform's depthRange.reserved
transformDepthBeforeCorrection(TIntermBlock * root,const TVariable * driverUniforms)103 bool TranslatorMetal::transformDepthBeforeCorrection(TIntermBlock *root,
104                                                      const TVariable *driverUniforms)
105 {
106     // Create a symbol reference to "gl_Position"
107     const TVariable *position  = BuiltInVariable::gl_Position();
108     TIntermSymbol *positionRef = new TIntermSymbol(position);
109 
110     // Create a swizzle to "gl_Position.z"
111     TVector<int> swizzleOffsetZ = {2};
112     TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
113 
114     // Create a ref to "depthRange.reserved"
115     TIntermBinary *viewportZScale = getDriverUniformDepthRangeReservedFieldRef(driverUniforms);
116 
117     // Create the expression "gl_Position.z * depthRange.reserved".
118     TIntermBinary *zScale = new TIntermBinary(EOpMul, positionZ->deepCopy(), viewportZScale);
119 
120     // Create the assignment "gl_Position.z = gl_Position.z * depthRange.reserved"
121     TIntermTyped *positionZLHS = positionZ->deepCopy();
122     TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, zScale);
123 
124     // Append the assignment as a statement at the end of the shader.
125     return RunAtTheEndOfShader(this, root, assignment, &getSymbolTable());
126 }
127 
128 }  // namespace sh
129