blob: e97e03fffa0e18d462cb9e40f85ad7caa5e7f4ab [file] [log] [blame]
//
// Copyright 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/Caps.h"
#include "libANGLE/Compiler.h"
#include "libANGLE/Context.h"
#include "libANGLE/Shader.h"
#include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
namespace rx
{
class TranslateTaskD3D : public angle::Closure
{
public:
TranslateTaskD3D(ShHandle handle,
ShCompileOptions options,
const std::string &source,
const std::string &sourcePath)
: mHandle(handle),
mOptions(options),
mSource(source),
mSourcePath(sourcePath),
mResult(false)
{}
void operator()() override
{
std::vector<const char *> srcStrings;
if (!mSourcePath.empty())
{
srcStrings.push_back(mSourcePath.c_str());
}
srcStrings.push_back(mSource.c_str());
mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions);
}
bool getResult() { return mResult; }
private:
ShHandle mHandle;
ShCompileOptions mOptions;
std::string mSource;
std::string mSourcePath;
bool mResult;
};
using PostTranslateFunctor =
std::function<bool(gl::ShCompilerInstance *compiler, std::string *infoLog)>;
class WaitableCompileEventD3D final : public WaitableCompileEvent
{
public:
WaitableCompileEventD3D(std::shared_ptr<angle::WaitableEvent> waitableEvent,
gl::ShCompilerInstance *compilerInstance,
PostTranslateFunctor &&postTranslateFunctor,
std::shared_ptr<TranslateTaskD3D> translateTask)
: WaitableCompileEvent(waitableEvent),
mCompilerInstance(compilerInstance),
mPostTranslateFunctor(std::move(postTranslateFunctor)),
mTranslateTask(translateTask)
{}
bool getResult() override { return mTranslateTask->getResult(); }
bool postTranslate(std::string *infoLog) override
{
return mPostTranslateFunctor(mCompilerInstance, infoLog);
}
private:
gl::ShCompilerInstance *mCompilerInstance;
PostTranslateFunctor mPostTranslateFunctor;
std::shared_ptr<TranslateTaskD3D> mTranslateTask;
};
ShaderD3D::ShaderD3D(const gl::ShaderState &data,
const angle::FeaturesD3D &features,
const gl::Extensions &extensions)
: ShaderImpl(data), mAdditionalOptions(0)
{
uncompile();
if (features.expandIntegerPowExpressions.enabled)
{
mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
}
if (features.getDimensionsIgnoresBaseLevel.enabled)
{
mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
}
if (features.preAddTexelFetchOffsets.enabled)
{
mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
}
if (features.rewriteUnaryMinusOperator.enabled)
{
mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR;
}
if (features.emulateIsnanFloat.enabled)
{
mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
}
if (features.skipVSConstantRegisterZero.enabled &&
mData.getShaderType() == gl::ShaderType::Vertex)
{
mAdditionalOptions |= SH_SKIP_D3D_CONSTANT_REGISTER_ZERO;
}
if (features.forceAtomicValueResolution.enabled)
{
mAdditionalOptions |= SH_FORCE_ATOMIC_VALUE_RESOLUTION;
}
if (extensions.multiview || extensions.multiview2)
{
mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
}
}
ShaderD3D::~ShaderD3D() {}
std::string ShaderD3D::getDebugInfo() const
{
if (mDebugInfo.empty())
{
return "";
}
return mDebugInfo + std::string("\n// ") + gl::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;
mUsesSecondaryColor = false;
mUsesFragCoord = false;
mUsesFrontFacing = false;
mUsesPointSize = false;
mUsesPointCoord = false;
mUsesDepthRange = false;
mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false;
mUsesVertexID = false;
mUsesViewID = 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::getUniformBlockRegister(const std::string &blockName) const
{
ASSERT(mUniformBlockRegisterMap.count(blockName) > 0);
return mUniformBlockRegisterMap.find(blockName)->second;
}
unsigned int ShaderD3D::getShaderStorageBlockRegister(const std::string &blockName) const
{
ASSERT(mShaderStorageBlockRegisterMap.count(blockName) > 0);
return mShaderStorageBlockRegisterMap.find(blockName)->second;
}
ShShaderOutput ShaderD3D::getCompilerOutputType() const
{
return mCompilerOutputType;
}
bool ShaderD3D::useImage2DFunction(const std::string &functionName) const
{
if (mUsedImage2DFunctionNames.empty())
{
return false;
}
return mUsedImage2DFunctionNames.find(functionName) != mUsedImage2DFunctionNames.end();
}
const std::map<std::string, unsigned int> &GetUniformRegisterMap(
const std::map<std::string, unsigned int> *uniformRegisterMap)
{
ASSERT(uniformRegisterMap);
return *uniformRegisterMap;
}
const std::set<std::string> &GetUsedImage2DFunctionNames(
const std::set<std::string> *usedImage2DFunctionNames)
{
ASSERT(usedImage2DFunctionNames);
return *usedImage2DFunctionNames;
}
std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *context,
gl::ShCompilerInstance *compilerInstance,
ShCompileOptions options)
{
std::string sourcePath;
uncompile();
ShCompileOptions additionalOptions = 0;
const std::string &source = mData.getSource();
#if !defined(ANGLE_ENABLE_WINDOWS_UWP)
if (gl::DebugAnnotationsActive())
{
sourcePath = getTempPath();
writeFile(sourcePath.c_str(), source.c_str(), source.length());
additionalOptions |= SH_LINE_DIRECTIVES | SH_SOURCE_PATH;
}
#endif
additionalOptions |= mAdditionalOptions;
options |= additionalOptions;
auto postTranslateFunctor = [this](gl::ShCompilerInstance *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;
mUsesSecondaryColor = translatedSource.find("GL_USES_SECONDARY_COLOR") != 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;
mHasANGLEMultiviewEnabled =
translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos;
mUsesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != 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->getHandle();
mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle));
mReadonlyImage2DRegisterIndex = sh::GetReadonlyImage2DRegisterIndex(compilerHandle);
mImage2DRegisterIndex = sh::GetImage2DRegisterIndex(compilerHandle);
mUsedImage2DFunctionNames =
GetUsedImage2DFunctionNames(sh::GetUsedImage2DFunctionNames(compilerHandle));
for (const sh::InterfaceBlock &interfaceBlock : mData.getUniformBlocks())
{
if (interfaceBlock.active)
{
unsigned int index = static_cast<unsigned int>(-1);
bool blockRegisterResult =
sh::GetUniformBlockRegister(compilerHandle, interfaceBlock.name, &index);
ASSERT(blockRegisterResult);
mUniformBlockRegisterMap[interfaceBlock.name] = index;
}
}
for (const sh::InterfaceBlock &interfaceBlock : mData.getShaderStorageBlocks())
{
if (interfaceBlock.active)
{
unsigned int index = static_cast<unsigned int>(-1);
bool blockRegisterResult =
sh::GetShaderStorageBlockRegister(compilerHandle, interfaceBlock.name, &index);
ASSERT(blockRegisterResult);
mShaderStorageBlockRegisterMap[interfaceBlock.name] = index;
}
}
mDebugInfo +=
std::string("// ") + gl::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;
};
auto workerThreadPool = context->getWorkerThreadPool();
auto translateTask = std::make_shared<TranslateTaskD3D>(compilerInstance->getHandle(), options,
source, sourcePath);
return std::make_shared<WaitableCompileEventD3D>(
angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask), compilerInstance,
std::move(postTranslateFunctor), translateTask);
}
bool ShaderD3D::hasUniform(const std::string &name) const
{
return mUniformRegisterMap.find(name) != mUniformRegisterMap.end();
}
} // namespace rx