blob: cd15daa26dcb65bff9e8d3e2a7c93a5ad87c4638 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08009#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000010#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000011#include <cfloat>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000012
Jamie Madill9e0478f2015-01-13 11:13:54 -050013#include "common/angleutils.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030014#include "common/debug.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/utilities.h"
Brandon Jones4a22f4b2018-10-23 14:36:47 -070016#include "compiler/translator/AtomicCounterFunctionHLSL.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020017#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080019#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/InfoSink.h"
Qin Jiajia3e217f62018-08-28 16:55:20 +080021#include "compiler/translator/ResourcesHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030023#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050024#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/UtilsHLSL.h"
26#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020027#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020028#include "compiler/translator/tree_util/FindSymbolNode.h"
29#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050030#include "compiler/translator/util.h"
31
Jamie Madill45bcc782016-11-07 13:58:48 -050032namespace sh
33{
34
Olli Etuaho96f6adf2017-08-16 11:18:54 +030035namespace
36{
37
38TString ArrayHelperFunctionName(const char *prefix, const TType &type)
39{
40 TStringStream fnName;
41 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080042 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030043 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080044 for (unsigned int arraySize : *type.getArraySizes())
45 {
46 fnName << arraySize << "_";
47 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030048 }
49 fnName << TypeString(type);
50 return fnName.str();
51}
52
Olli Etuaho40dbdd62017-10-13 13:34:19 +030053bool IsDeclarationWrittenOut(TIntermDeclaration *node)
54{
55 TIntermSequence *sequence = node->getSequence();
56 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
57 ASSERT(sequence->size() == 1);
58 ASSERT(variable);
59 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080060 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030061}
62
Qin Jiajiaa735ee22018-05-18 13:29:09 +080063bool IsInStd140UniformBlock(TIntermTyped *node)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020064{
65 TIntermBinary *binaryNode = node->getAsBinaryNode();
66
67 if (binaryNode)
68 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080069 return IsInStd140UniformBlock(binaryNode->getLeft());
Olli Etuaho2ef23e22017-11-01 16:39:11 +020070 }
71
72 const TType &type = node->getType();
73
Qin Jiajiaa735ee22018-05-18 13:29:09 +080074 if (type.getQualifier() == EvqUniform)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020075 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080076 // determine if we are in the standard layout
77 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
78 if (interfaceBlock)
79 {
80 return (interfaceBlock->blockStorage() == EbsStd140);
81 }
Olli Etuaho2ef23e22017-11-01 16:39:11 +020082 }
83
84 return false;
85}
86
Jiawei Shaoa6a78422018-06-28 08:32:54 +080087const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
88{
89 switch (op)
90 {
91 case EOpAtomicAdd:
92 return "InterlockedAdd(";
93 case EOpAtomicMin:
94 return "InterlockedMin(";
95 case EOpAtomicMax:
96 return "InterlockedMax(";
97 case EOpAtomicAnd:
98 return "InterlockedAnd(";
99 case EOpAtomicOr:
100 return "InterlockedOr(";
101 case EOpAtomicXor:
102 return "InterlockedXor(";
103 case EOpAtomicExchange:
104 return "InterlockedExchange(";
105 case EOpAtomicCompSwap:
106 return "InterlockedCompareExchange(";
107 default:
108 UNREACHABLE();
109 return "";
110 }
111}
112
Qin Jiajia46229052018-12-10 13:31:00 +0800113bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800114{
Qin Jiajia46229052018-12-10 13:31:00 +0800115 TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
116 if (aggregateNode == nullptr)
117 {
118 return false;
119 }
120
121 if (node.getOp() == EOpAssign && IsAtomicFunction(aggregateNode->getOp()))
122 {
123 return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped());
124 }
125
126 return false;
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800127}
128
jchen10efe061b2018-11-13 16:44:40 +0800129const char *kZeros = "_ANGLE_ZEROS_";
130constexpr int kZeroCount = 256;
131std::string DefineZeroArray()
132{
133 std::stringstream ss;
134 // For 'static', if the declaration does not include an initializer, the value is set to zero.
135 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
136 ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
137 return ss.str();
138}
139
140std::string GetZeroInitializer(size_t size)
141{
142 std::stringstream ss;
143 size_t quotient = size / kZeroCount;
144 size_t reminder = size % kZeroCount;
145
146 for (size_t i = 0; i < quotient; ++i)
147 {
148 if (i != 0)
149 {
150 ss << ", ";
151 }
152 ss << kZeros;
153 }
154
155 for (size_t i = 0; i < reminder; ++i)
156 {
157 if (quotient != 0 || i != 0)
158 {
159 ss << ", ";
160 }
161 ss << "0";
162 }
163
164 return ss.str();
165}
166
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300167} // anonymous namespace
168
Olli Etuahoc71862a2017-12-21 12:58:29 +0200169TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
170 const TVariable *aInstanceVariable)
171 : block(aBlock), instanceVariable(aInstanceVariable)
Jamie Madillb980c562018-11-27 11:34:27 -0500172{}
Olli Etuahoc71862a2017-12-21 12:58:29 +0200173
Olli Etuaho56a2f952016-12-08 12:16:27 +0000174void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300175{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000176 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
177 // regardless.
178 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
179 mOutputType == SH_HLSL_4_1_OUTPUT)
180 {
181 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
182 }
183 else
184 {
185 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
186 }
187}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300188
Olli Etuaho56a2f952016-12-08 12:16:27 +0000189void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200190{
191 ASSERT(constUnion != nullptr);
192 switch (constUnion->getType())
193 {
194 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000195 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200196 break;
197 case EbtInt:
198 out << constUnion->getIConst();
199 break;
200 case EbtUInt:
201 out << constUnion->getUConst();
202 break;
203 case EbtBool:
204 out << constUnion->getBConst();
205 break;
206 default:
207 UNREACHABLE();
208 }
209}
210
Olli Etuaho56a2f952016-12-08 12:16:27 +0000211const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
212 const TConstantUnion *const constUnion,
213 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200214{
215 const TConstantUnion *constUnionIterated = constUnion;
216 for (size_t i = 0; i < size; i++, constUnionIterated++)
217 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000218 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200219
220 if (i != size - 1)
221 {
222 out << ", ";
223 }
224 }
225 return constUnionIterated;
226}
227
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800228OutputHLSL::OutputHLSL(sh::GLenum shaderType,
229 int shaderVersion,
230 const TExtensionBehavior &extensionBehavior,
231 const char *sourcePath,
232 ShShaderOutput outputType,
233 int numRenderTargets,
234 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300235 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300236 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300237 TSymbolTable *symbolTable,
Jamie Madill4e712be2019-01-03 13:53:59 -0500238 PerformanceDiagnostics *perfDiagnostics,
239 const std::vector<InterfaceBlock> &shaderStorageBlocks)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300240 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200241 mShaderType(shaderType),
242 mShaderVersion(shaderVersion),
243 mExtensionBehavior(extensionBehavior),
244 mSourcePath(sourcePath),
245 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700246 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300247 mInsideFunction(false),
248 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000249 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300250 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300251 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300252 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800254 mUsesFragColor = false;
255 mUsesFragData = false;
256 mUsesDepthRange = false;
257 mUsesFragCoord = false;
258 mUsesPointCoord = false;
259 mUsesFrontFacing = false;
260 mUsesPointSize = false;
261 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300262 mHasMultiviewExtensionEnabled =
263 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300264 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500265 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500266 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800267 mUsesNumWorkGroups = false;
268 mUsesWorkGroupID = false;
269 mUsesLocalInvocationID = false;
270 mUsesGlobalInvocationID = false;
271 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500272 mUsesXor = false;
273 mUsesDiscardRewriting = false;
274 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530275 mRequiresIEEEStrictCompiling = false;
jchen10efe061b2018-11-13 16:44:40 +0800276 mUseZeroArray = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000277
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000278 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000279
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500280 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000281 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500282 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000283
Yunchao Hed7297bf2017-04-19 15:27:10 +0800284 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000285
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700286 mStructureHLSL = new StructureHLSL;
287 mTextureFunctionHLSL = new TextureFunctionHLSL;
288 mImageFunctionHLSL = new ImageFunctionHLSL;
289 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400290
Olli Etuahod8724a92017-12-29 18:40:36 +0200291 unsigned int firstUniformRegister =
292 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800293 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200294
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200295 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000296 {
Arun Patole63419392015-03-13 11:51:07 +0530297 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500298 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
299 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530300 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800301 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000302 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000303
Geoff Lang00140f42016-02-03 18:47:33 +0000304 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800305 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800306
Jamie Madill4e712be2019-01-03 13:53:59 -0500307 mSSBOOutputHLSL =
308 new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL, shaderStorageBlocks);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309}
310
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000311OutputHLSL::~OutputHLSL()
312{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800313 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400314 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800315 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300316 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800317 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700318 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200319 for (auto &eqFunction : mStructEqualityFunctions)
320 {
321 SafeDelete(eqFunction);
322 }
323 for (auto &eqFunction : mArrayEqualityFunctions)
324 {
325 SafeDelete(eqFunction);
326 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000327}
328
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200329void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000330{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200331 BuiltInFunctionEmulator builtInFunctionEmulator;
332 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800333 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
334 {
335 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
336 mShaderVersion);
337 }
338
Olli Etuahodfa75e82017-01-23 09:43:06 -0800339 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500340
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700341 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000342 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700343 ASSERT(success == CallDAG::INITDAG_SUCCESS);
344 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700345
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200346 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
347 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
348 // the shader code. When we add shader storage blocks we might also consider an alternative
349 // solution, since the struct mapping won't work very well for shader storage blocks.
350
Jamie Madill37997142015-01-28 10:06:34 -0500351 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500352 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200353 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500354 mInfoSinkStack.pop();
355
Jamie Madill37997142015-01-28 10:06:34 -0500356 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500357 mInfoSinkStack.pop();
358
Jamie Madill32aab012015-01-27 14:12:26 -0500359 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200360 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500361 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000362
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200363 objSink << mHeader.c_str();
364 objSink << mBody.c_str();
365 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200366
Olli Etuahodfa75e82017-01-23 09:43:06 -0800367 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000368}
369
Qin Jiajiaa602f902018-09-11 14:40:24 +0800370const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
371{
372 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
373}
374
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800375const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400376{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800377 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400378}
379
Jamie Madill9fe25e92014-07-18 10:33:08 -0400380const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
381{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800382 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400383}
384
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200385TString OutputHLSL::structInitializerString(int indent,
386 const TType &type,
387 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400388{
389 TString init;
390
Olli Etuahoed049ab2017-06-30 17:38:33 +0300391 TString indentString;
392 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400393 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300394 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400395 }
396
Olli Etuahoed049ab2017-06-30 17:38:33 +0300397 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400398 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300399 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300400 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400401 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300402 TStringStream indexedString;
403 indexedString << name << "[" << arrayIndex << "]";
404 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300405 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300406 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300407 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300408 {
409 init += ",";
410 }
411 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400412 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300413 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400414 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300415 else if (type.getBasicType() == EbtStruct)
416 {
417 init += indentString + "{\n";
418 const TStructure &structure = *type.getStruct();
419 const TFieldList &fields = structure.fields();
420 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
421 {
422 const TField &field = *fields[fieldIndex];
423 const TString &fieldName = name + "." + Decorate(field.name());
424 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400425
Olli Etuahoed049ab2017-06-30 17:38:33 +0300426 init += structInitializerString(indent + 1, fieldType, fieldName);
427 if (fieldIndex < fields.size() - 1)
428 {
429 init += ",";
430 }
431 init += "\n";
432 }
433 init += indentString + "}";
434 }
435 else
436 {
437 init += indentString + name;
438 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400439
440 return init;
441}
442
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200443TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
444{
445 TString mappedStructs;
446
447 for (auto &mappedStruct : std140Structs)
448 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200449 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200450 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800451 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
452 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200453 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800454 case EvqUniform:
455 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
456 {
457 continue;
458 }
459 break;
460 case EvqBuffer:
461 continue;
462 default:
463 UNREACHABLE();
464 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200465 }
466
467 unsigned int instanceCount = 1u;
468 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
469 if (isInstanceArray)
470 {
471 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
472 }
473
474 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
475 ++instanceArrayIndex)
476 {
477 TString originalName;
478 TString mappedName("map");
479
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200480 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200481 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200482 const ImmutableString &instanceName =
483 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200484 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
485 if (isInstanceArray)
486 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800487 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200488 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200489 originalName += instanceString;
490 mappedName += instanceString;
491 originalName += ".";
492 mappedName += "_";
493 }
494
495 TString fieldName = Decorate(mappedStruct.field->name());
496 originalName += fieldName;
497 mappedName += fieldName;
498
499 TType *structType = mappedStruct.field->type();
500 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200501 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200502
503 if (structType->isArray())
504 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300505 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200506 }
507
508 mappedStructs += " =\n";
509 mappedStructs += structInitializerString(0, *structType, originalName);
510 mappedStructs += ";\n";
511 }
512 }
513 return mappedStructs;
514}
515
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300516void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300518 for (const auto &attribute : mReferencedAttributes)
519 {
520 const TType &type = attribute.second->getType();
521 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400522
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300523 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
524 << zeroInitializer(type) << ";\n";
525 }
526}
527
528void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
529{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200530 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000531 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800532 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000533
534 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300535 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300536 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
537 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000538 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300539}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000540
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300541void OutputHLSL::header(TInfoSinkBase &out,
542 const std::vector<MappedStruct> &std140Structs,
543 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
544{
545 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000546
Jamie Madill8daaba12014-06-13 10:04:33 -0400547 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400548
Qin Jiajia3e217f62018-08-28 16:55:20 +0800549 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
550 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800551 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400552
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200553 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500554 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200555 out << "\n// Equality functions\n\n";
556 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500557 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200558 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200559 }
560 }
Olli Etuaho12690762015-03-31 12:55:28 +0300561 if (!mArrayAssignmentFunctions.empty())
562 {
563 out << "\n// Assignment functions\n\n";
564 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
565 {
566 out << assignmentFunction.functionDefinition << "\n";
567 }
568 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300569 if (!mArrayConstructIntoFunctions.empty())
570 {
571 out << "\n// Array constructor functions\n\n";
572 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
573 {
574 out << constructIntoFunction.functionDefinition << "\n";
575 }
576 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200577
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500578 if (mUsesDiscardRewriting)
579 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400580 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500581 }
582
Nicolas Capens655fe362014-04-11 13:12:34 -0400583 if (mUsesNestedBreak)
584 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400585 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400586 }
587
Arun Patole44efa0b2015-03-04 17:11:05 +0530588 if (mRequiresIEEEStrictCompiling)
589 {
590 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
591 }
592
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400593 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
594 "#define LOOP [loop]\n"
595 "#define FLATTEN [flatten]\n"
596 "#else\n"
597 "#define LOOP\n"
598 "#define FLATTEN\n"
599 "#endif\n";
600
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700601 // array stride for atomic counter buffers is always 4 per original extension
602 // ARB_shader_atomic_counters and discussion on
603 // https://github.com/KhronosGroup/OpenGL-API/issues/5
604 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
605
jchen10efe061b2018-11-13 16:44:40 +0800606 if (mUseZeroArray)
607 {
608 out << DefineZeroArray() << "\n";
609 }
610
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200611 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300613 const bool usingMRTExtension =
614 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000615
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000616 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300617 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400618 out << "\n";
619
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200620 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000621 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200622 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000623 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200624 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800625 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400626
Olli Etuahofbb1c792018-01-19 16:26:59 +0200627 out << "static " << TypeString(variableType) << " out_" << variableName
628 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000629 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000630 }
Jamie Madill46131a32013-06-20 11:55:50 -0400631 else
632 {
633 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
634
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800635 out << "static float4 gl_Color[" << numColorValues
636 << "] =\n"
637 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400638 for (unsigned int i = 0; i < numColorValues; i++)
639 {
640 out << " float4(0, 0, 0, 0)";
641 if (i + 1 != numColorValues)
642 {
643 out << ",";
644 }
645 out << "\n";
646 }
647
648 out << "};\n";
649 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000650
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400651 if (mUsesFragDepth)
652 {
653 out << "static float gl_Depth = 0.0;\n";
654 }
655
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000656 if (mUsesFragCoord)
657 {
658 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
659 }
660
661 if (mUsesPointCoord)
662 {
663 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
664 }
665
666 if (mUsesFrontFacing)
667 {
668 out << "static bool gl_FrontFacing = false;\n";
669 }
670
671 out << "\n";
672
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000673 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000674 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000675 out << "struct gl_DepthRangeParameters\n"
676 "{\n"
677 " float near;\n"
678 " float far;\n"
679 " float diff;\n"
680 "};\n"
681 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000682 }
683
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200684 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000685 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000686 out << "cbuffer DriverConstants : register(b1)\n"
687 "{\n";
688
689 if (mUsesDepthRange)
690 {
691 out << " float3 dx_DepthRange : packoffset(c0);\n";
692 }
693
694 if (mUsesFragCoord)
695 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000696 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000697 }
698
699 if (mUsesFragCoord || mUsesFrontFacing)
700 {
701 out << " float3 dx_DepthFront : packoffset(c2);\n";
702 }
703
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800704 if (mUsesFragCoord)
705 {
706 // dx_ViewScale is only used in the fragment shader to correct
707 // the value for glFragCoord if necessary
708 out << " float2 dx_ViewScale : packoffset(c3);\n";
709 }
710
Martin Radev72b4e1e2017-08-31 15:42:56 +0300711 if (mHasMultiviewExtensionEnabled)
712 {
713 // We have to add a value which we can use to keep track of which multi-view code
714 // path is to be selected in the GS.
715 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
716 }
717
Olli Etuaho618bebc2016-01-15 16:40:00 +0200718 if (mOutputType == SH_HLSL_4_1_OUTPUT)
719 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800720 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200721 }
722
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000723 out << "};\n";
724 }
725 else
726 {
727 if (mUsesDepthRange)
728 {
729 out << "uniform float3 dx_DepthRange : register(c0);";
730 }
731
732 if (mUsesFragCoord)
733 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000734 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000735 }
736
737 if (mUsesFragCoord || mUsesFrontFacing)
738 {
739 out << "uniform float3 dx_DepthFront : register(c2);\n";
740 }
741 }
742
743 out << "\n";
744
745 if (mUsesDepthRange)
746 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
748 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000749 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000750 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000751
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000752 if (usingMRTExtension && mNumRenderTargets > 1)
753 {
754 out << "#define GL_USES_MRT\n";
755 }
756
757 if (mUsesFragColor)
758 {
759 out << "#define GL_USES_FRAG_COLOR\n";
760 }
761
762 if (mUsesFragData)
763 {
764 out << "#define GL_USES_FRAG_DATA\n";
765 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766 }
Xinghua Caob1239382016-12-13 15:07:05 +0800767 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000769 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300770 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000771 out << "\n"
772 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400773
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000774 if (mUsesPointSize)
775 {
776 out << "static float gl_PointSize = float(1);\n";
777 }
778
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000779 if (mUsesInstanceID)
780 {
781 out << "static int gl_InstanceID;";
782 }
783
Corentin Wallezb076add2016-01-11 16:45:46 -0500784 if (mUsesVertexID)
785 {
786 out << "static int gl_VertexID;";
787 }
788
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000789 out << "\n"
790 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300791 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000792 out << "\n";
793
794 if (mUsesDepthRange)
795 {
796 out << "struct gl_DepthRangeParameters\n"
797 "{\n"
798 " float near;\n"
799 " float far;\n"
800 " float diff;\n"
801 "};\n"
802 "\n";
803 }
804
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200805 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000806 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800807 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500808 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800809
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000810 if (mUsesDepthRange)
811 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800812 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000813 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800814
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800815 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
816 // shaders. However, we declare it for all shaders (including Feature Level 10+).
817 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
818 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800819 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800820 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800821 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800822
Martin Radev72b4e1e2017-08-31 15:42:56 +0300823 if (mHasMultiviewExtensionEnabled)
824 {
825 // We have to add a value which we can use to keep track of which multi-view code
826 // path is to be selected in the GS.
827 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
828 }
829
Olli Etuaho618bebc2016-01-15 16:40:00 +0200830 if (mOutputType == SH_HLSL_4_1_OUTPUT)
831 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800832 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200833 }
834
Austin Kinross4fd18b12014-12-22 12:32:05 -0800835 out << "};\n"
836 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000837 }
838 else
839 {
840 if (mUsesDepthRange)
841 {
842 out << "uniform float3 dx_DepthRange : register(c0);\n";
843 }
844
Cooper Partine6664f02015-01-09 16:22:24 -0800845 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
846 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000847 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000848 }
849
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000850 if (mUsesDepthRange)
851 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500852 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
853 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000854 "\n";
855 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400856 }
Xinghua Caob1239382016-12-13 15:07:05 +0800857 else // Compute shader
858 {
859 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800860
861 out << "cbuffer DriverConstants : register(b1)\n"
862 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800863 if (mUsesNumWorkGroups)
864 {
Xinghua Caob1239382016-12-13 15:07:05 +0800865 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800866 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800867 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800868 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800869 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800870
Jiawei Shao203b26f2018-07-25 10:30:43 +0800871 std::ostringstream systemValueDeclaration;
872 std::ostringstream glBuiltinInitialization;
873
874 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
875 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
876 << "{\n";
877
Xinghua Caob1239382016-12-13 15:07:05 +0800878 if (mUsesWorkGroupID)
879 {
880 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800881 systemValueDeclaration << " uint3 dx_WorkGroupID : "
882 << "SV_GroupID;\n";
883 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800884 }
885
886 if (mUsesLocalInvocationID)
887 {
888 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800889 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
890 << "SV_GroupThreadID;\n";
891 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800892 }
893
894 if (mUsesGlobalInvocationID)
895 {
896 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800897 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
898 << "SV_DispatchThreadID;\n";
899 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800900 }
901
902 if (mUsesLocalInvocationIndex)
903 {
904 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800905 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
906 << "SV_GroupIndex;\n";
907 glBuiltinInitialization
908 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800909 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800910
911 systemValueDeclaration << "};\n\n";
912 glBuiltinInitialization << "};\n\n";
913
914 out << systemValueDeclaration.str();
915 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800916 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000917
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800918 if (!mappedStructs.empty())
919 {
920 out << "// Structures from std140 blocks with padding removed\n";
921 out << "\n";
922 out << mappedStructs;
923 out << "\n";
924 }
925
Geoff Lang1fe74c72016-08-25 13:23:01 -0400926 bool getDimensionsIgnoresBaseLevel =
927 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
928 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800929 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700930 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000932 if (mUsesFragCoord)
933 {
934 out << "#define GL_USES_FRAG_COORD\n";
935 }
936
937 if (mUsesPointCoord)
938 {
939 out << "#define GL_USES_POINT_COORD\n";
940 }
941
942 if (mUsesFrontFacing)
943 {
944 out << "#define GL_USES_FRONT_FACING\n";
945 }
946
947 if (mUsesPointSize)
948 {
949 out << "#define GL_USES_POINT_SIZE\n";
950 }
951
Martin Radev41ac68e2017-06-06 12:16:58 +0300952 if (mHasMultiviewExtensionEnabled)
953 {
954 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
955 }
956
957 if (mUsesViewID)
958 {
959 out << "#define GL_USES_VIEW_ID\n";
960 }
961
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400962 if (mUsesFragDepth)
963 {
964 out << "#define GL_USES_FRAG_DEPTH\n";
965 }
966
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000967 if (mUsesDepthRange)
968 {
969 out << "#define GL_USES_DEPTH_RANGE\n";
970 }
971
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000972 if (mUsesXor)
973 {
974 out << "bool xor(bool p, bool q)\n"
975 "{\n"
976 " return (p || q) && !(p && q);\n"
977 "}\n"
978 "\n";
979 }
980
Olli Etuahodfa75e82017-01-23 09:43:06 -0800981 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982}
983
984void OutputHLSL::visitSymbol(TIntermSymbol *node)
985{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200986 const TVariable &variable = node->variable();
987
988 // Empty symbols can only appear in declarations and function arguments, and in either of those
989 // cases the symbol nodes are not visited.
990 ASSERT(variable.symbolType() != SymbolType::Empty);
991
Jamie Madill32aab012015-01-27 14:12:26 -0500992 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993
Jamie Madill570e04d2013-06-21 09:15:33 -0400994 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800995 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400996 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200997 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400998 }
999
Olli Etuahofbb1c792018-01-19 16:26:59 +02001000 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001001 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +02001002
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001003 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001004 {
1005 mUsesDepthRange = true;
1006 out << name;
1007 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001008 else if (IsAtomicCounter(variable.getType().getBasicType()))
1009 {
1010 const TType &variableType = variable.getType();
1011 if (variableType.getQualifier() == EvqUniform)
1012 {
1013 TLayoutQualifier layout = variableType.getLayoutQualifier();
1014 mReferencedUniforms[uniqueId.get()] = &variable;
1015 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1016 }
1017 else
1018 {
1019 TString varName = DecorateVariableIfNeeded(variable);
1020 out << varName << ", " << varName << "_offset";
1021 }
1022 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001023 else
1024 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001025 const TType &variableType = variable.getType();
1026 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001027
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001028 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +02001029
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001030 if (qualifier == EvqUniform)
1031 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001032 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001033
1034 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001035 {
Olli Etuahoc71862a2017-12-21 12:58:29 +02001036 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1037 {
1038 const TVariable *instanceVariable = nullptr;
1039 if (variableType.isInterfaceBlock())
1040 {
1041 instanceVariable = &variable;
1042 }
1043 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1044 new TReferencedBlock(interfaceBlock, instanceVariable);
1045 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001046 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001047 else
1048 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001049 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001050 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001051
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001052 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001053 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001054 else if (qualifier == EvqBuffer)
1055 {
1056 UNREACHABLE();
1057 }
Jamie Madill19571812013-08-12 15:26:34 -07001058 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001059 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001060 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001061 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001062 }
Jamie Madill033dae62014-06-18 12:56:28 -04001063 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001064 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001065 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001066 out << DecorateVariableIfNeeded(variable);
1067 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001068 {
1069 mUsesViewID = true;
1070 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001071 }
Jamie Madill19571812013-08-12 15:26:34 -07001072 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001073 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001074 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001075 out << "out_" << name;
1076 }
1077 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001078 {
1079 out << "gl_Color[0]";
1080 mUsesFragColor = true;
1081 }
1082 else if (qualifier == EvqFragData)
1083 {
1084 out << "gl_Color";
1085 mUsesFragData = true;
1086 }
1087 else if (qualifier == EvqFragCoord)
1088 {
1089 mUsesFragCoord = true;
1090 out << name;
1091 }
1092 else if (qualifier == EvqPointCoord)
1093 {
1094 mUsesPointCoord = true;
1095 out << name;
1096 }
1097 else if (qualifier == EvqFrontFacing)
1098 {
1099 mUsesFrontFacing = true;
1100 out << name;
1101 }
1102 else if (qualifier == EvqPointSize)
1103 {
1104 mUsesPointSize = true;
1105 out << name;
1106 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001107 else if (qualifier == EvqInstanceID)
1108 {
1109 mUsesInstanceID = true;
1110 out << name;
1111 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001112 else if (qualifier == EvqVertexID)
1113 {
1114 mUsesVertexID = true;
1115 out << name;
1116 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001117 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001118 {
1119 mUsesFragDepth = true;
1120 out << "gl_Depth";
1121 }
Xinghua Caob1239382016-12-13 15:07:05 +08001122 else if (qualifier == EvqNumWorkGroups)
1123 {
1124 mUsesNumWorkGroups = true;
1125 out << name;
1126 }
1127 else if (qualifier == EvqWorkGroupID)
1128 {
1129 mUsesWorkGroupID = true;
1130 out << name;
1131 }
1132 else if (qualifier == EvqLocalInvocationID)
1133 {
1134 mUsesLocalInvocationID = true;
1135 out << name;
1136 }
1137 else if (qualifier == EvqGlobalInvocationID)
1138 {
1139 mUsesGlobalInvocationID = true;
1140 out << name;
1141 }
1142 else if (qualifier == EvqLocalInvocationIndex)
1143 {
1144 mUsesLocalInvocationIndex = true;
1145 out << name;
1146 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001147 else
1148 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001149 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001150 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001151 }
1152}
1153
Olli Etuaho7fb49552015-03-18 17:27:44 +02001154void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1155{
1156 if (type.isScalar() && !type.isArray())
1157 {
1158 if (op == EOpEqual)
1159 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001160 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001161 }
1162 else
1163 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001164 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001165 }
1166 }
1167 else
1168 {
1169 if (visit == PreVisit && op == EOpNotEqual)
1170 {
1171 out << "!";
1172 }
1173
1174 if (type.isArray())
1175 {
1176 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001177 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001178 }
1179 else if (type.getBasicType() == EbtStruct)
1180 {
1181 const TStructure &structure = *type.getStruct();
1182 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001183 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001184 }
1185 else
1186 {
1187 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001188 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001189 }
1190 }
1191}
1192
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001193void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1194{
1195 if (type.isArray())
1196 {
1197 const TString &functionName = addArrayAssignmentFunction(type);
1198 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1199 }
1200 else
1201 {
1202 outputTriplet(out, visit, "(", " = ", ")");
1203 }
1204}
1205
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001206bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001207{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001208 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001209 {
1210 TIntermNode *ancestor = getAncestorNode(n);
1211 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1212 if (ancestorBinary == nullptr)
1213 {
1214 return false;
1215 }
1216 switch (ancestorBinary->getOp())
1217 {
1218 case EOpIndexDirectStruct:
1219 {
1220 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1221 const TIntermConstantUnion *index =
1222 ancestorBinary->getRight()->getAsConstantUnion();
1223 const TField *field = structure->fields()[index->getIConst(0)];
1224 if (IsSampler(field->type()->getBasicType()))
1225 {
1226 return true;
1227 }
1228 break;
1229 }
1230 case EOpIndexDirect:
1231 break;
1232 default:
1233 // Returning a sampler from indirect indexing is not supported.
1234 return false;
1235 }
1236 }
1237 return false;
1238}
1239
Olli Etuahob6fa0432016-09-28 16:28:05 +01001240bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1241{
1242 TInfoSinkBase &out = getInfoSink();
1243 if (visit == PostVisit)
1244 {
1245 out << ".";
1246 node->writeOffsetsAsXYZW(&out);
1247 }
1248 return true;
1249}
1250
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001251bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1252{
Jamie Madill32aab012015-01-27 14:12:26 -05001253 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001254
1255 switch (node->getOp())
1256 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001257 case EOpComma:
1258 outputTriplet(out, visit, "(", ", ", ")");
1259 break;
1260 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001261 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001262 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001263 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1264 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001265 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001266 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1267 out << functionName << "(";
1268 node->getLeft()->traverse(this);
1269 TIntermSequence *seq = rightAgg->getSequence();
1270 for (auto &arrayElement : *seq)
1271 {
1272 out << ", ";
1273 arrayElement->traverse(this);
1274 }
1275 out << ")";
1276 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001277 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001278 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1279 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001280 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001281 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001282 // Assignment expressions with atomic functions should be transformed into atomic
1283 // function calls in HLSL.
1284 // e.g. original_value = atomicAdd(dest, value) should be translated into
1285 // InterlockedAdd(dest, value, original_value);
Qin Jiajia46229052018-12-10 13:31:00 +08001286 else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001287 {
1288 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1289 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1290 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1291 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1292 ASSERT(argumentSeq->size() >= 2u);
1293 for (auto &argument : *argumentSeq)
1294 {
1295 argument->traverse(this);
1296 out << ", ";
1297 }
1298 node->getLeft()->traverse(this);
1299 out << ")";
1300 return false;
1301 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001302 else if (IsInShaderStorageBlock(node->getLeft()))
1303 {
1304 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1305 out << ", ";
1306 if (IsInShaderStorageBlock(node->getRight()))
1307 {
1308 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1309 }
1310 else
1311 {
1312 node->getRight()->traverse(this);
1313 }
1314
1315 out << ")";
1316 return false;
1317 }
1318 else if (IsInShaderStorageBlock(node->getRight()))
1319 {
1320 node->getLeft()->traverse(this);
1321 out << " = ";
1322 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1323 return false;
1324 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001325
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001326 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001327 break;
1328 case EOpInitialize:
1329 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001330 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001331 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1332 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001333 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001334
1335 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001336 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001337
1338 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1339 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1340 // new variable is created before the assignment is evaluated), so we need to
1341 // convert
1342 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001343 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001344 {
1345 // Skip initializing the rest of the expression
1346 return false;
1347 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001348 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001349 {
1350 return false;
1351 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001352 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001353 else if (visit == InVisit)
1354 {
1355 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001356 if (IsInShaderStorageBlock(node->getRight()))
1357 {
1358 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1359 return false;
1360 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001361 }
1362 break;
1363 case EOpAddAssign:
1364 outputTriplet(out, visit, "(", " += ", ")");
1365 break;
1366 case EOpSubAssign:
1367 outputTriplet(out, visit, "(", " -= ", ")");
1368 break;
1369 case EOpMulAssign:
1370 outputTriplet(out, visit, "(", " *= ", ")");
1371 break;
1372 case EOpVectorTimesScalarAssign:
1373 outputTriplet(out, visit, "(", " *= ", ")");
1374 break;
1375 case EOpMatrixTimesScalarAssign:
1376 outputTriplet(out, visit, "(", " *= ", ")");
1377 break;
1378 case EOpVectorTimesMatrixAssign:
1379 if (visit == PreVisit)
1380 {
1381 out << "(";
1382 }
1383 else if (visit == InVisit)
1384 {
1385 out << " = mul(";
1386 node->getLeft()->traverse(this);
1387 out << ", transpose(";
1388 }
1389 else
1390 {
1391 out << ")))";
1392 }
1393 break;
1394 case EOpMatrixTimesMatrixAssign:
1395 if (visit == PreVisit)
1396 {
1397 out << "(";
1398 }
1399 else if (visit == InVisit)
1400 {
1401 out << " = transpose(mul(transpose(";
1402 node->getLeft()->traverse(this);
1403 out << "), transpose(";
1404 }
1405 else
1406 {
1407 out << "))))";
1408 }
1409 break;
1410 case EOpDivAssign:
1411 outputTriplet(out, visit, "(", " /= ", ")");
1412 break;
1413 case EOpIModAssign:
1414 outputTriplet(out, visit, "(", " %= ", ")");
1415 break;
1416 case EOpBitShiftLeftAssign:
1417 outputTriplet(out, visit, "(", " <<= ", ")");
1418 break;
1419 case EOpBitShiftRightAssign:
1420 outputTriplet(out, visit, "(", " >>= ", ")");
1421 break;
1422 case EOpBitwiseAndAssign:
1423 outputTriplet(out, visit, "(", " &= ", ")");
1424 break;
1425 case EOpBitwiseXorAssign:
1426 outputTriplet(out, visit, "(", " ^= ", ")");
1427 break;
1428 case EOpBitwiseOrAssign:
1429 outputTriplet(out, visit, "(", " |= ", ")");
1430 break;
1431 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001432 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001433 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001434 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001435 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001436 if (visit == PreVisit)
1437 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001438 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001439 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001440
1441 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001442 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1443 {
1444 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1445 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1446 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001447 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001448 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001449 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001450 return false;
1451 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001452 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001453 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001454 {
1455 // All parts of an expression that access a sampler in a struct need to use _ as
1456 // separator to access the sampler variable that has been moved out of the struct.
1457 outputTriplet(out, visit, "", "_", "");
1458 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001459 else if (IsAtomicCounter(leftType.getBasicType()))
1460 {
1461 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1462 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001463 else
1464 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001465 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001466 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001467 }
1468 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001470 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 // We do not currently support indirect references to interface blocks
1472 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001473
1474 const TType &leftType = node->getLeft()->getType();
1475 if (IsAtomicCounter(leftType.getBasicType()))
1476 {
1477 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1478 }
1479 else
1480 {
1481 outputTriplet(out, visit, "", "[", "]");
1482 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001483 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001484 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001486 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 const TStructure *structure = node->getLeft()->getType().getStruct();
1488 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1489 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001490
Olli Etuaho96963162016-03-21 11:54:33 +02001491 // In cases where indexing returns a sampler, we need to access the sampler variable
1492 // that has been moved out of the struct.
1493 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1494 if (visit == PreVisit && indexingReturnsSampler)
1495 {
1496 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1497 // This prefix is only output at the beginning of the indexing expression, which
1498 // may have multiple parts.
1499 out << "angle";
1500 }
1501 if (!indexingReturnsSampler)
1502 {
1503 // All parts of an expression that access a sampler in a struct need to use _ as
1504 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001505 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001506 }
1507 if (visit == InVisit)
1508 {
1509 if (indexingReturnsSampler)
1510 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001511 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001512 }
1513 else
1514 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001515 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001516 }
1517
1518 return false;
1519 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001520 }
1521 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001522 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001523 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001524 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1525 bool structInStd140UniformBlock =
1526 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1527 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001528 {
1529 out << "map";
1530 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001531 if (visit == InVisit)
1532 {
1533 const TInterfaceBlock *interfaceBlock =
1534 node->getLeft()->getType().getInterfaceBlock();
1535 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1536 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001537 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001538 {
1539 out << "_";
1540 }
1541 else
1542 {
1543 out << ".";
1544 }
1545 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001546
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 return false;
1548 }
1549 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001550 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 case EOpAdd:
1552 outputTriplet(out, visit, "(", " + ", ")");
1553 break;
1554 case EOpSub:
1555 outputTriplet(out, visit, "(", " - ", ")");
1556 break;
1557 case EOpMul:
1558 outputTriplet(out, visit, "(", " * ", ")");
1559 break;
1560 case EOpDiv:
1561 outputTriplet(out, visit, "(", " / ", ")");
1562 break;
1563 case EOpIMod:
1564 outputTriplet(out, visit, "(", " % ", ")");
1565 break;
1566 case EOpBitShiftLeft:
1567 outputTriplet(out, visit, "(", " << ", ")");
1568 break;
1569 case EOpBitShiftRight:
1570 outputTriplet(out, visit, "(", " >> ", ")");
1571 break;
1572 case EOpBitwiseAnd:
1573 outputTriplet(out, visit, "(", " & ", ")");
1574 break;
1575 case EOpBitwiseXor:
1576 outputTriplet(out, visit, "(", " ^ ", ")");
1577 break;
1578 case EOpBitwiseOr:
1579 outputTriplet(out, visit, "(", " | ", ")");
1580 break;
1581 case EOpEqual:
1582 case EOpNotEqual:
1583 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1584 break;
1585 case EOpLessThan:
1586 outputTriplet(out, visit, "(", " < ", ")");
1587 break;
1588 case EOpGreaterThan:
1589 outputTriplet(out, visit, "(", " > ", ")");
1590 break;
1591 case EOpLessThanEqual:
1592 outputTriplet(out, visit, "(", " <= ", ")");
1593 break;
1594 case EOpGreaterThanEqual:
1595 outputTriplet(out, visit, "(", " >= ", ")");
1596 break;
1597 case EOpVectorTimesScalar:
1598 outputTriplet(out, visit, "(", " * ", ")");
1599 break;
1600 case EOpMatrixTimesScalar:
1601 outputTriplet(out, visit, "(", " * ", ")");
1602 break;
1603 case EOpVectorTimesMatrix:
1604 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1605 break;
1606 case EOpMatrixTimesVector:
1607 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1608 break;
1609 case EOpMatrixTimesMatrix:
1610 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1611 break;
1612 case EOpLogicalOr:
1613 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1614 // been unfolded.
1615 ASSERT(!node->getRight()->hasSideEffects());
1616 outputTriplet(out, visit, "(", " || ", ")");
1617 return true;
1618 case EOpLogicalXor:
1619 mUsesXor = true;
1620 outputTriplet(out, visit, "xor(", ", ", ")");
1621 break;
1622 case EOpLogicalAnd:
1623 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1624 // been unfolded.
1625 ASSERT(!node->getRight()->hasSideEffects());
1626 outputTriplet(out, visit, "(", " && ", ")");
1627 return true;
1628 default:
1629 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630 }
1631
1632 return true;
1633}
1634
1635bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1636{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001637 TInfoSinkBase &out = getInfoSink();
1638
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001639 switch (node->getOp())
1640 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001641 case EOpNegative:
1642 outputTriplet(out, visit, "(-", "", ")");
1643 break;
1644 case EOpPositive:
1645 outputTriplet(out, visit, "(+", "", ")");
1646 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001647 case EOpLogicalNot:
1648 outputTriplet(out, visit, "(!", "", ")");
1649 break;
1650 case EOpBitwiseNot:
1651 outputTriplet(out, visit, "(~", "", ")");
1652 break;
1653 case EOpPostIncrement:
1654 outputTriplet(out, visit, "(", "", "++)");
1655 break;
1656 case EOpPostDecrement:
1657 outputTriplet(out, visit, "(", "", "--)");
1658 break;
1659 case EOpPreIncrement:
1660 outputTriplet(out, visit, "(++", "", ")");
1661 break;
1662 case EOpPreDecrement:
1663 outputTriplet(out, visit, "(--", "", ")");
1664 break;
1665 case EOpRadians:
1666 outputTriplet(out, visit, "radians(", "", ")");
1667 break;
1668 case EOpDegrees:
1669 outputTriplet(out, visit, "degrees(", "", ")");
1670 break;
1671 case EOpSin:
1672 outputTriplet(out, visit, "sin(", "", ")");
1673 break;
1674 case EOpCos:
1675 outputTriplet(out, visit, "cos(", "", ")");
1676 break;
1677 case EOpTan:
1678 outputTriplet(out, visit, "tan(", "", ")");
1679 break;
1680 case EOpAsin:
1681 outputTriplet(out, visit, "asin(", "", ")");
1682 break;
1683 case EOpAcos:
1684 outputTriplet(out, visit, "acos(", "", ")");
1685 break;
1686 case EOpAtan:
1687 outputTriplet(out, visit, "atan(", "", ")");
1688 break;
1689 case EOpSinh:
1690 outputTriplet(out, visit, "sinh(", "", ")");
1691 break;
1692 case EOpCosh:
1693 outputTriplet(out, visit, "cosh(", "", ")");
1694 break;
1695 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001696 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001697 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001698 case EOpAtanh:
1699 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001700 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 break;
1702 case EOpExp:
1703 outputTriplet(out, visit, "exp(", "", ")");
1704 break;
1705 case EOpLog:
1706 outputTriplet(out, visit, "log(", "", ")");
1707 break;
1708 case EOpExp2:
1709 outputTriplet(out, visit, "exp2(", "", ")");
1710 break;
1711 case EOpLog2:
1712 outputTriplet(out, visit, "log2(", "", ")");
1713 break;
1714 case EOpSqrt:
1715 outputTriplet(out, visit, "sqrt(", "", ")");
1716 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001717 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001718 outputTriplet(out, visit, "rsqrt(", "", ")");
1719 break;
1720 case EOpAbs:
1721 outputTriplet(out, visit, "abs(", "", ")");
1722 break;
1723 case EOpSign:
1724 outputTriplet(out, visit, "sign(", "", ")");
1725 break;
1726 case EOpFloor:
1727 outputTriplet(out, visit, "floor(", "", ")");
1728 break;
1729 case EOpTrunc:
1730 outputTriplet(out, visit, "trunc(", "", ")");
1731 break;
1732 case EOpRound:
1733 outputTriplet(out, visit, "round(", "", ")");
1734 break;
1735 case EOpRoundEven:
1736 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001737 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001738 break;
1739 case EOpCeil:
1740 outputTriplet(out, visit, "ceil(", "", ")");
1741 break;
1742 case EOpFract:
1743 outputTriplet(out, visit, "frac(", "", ")");
1744 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001745 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001746 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001747 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001748 else
1749 outputTriplet(out, visit, "isnan(", "", ")");
1750 mRequiresIEEEStrictCompiling = true;
1751 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001752 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001753 outputTriplet(out, visit, "isinf(", "", ")");
1754 break;
1755 case EOpFloatBitsToInt:
1756 outputTriplet(out, visit, "asint(", "", ")");
1757 break;
1758 case EOpFloatBitsToUint:
1759 outputTriplet(out, visit, "asuint(", "", ")");
1760 break;
1761 case EOpIntBitsToFloat:
1762 outputTriplet(out, visit, "asfloat(", "", ")");
1763 break;
1764 case EOpUintBitsToFloat:
1765 outputTriplet(out, visit, "asfloat(", "", ")");
1766 break;
1767 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001768 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001769 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001770 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001771 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001772 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001773 case EOpPackUnorm4x8:
1774 case EOpPackSnorm4x8:
1775 case EOpUnpackUnorm4x8:
1776 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001777 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001778 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001779 break;
1780 case EOpLength:
1781 outputTriplet(out, visit, "length(", "", ")");
1782 break;
1783 case EOpNormalize:
1784 outputTriplet(out, visit, "normalize(", "", ")");
1785 break;
1786 case EOpDFdx:
1787 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1788 {
1789 outputTriplet(out, visit, "(", "", ", 0.0)");
1790 }
1791 else
1792 {
1793 outputTriplet(out, visit, "ddx(", "", ")");
1794 }
1795 break;
1796 case EOpDFdy:
1797 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1798 {
1799 outputTriplet(out, visit, "(", "", ", 0.0)");
1800 }
1801 else
1802 {
1803 outputTriplet(out, visit, "ddy(", "", ")");
1804 }
1805 break;
1806 case EOpFwidth:
1807 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1808 {
1809 outputTriplet(out, visit, "(", "", ", 0.0)");
1810 }
1811 else
1812 {
1813 outputTriplet(out, visit, "fwidth(", "", ")");
1814 }
1815 break;
1816 case EOpTranspose:
1817 outputTriplet(out, visit, "transpose(", "", ")");
1818 break;
1819 case EOpDeterminant:
1820 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1821 break;
1822 case EOpInverse:
1823 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001824 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001825 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001826
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001827 case EOpAny:
1828 outputTriplet(out, visit, "any(", "", ")");
1829 break;
1830 case EOpAll:
1831 outputTriplet(out, visit, "all(", "", ")");
1832 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001833 case EOpLogicalNotComponentWise:
1834 outputTriplet(out, visit, "(!", "", ")");
1835 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001836 case EOpBitfieldReverse:
1837 outputTriplet(out, visit, "reversebits(", "", ")");
1838 break;
1839 case EOpBitCount:
1840 outputTriplet(out, visit, "countbits(", "", ")");
1841 break;
1842 case EOpFindLSB:
1843 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1844 // in GLSLTest and results are consistent with GL.
1845 outputTriplet(out, visit, "firstbitlow(", "", ")");
1846 break;
1847 case EOpFindMSB:
1848 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1849 // tested in GLSLTest and results are consistent with GL.
1850 outputTriplet(out, visit, "firstbithigh(", "", ")");
1851 break;
Qin Jiajia88faa692018-12-03 16:22:24 +08001852 case EOpArrayLength:
1853 {
1854 TIntermTyped *operand = node->getOperand();
1855 ASSERT(IsInShaderStorageBlock(operand));
1856 mSSBOOutputHLSL->outputLengthFunctionCall(operand);
1857 return false;
1858 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001859 default:
1860 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001861 }
1862
1863 return true;
1864}
1865
Olli Etuahofbb1c792018-01-19 16:26:59 +02001866ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001867{
1868 if (node->getAsSymbolNode())
1869 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001870 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1871 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001872 }
1873 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1874 switch (nodeBinary->getOp())
1875 {
1876 case EOpIndexDirect:
1877 {
1878 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1879
Olli Etuahofbb1c792018-01-19 16:26:59 +02001880 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001881 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001882 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001883 }
1884 case EOpIndexDirectStruct:
1885 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001886 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001887 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1888 const TField *field = s->fields()[index];
1889
Olli Etuahofbb1c792018-01-19 16:26:59 +02001890 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001891 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1892 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001893 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001894 }
1895 default:
1896 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001897 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001898 }
1899}
1900
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001901bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1902{
1903 TInfoSinkBase &out = getInfoSink();
1904
Olli Etuaho06235df2018-07-20 14:26:07 +03001905 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1906
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001907 if (mInsideFunction)
1908 {
1909 outputLineDirective(out, node->getLine().first_line);
1910 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001911 if (isMainBlock)
1912 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001913 if (mShaderType == GL_COMPUTE_SHADER)
1914 {
1915 out << "initGLBuiltins(input);\n";
1916 }
1917 else
1918 {
1919 out << "@@ MAIN PROLOGUE @@\n";
1920 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001921 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001922 }
1923
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001924 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001925 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001926 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001927
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001928 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001929
1930 // Don't output ; after case labels, they're terminated by :
1931 // This is needed especially since outputting a ; after a case statement would turn empty
1932 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001933 // Also the output code is clearer if we don't output ; after statements where it is not
1934 // needed:
1935 // * if statements
1936 // * switch statements
1937 // * blocks
1938 // * function definitions
1939 // * loops (do-while loops output the semicolon in VisitLoop)
1940 // * declarations that don't generate output.
1941 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1942 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1943 statement->getAsSwitchNode() == nullptr &&
1944 statement->getAsFunctionDefinition() == nullptr &&
1945 (statement->getAsDeclarationNode() == nullptr ||
1946 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1947 statement->getAsInvariantDeclarationNode() == nullptr)
1948 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001949 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001950 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001951 }
1952
1953 if (mInsideFunction)
1954 {
1955 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001956 if (isMainBlock && shaderNeedsGenerateOutput())
1957 {
1958 // We could have an empty main, a main function without a branch at the end, or a main
1959 // function with a discard statement at the end. In these cases we need to add a return
1960 // statement.
1961 bool needReturnStatement =
1962 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1963 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1964 if (needReturnStatement)
1965 {
1966 out << "return " << generateOutputCall() << ";\n";
1967 }
1968 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001969 out << "}\n";
1970 }
1971
1972 return false;
1973}
1974
Olli Etuaho336b1472016-10-05 16:37:55 +01001975bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1976{
1977 TInfoSinkBase &out = getInfoSink();
1978
1979 ASSERT(mCurrentFunctionMetadata == nullptr);
1980
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001981 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001982 ASSERT(index != CallDAG::InvalidIndex);
1983 mCurrentFunctionMetadata = &mASTMetadataList[index];
1984
Olli Etuahod4bd9632018-03-08 16:32:44 +02001985 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001986
Olli Etuahod4bd9632018-03-08 16:32:44 +02001987 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001988 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001989 // The stub strings below are replaced when shader is dynamically defined by its layout:
1990 switch (mShaderType)
1991 {
1992 case GL_VERTEX_SHADER:
1993 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1994 << "@@ VERTEX OUTPUT @@\n\n"
1995 << "VS_OUTPUT main(VS_INPUT input)";
1996 break;
1997 case GL_FRAGMENT_SHADER:
1998 out << "@@ PIXEL OUTPUT @@\n\n"
1999 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
2000 break;
2001 case GL_COMPUTE_SHADER:
2002 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
2003 << mWorkGroupSize[2] << ")]\n";
2004 out << "void main(CS_INPUT input)";
2005 break;
2006 default:
2007 UNREACHABLE();
2008 break;
2009 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002010 }
2011 else
2012 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002013 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02002014 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002015 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01002016
Olli Etuaho06235df2018-07-20 14:26:07 +03002017 size_t paramCount = func->getParamCount();
2018 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01002019 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002020 const TVariable *param = func->getParam(i);
2021 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01002022
Olli Etuaho06235df2018-07-20 14:26:07 +03002023 writeParameter(param, out);
2024
2025 if (i < paramCount - 1)
2026 {
2027 out << ", ";
2028 }
2029 }
2030
2031 out << ")\n";
2032 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002033
2034 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03002035 if (func->isMain())
2036 {
2037 mInsideMain = true;
2038 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002039 // The function body node will output braces.
2040 node->getBody()->traverse(this);
2041 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03002042 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01002043
2044 mCurrentFunctionMetadata = nullptr;
2045
2046 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2047 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2048 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002049 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01002050 mOutputLod0Function = true;
2051 node->traverse(this);
2052 mOutputLod0Function = false;
2053 }
2054
2055 return false;
2056}
2057
Olli Etuaho13389b62016-10-16 11:48:18 +01002058bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2059{
Olli Etuaho13389b62016-10-16 11:48:18 +01002060 if (visit == PreVisit)
2061 {
2062 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002063 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002064 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002065 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002066
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002067 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002068 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002069 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002070 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002071
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002072 if (!declarator->getAsSymbolNode() ||
2073 declarator->getAsSymbolNode()->variable().symbolType() !=
2074 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002075 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002076 if (declarator->getQualifier() == EvqShared)
2077 {
2078 out << "groupshared ";
2079 }
2080 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002081 {
2082 out << "static ";
2083 }
2084
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002085 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002086
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002087 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002088
2089 if (symbol)
2090 {
2091 symbol->traverse(this);
2092 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002093 if (declarator->getQualifier() != EvqShared ||
2094 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002095 {
2096 out << " = " + zeroInitializer(symbol->getType());
2097 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002098 }
2099 else
2100 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002101 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002102 }
2103 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002104 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002105 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002106 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002107 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002108 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002109
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002110 const TVariable &variable = symbol->variable();
2111
2112 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002113 {
2114 // Vertex outputs which are declared but not written to should still be declared to
2115 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002116 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002117 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002118 }
2119 }
2120 return false;
2121}
2122
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002123bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2124{
2125 // Do not do any translation
2126 return false;
2127}
2128
Olli Etuahod4bd9632018-03-08 16:32:44 +02002129void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002130{
2131 TInfoSinkBase &out = getInfoSink();
2132
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002133 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002134 // Skip the prototype if it is not implemented (and thus not used)
2135 if (index == CallDAG::InvalidIndex)
2136 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002137 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002138 }
2139
Olli Etuahod4bd9632018-03-08 16:32:44 +02002140 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002141
Olli Etuahod4bd9632018-03-08 16:32:44 +02002142 TString name = DecorateFunctionIfNeeded(func);
2143 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002144 << (mOutputLod0Function ? "Lod0(" : "(");
2145
Olli Etuahod4bd9632018-03-08 16:32:44 +02002146 size_t paramCount = func->getParamCount();
2147 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002148 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002149 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002150
Olli Etuahod4bd9632018-03-08 16:32:44 +02002151 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002152 {
2153 out << ", ";
2154 }
2155 }
2156
2157 out << ");\n";
2158
2159 // Also prototype the Lod0 variant if needed
2160 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2161 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2162 {
2163 mOutputLod0Function = true;
2164 node->traverse(this);
2165 mOutputLod0Function = false;
2166 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002167}
2168
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002169bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2170{
Jamie Madill32aab012015-01-27 14:12:26 -05002171 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002173 switch (node->getOp())
2174 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002175 case EOpCallBuiltInFunction:
2176 case EOpCallFunctionInAST:
2177 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002179 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002180
Corentin Wallez1239ee92015-03-19 14:38:02 -07002181 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002182 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002184 if (node->isArray())
2185 {
2186 UNIMPLEMENTED();
2187 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002188 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002189 ASSERT(index != CallDAG::InvalidIndex);
2190 lod0 &= mASTMetadataList[index].mNeedsLod0;
2191
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002192 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002193 out << DisambiguateFunctionName(node->getSequence());
2194 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002195 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002196 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002197 {
2198 // This path is used for internal functions that don't have their definitions in the
2199 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002200 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002201 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002202 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002203 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002204 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002205 TType type = (*arguments)[0]->getAsTyped()->getType();
2206 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002207 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002208 type.getMemoryQualifier().readonly);
2209 out << imageFunctionName << "(";
2210 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002211 else if (node->getFunction()->isAtomicCounterFunction())
2212 {
2213 const ImmutableString &name = node->getFunction()->name();
2214 ImmutableString atomicFunctionName =
2215 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2216 out << atomicFunctionName << "(";
2217 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218 else
2219 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002220 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002221 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002222 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2223 if (arguments->size() > 1)
2224 {
2225 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2226 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002227 const ImmutableString &textureFunctionName =
2228 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2229 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002230 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002231 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002232
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002233 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002234 {
Olli Etuaho96963162016-03-21 11:54:33 +02002235 TIntermTyped *typedArg = (*arg)->getAsTyped();
2236 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002237 {
2238 out << "texture_";
2239 (*arg)->traverse(this);
2240 out << ", sampler_";
2241 }
2242
2243 (*arg)->traverse(this);
2244
Olli Etuaho96963162016-03-21 11:54:33 +02002245 if (typedArg->getType().isStructureContainingSamplers())
2246 {
2247 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002248 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002249 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2250 std::string namePrefix = "angle_";
2251 namePrefix += structName.data();
2252 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002253 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002254 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002255 {
2256 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2257 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002258 out << ", texture_" << sampler->name();
2259 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002260 }
2261 else
2262 {
2263 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2264 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002265 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002266 }
2267 }
2268 }
2269
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002270 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002271 {
2272 out << ", ";
2273 }
2274 }
2275
2276 out << ")";
2277
2278 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002279 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002280 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002281 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002282 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002283 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002284 outputTriplet(out, visit, "(", " == ", ")");
2285 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002286 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002287 outputTriplet(out, visit, "(", " != ", ")");
2288 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002289 case EOpLessThanComponentWise:
2290 outputTriplet(out, visit, "(", " < ", ")");
2291 break;
2292 case EOpGreaterThanComponentWise:
2293 outputTriplet(out, visit, "(", " > ", ")");
2294 break;
2295 case EOpLessThanEqualComponentWise:
2296 outputTriplet(out, visit, "(", " <= ", ")");
2297 break;
2298 case EOpGreaterThanEqualComponentWise:
2299 outputTriplet(out, visit, "(", " >= ", ")");
2300 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002301 case EOpMod:
2302 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002303 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002304 break;
2305 case EOpModf:
2306 outputTriplet(out, visit, "modf(", ", ", ")");
2307 break;
2308 case EOpPow:
2309 outputTriplet(out, visit, "pow(", ", ", ")");
2310 break;
2311 case EOpAtan:
2312 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2313 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002314 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002315 break;
2316 case EOpMin:
2317 outputTriplet(out, visit, "min(", ", ", ")");
2318 break;
2319 case EOpMax:
2320 outputTriplet(out, visit, "max(", ", ", ")");
2321 break;
2322 case EOpClamp:
2323 outputTriplet(out, visit, "clamp(", ", ", ")");
2324 break;
2325 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302326 {
2327 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2328 if (lastParamNode->getType().getBasicType() == EbtBool)
2329 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002330 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2331 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302332 // so use emulated version.
2333 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002334 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302335 }
2336 else
2337 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002338 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302339 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002340 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302341 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002342 case EOpStep:
2343 outputTriplet(out, visit, "step(", ", ", ")");
2344 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002345 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002346 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2347 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002348 case EOpFrexp:
2349 case EOpLdexp:
2350 ASSERT(node->getUseEmulatedFunction());
2351 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2352 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002353 case EOpDistance:
2354 outputTriplet(out, visit, "distance(", ", ", ")");
2355 break;
2356 case EOpDot:
2357 outputTriplet(out, visit, "dot(", ", ", ")");
2358 break;
2359 case EOpCross:
2360 outputTriplet(out, visit, "cross(", ", ", ")");
2361 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002362 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002363 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002364 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002365 break;
2366 case EOpReflect:
2367 outputTriplet(out, visit, "reflect(", ", ", ")");
2368 break;
2369 case EOpRefract:
2370 outputTriplet(out, visit, "refract(", ", ", ")");
2371 break;
2372 case EOpOuterProduct:
2373 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002374 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002375 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002376 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002377 outputTriplet(out, visit, "(", " * ", ")");
2378 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002379 case EOpBitfieldExtract:
2380 case EOpBitfieldInsert:
2381 case EOpUaddCarry:
2382 case EOpUsubBorrow:
2383 case EOpUmulExtended:
2384 case EOpImulExtended:
2385 ASSERT(node->getUseEmulatedFunction());
2386 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2387 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002388 case EOpBarrier:
2389 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2390 // cheapest *WithGroupSync() function, without any functionality loss, but
2391 // with the potential for severe performance loss.
2392 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2393 break;
2394 case EOpMemoryBarrierShared:
2395 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2396 break;
2397 case EOpMemoryBarrierAtomicCounter:
2398 case EOpMemoryBarrierBuffer:
2399 case EOpMemoryBarrierImage:
2400 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2401 break;
2402 case EOpGroupMemoryBarrier:
2403 case EOpMemoryBarrier:
2404 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2405 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002406
2407 // Single atomic function calls without return value.
2408 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2409 case EOpAtomicAdd:
2410 case EOpAtomicMin:
2411 case EOpAtomicMax:
2412 case EOpAtomicAnd:
2413 case EOpAtomicOr:
2414 case EOpAtomicXor:
Qin Jiajia46229052018-12-10 13:31:00 +08002415 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
2416 // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
2417 // optional.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002418 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2419 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
Qin Jiajia46229052018-12-10 13:31:00 +08002420 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
2421 // compare_value, value) should all be modified into the form of "int temp; temp =
2422 // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
2423 // compare_value, value);" in the intermediate tree before traversing outputHLSL.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002424 case EOpAtomicExchange:
2425 case EOpAtomicCompSwap:
Qin Jiajia46229052018-12-10 13:31:00 +08002426 {
2427 ASSERT(node->getChildCount() > 1);
2428 TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
2429 if (IsInShaderStorageBlock(memNode))
2430 {
2431 // Atomic memory functions for SSBO.
2432 // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
2433 mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
2434 // Write the rest argument list to |out|.
2435 for (size_t i = 1; i < node->getChildCount(); i++)
2436 {
2437 out << ", ";
2438 TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
2439 if (IsInShaderStorageBlock(argument))
2440 {
2441 mSSBOOutputHLSL->outputLoadFunctionCall(argument);
2442 }
2443 else
2444 {
2445 argument->traverse(this);
2446 }
2447 }
2448
2449 out << ")";
2450 return false;
2451 }
2452 else
2453 {
2454 // Atomic memory functions for shared variable.
2455 if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
2456 {
2457 outputTriplet(out, visit,
2458 GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
2459 ")");
2460 }
2461 else
2462 {
2463 UNREACHABLE();
2464 }
2465 }
2466
2467 break;
2468 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002469 default:
2470 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471 }
2472
2473 return true;
2474}
2475
Olli Etuaho57961272016-09-14 13:57:46 +03002476void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002477{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002478 out << "if (";
2479
2480 node->getCondition()->traverse(this);
2481
2482 out << ")\n";
2483
Jamie Madill8c46ab12015-12-07 16:39:19 -05002484 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002485
2486 bool discard = false;
2487
2488 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002489 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002490 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002491 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002492
Olli Etuahoa6f22092015-05-08 18:31:10 +03002493 // Detect true discard
2494 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2495 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002496 else
2497 {
2498 // TODO(oetuaho): Check if the semicolon inside is necessary.
2499 // It's there as a result of conservative refactoring of the output.
2500 out << "{;}\n";
2501 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002502
Jamie Madill8c46ab12015-12-07 16:39:19 -05002503 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002504
Olli Etuahoa6f22092015-05-08 18:31:10 +03002505 if (node->getFalseBlock())
2506 {
2507 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002508
Jamie Madill8c46ab12015-12-07 16:39:19 -05002509 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002510
Olli Etuaho32db19b2016-10-04 14:43:16 +01002511 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002512 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002513
Jamie Madill8c46ab12015-12-07 16:39:19 -05002514 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002515
Olli Etuahoa6f22092015-05-08 18:31:10 +03002516 // Detect false discard
2517 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2518 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002519
Olli Etuahoa6f22092015-05-08 18:31:10 +03002520 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002521 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002522 {
2523 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002524 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002525}
2526
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002527bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2528{
2529 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2530 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2531 UNREACHABLE();
2532 return false;
2533}
2534
Olli Etuaho57961272016-09-14 13:57:46 +03002535bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002536{
2537 TInfoSinkBase &out = getInfoSink();
2538
Olli Etuaho3d932d82016-04-12 11:10:30 +03002539 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002540
2541 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002542 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002543 {
2544 out << "FLATTEN ";
2545 }
2546
Olli Etuaho57961272016-09-14 13:57:46 +03002547 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002548
2549 return false;
2550}
2551
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002552bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002553{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002554 TInfoSinkBase &out = getInfoSink();
2555
Olli Etuaho923ecef2017-10-11 12:01:38 +03002556 ASSERT(node->getStatementList());
2557 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002558 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002559 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002560 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002561 outputTriplet(out, visit, "switch (", ") ", "");
2562 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002563 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002564}
2565
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002566bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002567{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002568 TInfoSinkBase &out = getInfoSink();
2569
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002570 if (node->hasCondition())
2571 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002572 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002573 return true;
2574 }
2575 else
2576 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002577 out << "default:\n";
2578 return false;
2579 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002580}
2581
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002582void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2583{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002584 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002585 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002586}
2587
2588bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2589{
Nicolas Capens655fe362014-04-11 13:12:34 -04002590 mNestedLoopDepth++;
2591
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002592 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002593 mInsideDiscontinuousLoop =
2594 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002595
Jamie Madill8c46ab12015-12-07 16:39:19 -05002596 TInfoSinkBase &out = getInfoSink();
2597
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002598 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002599 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002600 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002601 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002602 mInsideDiscontinuousLoop = wasDiscontinuous;
2603 mNestedLoopDepth--;
2604
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002605 return false;
2606 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002607 }
2608
Corentin Wallez1239ee92015-03-19 14:38:02 -07002609 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002610 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002611 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002612 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002613
Jamie Madill8c46ab12015-12-07 16:39:19 -05002614 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002615 }
2616 else
2617 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002618 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002619
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002620 if (node->getInit())
2621 {
2622 node->getInit()->traverse(this);
2623 }
2624
2625 out << "; ";
2626
alokp@chromium.org52813552010-11-16 18:36:09 +00002627 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002628 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002629 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002630 }
2631
2632 out << "; ";
2633
alokp@chromium.org52813552010-11-16 18:36:09 +00002634 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002635 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002636 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002637 }
2638
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002639 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002640
Jamie Madill8c46ab12015-12-07 16:39:19 -05002641 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002642 }
2643
2644 if (node->getBody())
2645 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002646 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002647 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002648 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002649 else
2650 {
2651 // TODO(oetuaho): Check if the semicolon inside is necessary.
2652 // It's there as a result of conservative refactoring of the output.
2653 out << "{;}\n";
2654 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002655
Jamie Madill8c46ab12015-12-07 16:39:19 -05002656 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002657
alokp@chromium.org52813552010-11-16 18:36:09 +00002658 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002659 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002660 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002661 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002662
alokp@chromium.org52813552010-11-16 18:36:09 +00002663 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002664
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002665 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002666 }
2667
daniel@transgaming.com73536982012-03-21 20:45:49 +00002668 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002669
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002670 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002671 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002672
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002673 return false;
2674}
2675
2676bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2677{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002678 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002679 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002680 TInfoSinkBase &out = getInfoSink();
2681
2682 switch (node->getFlowOp())
2683 {
2684 case EOpKill:
2685 out << "discard";
2686 break;
2687 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002688 if (mNestedLoopDepth > 1)
2689 {
2690 mUsesNestedBreak = true;
2691 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002692
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002693 if (mExcessiveLoopIndex)
2694 {
2695 out << "{Break";
2696 mExcessiveLoopIndex->traverse(this);
2697 out << " = true; break;}\n";
2698 }
2699 else
2700 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002701 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002702 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002703 break;
2704 case EOpContinue:
2705 out << "continue";
2706 break;
2707 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002708 if (node->getExpression())
2709 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002710 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002711 out << "return ";
2712 }
2713 else
2714 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002715 if (mInsideMain && shaderNeedsGenerateOutput())
2716 {
2717 out << "return " << generateOutputCall();
2718 }
2719 else
2720 {
2721 out << "return";
2722 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002723 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002724 break;
2725 default:
2726 UNREACHABLE();
2727 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002728 }
2729
2730 return true;
2731}
2732
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002733// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002734// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2735// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002736bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002737{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002738 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002739
2740 // Parse loops of the form:
2741 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002742 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002743 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002744 int initial = 0;
2745 int limit = 0;
2746 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002747
2748 // Parse index name and intial value
2749 if (node->getInit())
2750 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002751 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002752
2753 if (init)
2754 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002755 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002756 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002757
2758 if (variable && variable->getQualifier() == EvqTemporary)
2759 {
2760 TIntermBinary *assign = variable->getAsBinaryNode();
2761
2762 if (assign->getOp() == EOpInitialize)
2763 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002764 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002765 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2766
2767 if (symbol && constant)
2768 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002769 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002770 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002771 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002772 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002773 }
2774 }
2775 }
2776 }
2777 }
2778 }
2779
2780 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002781 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002782 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002783 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002784
Olli Etuahob6af22b2017-12-15 14:05:44 +02002785 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002786 {
2787 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2788
2789 if (constant)
2790 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002791 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002792 {
2793 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002794 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002795 }
2796 }
2797 }
2798 }
2799
2800 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002801 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002802 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002803 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002804 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002805
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002806 if (binaryTerminal)
2807 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002808 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002809 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2810
2811 if (constant)
2812 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002813 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002814 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002815 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002816
2817 switch (op)
2818 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002819 case EOpAddAssign:
2820 increment = value;
2821 break;
2822 case EOpSubAssign:
2823 increment = -value;
2824 break;
2825 default:
2826 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002827 }
2828 }
2829 }
2830 }
2831 else if (unaryTerminal)
2832 {
2833 TOperator op = unaryTerminal->getOp();
2834
2835 switch (op)
2836 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002837 case EOpPostIncrement:
2838 increment = 1;
2839 break;
2840 case EOpPostDecrement:
2841 increment = -1;
2842 break;
2843 case EOpPreIncrement:
2844 increment = 1;
2845 break;
2846 case EOpPreDecrement:
2847 increment = -1;
2848 break;
2849 default:
2850 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002851 }
2852 }
2853 }
2854
Yunchao He4f285442017-04-21 12:15:49 +08002855 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002856 {
2857 if (comparator == EOpLessThanEqual)
2858 {
2859 comparator = EOpLessThan;
2860 limit += 1;
2861 }
2862
2863 if (comparator == EOpLessThan)
2864 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002865 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002866
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002867 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002868 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002869 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002870 }
2871
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002872 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002873 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002874
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002875 out << "{int ";
2876 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002877 out << ";\n"
2878 "bool Break";
2879 index->traverse(this);
2880 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002881
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002882 bool firstLoopFragment = true;
2883
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002884 while (iterations > 0)
2885 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002886 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002887
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002888 if (!firstLoopFragment)
2889 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002890 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002891 index->traverse(this);
2892 out << ") {\n";
2893 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002894
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002895 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002896 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002897 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002898 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002899
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002900 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002901 const char *unroll =
2902 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002903
Corentin Wallez1239ee92015-03-19 14:38:02 -07002904 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002905 index->traverse(this);
2906 out << " = ";
2907 out << initial;
2908
2909 out << "; ";
2910 index->traverse(this);
2911 out << " < ";
2912 out << clampedLimit;
2913
2914 out << "; ";
2915 index->traverse(this);
2916 out << " += ";
2917 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002918 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002919
Jamie Madill8c46ab12015-12-07 16:39:19 -05002920 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002921 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002922
2923 if (node->getBody())
2924 {
2925 node->getBody()->traverse(this);
2926 }
2927
Jamie Madill8c46ab12015-12-07 16:39:19 -05002928 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002929 out << ";}\n";
2930
2931 if (!firstLoopFragment)
2932 {
2933 out << "}\n";
2934 }
2935
2936 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002937
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002938 initial += MAX_LOOP_ITERATIONS * increment;
2939 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002940 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002941
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002942 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002943
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002944 mExcessiveLoopIndex = restoreIndex;
2945
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002946 return true;
2947 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002948 else
2949 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002950 }
2951
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002952 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002953}
2954
Jamie Madill8c46ab12015-12-07 16:39:19 -05002955void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2956 Visit visit,
2957 const char *preString,
2958 const char *inString,
2959 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002960{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002961 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002962 {
2963 out << preString;
2964 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002965 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002966 {
2967 out << inString;
2968 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002969 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002970 {
2971 out << postString;
2972 }
2973}
2974
Jamie Madill8c46ab12015-12-07 16:39:19 -05002975void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002976{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002977 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002978 {
Jamie Madill32aab012015-01-27 14:12:26 -05002979 out << "\n";
2980 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002981
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002982 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002983 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002984 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002985 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002986
Jamie Madill32aab012015-01-27 14:12:26 -05002987 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002988 }
2989}
2990
Olli Etuahod4bd9632018-03-08 16:32:44 +02002991void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002992{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002993 const TType &type = param->getType();
2994 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002995
Olli Etuahod4bd9632018-03-08 16:32:44 +02002996 TString nameStr = DecorateVariableIfNeeded(*param);
2997 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002998
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002999 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003000 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003001 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3002 {
3003 // Samplers are passed as indices to the sampler array.
3004 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003005 out << "const uint " << nameStr << ArrayString(type);
3006 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003007 }
3008 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3009 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003010 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
3011 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
3012 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
3013 << ArrayString(type);
3014 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003015 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003016 }
3017
Brandon Jones4a22f4b2018-10-23 14:36:47 -07003018 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
3019 // buffer offset.
3020 if (IsAtomicCounter(type.getBasicType()))
3021 {
3022 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
3023 << nameStr << "_offset";
3024 }
3025 else
3026 {
3027 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
3028 << ArrayString(type);
3029 }
Olli Etuaho96963162016-03-21 11:54:33 +02003030
3031 // If the structure parameter contains samplers, they need to be passed into the function as
3032 // separate parameters. HLSL doesn't natively support samplers in structs.
3033 if (type.isStructureContainingSamplers())
3034 {
3035 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003036 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02003037 std::string namePrefix = "angle";
3038 namePrefix += nameStr.c_str();
3039 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
3040 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003041 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02003042 {
Olli Etuaho28839f02017-08-15 11:38:16 +03003043 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02003044 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3045 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003046 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003047 }
3048 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3049 {
Olli Etuaho96963162016-03-21 11:54:33 +02003050 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003051 out << ", " << QualifierString(qualifier) << " "
3052 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
3053 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
3054 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
3055 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003056 }
3057 else
3058 {
Olli Etuaho96963162016-03-21 11:54:33 +02003059 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003060 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3061 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003062 }
3063 }
3064 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003065}
3066
jchen10efe061b2018-11-13 16:44:40 +08003067TString OutputHLSL::zeroInitializer(const TType &type) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003068{
3069 TString string;
3070
Jamie Madill94bf7f22013-07-08 13:31:15 -04003071 size_t size = type.getObjectSize();
jchen10efe061b2018-11-13 16:44:40 +08003072 if (size >= kZeroCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003073 {
jchen10efe061b2018-11-13 16:44:40 +08003074 mUseZeroArray = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003075 }
jchen10efe061b2018-11-13 16:44:40 +08003076 string = GetZeroInitializer(size).c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003077
daniel@transgaming.comead23042010-04-29 03:35:36 +00003078 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003079}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003080
Olli Etuahobd3cd502017-11-03 15:48:52 +02003081void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003082{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003083 // Array constructors should have been already pruned from the code.
3084 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003085
3086 if (visit == PreVisit)
3087 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003088 TString constructorName;
3089 if (node->getBasicType() == EbtStruct)
3090 {
3091 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3092 }
3093 else
3094 {
3095 constructorName =
3096 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3097 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003098 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003099 }
3100 else if (visit == InVisit)
3101 {
3102 out << ", ";
3103 }
3104 else if (visit == PostVisit)
3105 {
3106 out << ")";
3107 }
3108}
3109
Jamie Madill8c46ab12015-12-07 16:39:19 -05003110const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3111 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003112 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003113{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003114 ASSERT(!type.isArray());
3115
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003116 const TConstantUnion *constUnionIterated = constUnion;
3117
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003118 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003119 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003120 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003121 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003122
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003123 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003124
Jamie Madill98493dd2013-07-08 14:39:03 -04003125 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003126 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003127 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003128 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003129
Jamie Madill98493dd2013-07-08 14:39:03 -04003130 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003131 {
3132 out << ", ";
3133 }
3134 }
3135
3136 out << ")";
3137 }
3138 else
3139 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003140 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003141 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003142
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003143 if (writeType)
3144 {
Jamie Madill033dae62014-06-18 12:56:28 -04003145 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003146 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003147 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003148 if (writeType)
3149 {
3150 out << ")";
3151 }
3152 }
3153
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003154 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003155}
3156
Olli Etuahod68924e2017-01-02 17:34:40 +00003157void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003158{
Olli Etuahod68924e2017-01-02 17:34:40 +00003159 if (visit == PreVisit)
3160 {
3161 const char *opStr = GetOperatorString(op);
3162 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3163 out << "(";
3164 }
3165 else
3166 {
3167 outputTriplet(out, visit, nullptr, ", ", ")");
3168 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003169}
3170
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003171bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3172 TIntermSymbol *symbolNode,
3173 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003174{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003175 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3176 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003177
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003178 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003179 {
3180 // Type already printed
3181 out << "t" + str(mUniqueIndex) + " = ";
3182 expression->traverse(this);
3183 out << ", ";
3184 symbolNode->traverse(this);
3185 out << " = t" + str(mUniqueIndex);
3186
3187 mUniqueIndex++;
3188 return true;
3189 }
3190
3191 return false;
3192}
3193
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003194bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3195 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003196 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003197{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003198 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003199 {
3200 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003201 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003202 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003203 writeConstantUnionArray(out, initializer->getConstantValue(),
3204 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003205 out << "}";
3206 return true;
3207 }
3208 return false;
3209}
3210
Jamie Madill55e79e02015-02-09 15:35:00 -05003211TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3212{
3213 const TFieldList &fields = structure.fields();
3214
3215 for (const auto &eqFunction : mStructEqualityFunctions)
3216 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003217 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003218 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003219 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003220 }
3221 }
3222
3223 const TString &structNameString = StructNameString(structure);
3224
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003225 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003226 function->structure = &structure;
3227 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003228
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003229 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003230
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003231 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3232 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003233 << "{\n"
3234 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003235
3236 for (size_t i = 0; i < fields.size(); i++)
3237 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003238 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003239 const TType *fieldType = field->type();
3240
3241 const TString &fieldNameA = "a." + Decorate(field->name());
3242 const TString &fieldNameB = "b." + Decorate(field->name());
3243
3244 if (i > 0)
3245 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003246 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003247 }
3248
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003249 fnOut << "(";
3250 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3251 fnOut << fieldNameA;
3252 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3253 fnOut << fieldNameB;
3254 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3255 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003256 }
3257
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003258 fnOut << ";\n"
3259 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003260
3261 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003262
3263 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003264 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003265
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003266 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003267}
3268
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003269TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003270{
3271 for (const auto &eqFunction : mArrayEqualityFunctions)
3272 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003273 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003274 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003275 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003276 }
3277 }
3278
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003279 TType elementType(type);
3280 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003281
Olli Etuaho12690762015-03-31 12:55:28 +03003282 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003283 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003284
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003285 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003286
3287 TInfoSinkBase fnOut;
3288
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003289 const TString &typeName = TypeString(type);
3290 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3291 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003292 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003293 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003294 << type.getOutermostArraySize()
3295 << "; ++i)\n"
3296 " {\n"
3297 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003298
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003299 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003300 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003301 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003302 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003303 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003304
3305 fnOut << ") { return false; }\n"
3306 " }\n"
3307 " return true;\n"
3308 "}\n";
3309
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003310 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003311
3312 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003313 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003314
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003315 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003316}
3317
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003318TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003319{
3320 for (const auto &assignFunction : mArrayAssignmentFunctions)
3321 {
3322 if (assignFunction.type == type)
3323 {
3324 return assignFunction.functionName;
3325 }
3326 }
3327
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003328 TType elementType(type);
3329 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003330
3331 ArrayHelperFunction function;
3332 function.type = type;
3333
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003334 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003335
3336 TInfoSinkBase fnOut;
3337
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003338 const TString &typeName = TypeString(type);
3339 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3340 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003341 << "{\n"
3342 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003343 << type.getOutermostArraySize()
3344 << "; ++i)\n"
3345 " {\n"
3346 " ";
3347
3348 outputAssign(PreVisit, elementType, fnOut);
3349 fnOut << "a[i]";
3350 outputAssign(InVisit, elementType, fnOut);
3351 fnOut << "b[i]";
3352 outputAssign(PostVisit, elementType, fnOut);
3353
3354 fnOut << ";\n"
3355 " }\n"
3356 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003357
3358 function.functionDefinition = fnOut.c_str();
3359
3360 mArrayAssignmentFunctions.push_back(function);
3361
3362 return function.functionName;
3363}
3364
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003365TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003366{
3367 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3368 {
3369 if (constructIntoFunction.type == type)
3370 {
3371 return constructIntoFunction.functionName;
3372 }
3373 }
3374
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003375 TType elementType(type);
3376 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003377
3378 ArrayHelperFunction function;
3379 function.type = type;
3380
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003381 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003382
3383 TInfoSinkBase fnOut;
3384
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003385 const TString &typeName = TypeString(type);
3386 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3387 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003388 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003389 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003390 }
3391 fnOut << ")\n"
3392 "{\n";
3393
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003394 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003395 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003396 fnOut << " ";
3397 outputAssign(PreVisit, elementType, fnOut);
3398 fnOut << "a[" << i << "]";
3399 outputAssign(InVisit, elementType, fnOut);
3400 fnOut << "b" << i;
3401 outputAssign(PostVisit, elementType, fnOut);
3402 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003403 }
3404 fnOut << "}\n";
3405
3406 function.functionDefinition = fnOut.c_str();
3407
3408 mArrayConstructIntoFunctions.push_back(function);
3409
3410 return function.functionName;
3411}
3412
Jamie Madill2e295e22015-04-29 10:41:33 -04003413void OutputHLSL::ensureStructDefined(const TType &type)
3414{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003415 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003416 if (structure)
3417 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003418 ASSERT(type.getBasicType() == EbtStruct);
3419 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003420 }
3421}
3422
Olli Etuaho06235df2018-07-20 14:26:07 +03003423bool OutputHLSL::shaderNeedsGenerateOutput() const
3424{
3425 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3426}
3427
3428const char *OutputHLSL::generateOutputCall() const
3429{
3430 if (mShaderType == GL_VERTEX_SHADER)
3431 {
3432 return "generateOutput(input)";
3433 }
3434 else
3435 {
3436 return "generateOutput()";
3437 }
3438}
3439
Jamie Madill45bcc782016-11-07 13:58:48 -05003440} // namespace sh