// // 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() : 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) InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); } 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 && getOutputType() == SH_GLSL_CORE_OUTPUT) { 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"; } } }