| // |
| // 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 |