Commit 06235df9 by Olli Etuaho Committed by Commit Bot

Make HLSL shaders use only one main function

Instead of having separate main() and gl_main() functions in HLSL shaders, add initializing outputs and inputs directly to the main function that's in the AST. This works around some HLSL bugs and should not introduce name conflicts inside main() since all the user-defined variables are prefixed. BUG=angleproject:2325 TEST=angle_end2end_tests Change-Id: I5b000c96aac8f321cefe50b6a893008498eac0d5 Reviewed-on: https://chromium-review.googlesource.com/1146647Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 522095f7
...@@ -182,6 +182,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -182,6 +182,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
int numRenderTargets, int numRenderTargets,
const std::vector<Uniform> &uniforms, const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
sh::WorkGroupSize workGroupSize,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
PerformanceDiagnostics *perfDiagnostics) PerformanceDiagnostics *perfDiagnostics)
: TIntermTraverser(true, true, true, symbolTable), : TIntermTraverser(true, true, true, symbolTable),
...@@ -191,12 +192,13 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -191,12 +192,13 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mSourcePath(sourcePath), mSourcePath(sourcePath),
mOutputType(outputType), mOutputType(outputType),
mCompileOptions(compileOptions), mCompileOptions(compileOptions),
mInsideFunction(false),
mInsideMain(false),
mNumRenderTargets(numRenderTargets), mNumRenderTargets(numRenderTargets),
mCurrentFunctionMetadata(nullptr), mCurrentFunctionMetadata(nullptr),
mWorkGroupSize(workGroupSize),
mPerfDiagnostics(perfDiagnostics) mPerfDiagnostics(perfDiagnostics)
{ {
mInsideFunction = false;
mUsesFragColor = false; mUsesFragColor = false;
mUsesFragData = false; mUsesFragData = false;
mUsesDepthRange = false; mUsesDepthRange = false;
...@@ -1743,10 +1745,16 @@ bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node) ...@@ -1743,10 +1745,16 @@ bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
{ {
TInfoSinkBase &out = getInfoSink(); TInfoSinkBase &out = getInfoSink();
bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
if (mInsideFunction) if (mInsideFunction)
{ {
outputLineDirective(out, node->getLine().first_line); outputLineDirective(out, node->getLine().first_line);
out << "{\n"; out << "{\n";
if (isMainBlock)
{
out << "@@ MAIN PROLOGUE @@\n";
}
} }
for (TIntermNode *statement : *node->getSequence()) for (TIntermNode *statement : *node->getSequence())
...@@ -1781,6 +1789,19 @@ bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node) ...@@ -1781,6 +1789,19 @@ bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
if (mInsideFunction) if (mInsideFunction)
{ {
outputLineDirective(out, node->getLine().last_line); outputLineDirective(out, node->getLine().last_line);
if (isMainBlock && shaderNeedsGenerateOutput())
{
// We could have an empty main, a main function without a branch at the end, or a main
// function with a discard statement at the end. In these cases we need to add a return
// statement.
bool needReturnStatement =
node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
if (needReturnStatement)
{
out << "return " << generateOutputCall() << ";\n";
}
}
out << "}\n"; out << "}\n";
} }
...@@ -1797,40 +1818,64 @@ bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition ...@@ -1797,40 +1818,64 @@ bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition
ASSERT(index != CallDAG::InvalidIndex); ASSERT(index != CallDAG::InvalidIndex);
mCurrentFunctionMetadata = &mASTMetadataList[index]; mCurrentFunctionMetadata = &mASTMetadataList[index];
out << TypeString(node->getFunctionPrototype()->getType()) << " ";
const TFunction *func = node->getFunction(); const TFunction *func = node->getFunction();
if (func->isMain()) if (func->isMain())
{ {
out << "gl_main("; // The stub strings below are replaced when shader is dynamically defined by its layout:
switch (mShaderType)
{
case GL_VERTEX_SHADER:
out << "@@ VERTEX ATTRIBUTES @@\n\n"
<< "@@ VERTEX OUTPUT @@\n\n"
<< "VS_OUTPUT main(VS_INPUT input)";
break;
case GL_FRAGMENT_SHADER:
out << "@@ PIXEL OUTPUT @@\n\n"
<< "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
break;
case GL_COMPUTE_SHADER:
out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
<< mWorkGroupSize[2] << ")]\n";
out << "void main(CS_INPUT input)";
break;
default:
UNREACHABLE();
break;
}
} }
else else
{ {
out << TypeString(node->getFunctionPrototype()->getType()) << " ";
out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func) out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
<< (mOutputLod0Function ? "Lod0(" : "("); << (mOutputLod0Function ? "Lod0(" : "(");
}
size_t paramCount = func->getParamCount(); size_t paramCount = func->getParamCount();
for (unsigned int i = 0; i < paramCount; i++) for (unsigned int i = 0; i < paramCount; i++)
{ {
const TVariable *param = func->getParam(i); const TVariable *param = func->getParam(i);
ensureStructDefined(param->getType()); ensureStructDefined(param->getType());
writeParameter(param, out); writeParameter(param, out);
if (i < paramCount - 1) if (i < paramCount - 1)
{ {
out << ", "; out << ", ";
}
} }
}
out << ")\n"; out << ")\n";
}
mInsideFunction = true; mInsideFunction = true;
if (func->isMain())
{
mInsideMain = true;
}
// The function body node will output braces. // The function body node will output braces.
node->getBody()->traverse(this); node->getBody()->traverse(this);
mInsideFunction = false; mInsideFunction = false;
mInsideMain = false;
mCurrentFunctionMetadata = nullptr; mCurrentFunctionMetadata = nullptr;
...@@ -2455,11 +2500,19 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) ...@@ -2455,11 +2500,19 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
case EOpReturn: case EOpReturn:
if (node->getExpression()) if (node->getExpression())
{ {
ASSERT(!mInsideMain);
out << "return "; out << "return ";
} }
else else
{ {
out << "return"; if (mInsideMain && shaderNeedsGenerateOutput())
{
out << "return " << generateOutputCall();
}
else
{
out << "return";
}
} }
break; break;
default: default:
...@@ -3154,4 +3207,21 @@ void OutputHLSL::ensureStructDefined(const TType &type) ...@@ -3154,4 +3207,21 @@ void OutputHLSL::ensureStructDefined(const TType &type)
} }
} }
bool OutputHLSL::shaderNeedsGenerateOutput() const
{
return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
}
const char *OutputHLSL::generateOutputCall() const
{
if (mShaderType == GL_VERTEX_SHADER)
{
return "generateOutput(input)";
}
else
{
return "generateOutput()";
}
}
} // namespace sh } // namespace sh
...@@ -53,6 +53,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -53,6 +53,7 @@ class OutputHLSL : public TIntermTraverser
int numRenderTargets, int numRenderTargets,
const std::vector<Uniform> &uniforms, const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions, ShCompileOptions compileOptions,
sh::WorkGroupSize workGroupSize,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
PerformanceDiagnostics *perfDiagnostics); PerformanceDiagnostics *perfDiagnostics);
...@@ -146,6 +147,9 @@ class OutputHLSL : public TIntermTraverser ...@@ -146,6 +147,9 @@ class OutputHLSL : public TIntermTraverser
// Ensures if the type is a struct, the struct is defined // Ensures if the type is a struct, the struct is defined
void ensureStructDefined(const TType &type); void ensureStructDefined(const TType &type);
bool shaderNeedsGenerateOutput() const;
const char *generateOutputCall() const;
sh::GLenum mShaderType; sh::GLenum mShaderType;
int mShaderVersion; int mShaderVersion;
const TExtensionBehavior &mExtensionBehavior; const TExtensionBehavior &mExtensionBehavior;
...@@ -154,6 +158,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -154,6 +158,7 @@ class OutputHLSL : public TIntermTraverser
ShCompileOptions mCompileOptions; ShCompileOptions mCompileOptions;
bool mInsideFunction; bool mInsideFunction;
bool mInsideMain;
// Output streams // Output streams
TInfoSinkBase mHeader; TInfoSinkBase mHeader;
...@@ -250,6 +255,8 @@ class OutputHLSL : public TIntermTraverser ...@@ -250,6 +255,8 @@ class OutputHLSL : public TIntermTraverser
// arrays can't be return values in HLSL. // arrays can't be return values in HLSL.
std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions; std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
sh::WorkGroupSize mWorkGroupSize;
PerformanceDiagnostics *mPerfDiagnostics; PerformanceDiagnostics *mPerfDiagnostics;
private: private:
......
...@@ -128,7 +128,8 @@ void TranslatorHLSL::translate(TIntermBlock *root, ...@@ -128,7 +128,8 @@ void TranslatorHLSL::translate(TIntermBlock *root,
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), getSourcePath(), getOutputType(), numRenderTargets, getUniforms(),
compileOptions, &getSymbolTable(), perfDiagnostics); compileOptions, getComputeShaderLocalSize(), &getSymbolTable(),
perfDiagnostics);
outputHLSL.output(root, getInfoSink().obj); outputHLSL.output(root, getInfoSink().obj);
......
...@@ -145,8 +145,11 @@ void WriteArrayString(std::ostringstream &strstr, unsigned int i) ...@@ -145,8 +145,11 @@ void WriteArrayString(std::ostringstream &strstr, unsigned int i)
strstr << "]"; strstr << "]";
} }
constexpr const char *VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; constexpr const char *VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@";
constexpr const char *PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; constexpr const char *VERTEX_OUTPUT_STUB_STRING = "@@ VERTEX OUTPUT @@";
constexpr const char *PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@";
constexpr const char *PIXEL_MAIN_PARAMETERS_STUB_STRING = "@@ PIXEL MAIN PARAMETERS @@";
constexpr const char *MAIN_PROLOGUE_STUB_STRING = "@@ MAIN PROLOGUE @@";
} // anonymous namespace } // anonymous namespace
// BuiltinInfo implementation // BuiltinInfo implementation
...@@ -478,7 +481,10 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -478,7 +481,10 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData()); ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData());
std::ostringstream vertexStream; std::ostringstream vertexStream;
vertexStream << vertexShaderGL->getTranslatedSource(context); vertexStream << "struct VS_OUTPUT\n";
const auto &vertexBuiltins = builtinsD3D[gl::ShaderType::Vertex];
generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(),
vertexStream);
// Instanced PointSprite emulation requires additional entries originally generated in the // Instanced PointSprite emulation requires additional entries originally generated in the
// GeometryShader HLSL. These include pointsize clamp values. // GeometryShader HLSL. These include pointsize clamp values.
...@@ -490,69 +496,56 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -490,69 +496,56 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
<< static_cast<int>(data.getCaps().maxAliasedPointSize) << ".0f;\n"; << static_cast<int>(data.getCaps().maxAliasedPointSize) << ".0f;\n";
} }
// Add stub string to be replaced when shader is dynamically defined by its layout std::ostringstream vertexGenerateOutput;
vertexStream << "\n" << std::string(VERTEX_ATTRIBUTE_STUB_STRING) << "\n"; vertexGenerateOutput << "VS_OUTPUT generateOutput(VS_INPUT input)\n"
<< "{\n"
const auto &vertexBuiltins = builtinsD3D[gl::ShaderType::Vertex]; << " VS_OUTPUT output;\n";
// Write the HLSL input/output declarations
vertexStream << "struct VS_OUTPUT\n";
generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(),
vertexStream);
vertexStream << "\n"
<< "VS_OUTPUT main(VS_INPUT input)\n"
<< "{\n"
<< " initAttributes(input);\n";
vertexStream << "\n"
<< " gl_main();\n"
<< "\n"
<< " VS_OUTPUT output;\n";
if (vertexBuiltins.glPosition.enabled) if (vertexBuiltins.glPosition.enabled)
{ {
vertexStream << " output.gl_Position = gl_Position;\n"; vertexGenerateOutput << " output.gl_Position = gl_Position;\n";
} }
if (vertexBuiltins.glViewIDOVR.enabled) if (vertexBuiltins.glViewIDOVR.enabled)
{ {
vertexStream << " output.gl_ViewID_OVR = ViewID_OVR;\n"; vertexGenerateOutput << " output.gl_ViewID_OVR = ViewID_OVR;\n";
} }
if (programMetadata.hasANGLEMultiviewEnabled() && programMetadata.canSelectViewInVertexShader()) if (programMetadata.hasANGLEMultiviewEnabled() && programMetadata.canSelectViewInVertexShader())
{ {
ASSERT(vertexBuiltins.glViewportIndex.enabled && vertexBuiltins.glLayer.enabled); ASSERT(vertexBuiltins.glViewportIndex.enabled && vertexBuiltins.glLayer.enabled);
vertexStream << " if (multiviewSelectViewportIndex)\n" vertexGenerateOutput << " if (multiviewSelectViewportIndex)\n"
<< " {\n" << " {\n"
<< " output.gl_ViewportIndex = ViewID_OVR;\n" << " output.gl_ViewportIndex = ViewID_OVR;\n"
<< " } else {\n" << " } else {\n"
<< " output.gl_ViewportIndex = 0;\n" << " output.gl_ViewportIndex = 0;\n"
<< " output.gl_Layer = ViewID_OVR;\n" << " output.gl_Layer = ViewID_OVR;\n"
<< " }\n"; << " }\n";
} }
// On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust.
if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{ {
vertexStream << " output.dx_Position.x = gl_Position.x;\n"; vertexGenerateOutput << " output.dx_Position.x = gl_Position.x;\n";
if (programMetadata.usesViewScale()) if (programMetadata.usesViewScale())
{ {
// This code assumes that dx_ViewScale.y = -1.0f when rendering to texture, and +1.0f // This code assumes that dx_ViewScale.y = -1.0f when rendering to texture, and +1.0f
// when rendering to the default framebuffer. No other values are valid. // when rendering to the default framebuffer. No other values are valid.
vertexStream << " output.dx_Position.y = dx_ViewScale.y * gl_Position.y;\n"; vertexGenerateOutput << " output.dx_Position.y = dx_ViewScale.y * gl_Position.y;\n";
} }
else else
{ {
vertexStream << " output.dx_Position.y = - gl_Position.y;\n"; vertexGenerateOutput << " output.dx_Position.y = - gl_Position.y;\n";
} }
vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" vertexGenerateOutput
<< " output.dx_Position.w = gl_Position.w;\n"; << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " output.dx_Position.w = gl_Position.w;\n";
} }
else else
{ {
vertexStream << " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + " vertexGenerateOutput << " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + "
"dx_ViewAdjust.x * gl_Position.w;\n"; "dx_ViewAdjust.x * gl_Position.w;\n";
// If usesViewScale() is true and we're using the D3D11 renderer via Feature Level 9_*, // If usesViewScale() is true and we're using the D3D11 renderer via Feature Level 9_*,
// then we need to multiply the gl_Position.y by the viewScale. // then we need to multiply the gl_Position.y by the viewScale.
...@@ -560,28 +553,30 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -560,28 +553,30 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
if (programMetadata.usesViewScale() && if (programMetadata.usesViewScale() &&
(shaderModel >= 4 && mRenderer->getShaderModelSuffix() != "")) (shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""))
{ {
vertexStream << " output.dx_Position.y = dx_ViewScale.y * (gl_Position.y * " vertexGenerateOutput << " output.dx_Position.y = dx_ViewScale.y * (gl_Position.y * "
"dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"; "dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n";
} }
else else
{ {
vertexStream << " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + " vertexGenerateOutput
"dx_ViewAdjust.y * gl_Position.w);\n"; << " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + "
"dx_ViewAdjust.y * gl_Position.w);\n";
} }
vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" vertexGenerateOutput
<< " output.dx_Position.w = gl_Position.w;\n"; << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " output.dx_Position.w = gl_Position.w;\n";
} }
// We don't need to output gl_PointSize if we use are emulating point sprites via instancing. // We don't need to output gl_PointSize if we use are emulating point sprites via instancing.
if (vertexBuiltins.glPointSize.enabled) if (vertexBuiltins.glPointSize.enabled)
{ {
vertexStream << " output.gl_PointSize = gl_PointSize;\n"; vertexGenerateOutput << " output.gl_PointSize = gl_PointSize;\n";
} }
if (vertexBuiltins.glFragCoord.enabled) if (vertexBuiltins.glFragCoord.enabled)
{ {
vertexStream << " output.gl_FragCoord = gl_Position;\n"; vertexGenerateOutput << " output.gl_FragCoord = gl_Position;\n";
} }
const auto &registerInfos = varyingPacking.getRegisterList(); const auto &registerInfos = varyingPacking.getRegisterList();
...@@ -592,58 +587,62 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -592,58 +587,62 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
const auto &varying = *packedVarying.varying; const auto &varying = *packedVarying.varying;
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
vertexStream << " output.v" << registerIndex << " = "; vertexGenerateOutput << " output.v" << registerIndex << " = ";
if (packedVarying.isStructField()) if (packedVarying.isStructField())
{ {
vertexStream << DecorateVariable(packedVarying.parentStructName) << "."; vertexGenerateOutput << DecorateVariable(packedVarying.parentStructName) << ".";
} }
vertexStream << DecorateVariable(varying.name); vertexGenerateOutput << DecorateVariable(varying.name);
if (varying.isArray()) if (varying.isArray())
{ {
WriteArrayString(vertexStream, registerInfo.varyingArrayIndex); WriteArrayString(vertexGenerateOutput, registerInfo.varyingArrayIndex);
} }
if (VariableRowCount(varying.type) > 1) if (VariableRowCount(varying.type) > 1)
{ {
WriteArrayString(vertexStream, registerInfo.varyingRowIndex); WriteArrayString(vertexGenerateOutput, registerInfo.varyingRowIndex);
} }
vertexStream << ";\n"; vertexGenerateOutput << ";\n";
} }
// Instanced PointSprite emulation requires additional entries to calculate // Instanced PointSprite emulation requires additional entries to calculate
// the final output vertex positions of the quad that represents each sprite. // the final output vertex positions of the quad that represents each sprite.
if (useInstancedPointSpriteEmulation) if (useInstancedPointSpriteEmulation)
{ {
vertexStream << "\n" vertexGenerateOutput
<< " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n"; << "\n"
<< " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n";
vertexStream << " output.dx_Position.x += (input.spriteVertexPos.x * gl_PointSize / " vertexGenerateOutput
"(dx_ViewCoords.x*2)) * output.dx_Position.w;"; << " output.dx_Position.x += (input.spriteVertexPos.x * gl_PointSize / "
"(dx_ViewCoords.x*2)) * output.dx_Position.w;";
if (programMetadata.usesViewScale()) if (programMetadata.usesViewScale())
{ {
// Multiply by ViewScale to invert the rendering when appropriate // Multiply by ViewScale to invert the rendering when appropriate
vertexStream << " output.dx_Position.y += (-dx_ViewScale.y * " vertexGenerateOutput
"input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2)) * " << " output.dx_Position.y += (-dx_ViewScale.y * "
"output.dx_Position.w;"; "input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2)) * "
"output.dx_Position.w;";
} }
else else
{ {
vertexStream << " output.dx_Position.y += (input.spriteVertexPos.y * gl_PointSize / " vertexGenerateOutput
"(dx_ViewCoords.y*2)) * output.dx_Position.w;"; << " output.dx_Position.y += (input.spriteVertexPos.y * gl_PointSize / "
"(dx_ViewCoords.y*2)) * output.dx_Position.w;";
} }
vertexStream vertexGenerateOutput
<< " output.dx_Position.z += input.spriteVertexPos.z * output.dx_Position.w;\n"; << " output.dx_Position.z += input.spriteVertexPos.z * output.dx_Position.w;\n";
if (programMetadata.usesPointCoord()) if (programMetadata.usesPointCoord())
{ {
vertexStream << "\n" vertexGenerateOutput << "\n"
<< " output.gl_PointCoord = input.spriteTexCoord;\n"; << " output.gl_PointCoord = input.spriteTexCoord;\n";
} }
} }
...@@ -653,75 +652,62 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -653,75 +652,62 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
if (programMetadata.usesInsertedPointCoordValue()) if (programMetadata.usesInsertedPointCoordValue())
{ {
ASSERT(!useInstancedPointSpriteEmulation); ASSERT(!useInstancedPointSpriteEmulation);
vertexStream << "\n" vertexGenerateOutput << "\n"
<< " output.gl_PointCoord = float2(0.5, 0.5);\n"; << " output.gl_PointCoord = float2(0.5, 0.5);\n";
} }
vertexStream << "\n" vertexGenerateOutput << "\n"
<< " return output;\n" << " return output;\n"
<< "}\n"; << "}";
std::string vertexSource = vertexShaderGL->getTranslatedSource(context);
angle::ReplaceSubstring(&vertexSource, std::string(MAIN_PROLOGUE_STUB_STRING),
" initAttributes(input);\n");
angle::ReplaceSubstring(&vertexSource, std::string(VERTEX_OUTPUT_STUB_STRING),
vertexGenerateOutput.str());
vertexStream << vertexSource;
const auto &pixelBuiltins = builtinsD3D[gl::ShaderType::Fragment]; const auto &pixelBuiltins = builtinsD3D[gl::ShaderType::Fragment];
std::ostringstream pixelStream; std::ostringstream pixelStream;
pixelStream << fragmentShaderGL->getTranslatedSource(context);
pixelStream << "struct PS_INPUT\n"; pixelStream << "struct PS_INPUT\n";
generateVaryingLinkHLSL(varyingPacking, pixelBuiltins, builtinsD3D.usesPointSize(), generateVaryingLinkHLSL(varyingPacking, pixelBuiltins, builtinsD3D.usesPointSize(),
pixelStream); pixelStream);
pixelStream << "\n"; pixelStream << "\n";
pixelStream << std::string(PIXEL_OUTPUT_STUB_STRING) << "\n"; std::ostringstream pixelPrologue;
if (fragmentShader->usesFrontFacing())
{
if (shaderModel >= 4)
{
pixelStream << "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
<< "{\n";
}
else
{
pixelStream << "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
<< "{\n";
}
}
else
{
pixelStream << "PS_OUTPUT main(PS_INPUT input)\n"
<< "{\n";
}
if (fragmentShader->usesViewID()) if (fragmentShader->usesViewID())
{ {
ASSERT(pixelBuiltins.glViewIDOVR.enabled); ASSERT(pixelBuiltins.glViewIDOVR.enabled);
pixelStream << " ViewID_OVR = input.gl_ViewID_OVR;\n"; pixelPrologue << " ViewID_OVR = input.gl_ViewID_OVR;\n";
} }
if (pixelBuiltins.glFragCoord.enabled) if (pixelBuiltins.glFragCoord.enabled)
{ {
pixelStream << " float rhw = 1.0 / input.gl_FragCoord.w;\n"; pixelPrologue << " float rhw = 1.0 / input.gl_FragCoord.w;\n";
// Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader. // Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader.
// Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using
// dx_ViewCoords. // dx_ViewCoords.
if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{ {
pixelStream << " gl_FragCoord.x = input.dx_Position.x;\n" pixelPrologue << " gl_FragCoord.x = input.dx_Position.x;\n"
<< " gl_FragCoord.y = input.dx_Position.y;\n"; << " gl_FragCoord.y = input.dx_Position.y;\n";
} }
else if (shaderModel == 3) else if (shaderModel == 3)
{ {
pixelStream << " gl_FragCoord.x = input.dx_Position.x + 0.5;\n" pixelPrologue << " gl_FragCoord.x = input.dx_Position.x + 0.5;\n"
<< " gl_FragCoord.y = input.dx_Position.y + 0.5;\n"; << " gl_FragCoord.y = input.dx_Position.y + 0.5;\n";
} }
else else
{ {
// dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See
// Renderer::setViewport() // Renderer::setViewport()
pixelStream << " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + " pixelPrologue
"dx_ViewCoords.z;\n" << " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + "
<< " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + " "dx_ViewCoords.z;\n"
"dx_ViewCoords.w;\n"; << " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + "
"dx_ViewCoords.w;\n";
} }
if (programMetadata.usesViewScale()) if (programMetadata.usesViewScale())
...@@ -761,32 +747,32 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -761,32 +747,32 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
// gl_FragCoord.y" // gl_FragCoord.y"
// //
// Simplifying, this becomes: // Simplifying, this becomes:
pixelStream pixelPrologue
<< " gl_FragCoord.y = (1.0f + dx_ViewScale.y) * gl_FragCoord.y /" << " gl_FragCoord.y = (1.0f + dx_ViewScale.y) * gl_FragCoord.y /"
"(1.0f - input.gl_FragCoord.y * rhw) - dx_ViewScale.y * gl_FragCoord.y;\n"; "(1.0f - input.gl_FragCoord.y * rhw) - dx_ViewScale.y * gl_FragCoord.y;\n";
} }
} }
pixelStream << " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + " pixelPrologue << " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + "
"dx_DepthFront.y;\n" "dx_DepthFront.y;\n"
<< " gl_FragCoord.w = rhw;\n"; << " gl_FragCoord.w = rhw;\n";
} }
if (pixelBuiltins.glPointCoord.enabled && shaderModel >= 3) if (pixelBuiltins.glPointCoord.enabled && shaderModel >= 3)
{ {
pixelStream << " gl_PointCoord.x = input.gl_PointCoord.x;\n" pixelPrologue << " gl_PointCoord.x = input.gl_PointCoord.x;\n"
<< " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; << " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
} }
if (fragmentShader->usesFrontFacing()) if (fragmentShader->usesFrontFacing())
{ {
if (shaderModel <= 3) if (shaderModel <= 3)
{ {
pixelStream << " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; pixelPrologue << " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
} }
else else
{ {
pixelStream << " gl_FrontFacing = isFrontFace;\n"; pixelPrologue << " gl_FrontFacing = isFrontFace;\n";
} }
} }
...@@ -802,52 +788,71 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, ...@@ -802,52 +788,71 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context,
if (packedVarying.vertexOnly || !varying.active) if (packedVarying.vertexOnly || !varying.active)
continue; continue;
pixelStream << " "; pixelPrologue << " ";
if (packedVarying.isStructField()) if (packedVarying.isStructField())
{ {
pixelStream << DecorateVariable(packedVarying.parentStructName) << "."; pixelPrologue << DecorateVariable(packedVarying.parentStructName) << ".";
} }
pixelStream << DecorateVariable(varying.name); pixelPrologue << DecorateVariable(varying.name);
if (varying.isArray()) if (varying.isArray())
{ {
WriteArrayString(pixelStream, registerInfo.varyingArrayIndex); WriteArrayString(pixelPrologue, registerInfo.varyingArrayIndex);
} }
GLenum transposedType = TransposeMatrixType(varying.type); GLenum transposedType = TransposeMatrixType(varying.type);
if (VariableRowCount(transposedType) > 1) if (VariableRowCount(transposedType) > 1)
{ {
WriteArrayString(pixelStream, registerInfo.varyingRowIndex); WriteArrayString(pixelPrologue, registerInfo.varyingRowIndex);
} }
pixelStream << " = input.v" << registerIndex; pixelPrologue << " = input.v" << registerIndex;
switch (VariableColumnCount(transposedType)) switch (VariableColumnCount(transposedType))
{ {
case 1: case 1:
pixelStream << ".x"; pixelPrologue << ".x";
break; break;
case 2: case 2:
pixelStream << ".xy"; pixelPrologue << ".xy";
break; break;
case 3: case 3:
pixelStream << ".xyz"; pixelPrologue << ".xyz";
break; break;
case 4: case 4:
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
pixelStream << ";\n"; pixelPrologue << ";\n";
} }
pixelStream << "\n" std::string pixelSource = fragmentShaderGL->getTranslatedSource(context);
<< " gl_main();\n"
<< "\n" if (fragmentShader->usesFrontFacing())
<< " return generateOutput();\n" {
<< "}\n"; if (shaderModel >= 4)
{
angle::ReplaceSubstring(&pixelSource, std::string(PIXEL_MAIN_PARAMETERS_STUB_STRING),
"PS_INPUT input, bool isFrontFace : SV_IsFrontFace");
}
else
{
angle::ReplaceSubstring(&pixelSource, std::string(PIXEL_MAIN_PARAMETERS_STUB_STRING),
"PS_INPUT input, float vFace : VFACE");
}
}
else
{
angle::ReplaceSubstring(&pixelSource, std::string(PIXEL_MAIN_PARAMETERS_STUB_STRING),
"PS_INPUT input");
}
angle::ReplaceSubstring(&pixelSource, std::string(MAIN_PROLOGUE_STUB_STRING),
pixelPrologue.str());
pixelStream << pixelSource;
(*shaderHLSL)[gl::ShaderType::Vertex] = vertexStream.str(); (*shaderHLSL)[gl::ShaderType::Vertex] = vertexStream.str();
(*shaderHLSL)[gl::ShaderType::Fragment] = pixelStream.str(); (*shaderHLSL)[gl::ShaderType::Fragment] = pixelStream.str();
...@@ -858,9 +863,8 @@ std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *contex ...@@ -858,9 +863,8 @@ std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *contex
{ {
gl::Shader *computeShaderGL = programData.getAttachedShader(ShaderType::Compute); gl::Shader *computeShaderGL = programData.getAttachedShader(ShaderType::Compute);
std::stringstream computeStream; std::stringstream computeStream;
std::string translatedSource = computeShaderGL->getTranslatedSource(context);
computeStream << translatedSource;
std::string translatedSource = computeShaderGL->getTranslatedSource(context);
bool usesWorkGroupID = translatedSource.find("GL_USES_WORK_GROUP_ID") != std::string::npos; bool usesWorkGroupID = translatedSource.find("GL_USES_WORK_GROUP_ID") != std::string::npos;
bool usesLocalInvocationID = bool usesLocalInvocationID =
translatedSource.find("GL_USES_LOCAL_INVOCATION_ID") != std::string::npos; translatedSource.find("GL_USES_LOCAL_INVOCATION_ID") != std::string::npos;
...@@ -896,33 +900,28 @@ std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *contex ...@@ -896,33 +900,28 @@ std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *contex
computeStream << "};\n\n"; computeStream << "};\n\n";
const sh::WorkGroupSize &localSize = computeShaderGL->getWorkGroupSize(context); std::ostringstream computePrologue;
computeStream << "[numthreads(" << localSize[0] << ", " << localSize[1] << ", " << localSize[2]
<< ")]\n";
computeStream << "void main(CS_INPUT input)\n"
<< "{\n";
if (usesWorkGroupID) if (usesWorkGroupID)
{ {
computeStream << " gl_WorkGroupID = input.dx_WorkGroupID;\n"; computePrologue << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
} }
if (usesLocalInvocationID) if (usesLocalInvocationID)
{ {
computeStream << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n"; computePrologue << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
} }
if (usesGlobalInvocationID) if (usesGlobalInvocationID)
{ {
computeStream << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n"; computePrologue << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
} }
if (usesLocalInvocationIndex) if (usesLocalInvocationIndex)
{ {
computeStream << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n"; computePrologue << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
} }
computeStream << "\n" angle::ReplaceSubstring(&translatedSource, std::string(MAIN_PROLOGUE_STUB_STRING),
<< " gl_main();\n" computePrologue.str());
<< "}\n"; computeStream << translatedSource;
return computeStream.str(); return computeStream.str();
} }
......
...@@ -4615,6 +4615,40 @@ TEST_P(GLSLTest_ES3, AssignAssignmentToSwizzled) ...@@ -4615,6 +4615,40 @@ TEST_P(GLSLTest_ES3, AssignAssignmentToSwizzled)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
} }
// Test a fragment shader that returns inside if (that being the only branch that actually gets
// executed). Regression test for http://anglebug.com/2325
TEST_P(GLSLTest, IfElseIfAndReturn)
{
const std::string &vertexShader =
R"(attribute vec4 a_position;
varying vec2 vPos;
void main()
{
gl_Position = a_position;
vPos = a_position.xy;
})";
const std::string &fragmentShader =
R"(precision mediump float;
varying vec2 vPos;
void main()
{
if (vPos.x < 1.0) // This colors the whole canvas green
{
gl_FragColor = vec4(0, 1, 0, 1);
return;
}
else if (vPos.x < 1.1) // This should have no effect
{
gl_FragColor = vec4(1, 0, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
drawQuad(program.get(), "a_position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
......
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