blob: ce4e9ea28f5dc9887533452feddfa992eb50aede [file] [log] [blame]
//
// 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