summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp311
1 files changed, 311 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp
new file mode 100644
index 0000000000..d07ed2975e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp
@@ -0,0 +1,311 @@
+//
+// Copyright 2002 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.
+//
+
+#include "compiler/translator/TranslatorHLSL.h"
+
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
+#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
+#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
+#include "compiler/translator/tree_ops/SplitSequenceOperator.h"
+#include "compiler/translator/tree_ops/d3d/AddDefaultReturnStatements.h"
+#include "compiler/translator/tree_ops/d3d/AggregateAssignArraysInSSBOs.h"
+#include "compiler/translator/tree_ops/d3d/AggregateAssignStructsInSSBOs.h"
+#include "compiler/translator/tree_ops/d3d/ArrayReturnValueToOutParameter.h"
+#include "compiler/translator/tree_ops/d3d/BreakVariableAliasingInInnerLoops.h"
+#include "compiler/translator/tree_ops/d3d/ExpandIntegerPowExpressions.h"
+#include "compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.h"
+#include "compiler/translator/tree_ops/d3d/RewriteAtomicFunctionExpressions.h"
+#include "compiler/translator/tree_ops/d3d/RewriteElseBlocks.h"
+#include "compiler/translator/tree_ops/d3d/RewriteExpressionsWithShaderStorageBlock.h"
+#include "compiler/translator/tree_ops/d3d/RewriteUnaryMinusOperatorInt.h"
+#include "compiler/translator/tree_ops/d3d/SeparateArrayConstructorStatements.h"
+#include "compiler/translator/tree_ops/d3d/SeparateArrayInitialization.h"
+#include "compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.h"
+#include "compiler/translator/tree_ops/d3d/UnfoldShortCircuitToIf.h"
+#include "compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.h"
+#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+
+namespace sh
+{
+
+TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{}
+
+bool TranslatorHLSL::translate(TIntermBlock *root,
+ const ShCompileOptions &compileOptions,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ // A few transformations leave the tree in an inconsistent state. For example, when unfolding
+ // the short-circuit in the following function:
+ //
+ // mediump float f(float a) { return a > 0 ? 0.0 : 1.0; }
+ //
+ // a temp variable is created to hold the result of the expression. Currently the precision of
+ // the return value of the function is not propagated to its return expressions. Additionally,
+ // an expression such as
+ //
+ // cond ? gl_NumWorkGroups.x : gl_NumWorkGroups.y
+ //
+ // does not have a precision as the built-in does not specify a precision.
+ //
+ // Precision is not applicable to HLSL so fixing these issues are deferred.
+ mValidateASTOptions.validatePrecision = false;
+
+ const ShBuiltInResources &resources = getResources();
+ int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
+ int maxDualSourceDrawBuffers =
+ resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
+
+ if (!sh::AddDefaultReturnStatements(this, root))
+ {
+ return false;
+ }
+
+ // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
+ // may need to generate new statements from loop conditions or loop expressions.
+ // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
+ if (!SimplifyLoopConditions(
+ this, root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ &getSymbolTable()))
+ {
+ return false;
+ }
+
+ if (!SplitSequenceOperator(
+ this, root,
+ IntermNodePatternMatcher::kExpressionReturningArray |
+ IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
+ IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
+ &getSymbolTable()))
+ {
+ return false;
+ }
+
+ // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
+ if (!UnfoldShortCircuitToIf(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+
+ if (!SeparateArrayConstructorStatements(this, root))
+ {
+ return false;
+ }
+
+ if (getShaderVersion() >= 310)
+ {
+ // Do element-by-element assignments of arrays in SSBOs. This allows the D3D backend to use
+ // RWByteAddressBuffer.Load() and .Store(), which only operate on values up to 16 bytes in
+ // size. Note that this must be done before SeparateExpressionsReturningArrays.
+ if (!sh::AggregateAssignArraysInSSBOs(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+ // Do field-by-field assignment of structs in SSBOs. This allows the D3D backend to use
+ // RWByteAddressBuffer.Load() and .Store(), which only operate on values up to 16 bytes in
+ // size.
+ if (!sh::AggregateAssignStructsInSSBOs(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+ }
+
+ if (!SeparateExpressionsReturningArrays(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+
+ // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
+ if (!SeparateArrayInitialization(this, root))
+ {
+ return false;
+ }
+
+ // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
+ // as a return value to use an out parameter to transfer the array data instead.
+ if (!ArrayReturnValueToOutParameter(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+
+ if (!shouldRunLoopAndIndexingValidation(compileOptions))
+ {
+ // HLSL doesn't support dynamic indexing of vectors and matrices.
+ if (!RemoveDynamicIndexingOfNonSSBOVectorOrMatrix(this, root, &getSymbolTable(),
+ perfDiagnostics))
+ {
+ return false;
+ }
+ }
+
+ // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
+ // use a vertex attribute as a condition, and some related computation in the else block.
+ if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
+ {
+ if (!sh::RewriteElseBlocks(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+ }
+
+ // Work around an HLSL compiler frontend aliasing optimization bug.
+ // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
+ // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
+ // version and only apply the workaround if it is too old.
+ if (!sh::BreakVariableAliasingInInnerLoops(this, root))
+ {
+ return false;
+ }
+
+ // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
+ // introduce variable declarations inside the main scope of any switch statement. It cannot
+ // result in no-op cases at the end of switch statements, because unreferenced variables
+ // have already been pruned.
+ if (!WrapSwitchStatementsInBlocks(this, root))
+ {
+ return false;
+ }
+
+ if (compileOptions.expandSelectHLSLIntegerPowExpressions)
+ {
+ if (!sh::ExpandIntegerPowExpressions(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions.rewriteTexelFetchOffsetToTexelFetch)
+ {
+ if (!sh::RewriteTexelFetchOffset(this, root, getSymbolTable(), getShaderVersion()))
+ {
+ return false;
+ }
+ }
+
+ if (compileOptions.rewriteIntegerUnaryMinusOperator && getShaderType() == GL_VERTEX_SHADER)
+ {
+ if (!sh::RewriteUnaryMinusOperatorInt(this, root))
+ {
+ return false;
+ }
+ }
+
+ if (getShaderVersion() >= 310)
+ {
+ // Due to ssbo also can be used as the argument of atomic memory functions, we should put
+ // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions.
+ if (!sh::RewriteExpressionsWithShaderStorageBlock(this, root, &getSymbolTable()))
+ {
+ return false;
+ }
+ if (!sh::RewriteAtomicFunctionExpressions(this, root, &getSymbolTable(),
+ getShaderVersion()))
+ {
+ return false;
+ }
+ }
+
+ mUniformBlockOptimizedMap.clear();
+ mSlowCompilingUniformBlockSet.clear();
+ // In order to get the exact maximum of slots are available for shader resources, which would
+ // been bound with StructuredBuffer, we only translate uniform block with a large array member
+ // into StructuredBuffer when shader version is 300.
+ if (getShaderVersion() == 300 && compileOptions.allowTranslateUniformBlockToStructuredBuffer)
+ {
+ if (!sh::RecordUniformBlocksWithLargeArrayMember(root, mUniformBlockOptimizedMap,
+ mSlowCompilingUniformBlockSet))
+ {
+ return false;
+ }
+ }
+
+ sh::OutputHLSL outputHLSL(
+ getShaderType(), getShaderSpec(), getShaderVersion(), getExtensionBehavior(),
+ getSourcePath(), getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
+ compileOptions, getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics,
+ mUniformBlockOptimizedMap, mShaderStorageBlocks, isEarlyFragmentTestsSpecified());
+
+ outputHLSL.output(root, getInfoSink().obj);
+
+ mShaderStorageBlockRegisterMap = outputHLSL.getShaderStorageBlockRegisterMap();
+ mUniformBlockRegisterMap = outputHLSL.getUniformBlockRegisterMap();
+ mUniformBlockUseStructuredBufferMap = outputHLSL.getUniformBlockUseStructuredBufferMap();
+ mUniformRegisterMap = outputHLSL.getUniformRegisterMap();
+ mReadonlyImage2DRegisterIndex = outputHLSL.getReadonlyImage2DRegisterIndex();
+ mImage2DRegisterIndex = outputHLSL.getImage2DRegisterIndex();
+ mUsedImage2DFunctionNames = outputHLSL.getUsedImage2DFunctionNames();
+
+ return true;
+}
+
+bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not necessary when translating to HLSL.
+ return false;
+}
+
+bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const
+{
+ return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0);
+}
+
+unsigned int TranslatorHLSL::getShaderStorageBlockRegister(
+ const std::string &shaderStorageBlockName) const
+{
+ ASSERT(hasShaderStorageBlock(shaderStorageBlockName));
+ return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second;
+}
+
+bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
+{
+ return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
+}
+
+unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
+{
+ ASSERT(hasUniformBlock(uniformBlockName));
+ return mUniformBlockRegisterMap.find(uniformBlockName)->second;
+}
+
+const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
+{
+ return &mUniformRegisterMap;
+}
+
+const std::set<std::string> *TranslatorHLSL::getSlowCompilingUniformBlockSet() const
+{
+ return &mSlowCompilingUniformBlockSet;
+}
+
+unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
+{
+ return mReadonlyImage2DRegisterIndex;
+}
+
+unsigned int TranslatorHLSL::getImage2DRegisterIndex() const
+{
+ return mImage2DRegisterIndex;
+}
+
+const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const
+{
+ return &mUsedImage2DFunctionNames;
+}
+
+bool TranslatorHLSL::shouldUniformBlockUseStructuredBuffer(
+ const std::string &uniformBlockName) const
+{
+ auto uniformBlockIter = mUniformBlockUseStructuredBufferMap.find(uniformBlockName);
+ return uniformBlockIter != mUniformBlockUseStructuredBufferMap.end() &&
+ uniformBlockIter->second;
+}
+
+} // namespace sh