blob: ed0247b7d12603e763b89b3eecb0fae5f24d4113 [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/system_utils.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/ContextImpl.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/trace.h"
namespace rx
{
namespace
{
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> &GetSlowCompilingUniformBlockSet(
const std::set<std::string> *slowCompilingUniformBlockSet)
{
ASSERT(slowCompilingUniformBlockSet);
return *slowCompilingUniformBlockSet;
}
const std::set<std::string> &GetUsedImage2DFunctionNames(
const std::set<std::string> *usedImage2DFunctionNames)
{
ASSERT(usedImage2DFunctionNames);
return *usedImage2DFunctionNames;
}
class ShaderTranslateTaskD3D final : public ShaderTranslateTask
{
public:
ShaderTranslateTaskD3D(const SharedCompiledShaderStateD3D &shader, std::string &&sourcePath)
: mSourcePath(std::move(sourcePath)), mShader(shader)
{}
~ShaderTranslateTaskD3D() override = default;
bool translate(ShHandle compiler,
const ShCompileOptions &options,
const std::string &source) override
{
ANGLE_TRACE_EVENT1("gpu.angle", "ShaderTranslateTaskD3D::run", "source", source);
angle::FixedVector<const char *, 2> srcStrings;
if (!mSourcePath.empty())
{
srcStrings.push_back(mSourcePath.c_str());
}
srcStrings.push_back(source.c_str());
return sh::Compile(compiler, srcStrings.data(), srcStrings.size(), options);
}
void postTranslate(ShHandle compiler, const gl::CompiledShaderState &compiledState) override
{
const std::string &translatedSource = compiledState.translatedSource;
CompiledShaderStateD3D *state = mShader.get();
// Note: We shouldn't need to cache this.
state->compilerOutputType = sh::GetShaderOutputType(compiler);
state->usesMultipleRenderTargets =
translatedSource.find("GL_USES_MRT") != std::string::npos;
state->usesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
state->usesFragData = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
state->usesSecondaryColor =
translatedSource.find("GL_USES_SECONDARY_COLOR") != std::string::npos;
state->usesFragCoord = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
state->usesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
state->usesSampleID = translatedSource.find("GL_USES_SAMPLE_ID") != std::string::npos;
state->usesSamplePosition =
translatedSource.find("GL_USES_SAMPLE_POSITION") != std::string::npos;
state->usesSampleMaskIn =
translatedSource.find("GL_USES_SAMPLE_MASK_IN") != std::string::npos;
state->usesSampleMask =
translatedSource.find("GL_USES_SAMPLE_MASK_OUT") != std::string::npos;
state->usesHelperInvocation =
translatedSource.find("GL_USES_HELPER_INVOCATION") != std::string::npos;
state->usesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
state->usesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
state->usesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
state->hasMultiviewEnabled =
translatedSource.find("GL_MULTIVIEW_ENABLED") != std::string::npos;
state->usesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
state->usesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
state->usesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
state->usesNestedBreak =
translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
state->requiresIEEEStrictCompiling =
translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
if (translatedSource.find("GL_USES_FRAG_DEPTH_GREATER") != std::string::npos)
{
state->fragDepthUsage = FragDepthUsage::Greater;
}
else if (translatedSource.find("GL_USES_FRAG_DEPTH_LESS") != std::string::npos)
{
state->fragDepthUsage = FragDepthUsage::Less;
}
else if (translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos)
{
state->fragDepthUsage = FragDepthUsage::Any;
}
state->clipDistanceSize = sh::GetClipDistanceArraySize(compiler);
state->cullDistanceSize = sh::GetCullDistanceArraySize(compiler);
state->uniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compiler));
state->readonlyImage2DRegisterIndex = sh::GetReadonlyImage2DRegisterIndex(compiler);
state->image2DRegisterIndex = sh::GetImage2DRegisterIndex(compiler);
state->usedImage2DFunctionNames =
GetUsedImage2DFunctionNames(sh::GetUsedImage2DFunctionNames(compiler));
for (const sh::InterfaceBlock &interfaceBlock : compiledState.uniformBlocks)
{
if (interfaceBlock.active)
{
unsigned int index = static_cast<unsigned int>(-1);
bool blockRegisterResult =
sh::GetUniformBlockRegister(compiler, interfaceBlock.name, &index);
ASSERT(blockRegisterResult);
bool useStructuredBuffer =
sh::ShouldUniformBlockUseStructuredBuffer(compiler, interfaceBlock.name);
state->uniformBlockRegisterMap[interfaceBlock.name] = index;
state->uniformBlockUseStructuredBufferMap[interfaceBlock.name] =
useStructuredBuffer;
}
}
state->slowCompilingUniformBlockSet =
GetSlowCompilingUniformBlockSet(sh::GetSlowCompilingUniformBlockSet(compiler));
for (const sh::InterfaceBlock &interfaceBlock : compiledState.shaderStorageBlocks)
{
if (interfaceBlock.active)
{
unsigned int index = static_cast<unsigned int>(-1);
bool blockRegisterResult =
sh::GetShaderStorageBlockRegister(compiler, interfaceBlock.name, &index);
ASSERT(blockRegisterResult);
state->shaderStorageBlockRegisterMap[interfaceBlock.name] = index;
}
}
state->debugInfo +=
"// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
}
private:
std::string mSourcePath;
SharedCompiledShaderStateD3D mShader;
};
} // anonymous namespace
CompiledShaderStateD3D::CompiledShaderStateD3D()
: compilerOutputType(SH_ESSL_OUTPUT),
usesMultipleRenderTargets(false),
usesFragColor(false),
usesFragData(false),
usesSecondaryColor(false),
usesFragCoord(false),
usesFrontFacing(false),
usesHelperInvocation(false),
usesPointSize(false),
usesPointCoord(false),
usesDepthRange(false),
usesSampleID(false),
usesSamplePosition(false),
usesSampleMaskIn(false),
usesSampleMask(false),
hasMultiviewEnabled(false),
usesVertexID(false),
usesViewID(false),
usesDiscardRewriting(false),
usesNestedBreak(false),
requiresIEEEStrictCompiling(false),
fragDepthUsage(FragDepthUsage::Unused),
clipDistanceSize(0),
cullDistanceSize(0),
readonlyImage2DRegisterIndex(0),
image2DRegisterIndex(0)
{}
CompiledShaderStateD3D::~CompiledShaderStateD3D() = default;
ShaderD3D::ShaderD3D(const gl::ShaderState &state, RendererD3D *renderer)
: ShaderImpl(state), mRenderer(renderer)
{}
ShaderD3D::~ShaderD3D() {}
std::string ShaderD3D::getDebugInfo() const
{
if (!mCompiledState || mCompiledState->debugInfo.empty())
{
return "";
}
return mCompiledState->debugInfo + std::string("\n// ") +
gl::GetShaderTypeString(mState.getShaderType()) + " SHADER END\n";
}
void CompiledShaderStateD3D::generateWorkarounds(CompilerWorkaroundsD3D *workarounds) const
{
if (usesDiscardRewriting)
{
// ANGLE issue 486:
// Work-around a D3D9 compiler bug that presents itself when using conditional discard, by
// disabling optimization
workarounds->skipOptimization = true;
}
else if (usesNestedBreak)
{
// 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 (requiresIEEEStrictCompiling)
{
// IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
workarounds->enableIEEEStrictness = true;
}
}
unsigned int CompiledShaderStateD3D::getUniformRegister(const std::string &uniformName) const
{
ASSERT(uniformRegisterMap.count(uniformName) > 0);
return uniformRegisterMap.find(uniformName)->second;
}
unsigned int CompiledShaderStateD3D::getUniformBlockRegister(const std::string &blockName) const
{
ASSERT(uniformBlockRegisterMap.count(blockName) > 0);
return uniformBlockRegisterMap.find(blockName)->second;
}
bool CompiledShaderStateD3D::shouldUniformBlockUseStructuredBuffer(
const std::string &blockName) const
{
ASSERT(uniformBlockUseStructuredBufferMap.count(blockName) > 0);
return uniformBlockUseStructuredBufferMap.find(blockName)->second;
}
unsigned int CompiledShaderStateD3D::getShaderStorageBlockRegister(
const std::string &blockName) const
{
ASSERT(shaderStorageBlockRegisterMap.count(blockName) > 0);
return shaderStorageBlockRegisterMap.find(blockName)->second;
}
bool CompiledShaderStateD3D::useImage2DFunction(const std::string &functionName) const
{
if (usedImage2DFunctionNames.empty())
{
return false;
}
return usedImage2DFunctionNames.find(functionName) != usedImage2DFunctionNames.end();
}
const std::set<std::string> &CompiledShaderStateD3D::getSlowCompilingUniformBlockSet() const
{
return slowCompilingUniformBlockSet;
}
std::shared_ptr<ShaderTranslateTask> ShaderD3D::compile(const gl::Context *context,
ShCompileOptions *options)
{
// Create a new compiled shader state. Currently running program link jobs will use the
// previous state.
mCompiledState = std::make_shared<CompiledShaderStateD3D>();
std::string sourcePath;
const angle::FeaturesD3D &features = mRenderer->getFeatures();
const gl::Extensions &extensions = mRenderer->getNativeExtensions();
const std::string &source = mState.getSource();
#if !defined(ANGLE_ENABLE_WINDOWS_UWP)
if (gl::DebugAnnotationsActive(context))
{
sourcePath = angle::CreateTemporaryFile().value();
writeFile(sourcePath.c_str(), source.c_str(), source.length());
options->lineDirectives = true;
options->sourcePath = true;
}
#endif
if (features.expandIntegerPowExpressions.enabled)
{
options->expandSelectHLSLIntegerPowExpressions = true;
}
if (features.getDimensionsIgnoresBaseLevel.enabled)
{
options->HLSLGetDimensionsIgnoresBaseLevel = true;
}
if (features.preAddTexelFetchOffsets.enabled)
{
options->rewriteTexelFetchOffsetToTexelFetch = true;
}
if (features.rewriteUnaryMinusOperator.enabled)
{
options->rewriteIntegerUnaryMinusOperator = true;
}
if (features.emulateIsnanFloat.enabled)
{
options->emulateIsnanFloatFunction = true;
}
if (features.skipVSConstantRegisterZero.enabled &&
mState.getShaderType() == gl::ShaderType::Vertex)
{
options->skipD3DConstantRegisterZero = true;
}
if (features.forceAtomicValueResolution.enabled)
{
options->forceAtomicValueResolution = true;
}
if (features.allowTranslateUniformBlockToStructuredBuffer.enabled)
{
options->allowTranslateUniformBlockToStructuredBuffer = true;
}
if (extensions.multiviewOVR || extensions.multiview2OVR)
{
options->initializeBuiltinsForInstancedMultiview = true;
}
if (extensions.shaderPixelLocalStorageANGLE)
{
options->pls = mRenderer->getNativePixelLocalStorageOptions();
}
// The D3D translations are not currently validation-error-free
options->validateAST = false;
return std::shared_ptr<ShaderTranslateTask>(
new ShaderTranslateTaskD3D(mCompiledState, std::move(sourcePath)));
}
bool CompiledShaderStateD3D::hasUniform(const std::string &name) const
{
return uniformRegisterMap.find(name) != uniformRegisterMap.end();
}
} // namespace rx