Commit af1eed2e by Shahbaz Youssefi Committed by Angle LUCI CQ

Vulkan: Generate gl_FragColor/Data declarations in AST

gl_FragColor and gl_FragData are not available in Vulkan. Prior to this change, their declaration as webgl_FragColor and webgl_FragData was done in text. This change implements an AST transformation that declares a normal fragment output variable and replaces all references to these built-ins with those variables. Bug: angleproject:4889 Change-Id: If224e089dec25e4aa580beb135e1be2890de7887 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2953042Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 4fbb6f43
...@@ -189,7 +189,6 @@ angle_translator_sources = [ ...@@ -189,7 +189,6 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/gl/mac/AddAndTrueToLoopCondition.h", "src/compiler/translator/tree_ops/gl/mac/AddAndTrueToLoopCondition.h",
"src/compiler/translator/tree_ops/gl/mac/RewriteDoWhile.h", "src/compiler/translator/tree_ops/gl/mac/RewriteDoWhile.h",
"src/compiler/translator/tree_ops/gl/mac/UnfoldShortCircuitAST.h", "src/compiler/translator/tree_ops/gl/mac/UnfoldShortCircuitAST.h",
"src/compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.h",
"src/compiler/translator/tree_ops/vulkan/EarlyFragmentTestsOptimization.h", "src/compiler/translator/tree_ops/vulkan/EarlyFragmentTestsOptimization.h",
"src/compiler/translator/tree_util/AsNode.h", "src/compiler/translator/tree_util/AsNode.h",
"src/compiler/translator/tree_util/BuiltIn.h", "src/compiler/translator/tree_util/BuiltIn.h",
...@@ -335,7 +334,10 @@ angle_translator_lib_vulkan_sources = [ ...@@ -335,7 +334,10 @@ angle_translator_lib_vulkan_sources = [
"src/compiler/translator/TranslatorVulkan.cpp", "src/compiler/translator/TranslatorVulkan.cpp",
"src/compiler/translator/glslang_wrapper.cpp", "src/compiler/translator/glslang_wrapper.cpp",
"src/compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.cpp", "src/compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.cpp",
"src/compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.h",
"src/compiler/translator/tree_ops/vulkan/EarlyFragmentTestsOptimization.cpp", "src/compiler/translator/tree_ops/vulkan/EarlyFragmentTestsOptimization.cpp",
"src/compiler/translator/tree_ops/vulkan/EmulateFragColorData.cpp",
"src/compiler/translator/tree_ops/vulkan/EmulateFragColorData.h",
"src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.cpp", "src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.cpp",
"src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h", "src/compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h",
"src/compiler/translator/tree_ops/vulkan/MonomorphizeUnsupportedFunctionsInVulkanGLSL.cpp", "src/compiler/translator/tree_ops/vulkan/MonomorphizeUnsupportedFunctionsInVulkanGLSL.cpp",
......
...@@ -61,11 +61,11 @@ void TOutputGLSL::visitSymbol(TIntermSymbol *node) ...@@ -61,11 +61,11 @@ void TOutputGLSL::visitSymbol(TIntermSymbol *node)
} }
else if (name == "gl_SecondaryFragColorEXT") else if (name == "gl_SecondaryFragColorEXT")
{ {
out << "angle_SecondaryFragColor"; out << "webgl_SecondaryFragColor";
} }
else if (name == "gl_SecondaryFragDataEXT") else if (name == "gl_SecondaryFragDataEXT")
{ {
out << "angle_SecondaryFragData"; out << "webgl_SecondaryFragData";
} }
else else
{ {
......
...@@ -126,11 +126,17 @@ void TOutputVulkanGLSL::writeLayoutQualifier(TIntermSymbol *symbol) ...@@ -126,11 +126,17 @@ void TOutputVulkanGLSL::writeLayoutQualifier(TIntermSymbol *symbol)
if (needsLocation) if (needsLocation)
{ {
const unsigned int locationCount = uint32_t location = 0;
CalculateVaryingLocationCount(symbol->getType(), getShaderType()); if (layoutQualifier.index <= 0)
uint32_t location = IsShaderIn(type.getQualifier()) {
? nextUnusedInputLocation(locationCount) // Note: for index == 1 (dual source blending), don't count locations as they are
: nextUnusedOutputLocation(locationCount); // expected to alias the color output locations. Only one dual-source output is
// supported, so location will be always 0.
const unsigned int locationCount =
CalculateVaryingLocationCount(symbol->getType(), getShaderType());
location = IsShaderIn(type.getQualifier()) ? nextUnusedInputLocation(locationCount)
: nextUnusedOutputLocation(locationCount);
}
out << separator << "location=" << location; out << separator << "location=" << location;
separator = kCommaSeparator; separator = kCommaSeparator;
......
...@@ -189,11 +189,11 @@ bool TranslatorGLSL::translate(TIntermBlock *root, ...@@ -189,11 +189,11 @@ bool TranslatorGLSL::translate(TIntermBlock *root,
} }
if (hasGLSecondaryFragColor) if (hasGLSecondaryFragColor)
{ {
sink << "out vec4 angle_SecondaryFragColor;\n"; sink << "out vec4 webgl_SecondaryFragColor;\n";
} }
if (hasGLSecondaryFragData) if (hasGLSecondaryFragData)
{ {
sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers sink << "out vec4 webgl_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
<< "];\n"; << "];\n";
} }
......
...@@ -859,7 +859,7 @@ bool TranslatorMetalDirect::translateImpl(TInfoSinkBase &sink, ...@@ -859,7 +859,7 @@ bool TranslatorMetalDirect::translateImpl(TInfoSinkBase &sink,
} }
} }
SymbolEnv symbolEnv(*this, *root); SymbolEnv symbolEnv(*this, *root);
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // Declare gl_FragColor and gl_FragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used. // if it's core profile shaders and they are used.
if (getShaderType() == GL_FRAGMENT_SHADER) if (getShaderType() == GL_FRAGMENT_SHADER)
{ {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "compiler/translator/tree_ops/RewriteDfdy.h" #include "compiler/translator/tree_ops/RewriteDfdy.h"
#include "compiler/translator/tree_ops/RewriteStructSamplers.h" #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
#include "compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.h" #include "compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.h"
#include "compiler/translator/tree_ops/vulkan/EmulateFragColorData.h"
#include "compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h" #include "compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h"
#include "compiler/translator/tree_ops/vulkan/MonomorphizeUnsupportedFunctionsInVulkanGLSL.h" #include "compiler/translator/tree_ops/vulkan/MonomorphizeUnsupportedFunctionsInVulkanGLSL.h"
#include "compiler/translator/tree_ops/vulkan/ReplaceForShaderFramebufferFetch.h" #include "compiler/translator/tree_ops/vulkan/ReplaceForShaderFramebufferFetch.h"
...@@ -1048,67 +1049,24 @@ bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink, ...@@ -1048,67 +1049,24 @@ bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink,
} }
} }
bool hasGLFragColor = false; bool usePreRotation = (compileOptions & SH_ADD_PRE_ROTATION) != 0;
bool hasGLFragData = false; bool hasGLSampleMask = false;
bool usePreRotation = (compileOptions & SH_ADD_PRE_ROTATION) != 0;
bool hasGLSampleMask = false;
bool hasGLSecondaryFragColor = false;
bool hasGLSecondaryFragData = false;
for (const ShaderVariable &outputVar : mOutputVariables) for (const ShaderVariable &outputVar : mOutputVariables)
{ {
if (outputVar.name == "gl_FragColor") if (outputVar.name == "gl_SampleMask")
{
ASSERT(!hasGLFragColor);
hasGLFragColor = true;
continue;
}
else if (outputVar.name == "gl_FragData")
{
ASSERT(!hasGLFragData);
hasGLFragData = true;
continue;
}
else if (outputVar.name == "gl_SampleMask")
{ {
ASSERT(!hasGLSampleMask); ASSERT(!hasGLSampleMask);
hasGLSampleMask = true; hasGLSampleMask = true;
continue; continue;
} }
else if (outputVar.name == "gl_SecondaryFragColorEXT")
{
ASSERT(!hasGLSecondaryFragColor);
hasGLSecondaryFragColor = true;
continue;
}
else if (outputVar.name == "gl_SecondaryFragDataEXT")
{
ASSERT(!hasGLSecondaryFragData);
hasGLSecondaryFragData = true;
continue;
}
} }
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // Emulate gl_FragColor and gl_FragData with normal output variables.
// if it's core profile shaders and they are used. mValidateASTOptions.validateVariableReferences = false;
ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && if (!EmulateFragColorData(this, root, &getSymbolTable()))
(hasGLFragData || hasGLSecondaryFragData)));
if (hasGLFragColor)
{ {
sink << "layout(location = 0) out vec4 webgl_FragColor;\n"; return false;
}
if (hasGLFragData)
{
sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
}
if (hasGLSecondaryFragColor)
{
sink << "layout(location = 0, index = 1) out vec4 angle_SecondaryFragColor;\n";
}
if (hasGLSecondaryFragData)
{
sink << "layout(location = 0, index = 1) out vec4 angle_SecondaryFragData["
<< getResources().MaxDualSourceDrawBuffers << "];\n";
} }
if (usesPointCoord) if (usesPointCoord)
......
//
// Copyright 2021 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.
//
// EmulateFragColorData: Emulate gl_FragColor and gl_FragData.
//
#include "compiler/translator/tree_ops/vulkan/EmulateFragColorData.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/ImmutableStringBuilder.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/ReplaceVariable.h"
namespace sh
{
namespace
{
// Traverser that:
//
// 1. Declares outputs corresponding to gl_FragColor and gl_FragData (and their corresponding
// Secondary versions for framebuffer fetch).
// 2. Replaces built-in references with these variables.
class EmulateFragColorDataTraverser : public TIntermTraverser
{
public:
EmulateFragColorDataTraverser(TCompiler *compiler, TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable), mResources(compiler->getResources())
{}
void visitSymbol(TIntermSymbol *symbol) override
{
const TVariable *variable = &symbol->variable();
const TType &type = variable->getType();
// If this built-in was already visited, reuse the variable defined for it.
auto replacement = mVariableMap.find(variable);
if (replacement != mVariableMap.end())
{
queueReplacement(replacement->second->deepCopy(), OriginalNode::IS_DROPPED);
return;
}
unsigned int arraySize = 0;
int index = 0;
const char *name = "";
// Replace the built-ins being emulated with a variable of the appropriate type.
switch (type.getQualifier())
{
case EvqFragColor:
name = "webgl_FragColor";
break;
case EvqFragData:
name = "webgl_FragData";
arraySize = mResources.MaxDrawBuffers;
break;
case EvqSecondaryFragColorEXT:
name = "webgl_SecondaryFragColor";
index = 1;
break;
case EvqSecondaryFragDataEXT:
name = "webgl_SecondaryFragData";
index = 1;
arraySize = mResources.MaxDualSourceDrawBuffers;
break;
default:
// Not the built-in we are looking for.
return;
}
TType *outputType = new TType(*StaticType::GetQualified<EbtFloat, EvqFragmentOut, 4, 1>());
if (arraySize > 0)
{
outputType->makeArray(arraySize);
}
if (index > 0)
{
TLayoutQualifier layoutQualifier = outputType->getLayoutQualifier();
layoutQualifier.index = index;
outputType->setLayoutQualifier(layoutQualifier);
}
TVariable *replacementVar = new TVariable(mSymbolTable, ImmutableString(name), outputType,
SymbolType::AngleInternal);
TIntermSymbol *newSymbol = new TIntermSymbol(replacementVar);
mVariableMap[variable] = newSymbol;
queueReplacement(newSymbol, OriginalNode::IS_DROPPED);
}
void addDeclarations(TIntermBlock *root)
{
// Insert the declaration before the first function.
size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
TIntermSequence declarations;
for (auto &replaced : mVariableMap)
{
TIntermDeclaration *decl = new TIntermDeclaration;
TIntermSymbol *symbol = replaced.second->deepCopy()->getAsSymbolNode();
decl->appendDeclarator(symbol);
declarations.push_back(decl);
}
root->insertChildNodes(firstFunctionIndex, declarations);
}
private:
const ShBuiltInResources &mResources;
// A map of already replaced built-in variables.
VariableReplacementMap mVariableMap;
};
} // anonymous namespace
bool EmulateFragColorData(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable)
{
if (compiler->getShaderType() != GL_FRAGMENT_SHADER)
{
return true;
}
EmulateFragColorDataTraverser traverser(compiler, symbolTable);
root->traverse(&traverser);
if (!traverser.updateTree(compiler, root))
{
return false;
}
traverser.addDeclarations(root);
return compiler->validateAST(root);
}
} // namespace sh
//
// Copyright 2021 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.
//
// EmulateFragColorData: Turn gl_FragColor and gl_FragData into normal fragment shader outputs.
// These built-ins are not supported by Vulkan.
//
#ifndef COMPILER_TRANSLATOR_TREEOPS_VULKAN_EMULATEFRAGCOLORDATA_H_
#define COMPILER_TRANSLATOR_TREEOPS_VULKAN_EMULATEFRAGCOLORDATA_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermBlock;
class TSymbolTable;
ANGLE_NO_DISCARD bool EmulateFragColorData(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_VULKAN_EMULATEFRAGCOLORDATA_H_
...@@ -33,6 +33,9 @@ enum ...@@ -33,6 +33,9 @@ enum
IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS =
IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers
// The vast majority of devices support only one dual-source draw buffer
IMPLEMENTATION_MAX_DUAL_SOURCE_DRAW_BUFFERS = 1,
IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16,
IMPLEMENTATION_MAX_GEOMETRY_SHADER_UNIFORM_BUFFERS = 16, IMPLEMENTATION_MAX_GEOMETRY_SHADER_UNIFORM_BUFFERS = 16,
IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16,
......
...@@ -3732,6 +3732,9 @@ void Context::initCaps() ...@@ -3732,6 +3732,9 @@ void Context::initCaps()
ANGLE_LIMIT_CAP(mState.mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS); ANGLE_LIMIT_CAP(mState.mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS);
ANGLE_LIMIT_CAP(mState.mExtensions.maxDualSourceDrawBuffers,
IMPLEMENTATION_MAX_DUAL_SOURCE_DRAW_BUFFERS);
// WebGL compatibility // WebGL compatibility
mState.mExtensions.webglCompatibility = mWebGLContext; mState.mExtensions.webglCompatibility = mWebGLContext;
for (const auto &extensionInfo : GetExtensionInfoMap()) for (const auto &extensionInfo : GetExtensionInfoMap())
......
...@@ -324,12 +324,12 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context, ...@@ -324,12 +324,12 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0, mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0,
"webgl_FragColor"); "webgl_FragColor");
mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1, mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1,
"angle_SecondaryFragColor"); "webgl_SecondaryFragColor");
} }
else if (output.name == "gl_SecondaryFragDataEXT") else if (output.name == "gl_SecondaryFragDataEXT")
{ {
// Basically we should have a loop here going over the output // Basically we should have a loop here going over the output
// array binding "webgl_FragData[i]" and "angle_SecondaryFragData[i]" array // array binding "webgl_FragData[i]" and "webgl_SecondaryFragData[i]" array
// indices to the correct color buffers and color indices. // indices to the correct color buffers and color indices.
// However I'm not sure if this construct is legal or not, neither ARB or // However I'm not sure if this construct is legal or not, neither ARB or
// EXT version of the spec mention this. They only mention that // EXT version of the spec mention this. They only mention that
...@@ -349,7 +349,7 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context, ...@@ -349,7 +349,7 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0, "webgl_FragData"); mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0, "webgl_FragData");
mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1, mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1,
"angle_SecondaryFragData"); "webgl_SecondaryFragData");
} }
} }
} }
......
...@@ -334,13 +334,13 @@ void AssignSecondaryOutputLocations(const gl::ProgramState &programState, ...@@ -334,13 +334,13 @@ void AssignSecondaryOutputLocations(const gl::ProgramState &programState,
if (outputVar.name == "gl_SecondaryFragColorEXT") if (outputVar.name == "gl_SecondaryFragColorEXT")
{ {
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
"angle_SecondaryFragColor", 0, "webgl_SecondaryFragColor", 0,
ShaderInterfaceVariableInfo::kInvalid, 0, 0); ShaderInterfaceVariableInfo::kInvalid, 0, 0);
} }
else if (outputVar.name == "gl_SecondaryFragDataEXT") else if (outputVar.name == "gl_SecondaryFragDataEXT")
{ {
AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment,
"angle_SecondaryFragData", 0, ShaderInterfaceVariableInfo::kInvalid, "webgl_SecondaryFragData", 0, ShaderInterfaceVariableInfo::kInvalid,
0, 0); 0, 0);
} }
} }
......
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