void TOutputGLSL::visitSymbol(TIntermSymbol *node) { TInfoSinkBase& out = objSink(); const TString &symbol = node->getSymbol(); if (symbol == "gl_FragDepthEXT") { out << "gl_FragDepth"; } else if (symbol == "gl_FragColor" && IsGLSL130OrNewer(getShaderOutput())) { out << "webgl_FragColor"; } else if (symbol == "gl_FragData" && IsGLSL130OrNewer(getShaderOutput())) { out << "webgl_FragData"; } else if (symbol == "gl_SecondaryFragColorEXT") { out << "angle_SecondaryFragColor"; } else if (symbol == "gl_SecondaryFragDataEXT") { out << "angle_SecondaryFragData"; } else { TOutputGLSLBase::visitSymbol(node); } }
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 TOutputGLSLBase::writeVariableType(const TType &type) { TInfoSinkBase &out = objSink(); if (type.isInvariant()) { out << "invariant "; } TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { if (IsGLSL130OrNewer(mOutput)) { switch (qualifier) { case EvqAttribute: out << "in "; break; case EvqVaryingIn: out << "in "; break; case EvqVaryingOut: out << "out "; break; default: out << type.getQualifierString() << " "; break; } } else { out << type.getQualifierString() << " "; } } // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) { TStructure *structure = type.getStruct(); declareStruct(structure); if (!structure->name().empty()) { mDeclaredStructs.insert(structure->uniqueId()); } } else { if (writeVariablePrecision(type.getPrecision())) out << " "; out << getTypeName(type); } }
TString TOutputGLSL::translateTextureFunction(TString &name) { static const char *simpleRename[] = { "texture2DLodEXT", "texture2DLod", "texture2DProjLodEXT", "texture2DProjLod", "textureCubeLodEXT", "textureCubeLod", "texture2DGradEXT", "texture2DGradARB", "texture2DProjGradEXT", "texture2DProjGradARB", "textureCubeGradEXT", "textureCubeGradARB", NULL, NULL }; static const char *legacyToCoreRename[] = { "texture2D", "texture", "texture2DProj", "textureProj", "texture2DLod", "textureLod", "texture2DProjLod", "textureProjLod", "texture2DRect", "texture", "textureCube", "texture", "textureCubeLod", "textureLod", // Extensions "texture2DLodEXT", "textureLod", "texture2DProjLodEXT", "textureProjLod", "textureCubeLodEXT", "textureLod", "texture2DGradEXT", "textureGrad", "texture2DProjGradEXT", "textureProjGrad", "textureCubeGradEXT", "textureGrad", NULL, NULL }; const char **mapping = (IsGLSL130OrNewer(getShaderOutput())) ? legacyToCoreRename : simpleRename; for (int i = 0; mapping[i] != NULL; i += 2) { if (name == mapping[i]) { return mapping[i+1]; } } return name; }
void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); writePragma(); // Write extension behaviour as needed writeExtensionBehavior(root); bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); 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) { const bool mayHaveESSL1SecondaryOutputs = IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") && getShaderVersion() == 100; const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); bool hasGLFragColor = false; bool hasGLFragData = false; bool hasGLSecondaryFragColor = false; bool hasGLSecondaryFragData = false; for (const auto &outputVar : outputVariables) { if (declareGLFragmentOutputs) { if (outputVar.name == "gl_FragColor") { ASSERT(!hasGLFragColor); hasGLFragColor = true; continue; } else if (outputVar.name == "gl_FragData") { ASSERT(!hasGLFragData); hasGLFragData = true; continue; } } if (mayHaveESSL1SecondaryOutputs) { if (outputVar.name == "gl_SecondaryFragColorEXT") { ASSERT(!hasGLSecondaryFragColor); hasGLSecondaryFragColor = true; continue; } else if (outputVar.name == "gl_SecondaryFragDataEXT") { ASSERT(!hasGLSecondaryFragData); hasGLSecondaryFragData = true; continue; } } } ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && (hasGLFragData || hasGLSecondaryFragData))); if (hasGLFragColor) { sink << "out vec4 webgl_FragColor;\n"; } if (hasGLFragData) { sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; } if (hasGLSecondaryFragColor) { sink << "out vec4 angle_SecondaryFragColor;\n"; } if (hasGLSecondaryFragData) { sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers << "];\n"; } } // Write translated shader. TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion(), getOutputType()); root->traverse(&outputGLSL); }
void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); // Write extension behaviour as needed writeExtensionBehavior(root); // Write pragmas after extensions because some drivers consider pragmas // like non-preprocessor tokens. writePragma(compileOptions); // If flattening the global invariant pragma, write invariant declarations for built-in // variables. It should be harmless to do this twice in the case that the shader also explicitly // did this. However, it's important to emit invariant qualifiers only for those built-in // variables that are actually used, to avoid affecting the behavior of the shader. if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && getPragma().stdgl.invariantAll) { ASSERT(wereVariablesCollected()); switch (getShaderType()) { case GL_VERTEX_SHADER: sink << "invariant gl_Position;\n"; // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment // shaders if it's statically referenced. conditionallyOutputInvariantDeclaration("gl_PointSize"); break; case GL_FRAGMENT_SHADER: // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment // shaders, so we can use simple logic to determine whether to declare these // variables invariant. conditionallyOutputInvariantDeclaration("gl_FragCoord"); conditionallyOutputInvariantDeclaration("gl_PointCoord"); break; default: // Currently not reached, but leave this in for future expansion. ASSERT(false); break; } } if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) { sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); } bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), 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) { const bool mayHaveESSL1SecondaryOutputs = IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") && getShaderVersion() == 100; const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); bool hasGLFragColor = false; bool hasGLFragData = false; bool hasGLSecondaryFragColor = false; bool hasGLSecondaryFragData = false; for (const auto &outputVar : outputVariables) { if (declareGLFragmentOutputs) { if (outputVar.name == "gl_FragColor") { ASSERT(!hasGLFragColor); hasGLFragColor = true; continue; } else if (outputVar.name == "gl_FragData") { ASSERT(!hasGLFragData); hasGLFragData = true; continue; } } if (mayHaveESSL1SecondaryOutputs) { if (outputVar.name == "gl_SecondaryFragColorEXT") { ASSERT(!hasGLSecondaryFragColor); hasGLSecondaryFragColor = true; continue; } else if (outputVar.name == "gl_SecondaryFragDataEXT") { ASSERT(!hasGLSecondaryFragData); hasGLSecondaryFragData = true; continue; } } } ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && (hasGLFragData || hasGLSecondaryFragData))); if (hasGLFragColor) { sink << "out vec4 webgl_FragColor;\n"; } if (hasGLFragData) { sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; } if (hasGLSecondaryFragColor) { sink << "out vec4 angle_SecondaryFragColor;\n"; } if (hasGLSecondaryFragData) { sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers << "];\n"; } } if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) { const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] << ", local_size_z=" << localSize[2] << ") in;\n"; } // Write translated shader. TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), compileOptions); root->traverse(&outputGLSL); }
bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll() { // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't // translate to that version, return true for the next higher version. return IsGLSL130OrNewer(getOutputType()); }