Hash :
7b9b284b
Author :
Date :
2015-06-15T11:02:49
Refactor GLSL version calculations for emulated functions. Pass the target GLSL version to InitBuiltInFunctionEmulatorForGLSL so that it can be updated to generate emulated functions for multiple versions. BUG=angleproject:1044 Change-Id: I34c408df52fd0f7d6c2f66d0579ac854afd93b87 Reviewed-on: https://chromium-review.googlesource.com/277700 Reviewed-by: Jamie Madill <jmadill@chromium.org> Tested-by: Geoff Lang <geofflang@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
//
// Copyright (c) 2002-2013 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.
//
#include "compiler/translator/TranslatorGLSL.h"
#include "angle_gl.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/OutputGLSL.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,
ShShaderSpec spec,
ShShaderOutput output)
: TCompiler(type, spec, output) {
}
void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
{
InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
}
int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
}
void TranslatorGLSL::translate(TIntermNode *root, int) {
TInfoSinkBase& sink = getInfoSink().obj;
// Write GLSL version.
writeVersion(root);
writePragma();
// Write extension behaviour as needed
writeExtensionBehavior();
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
if (precisionEmulation)
{
EmulatePrecision emulatePrecision;
root->traverse(&emulatePrecision);
emulatePrecision.updateTree();
emulatePrecision.writeEmulationHelpers(sink, getOutputType());
}
// Write emulated built-in functions if needed.
if (!getBuiltInFunctionEmulator().IsOutputEmpty())
{
sink << "// BEGIN: Generated code for built-in function emulation\n\n";
sink << "#define webgl_emu_precision\n\n";
getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink);
sink << "// END: Generated code for built-in function emulation\n\n";
}
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// 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 && IsGLSL130OrNewer(getOutputType()))
{
TFragmentOutSearcher searcher;
root->traverse(&searcher);
ASSERT(!(searcher.usesGlFragData() && searcher.usesGlFragColor()));
if (searcher.usesGlFragColor())
{
sink << "out vec4 webgl_FragColor;\n";
}
if (searcher.usesGlFragData())
{
sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
}
}
// Write translated shader.
TOutputGLSL outputGLSL(sink,
getArrayIndexClampingStrategy(),
getHashFunction(),
getNameMap(),
getSymbolTable(),
getShaderVersion(),
getOutputType());
root->traverse(&outputGLSL);
}
void TranslatorGLSL::writeVersion(TIntermNode *root)
{
TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
root->traverse(&versionGLSL);
int version = versionGLSL.getVersion();
// We need to write version directive only if it is greater than 110.
// If there is no version directive in the shader, 110 is implied.
if (version > 110)
{
TInfoSinkBase& sink = getInfoSink().obj;
sink << "#version " << version << "\n";
}
}
void TranslatorGLSL::writeExtensionBehavior() {
TInfoSinkBase& sink = getInfoSink().obj;
const TExtensionBehavior& extBehavior = getExtensionBehavior();
for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
iter != extBehavior.end(); ++iter) {
if (iter->second == EBhUndefined)
continue;
// For GLSL output, we don't need to emit most extensions explicitly,
// but some we need to translate.
if (iter->first == "GL_EXT_shader_texture_lod") {
sink << "#extension GL_ARB_shader_texture_lod : "
<< getBehaviorString(iter->second) << "\n";
}
}
}