blob: 4978b92710c4541baee8c0cdefeb77446d4307e1 [file] [log] [blame]
//
// Copyright (c) 2014 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.
//
// ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl.
#include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "common/utilities.h"
#include "libANGLE/Compiler.h"
#include "libANGLE/Shader.h"
#include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
// Definitions local to the translation unit
namespace
{
const char *GetShaderTypeString(GLenum type)
{
switch (type)
{
case GL_VERTEX_SHADER:
return "VERTEX";
case GL_FRAGMENT_SHADER:
return "FRAGMENT";
case GL_COMPUTE_SHADER:
return "COMPUTE";
default:
UNREACHABLE();
return "";
}
}
} // anonymous namespace
namespace rx
{
ShaderD3D::ShaderD3D(const gl::ShaderState &data, const angle::WorkaroundsD3D &workarounds)
: ShaderImpl(data), mAdditionalOptions(0)
{
uncompile();
if (workarounds.expandIntegerPowExpressions)
{
mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
}
if (workarounds.getDimensionsIgnoresBaseLevel)
{
mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
}
if (workarounds.preAddTexelFetchOffsets)
{
mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
}
if (workarounds.rewriteUnaryMinusOperator)
{
mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR;
}
if (workarounds.emulateIsnanFloat)
{
mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
}
}
ShaderD3D::~ShaderD3D()
{
}
std::string ShaderD3D::getDebugInfo() const
{
if (mDebugInfo.empty())
{
return "";
}
return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) +
" SHADER END\n";
}
// initialize/clean up previous state
void ShaderD3D::uncompile()
{
// set by compileToHLSL
mCompilerOutputType = SH_ESSL_OUTPUT;
mUsesMultipleRenderTargets = false;
mUsesFragColor = false;
mUsesFragData = false;
mUsesFragCoord = false;
mUsesFrontFacing = false;
mUsesPointSize = false;
mUsesPointCoord = false;
mUsesDepthRange = false;
mUsesFragDepth = false;
mUsesDiscardRewriting = false;
mUsesNestedBreak = false;
mRequiresIEEEStrictCompiling = false;
mDebugInfo.clear();
}
void ShaderD3D::generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const
{
if (mUsesDiscardRewriting)
{
// ANGLE issue 486:
// Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization
workarounds->skipOptimization = true;
}
else if (mUsesNestedBreak)
{
// ANGLE issue 603:
// Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization
// We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence
workarounds->useMaxOptimization = true;
}
if (mRequiresIEEEStrictCompiling)
{
// IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
workarounds->enableIEEEStrictness = true;
}
}
unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const
{
ASSERT(mUniformRegisterMap.count(uniformName) > 0);
return mUniformRegisterMap.find(uniformName)->second;
}
unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const
{
ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0);
return mInterfaceBlockRegisterMap.find(blockName)->second;
}
ShShaderOutput ShaderD3D::getCompilerOutputType() const
{
return mCompilerOutputType;
}
ShCompileOptions ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream,
std::string *sourcePath)
{
uncompile();
ShCompileOptions additionalOptions = 0;
const std::string &source = mData.getSource();
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
if (gl::DebugAnnotationsActive())
{
*sourcePath = getTempPath();
writeFile(sourcePath->c_str(), source.c_str(), source.length());
additionalOptions |= SH_LINE_DIRECTIVES | SH_SOURCE_PATH;
}
#endif
additionalOptions |= mAdditionalOptions;
*shaderSourceStream << source;
return additionalOptions;
}
bool ShaderD3D::hasUniform(const D3DUniform *d3dUniform) const
{
return mUniformRegisterMap.find(d3dUniform->name) != mUniformRegisterMap.end();
}
const std::map<std::string, unsigned int> &GetUniformRegisterMap(
const std::map<std::string, unsigned int> *uniformRegisterMap)
{
ASSERT(uniformRegisterMap);
return *uniformRegisterMap;
}
bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
{
// TODO(jmadill): We shouldn't need to cache this.
mCompilerOutputType = compiler->getShaderOutputType();
const std::string &translatedSource = mData.getTranslatedSource();
mUsesMultipleRenderTargets = translatedSource.find("GL_USES_MRT") != std::string::npos;
mUsesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
mUsesFragData = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
mUsesFragCoord = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
mUsesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mUsesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
mRequiresIEEEStrictCompiling =
translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle));
for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks())
{
if (interfaceBlock.staticUse)
{
unsigned int index = static_cast<unsigned int>(-1);
bool blockRegisterResult =
sh::GetInterfaceBlockRegister(compilerHandle, interfaceBlock.name, &index);
ASSERT(blockRegisterResult);
mInterfaceBlockRegisterMap[interfaceBlock.name] = index;
}
}
mDebugInfo +=
std::string("// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
mDebugInfo += "\n// GLSL BEGIN\n\n" + mData.getSource() + "\n\n// GLSL END\n\n\n";
mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
// Successive steps will append more info
return true;
}
} // namespace rx