Commit 0932df61 by Kimmo Kinnunen Committed by Jamie Madill

Expose GL built-in output variables in ShGetOutputVariables

Expose GL built-in output variables in ShGetOutputVariables. Currently gl_FragColor, gl_FragData and gl_FragDepthEXT are exposed. The output variable names in the returned array are the input shader names, not the output shader names. This is needed in future features in which the emulation layer (command buffer/libANGLE) needs to know which output variables caller used. Example of such a feature is EXT_blend_func_extended, where gl_SecondaryFragColorEXT and gl_SecondaryFragDataEXT cause the need to bind the emulated output variables to their respective color indices. BUG=angleproject:1085 TEST=angle_unittests Change-Id: I7ca3e0fe6bdd3e3c66113518aa771cbb013fc014 Reviewed-on: https://chromium-review.googlesource.com/287230Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Tested-by: 's avatarKimmo Kinnunen <kkinnunen@nvidia.com>
parent 94d0e3e8
...@@ -12,51 +12,6 @@ ...@@ -12,51 +12,6 @@
#include "compiler/translator/OutputGLSL.h" #include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/VersionGLSL.h" #include "compiler/translator/VersionGLSL.h"
namespace
{
// To search for what output variables are used in a fragment shader.
// We handle gl_FragColor and gl_FragData at the moment.
class TFragmentOutSearcher : public TIntermTraverser
{
public:
TFragmentOutSearcher()
: TIntermTraverser(true, false, false),
mUsesGlFragColor(false),
mUsesGlFragData(false)
{
}
bool usesGlFragColor() const
{
return mUsesGlFragColor;
}
bool usesGlFragData() const
{
return mUsesGlFragData;
}
protected:
virtual void visitSymbol(TIntermSymbol *node) override
{
if (node->getSymbol() == "gl_FragColor")
{
mUsesGlFragColor = true;
}
else if (node->getSymbol() == "gl_FragData")
{
mUsesGlFragData = true;
}
}
private:
bool mUsesGlFragColor;
bool mUsesGlFragData;
};
} // namespace anonymous
TranslatorGLSL::TranslatorGLSL(sh::GLenum type, TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
ShShaderSpec spec, ShShaderSpec spec,
ShShaderOutput output) ShShaderOutput output)
...@@ -111,14 +66,25 @@ void TranslatorGLSL::translate(TIntermNode *root, int) { ...@@ -111,14 +66,25 @@ void TranslatorGLSL::translate(TIntermNode *root, int) {
// 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 && IsGLSL130OrNewer(getOutputType())) if (getShaderType() == GL_FRAGMENT_SHADER && IsGLSL130OrNewer(getOutputType()))
{ {
TFragmentOutSearcher searcher; bool usesGLFragColor = false;
root->traverse(&searcher); bool usesGLFragData = false;
ASSERT(!(searcher.usesGlFragData() && searcher.usesGlFragColor())); for (auto outputVar : outputVariables)
if (searcher.usesGlFragColor()) {
if (outputVar.name == "gl_FragColor")
{
usesGLFragColor = true;
}
else if (outputVar.name == "gl_FragData")
{
usesGLFragData = true;
}
}
ASSERT(!(usesGLFragColor && usesGLFragData));
if (usesGLFragColor)
{ {
sink << "out vec4 webgl_FragColor;\n"; sink << "out vec4 webgl_FragColor;\n";
} }
if (searcher.usesGlFragData()) if (usesGLFragData)
{ {
sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
} }
......
...@@ -148,6 +148,9 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, ...@@ -148,6 +148,9 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
mPositionAdded(false), mPositionAdded(false),
mPointSizeAdded(false), mPointSizeAdded(false),
mLastFragDataAdded(false), mLastFragDataAdded(false),
mFragColorAdded(false),
mFragDataAdded(false),
mFragDepthAdded(false),
mHashFunction(hashFunction), mHashFunction(hashFunction),
mSymbolTable(symbolTable) mSymbolTable(symbolTable)
{ {
...@@ -366,6 +369,57 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -366,6 +369,57 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
mLastFragDataAdded = true; mLastFragDataAdded = true;
} }
return; return;
case EvqFragColor:
if (!mFragColorAdded)
{
Attribute info;
const char kName[] = "gl_FragColor";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT_VEC4;
info.arraySize = 0;
info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
info.staticUse = true;
mOutputVariables->push_back(info);
mFragColorAdded = true;
}
return;
case EvqFragData:
if (!mFragDataAdded)
{
Attribute info;
const char kName[] = "gl_FragData";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT_VEC4;
info.arraySize = static_cast<const TVariable *>(
mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))
->getConstPointer()
->getIConst();
info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
info.staticUse = true;
mOutputVariables->push_back(info);
mFragDataAdded = true;
}
return;
case EvqFragDepth:
if (!mFragDepthAdded)
{
Attribute info;
const char kName[] = "gl_FragDepthEXT";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT;
info.arraySize = 0;
info.precision =
GLVariablePrecision(static_cast<const TVariable *>(
mSymbolTable.findBuiltIn("gl_FragDepthEXT", 100))
->getType());
info.staticUse = true;
mOutputVariables->push_back(info);
mFragDepthAdded = true;
}
return;
default: default:
break; break;
} }
......
...@@ -56,6 +56,9 @@ class CollectVariables : public TIntermTraverser ...@@ -56,6 +56,9 @@ class CollectVariables : public TIntermTraverser
bool mPositionAdded; bool mPositionAdded;
bool mPointSizeAdded; bool mPointSizeAdded;
bool mLastFragDataAdded; bool mLastFragDataAdded;
bool mFragColorAdded;
bool mFragDataAdded;
bool mFragDepthAdded;
ShHashFunction64 mHashFunction; ShHashFunction64 mHashFunction;
......
...@@ -94,6 +94,24 @@ class CollectVariablesTest : public testing::Test ...@@ -94,6 +94,24 @@ class CollectVariablesTest : public testing::Test
EXPECT_TRUE(foundNear && foundFar && foundDiff); EXPECT_TRUE(foundNear && foundFar && foundDiff);
} }
// For use in tests for output varibles.
void validateOutputVariableForShader(const std::string &shaderString,
const char *varName,
const sh::Attribute **outResult)
{
const char *shaderStrings[] = {shaderString.c_str()};
ASSERT_TRUE(mTranslator->compile(shaderStrings, 1, SH_VARIABLES))
<< mTranslator->getInfoSink().info.str();
const std::vector<sh::Attribute> &outputVariables = mTranslator->getOutputVariables();
ASSERT_LT(0u, outputVariables.size());
const sh::Attribute &outputVariable = outputVariables[0];
EXPECT_EQ(-1, outputVariable.location);
EXPECT_TRUE(outputVariable.staticUse);
EXPECT_EQ(varName, outputVariable.name);
*outResult = &outputVariable;
}
GLenum mShaderType; GLenum mShaderType;
TranslatorGLSL *mTranslator; TranslatorGLSL *mTranslator;
}; };
...@@ -448,3 +466,93 @@ TEST_F(CollectFragmentVariablesTest, DepthRange) ...@@ -448,3 +466,93 @@ TEST_F(CollectFragmentVariablesTest, DepthRange)
validateDepthRangeShader(shaderString); validateDepthRangeShader(shaderString);
} }
// Test that gl_FragColor built-in usage in ESSL1 fragment shader is reflected in the output
// variables list.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragColor)
{
const std::string &fragColorShader =
"precision mediump float;\n"
"void main() {\n"
" gl_FragColor = vec4(1.0);\n"
"}\n";
const sh::Attribute *outputVariable = nullptr;
validateOutputVariableForShader(fragColorShader, "gl_FragColor", &outputVariable);
ASSERT_NE(outputVariable, nullptr);
EXPECT_EQ(0u, outputVariable->arraySize);
EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);
}
// Test that gl_FragData built-in usage in ESSL1 fragment shader is reflected in the output
// variables list.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragData)
{
const std::string &fragDataShader =
"#extension GL_EXT_draw_buffers : require\n"
"precision mediump float;\n"
"void main() {\n"
" gl_FragData[0] = vec4(1.0);\n"
" gl_FragData[1] = vec4(0.5);\n"
"}\n";
ShBuiltInResources resources = mTranslator->getResources();
resources.EXT_draw_buffers = 1;
const unsigned int kMaxDrawBuffers = 3u;
resources.MaxDrawBuffers = kMaxDrawBuffers;
initTranslator(resources);
const sh::Attribute *outputVariable = nullptr;
validateOutputVariableForShader(fragDataShader, "gl_FragData", &outputVariable);
ASSERT_NE(outputVariable, nullptr);
EXPECT_EQ(kMaxDrawBuffers, outputVariable->arraySize);
EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);
}
// Test that gl_FragDataEXT built-in usage in ESSL1 fragment shader is reflected in the output
// variables list. Also test that the precision is mediump.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthMediump)
{
const std::string &fragDepthShader =
"#extension GL_EXT_frag_depth : require\n"
"precision mediump float;\n"
"void main() {\n"
" gl_FragDepthEXT = 0.7;"
"}\n";
ShBuiltInResources resources = mTranslator->getResources();
resources.EXT_frag_depth = 1;
initTranslator(resources);
const sh::Attribute *outputVariable = nullptr;
validateOutputVariableForShader(fragDepthShader, "gl_FragDepthEXT", &outputVariable);
ASSERT_NE(outputVariable, nullptr);
EXPECT_EQ(0u, outputVariable->arraySize);
EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);
EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);
}
// Test that gl_FragDataEXT built-in usage in ESSL1 fragment shader is reflected in the output
// variables list. Also test that the precision is highp if user requests it.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthHighp)
{
const std::string &fragDepthHighShader =
"#extension GL_EXT_frag_depth : require\n"
"void main() {\n"
" gl_FragDepthEXT = 0.7;"
"}\n";
ShBuiltInResources resources = mTranslator->getResources();
resources.EXT_frag_depth = 1;
resources.FragmentPrecisionHigh = 1;
initTranslator(resources);
const sh::Attribute *outputVariable = nullptr;
validateOutputVariableForShader(fragDepthHighShader, "gl_FragDepthEXT", &outputVariable);
ASSERT_NE(outputVariable, nullptr);
EXPECT_EQ(0u, outputVariable->arraySize);
EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision);
}
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