| // | |
| // 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; | |
| mUsesHelperInvocation = 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; | |
| mUsesHelperInvocation = | |
| translatedSource.find("GL_USES_HELPER_INVOCATION") != 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 |