Vulkan: Implement new GLSL translator back-end.
The Vulkan GLSL translator back-end will handle validating and
translating our WebGL/ESSL shaders into Vulkan-specific GLSL.
glslang (the Vulkan one) accepts both GLSL and GLSL ES shaders
as inputs, and both the desktop and ESSL back-ends give
incompleteness warnings when used. For now, use the desktop GL
450 as a target for Vulkan GLSL.
The Vulkan-specific changes are currently only to add locations
to every vertex input and fragment output.
BUG=angleproject:1575
Change-Id: I7c3f32f522e9d18e5f8618eb7927336bf4fbdcf2
Reviewed-on: https://chromium-review.googlesource.com/412266
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/CodeGen.cpp b/src/compiler/translator/CodeGen.cpp
index f9f50c4..75f0d36 100644
--- a/src/compiler/translator/CodeGen.cpp
+++ b/src/compiler/translator/CodeGen.cpp
@@ -16,6 +16,10 @@
#include "compiler/translator/TranslatorHLSL.h"
#endif // ANGLE_ENABLE_HLSL
+#ifdef ANGLE_ENABLE_VULKAN
+#include "compiler/translator/TranslatorVulkan.h"
+#endif // ANGLE_ENABLE_VULKAN
+
namespace sh
{
@@ -68,9 +72,13 @@
#endif // ANGLE_ENABLE_HLSL
case SH_GLSL_VULKAN_OUTPUT:
- UNIMPLEMENTED();
- // TODO(jmadill): Vulkan GLSL
+#ifdef ANGLE_ENABLE_VULKAN
+ return new TranslatorVulkan(type, spec);
+#else
+ // This compiler is not supported in this configuration. Return NULL per the
+ // ShConstructCompiler API.
return nullptr;
+#endif // ANGLE_ENABLE_VULKAN
default:
// Unknown format. Return NULL per the sh::ConstructCompiler API.
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index 5f7d7d9..4c26c73 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -39,7 +39,7 @@
TInfoSinkBase &objSink() { return mObjSink; }
void writeFloat(TInfoSinkBase &out, float f);
void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
- void writeLayoutQualifier(const TType &type);
+ virtual void writeLayoutQualifier(const TType &type);
void writeInvariantQualifier(const TType &type);
void writeVariableType(const TType &type);
virtual bool writeVariablePrecision(TPrecision precision) = 0;
diff --git a/src/compiler/translator/OutputVulkanGLSL.cpp b/src/compiler/translator/OutputVulkanGLSL.cpp
new file mode 100644
index 0000000..c2c7813
--- /dev/null
+++ b/src/compiler/translator/OutputVulkanGLSL.cpp
@@ -0,0 +1,91 @@
+//
+// Copyright (c) 2016 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.
+//
+// OutputVulkanGLSL:
+// Code that outputs shaders that fit GL_KHR_vulkan_glsl.
+// 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
+//
+
+#include "compiler/translator/OutputVulkanGLSL.h"
+
+namespace sh
+{
+
+TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable &symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions)
+ : TOutputGLSLBase(objSink,
+ clampingStrategy,
+ hashFunction,
+ nameMap,
+ symbolTable,
+ shaderType,
+ shaderVersion,
+ output,
+ compileOptions)
+{
+}
+
+// TODO(jmadill): This is not complete.
+void TOutputVulkanGLSL::writeLayoutQualifier(const TType &type)
+{
+ TInfoSinkBase &out = objSink();
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+ out << "layout(";
+
+ if (type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut ||
+ type.getQualifier() == EvqVertexIn)
+ {
+ // TODO(jmadill): Multiple output locations.
+ out << "location = "
+ << "0";
+ }
+
+ if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
+ {
+ ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
+ out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
+ }
+
+ out << ") ";
+}
+
+bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase &out = objSink();
+ out << getPrecisionString(precision);
+ return true;
+}
+
+void TOutputVulkanGLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ const TString &symbol = node->getSymbol();
+ if (symbol == "gl_FragColor")
+ {
+ out << "webgl_FragColor";
+ }
+ else if (symbol == "gl_FragData")
+ {
+ out << "webgl_FragData";
+ }
+ else
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ }
+}
+
+} // namespace sh
diff --git a/src/compiler/translator/OutputVulkanGLSL.h b/src/compiler/translator/OutputVulkanGLSL.h
new file mode 100644
index 0000000..75f2f35
--- /dev/null
+++ b/src/compiler/translator/OutputVulkanGLSL.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2016 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.
+//
+// OutputVulkanGLSL:
+// Code that outputs shaders that fit GL_KHR_vulkan_glsl.
+// 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
+//
+
+#include "compiler/translator/OutputGLSL.h"
+
+namespace sh
+{
+
+class TOutputVulkanGLSL : public TOutputGLSLBase
+{
+ public:
+ TOutputVulkanGLSL(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable &symbolTable,
+ sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput output,
+ ShCompileOptions compileOptions);
+
+ protected:
+ void writeLayoutQualifier(const TType &type) override;
+ bool writeVariablePrecision(TPrecision precision) override;
+ void visitSymbol(TIntermSymbol *node) override;
+};
+
+} // namespace sh
diff --git a/src/compiler/translator/TranslatorVulkan.cpp b/src/compiler/translator/TranslatorVulkan.cpp
new file mode 100644
index 0000000..5bc7eb0
--- /dev/null
+++ b/src/compiler/translator/TranslatorVulkan.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2016 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.
+//
+// TranslatorVulkan:
+// A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
+// 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
+//
+
+#include "compiler/translator/TranslatorVulkan.h"
+
+#include "angle_gl.h"
+#include "compiler/translator/OutputVulkanGLSL.h"
+
+namespace sh
+{
+
+TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
+ : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
+{
+}
+
+void TranslatorVulkan::translate(TIntermNode *root, ShCompileOptions compileOptions)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+
+ sink << "#version 450 core\n";
+
+ // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
+ // if it's core profile shaders and they are used.
+ if (getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ bool hasGLFragColor = false;
+ bool hasGLFragData = false;
+
+ for (const auto &outputVar : outputVariables)
+ {
+ if (outputVar.name == "gl_FragColor")
+ {
+ ASSERT(!hasGLFragColor);
+ hasGLFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_FragData")
+ {
+ ASSERT(!hasGLFragData);
+ hasGLFragData = true;
+ continue;
+ }
+ }
+ ASSERT(!(hasGLFragColor && hasGLFragData));
+ if (hasGLFragColor)
+ {
+ sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
+ }
+ if (hasGLFragData)
+ {
+ sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
+ }
+ }
+
+ // Write translated shader.
+ TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
+ getNameMap(), getSymbolTable(), getShaderType(),
+ getShaderVersion(), getOutputType(), compileOptions);
+ root->traverse(&outputGLSL);
+}
+
+bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not necessary.
+ return false;
+}
+
+} // namespace sh
diff --git a/src/compiler/translator/TranslatorVulkan.h b/src/compiler/translator/TranslatorVulkan.h
new file mode 100644
index 0000000..5bca394
--- /dev/null
+++ b/src/compiler/translator/TranslatorVulkan.h
@@ -0,0 +1,32 @@
+//
+// Copyright (c) 2016 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.
+//
+// TranslatorVulkan:
+// A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl.
+// 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
+//
+
+#ifndef COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_
+#define COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+
+class TranslatorVulkan : public TCompiler
+{
+ public:
+ TranslatorVulkan(sh::GLenum type, ShShaderSpec spec);
+
+ protected:
+ void translate(TIntermNode *root, ShCompileOptions compileOptions) override;
+ bool shouldFlattenPragmaStdglInvariantAll() override;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_