blob: 49345688bb867e8a6ee0e48978d70e3dfaaf8afd [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"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020016#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050017#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080018#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/InfoSink.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030021#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/UniformHLSL.h"
24#include "compiler/translator/UtilsHLSL.h"
25#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020026#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020027#include "compiler/translator/tree_util/FindSymbolNode.h"
28#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080041 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030042 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080043 for (unsigned int arraySize : *type.getArraySizes())
44 {
45 fnName << arraySize << "_";
46 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030047 }
48 fnName << TypeString(type);
49 return fnName.str();
50}
51
Olli Etuaho40dbdd62017-10-13 13:34:19 +030052bool IsDeclarationWrittenOut(TIntermDeclaration *node)
53{
54 TIntermSequence *sequence = node->getSequence();
55 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
56 ASSERT(sequence->size() == 1);
57 ASSERT(variable);
58 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080059 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030060}
61
Olli Etuaho2ef23e22017-11-01 16:39:11 +020062bool IsInStd140InterfaceBlock(TIntermTyped *node)
63{
64 TIntermBinary *binaryNode = node->getAsBinaryNode();
65
66 if (binaryNode)
67 {
68 return IsInStd140InterfaceBlock(binaryNode->getLeft());
69 }
70
71 const TType &type = node->getType();
72
73 // determine if we are in the standard layout
74 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
75 if (interfaceBlock)
76 {
77 return (interfaceBlock->blockStorage() == EbsStd140);
78 }
79
80 return false;
81}
82
Jiawei Shaoa6a78422018-06-28 08:32:54 +080083const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
84{
85 switch (op)
86 {
87 case EOpAtomicAdd:
88 return "InterlockedAdd(";
89 case EOpAtomicMin:
90 return "InterlockedMin(";
91 case EOpAtomicMax:
92 return "InterlockedMax(";
93 case EOpAtomicAnd:
94 return "InterlockedAnd(";
95 case EOpAtomicOr:
96 return "InterlockedOr(";
97 case EOpAtomicXor:
98 return "InterlockedXor(";
99 case EOpAtomicExchange:
100 return "InterlockedExchange(";
101 case EOpAtomicCompSwap:
102 return "InterlockedCompareExchange(";
103 default:
104 UNREACHABLE();
105 return "";
106 }
107}
108
109bool IsAtomicFunctionDirectAssign(const TIntermBinary &node)
110{
111 return node.getOp() == EOpAssign && node.getRight()->getAsAggregate() &&
112 IsAtomicFunction(node.getRight()->getAsAggregate()->getOp());
113}
114
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300115} // anonymous namespace
116
Olli Etuahoc71862a2017-12-21 12:58:29 +0200117TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
118 const TVariable *aInstanceVariable)
119 : block(aBlock), instanceVariable(aInstanceVariable)
120{
121}
122
Olli Etuaho56a2f952016-12-08 12:16:27 +0000123void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300124{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000125 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
126 // regardless.
127 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
128 mOutputType == SH_HLSL_4_1_OUTPUT)
129 {
130 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
131 }
132 else
133 {
134 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
135 }
136}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300137
Olli Etuaho56a2f952016-12-08 12:16:27 +0000138void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200139{
140 ASSERT(constUnion != nullptr);
141 switch (constUnion->getType())
142 {
143 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000144 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200145 break;
146 case EbtInt:
147 out << constUnion->getIConst();
148 break;
149 case EbtUInt:
150 out << constUnion->getUConst();
151 break;
152 case EbtBool:
153 out << constUnion->getBConst();
154 break;
155 default:
156 UNREACHABLE();
157 }
158}
159
Olli Etuaho56a2f952016-12-08 12:16:27 +0000160const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
161 const TConstantUnion *const constUnion,
162 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200163{
164 const TConstantUnion *constUnionIterated = constUnion;
165 for (size_t i = 0; i < size; i++, constUnionIterated++)
166 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000167 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200168
169 if (i != size - 1)
170 {
171 out << ", ";
172 }
173 }
174 return constUnionIterated;
175}
176
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800177OutputHLSL::OutputHLSL(sh::GLenum shaderType,
178 int shaderVersion,
179 const TExtensionBehavior &extensionBehavior,
180 const char *sourcePath,
181 ShShaderOutput outputType,
182 int numRenderTargets,
183 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300184 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300185 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300186 TSymbolTable *symbolTable,
187 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300188 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200189 mShaderType(shaderType),
190 mShaderVersion(shaderVersion),
191 mExtensionBehavior(extensionBehavior),
192 mSourcePath(sourcePath),
193 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700194 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300195 mInsideFunction(false),
196 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000197 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300198 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300199 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300200 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800202 mUsesFragColor = false;
203 mUsesFragData = false;
204 mUsesDepthRange = false;
205 mUsesFragCoord = false;
206 mUsesPointCoord = false;
207 mUsesFrontFacing = false;
208 mUsesPointSize = false;
209 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300210 mHasMultiviewExtensionEnabled =
211 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300212 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500213 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500214 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800215 mUsesNumWorkGroups = false;
216 mUsesWorkGroupID = false;
217 mUsesLocalInvocationID = false;
218 mUsesGlobalInvocationID = false;
219 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500220 mUsesXor = false;
221 mUsesDiscardRewriting = false;
222 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530223 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000224
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000225 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000228 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500229 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000230
Yunchao Hed7297bf2017-04-19 15:27:10 +0800231 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000232
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500233 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300234 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800235 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400236
Olli Etuahod8724a92017-12-29 18:40:36 +0200237 unsigned int firstUniformRegister =
238 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Xinghua Cao06a22622018-05-18 16:48:41 +0800239 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200240
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200241 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000242 {
Arun Patole63419392015-03-13 11:51:07 +0530243 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500244 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
245 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530246 // In both cases total 3 uniform registers need to be reserved.
247 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000248 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000249
Geoff Lang00140f42016-02-03 18:47:33 +0000250 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800251 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252}
253
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000254OutputHLSL::~OutputHLSL()
255{
Jamie Madill8daaba12014-06-13 10:04:33 -0400256 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400257 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300258 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800259 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200260 for (auto &eqFunction : mStructEqualityFunctions)
261 {
262 SafeDelete(eqFunction);
263 }
264 for (auto &eqFunction : mArrayEqualityFunctions)
265 {
266 SafeDelete(eqFunction);
267 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000268}
269
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200270void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000271{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200272 BuiltInFunctionEmulator builtInFunctionEmulator;
273 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800274 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
275 {
276 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
277 mShaderVersion);
278 }
279
Olli Etuahodfa75e82017-01-23 09:43:06 -0800280 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500281
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700282 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000283 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700284 ASSERT(success == CallDAG::INITDAG_SUCCESS);
285 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700286
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200287 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
288 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
289 // the shader code. When we add shader storage blocks we might also consider an alternative
290 // solution, since the struct mapping won't work very well for shader storage blocks.
291
Jamie Madill37997142015-01-28 10:06:34 -0500292 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500293 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200294 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500295 mInfoSinkStack.pop();
296
Jamie Madill37997142015-01-28 10:06:34 -0500297 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500298 mInfoSinkStack.pop();
299
Jamie Madill32aab012015-01-27 14:12:26 -0500300 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200301 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500302 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000303
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200304 objSink << mHeader.c_str();
305 objSink << mBody.c_str();
306 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200307
Olli Etuahodfa75e82017-01-23 09:43:06 -0800308 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000309}
310
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800311const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400312{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800313 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400314}
315
Jamie Madill9fe25e92014-07-18 10:33:08 -0400316const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
317{
318 return mUniformHLSL->getUniformRegisterMap();
319}
320
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200321TString OutputHLSL::structInitializerString(int indent,
322 const TType &type,
323 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400324{
325 TString init;
326
Olli Etuahoed049ab2017-06-30 17:38:33 +0300327 TString indentString;
328 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300330 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400331 }
332
Olli Etuahoed049ab2017-06-30 17:38:33 +0300333 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400334 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300335 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300336 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400337 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300338 TStringStream indexedString;
339 indexedString << name << "[" << arrayIndex << "]";
340 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300341 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300342 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300343 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300344 {
345 init += ",";
346 }
347 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400350 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300351 else if (type.getBasicType() == EbtStruct)
352 {
353 init += indentString + "{\n";
354 const TStructure &structure = *type.getStruct();
355 const TFieldList &fields = structure.fields();
356 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
357 {
358 const TField &field = *fields[fieldIndex];
359 const TString &fieldName = name + "." + Decorate(field.name());
360 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400361
Olli Etuahoed049ab2017-06-30 17:38:33 +0300362 init += structInitializerString(indent + 1, fieldType, fieldName);
363 if (fieldIndex < fields.size() - 1)
364 {
365 init += ",";
366 }
367 init += "\n";
368 }
369 init += indentString + "}";
370 }
371 else
372 {
373 init += indentString + name;
374 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400375
376 return init;
377}
378
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200379TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
380{
381 TString mappedStructs;
382
383 for (auto &mappedStruct : std140Structs)
384 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200385 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200386 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200387 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200388 {
389 continue;
390 }
391
392 unsigned int instanceCount = 1u;
393 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
394 if (isInstanceArray)
395 {
396 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
397 }
398
399 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
400 ++instanceArrayIndex)
401 {
402 TString originalName;
403 TString mappedName("map");
404
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200405 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200406 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200407 const ImmutableString &instanceName =
408 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200409 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
410 if (isInstanceArray)
411 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200412 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200413 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200414 originalName += instanceString;
415 mappedName += instanceString;
416 originalName += ".";
417 mappedName += "_";
418 }
419
420 TString fieldName = Decorate(mappedStruct.field->name());
421 originalName += fieldName;
422 mappedName += fieldName;
423
424 TType *structType = mappedStruct.field->type();
425 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200426 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200427
428 if (structType->isArray())
429 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300430 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431 }
432
433 mappedStructs += " =\n";
434 mappedStructs += structInitializerString(0, *structType, originalName);
435 mappedStructs += ";\n";
436 }
437 }
438 return mappedStructs;
439}
440
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300441void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300443 for (const auto &attribute : mReferencedAttributes)
444 {
445 const TType &type = attribute.second->getType();
446 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400447
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300448 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
449 << zeroInitializer(type) << ";\n";
450 }
451}
452
453void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
454{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200455 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000456 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800457 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000458
459 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300460 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300461 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
462 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000463 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300464}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000465
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300466void OutputHLSL::header(TInfoSinkBase &out,
467 const std::vector<MappedStruct> &std140Structs,
468 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
469{
470 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000471
Jamie Madill8daaba12014-06-13 10:04:33 -0400472 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400473
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300474 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800475 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400476
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200477 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500478 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200479 out << "\n// Equality functions\n\n";
480 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500481 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200482 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200483 }
484 }
Olli Etuaho12690762015-03-31 12:55:28 +0300485 if (!mArrayAssignmentFunctions.empty())
486 {
487 out << "\n// Assignment functions\n\n";
488 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
489 {
490 out << assignmentFunction.functionDefinition << "\n";
491 }
492 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300493 if (!mArrayConstructIntoFunctions.empty())
494 {
495 out << "\n// Array constructor functions\n\n";
496 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
497 {
498 out << constructIntoFunction.functionDefinition << "\n";
499 }
500 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200501
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500502 if (mUsesDiscardRewriting)
503 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400504 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500505 }
506
Nicolas Capens655fe362014-04-11 13:12:34 -0400507 if (mUsesNestedBreak)
508 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400509 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400510 }
511
Arun Patole44efa0b2015-03-04 17:11:05 +0530512 if (mRequiresIEEEStrictCompiling)
513 {
514 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
515 }
516
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400517 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
518 "#define LOOP [loop]\n"
519 "#define FLATTEN [flatten]\n"
520 "#else\n"
521 "#define LOOP\n"
522 "#define FLATTEN\n"
523 "#endif\n";
524
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200525 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300527 const bool usingMRTExtension =
528 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000529
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000530 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300531 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400532 out << "\n";
533
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200534 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000535 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200536 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000537 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200538 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800539 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400540
Olli Etuahofbb1c792018-01-19 16:26:59 +0200541 out << "static " << TypeString(variableType) << " out_" << variableName
542 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000543 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000544 }
Jamie Madill46131a32013-06-20 11:55:50 -0400545 else
546 {
547 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
548
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800549 out << "static float4 gl_Color[" << numColorValues
550 << "] =\n"
551 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400552 for (unsigned int i = 0; i < numColorValues; i++)
553 {
554 out << " float4(0, 0, 0, 0)";
555 if (i + 1 != numColorValues)
556 {
557 out << ",";
558 }
559 out << "\n";
560 }
561
562 out << "};\n";
563 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000564
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400565 if (mUsesFragDepth)
566 {
567 out << "static float gl_Depth = 0.0;\n";
568 }
569
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000570 if (mUsesFragCoord)
571 {
572 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
573 }
574
575 if (mUsesPointCoord)
576 {
577 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
578 }
579
580 if (mUsesFrontFacing)
581 {
582 out << "static bool gl_FrontFacing = false;\n";
583 }
584
585 out << "\n";
586
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000587 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000589 out << "struct gl_DepthRangeParameters\n"
590 "{\n"
591 " float near;\n"
592 " float far;\n"
593 " float diff;\n"
594 "};\n"
595 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000596 }
597
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200598 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000599 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000600 out << "cbuffer DriverConstants : register(b1)\n"
601 "{\n";
602
603 if (mUsesDepthRange)
604 {
605 out << " float3 dx_DepthRange : packoffset(c0);\n";
606 }
607
608 if (mUsesFragCoord)
609 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000610 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000611 }
612
613 if (mUsesFragCoord || mUsesFrontFacing)
614 {
615 out << " float3 dx_DepthFront : packoffset(c2);\n";
616 }
617
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800618 if (mUsesFragCoord)
619 {
620 // dx_ViewScale is only used in the fragment shader to correct
621 // the value for glFragCoord if necessary
622 out << " float2 dx_ViewScale : packoffset(c3);\n";
623 }
624
Martin Radev72b4e1e2017-08-31 15:42:56 +0300625 if (mHasMultiviewExtensionEnabled)
626 {
627 // We have to add a value which we can use to keep track of which multi-view code
628 // path is to be selected in the GS.
629 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
630 }
631
Olli Etuaho618bebc2016-01-15 16:40:00 +0200632 if (mOutputType == SH_HLSL_4_1_OUTPUT)
633 {
634 mUniformHLSL->samplerMetadataUniforms(out, "c4");
635 }
636
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000637 out << "};\n";
638 }
639 else
640 {
641 if (mUsesDepthRange)
642 {
643 out << "uniform float3 dx_DepthRange : register(c0);";
644 }
645
646 if (mUsesFragCoord)
647 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000648 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000649 }
650
651 if (mUsesFragCoord || mUsesFrontFacing)
652 {
653 out << "uniform float3 dx_DepthFront : register(c2);\n";
654 }
655 }
656
657 out << "\n";
658
659 if (mUsesDepthRange)
660 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500661 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
662 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000663 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000664 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000665
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000666 if (usingMRTExtension && mNumRenderTargets > 1)
667 {
668 out << "#define GL_USES_MRT\n";
669 }
670
671 if (mUsesFragColor)
672 {
673 out << "#define GL_USES_FRAG_COLOR\n";
674 }
675
676 if (mUsesFragData)
677 {
678 out << "#define GL_USES_FRAG_DATA\n";
679 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680 }
Xinghua Caob1239382016-12-13 15:07:05 +0800681 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000683 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300684 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000685 out << "\n"
686 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400687
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000688 if (mUsesPointSize)
689 {
690 out << "static float gl_PointSize = float(1);\n";
691 }
692
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000693 if (mUsesInstanceID)
694 {
695 out << "static int gl_InstanceID;";
696 }
697
Corentin Wallezb076add2016-01-11 16:45:46 -0500698 if (mUsesVertexID)
699 {
700 out << "static int gl_VertexID;";
701 }
702
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000703 out << "\n"
704 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300705 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000706 out << "\n";
707
708 if (mUsesDepthRange)
709 {
710 out << "struct gl_DepthRangeParameters\n"
711 "{\n"
712 " float near;\n"
713 " float far;\n"
714 " float diff;\n"
715 "};\n"
716 "\n";
717 }
718
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200719 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000720 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800721 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800723
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000724 if (mUsesDepthRange)
725 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800726 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000727 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800728
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800729 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
730 // shaders. However, we declare it for all shaders (including Feature Level 10+).
731 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
732 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800733 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800734 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800735 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800736
Martin Radev72b4e1e2017-08-31 15:42:56 +0300737 if (mHasMultiviewExtensionEnabled)
738 {
739 // We have to add a value which we can use to keep track of which multi-view code
740 // path is to be selected in the GS.
741 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
742 }
743
Olli Etuaho618bebc2016-01-15 16:40:00 +0200744 if (mOutputType == SH_HLSL_4_1_OUTPUT)
745 {
746 mUniformHLSL->samplerMetadataUniforms(out, "c4");
747 }
748
Austin Kinross4fd18b12014-12-22 12:32:05 -0800749 out << "};\n"
750 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000751 }
752 else
753 {
754 if (mUsesDepthRange)
755 {
756 out << "uniform float3 dx_DepthRange : register(c0);\n";
757 }
758
Cooper Partine6664f02015-01-09 16:22:24 -0800759 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
760 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000761 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000762 }
763
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000764 if (mUsesDepthRange)
765 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
767 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000768 "\n";
769 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400770 }
Xinghua Caob1239382016-12-13 15:07:05 +0800771 else // Compute shader
772 {
773 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800774
775 out << "cbuffer DriverConstants : register(b1)\n"
776 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800777 if (mUsesNumWorkGroups)
778 {
Xinghua Caob1239382016-12-13 15:07:05 +0800779 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800780 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800781 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
782 mUniformHLSL->samplerMetadataUniforms(out, "c1");
783 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800784
Jiawei Shao203b26f2018-07-25 10:30:43 +0800785 std::ostringstream systemValueDeclaration;
786 std::ostringstream glBuiltinInitialization;
787
788 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
789 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
790 << "{\n";
791
Xinghua Caob1239382016-12-13 15:07:05 +0800792 if (mUsesWorkGroupID)
793 {
794 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800795 systemValueDeclaration << " uint3 dx_WorkGroupID : "
796 << "SV_GroupID;\n";
797 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800798 }
799
800 if (mUsesLocalInvocationID)
801 {
802 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800803 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
804 << "SV_GroupThreadID;\n";
805 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800806 }
807
808 if (mUsesGlobalInvocationID)
809 {
810 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800811 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
812 << "SV_DispatchThreadID;\n";
813 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800814 }
815
816 if (mUsesLocalInvocationIndex)
817 {
818 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800819 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
820 << "SV_GroupIndex;\n";
821 glBuiltinInitialization
822 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800823 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800824
825 systemValueDeclaration << "};\n\n";
826 glBuiltinInitialization << "};\n\n";
827
828 out << systemValueDeclaration.str();
829 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800830 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000831
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800832 if (!mappedStructs.empty())
833 {
834 out << "// Structures from std140 blocks with padding removed\n";
835 out << "\n";
836 out << mappedStructs;
837 out << "\n";
838 }
839
Geoff Lang1fe74c72016-08-25 13:23:01 -0400840 bool getDimensionsIgnoresBaseLevel =
841 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
842 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800843 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000845 if (mUsesFragCoord)
846 {
847 out << "#define GL_USES_FRAG_COORD\n";
848 }
849
850 if (mUsesPointCoord)
851 {
852 out << "#define GL_USES_POINT_COORD\n";
853 }
854
855 if (mUsesFrontFacing)
856 {
857 out << "#define GL_USES_FRONT_FACING\n";
858 }
859
860 if (mUsesPointSize)
861 {
862 out << "#define GL_USES_POINT_SIZE\n";
863 }
864
Martin Radev41ac68e2017-06-06 12:16:58 +0300865 if (mHasMultiviewExtensionEnabled)
866 {
867 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
868 }
869
870 if (mUsesViewID)
871 {
872 out << "#define GL_USES_VIEW_ID\n";
873 }
874
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400875 if (mUsesFragDepth)
876 {
877 out << "#define GL_USES_FRAG_DEPTH\n";
878 }
879
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000880 if (mUsesDepthRange)
881 {
882 out << "#define GL_USES_DEPTH_RANGE\n";
883 }
884
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000885 if (mUsesXor)
886 {
887 out << "bool xor(bool p, bool q)\n"
888 "{\n"
889 " return (p || q) && !(p && q);\n"
890 "}\n"
891 "\n";
892 }
893
Olli Etuahodfa75e82017-01-23 09:43:06 -0800894 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000895}
896
897void OutputHLSL::visitSymbol(TIntermSymbol *node)
898{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200899 const TVariable &variable = node->variable();
900
901 // Empty symbols can only appear in declarations and function arguments, and in either of those
902 // cases the symbol nodes are not visited.
903 ASSERT(variable.symbolType() != SymbolType::Empty);
904
Jamie Madill32aab012015-01-27 14:12:26 -0500905 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906
Jamie Madill570e04d2013-06-21 09:15:33 -0400907 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200908 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400909 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200910 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400911 }
912
Olli Etuahofbb1c792018-01-19 16:26:59 +0200913 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200914 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200915
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000916 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000917 {
918 mUsesDepthRange = true;
919 out << name;
920 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921 else
922 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200923 const TType &variableType = variable.getType();
924 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000925
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200926 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200927
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000928 if (qualifier == EvqUniform)
929 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200930 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400931
932 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000933 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200934 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
935 {
936 const TVariable *instanceVariable = nullptr;
937 if (variableType.isInterfaceBlock())
938 {
939 instanceVariable = &variable;
940 }
941 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
942 new TReferencedBlock(interfaceBlock, instanceVariable);
943 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000944 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000945 else
946 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200947 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000948 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400949
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200950 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000951 }
Jamie Madill19571812013-08-12 15:26:34 -0700952 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000953 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200954 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400955 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000956 }
Jamie Madill033dae62014-06-18 12:56:28 -0400957 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000958 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200959 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +0300960 out << DecorateVariableIfNeeded(variable);
961 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +0300962 {
963 mUsesViewID = true;
964 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000965 }
Jamie Madill19571812013-08-12 15:26:34 -0700966 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400967 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200968 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400969 out << "out_" << name;
970 }
971 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000972 {
973 out << "gl_Color[0]";
974 mUsesFragColor = true;
975 }
976 else if (qualifier == EvqFragData)
977 {
978 out << "gl_Color";
979 mUsesFragData = true;
980 }
981 else if (qualifier == EvqFragCoord)
982 {
983 mUsesFragCoord = true;
984 out << name;
985 }
986 else if (qualifier == EvqPointCoord)
987 {
988 mUsesPointCoord = true;
989 out << name;
990 }
991 else if (qualifier == EvqFrontFacing)
992 {
993 mUsesFrontFacing = true;
994 out << name;
995 }
996 else if (qualifier == EvqPointSize)
997 {
998 mUsesPointSize = true;
999 out << name;
1000 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001001 else if (qualifier == EvqInstanceID)
1002 {
1003 mUsesInstanceID = true;
1004 out << name;
1005 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001006 else if (qualifier == EvqVertexID)
1007 {
1008 mUsesVertexID = true;
1009 out << name;
1010 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001011 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001012 {
1013 mUsesFragDepth = true;
1014 out << "gl_Depth";
1015 }
Xinghua Caob1239382016-12-13 15:07:05 +08001016 else if (qualifier == EvqNumWorkGroups)
1017 {
1018 mUsesNumWorkGroups = true;
1019 out << name;
1020 }
1021 else if (qualifier == EvqWorkGroupID)
1022 {
1023 mUsesWorkGroupID = true;
1024 out << name;
1025 }
1026 else if (qualifier == EvqLocalInvocationID)
1027 {
1028 mUsesLocalInvocationID = true;
1029 out << name;
1030 }
1031 else if (qualifier == EvqGlobalInvocationID)
1032 {
1033 mUsesGlobalInvocationID = true;
1034 out << name;
1035 }
1036 else if (qualifier == EvqLocalInvocationIndex)
1037 {
1038 mUsesLocalInvocationIndex = true;
1039 out << name;
1040 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001041 else
1042 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001043 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001044 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045 }
1046}
1047
Olli Etuaho7fb49552015-03-18 17:27:44 +02001048void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1049{
1050 if (type.isScalar() && !type.isArray())
1051 {
1052 if (op == EOpEqual)
1053 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001054 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001055 }
1056 else
1057 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001058 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001059 }
1060 }
1061 else
1062 {
1063 if (visit == PreVisit && op == EOpNotEqual)
1064 {
1065 out << "!";
1066 }
1067
1068 if (type.isArray())
1069 {
1070 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001071 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001072 }
1073 else if (type.getBasicType() == EbtStruct)
1074 {
1075 const TStructure &structure = *type.getStruct();
1076 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001077 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001078 }
1079 else
1080 {
1081 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001082 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001083 }
1084 }
1085}
1086
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001087void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1088{
1089 if (type.isArray())
1090 {
1091 const TString &functionName = addArrayAssignmentFunction(type);
1092 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1093 }
1094 else
1095 {
1096 outputTriplet(out, visit, "(", " = ", ")");
1097 }
1098}
1099
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001100bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001101{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001102 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001103 {
1104 TIntermNode *ancestor = getAncestorNode(n);
1105 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1106 if (ancestorBinary == nullptr)
1107 {
1108 return false;
1109 }
1110 switch (ancestorBinary->getOp())
1111 {
1112 case EOpIndexDirectStruct:
1113 {
1114 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1115 const TIntermConstantUnion *index =
1116 ancestorBinary->getRight()->getAsConstantUnion();
1117 const TField *field = structure->fields()[index->getIConst(0)];
1118 if (IsSampler(field->type()->getBasicType()))
1119 {
1120 return true;
1121 }
1122 break;
1123 }
1124 case EOpIndexDirect:
1125 break;
1126 default:
1127 // Returning a sampler from indirect indexing is not supported.
1128 return false;
1129 }
1130 }
1131 return false;
1132}
1133
Olli Etuahob6fa0432016-09-28 16:28:05 +01001134bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1135{
1136 TInfoSinkBase &out = getInfoSink();
1137 if (visit == PostVisit)
1138 {
1139 out << ".";
1140 node->writeOffsetsAsXYZW(&out);
1141 }
1142 return true;
1143}
1144
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1146{
Jamie Madill32aab012015-01-27 14:12:26 -05001147 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148
1149 switch (node->getOp())
1150 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001151 case EOpComma:
1152 outputTriplet(out, visit, "(", ", ", ")");
1153 break;
1154 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001155 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001156 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001157 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1158 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001159 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001160 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1161 out << functionName << "(";
1162 node->getLeft()->traverse(this);
1163 TIntermSequence *seq = rightAgg->getSequence();
1164 for (auto &arrayElement : *seq)
1165 {
1166 out << ", ";
1167 arrayElement->traverse(this);
1168 }
1169 out << ")";
1170 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001171 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001172 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1173 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001174 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001175 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001176 // Assignment expressions with atomic functions should be transformed into atomic
1177 // function calls in HLSL.
1178 // e.g. original_value = atomicAdd(dest, value) should be translated into
1179 // InterlockedAdd(dest, value, original_value);
1180 else if (IsAtomicFunctionDirectAssign(*node))
1181 {
1182 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1183 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1184 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1185 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1186 ASSERT(argumentSeq->size() >= 2u);
1187 for (auto &argument : *argumentSeq)
1188 {
1189 argument->traverse(this);
1190 out << ", ";
1191 }
1192 node->getLeft()->traverse(this);
1193 out << ")";
1194 return false;
1195 }
1196
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001197 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001198 break;
1199 case EOpInitialize:
1200 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001201 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001202 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1203 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001204 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001205
1206 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001207 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001208
1209 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1210 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1211 // new variable is created before the assignment is evaluated), so we need to
1212 // convert
1213 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001214 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001215 {
1216 // Skip initializing the rest of the expression
1217 return false;
1218 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001219 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001220 {
1221 return false;
1222 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001223 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001224 else if (visit == InVisit)
1225 {
1226 out << " = ";
1227 }
1228 break;
1229 case EOpAddAssign:
1230 outputTriplet(out, visit, "(", " += ", ")");
1231 break;
1232 case EOpSubAssign:
1233 outputTriplet(out, visit, "(", " -= ", ")");
1234 break;
1235 case EOpMulAssign:
1236 outputTriplet(out, visit, "(", " *= ", ")");
1237 break;
1238 case EOpVectorTimesScalarAssign:
1239 outputTriplet(out, visit, "(", " *= ", ")");
1240 break;
1241 case EOpMatrixTimesScalarAssign:
1242 outputTriplet(out, visit, "(", " *= ", ")");
1243 break;
1244 case EOpVectorTimesMatrixAssign:
1245 if (visit == PreVisit)
1246 {
1247 out << "(";
1248 }
1249 else if (visit == InVisit)
1250 {
1251 out << " = mul(";
1252 node->getLeft()->traverse(this);
1253 out << ", transpose(";
1254 }
1255 else
1256 {
1257 out << ")))";
1258 }
1259 break;
1260 case EOpMatrixTimesMatrixAssign:
1261 if (visit == PreVisit)
1262 {
1263 out << "(";
1264 }
1265 else if (visit == InVisit)
1266 {
1267 out << " = transpose(mul(transpose(";
1268 node->getLeft()->traverse(this);
1269 out << "), transpose(";
1270 }
1271 else
1272 {
1273 out << "))))";
1274 }
1275 break;
1276 case EOpDivAssign:
1277 outputTriplet(out, visit, "(", " /= ", ")");
1278 break;
1279 case EOpIModAssign:
1280 outputTriplet(out, visit, "(", " %= ", ")");
1281 break;
1282 case EOpBitShiftLeftAssign:
1283 outputTriplet(out, visit, "(", " <<= ", ")");
1284 break;
1285 case EOpBitShiftRightAssign:
1286 outputTriplet(out, visit, "(", " >>= ", ")");
1287 break;
1288 case EOpBitwiseAndAssign:
1289 outputTriplet(out, visit, "(", " &= ", ")");
1290 break;
1291 case EOpBitwiseXorAssign:
1292 outputTriplet(out, visit, "(", " ^= ", ")");
1293 break;
1294 case EOpBitwiseOrAssign:
1295 outputTriplet(out, visit, "(", " |= ", ")");
1296 break;
1297 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001298 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001299 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001300 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001301 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001302 if (visit == PreVisit)
1303 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001304 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001305 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuahoc71862a2017-12-21 12:58:29 +02001306 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1307 {
1308 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1309 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1310 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001311 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001312 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1313 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001314 return false;
1315 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001316 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001317 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001318 {
1319 // All parts of an expression that access a sampler in a struct need to use _ as
1320 // separator to access the sampler variable that has been moved out of the struct.
1321 outputTriplet(out, visit, "", "_", "");
1322 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001323 else
1324 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001325 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001326 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001327 }
1328 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001329 case EOpIndexIndirect:
1330 // We do not currently support indirect references to interface blocks
1331 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1332 outputTriplet(out, visit, "", "[", "]");
1333 break;
1334 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001335 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001336 const TStructure *structure = node->getLeft()->getType().getStruct();
1337 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1338 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001339
Olli Etuaho96963162016-03-21 11:54:33 +02001340 // In cases where indexing returns a sampler, we need to access the sampler variable
1341 // that has been moved out of the struct.
1342 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1343 if (visit == PreVisit && indexingReturnsSampler)
1344 {
1345 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1346 // This prefix is only output at the beginning of the indexing expression, which
1347 // may have multiple parts.
1348 out << "angle";
1349 }
1350 if (!indexingReturnsSampler)
1351 {
1352 // All parts of an expression that access a sampler in a struct need to use _ as
1353 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001354 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001355 }
1356 if (visit == InVisit)
1357 {
1358 if (indexingReturnsSampler)
1359 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001360 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001361 }
1362 else
1363 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001364 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001365 }
1366
1367 return false;
1368 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001369 }
1370 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001371 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001372 {
1373 bool structInStd140Block =
1374 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1375 if (visit == PreVisit && structInStd140Block)
1376 {
1377 out << "map";
1378 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001379 if (visit == InVisit)
1380 {
1381 const TInterfaceBlock *interfaceBlock =
1382 node->getLeft()->getType().getInterfaceBlock();
1383 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1384 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001385 if (structInStd140Block)
1386 {
1387 out << "_";
1388 }
1389 else
1390 {
1391 out << ".";
1392 }
1393 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001394
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001395 return false;
1396 }
1397 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001398 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001399 case EOpAdd:
1400 outputTriplet(out, visit, "(", " + ", ")");
1401 break;
1402 case EOpSub:
1403 outputTriplet(out, visit, "(", " - ", ")");
1404 break;
1405 case EOpMul:
1406 outputTriplet(out, visit, "(", " * ", ")");
1407 break;
1408 case EOpDiv:
1409 outputTriplet(out, visit, "(", " / ", ")");
1410 break;
1411 case EOpIMod:
1412 outputTriplet(out, visit, "(", " % ", ")");
1413 break;
1414 case EOpBitShiftLeft:
1415 outputTriplet(out, visit, "(", " << ", ")");
1416 break;
1417 case EOpBitShiftRight:
1418 outputTriplet(out, visit, "(", " >> ", ")");
1419 break;
1420 case EOpBitwiseAnd:
1421 outputTriplet(out, visit, "(", " & ", ")");
1422 break;
1423 case EOpBitwiseXor:
1424 outputTriplet(out, visit, "(", " ^ ", ")");
1425 break;
1426 case EOpBitwiseOr:
1427 outputTriplet(out, visit, "(", " | ", ")");
1428 break;
1429 case EOpEqual:
1430 case EOpNotEqual:
1431 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1432 break;
1433 case EOpLessThan:
1434 outputTriplet(out, visit, "(", " < ", ")");
1435 break;
1436 case EOpGreaterThan:
1437 outputTriplet(out, visit, "(", " > ", ")");
1438 break;
1439 case EOpLessThanEqual:
1440 outputTriplet(out, visit, "(", " <= ", ")");
1441 break;
1442 case EOpGreaterThanEqual:
1443 outputTriplet(out, visit, "(", " >= ", ")");
1444 break;
1445 case EOpVectorTimesScalar:
1446 outputTriplet(out, visit, "(", " * ", ")");
1447 break;
1448 case EOpMatrixTimesScalar:
1449 outputTriplet(out, visit, "(", " * ", ")");
1450 break;
1451 case EOpVectorTimesMatrix:
1452 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1453 break;
1454 case EOpMatrixTimesVector:
1455 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1456 break;
1457 case EOpMatrixTimesMatrix:
1458 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1459 break;
1460 case EOpLogicalOr:
1461 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1462 // been unfolded.
1463 ASSERT(!node->getRight()->hasSideEffects());
1464 outputTriplet(out, visit, "(", " || ", ")");
1465 return true;
1466 case EOpLogicalXor:
1467 mUsesXor = true;
1468 outputTriplet(out, visit, "xor(", ", ", ")");
1469 break;
1470 case EOpLogicalAnd:
1471 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1472 // been unfolded.
1473 ASSERT(!node->getRight()->hasSideEffects());
1474 outputTriplet(out, visit, "(", " && ", ")");
1475 return true;
1476 default:
1477 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001478 }
1479
1480 return true;
1481}
1482
1483bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1484{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001485 TInfoSinkBase &out = getInfoSink();
1486
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001487 switch (node->getOp())
1488 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001489 case EOpNegative:
1490 outputTriplet(out, visit, "(-", "", ")");
1491 break;
1492 case EOpPositive:
1493 outputTriplet(out, visit, "(+", "", ")");
1494 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001495 case EOpLogicalNot:
1496 outputTriplet(out, visit, "(!", "", ")");
1497 break;
1498 case EOpBitwiseNot:
1499 outputTriplet(out, visit, "(~", "", ")");
1500 break;
1501 case EOpPostIncrement:
1502 outputTriplet(out, visit, "(", "", "++)");
1503 break;
1504 case EOpPostDecrement:
1505 outputTriplet(out, visit, "(", "", "--)");
1506 break;
1507 case EOpPreIncrement:
1508 outputTriplet(out, visit, "(++", "", ")");
1509 break;
1510 case EOpPreDecrement:
1511 outputTriplet(out, visit, "(--", "", ")");
1512 break;
1513 case EOpRadians:
1514 outputTriplet(out, visit, "radians(", "", ")");
1515 break;
1516 case EOpDegrees:
1517 outputTriplet(out, visit, "degrees(", "", ")");
1518 break;
1519 case EOpSin:
1520 outputTriplet(out, visit, "sin(", "", ")");
1521 break;
1522 case EOpCos:
1523 outputTriplet(out, visit, "cos(", "", ")");
1524 break;
1525 case EOpTan:
1526 outputTriplet(out, visit, "tan(", "", ")");
1527 break;
1528 case EOpAsin:
1529 outputTriplet(out, visit, "asin(", "", ")");
1530 break;
1531 case EOpAcos:
1532 outputTriplet(out, visit, "acos(", "", ")");
1533 break;
1534 case EOpAtan:
1535 outputTriplet(out, visit, "atan(", "", ")");
1536 break;
1537 case EOpSinh:
1538 outputTriplet(out, visit, "sinh(", "", ")");
1539 break;
1540 case EOpCosh:
1541 outputTriplet(out, visit, "cosh(", "", ")");
1542 break;
1543 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpAtanh:
1547 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001548 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 break;
1550 case EOpExp:
1551 outputTriplet(out, visit, "exp(", "", ")");
1552 break;
1553 case EOpLog:
1554 outputTriplet(out, visit, "log(", "", ")");
1555 break;
1556 case EOpExp2:
1557 outputTriplet(out, visit, "exp2(", "", ")");
1558 break;
1559 case EOpLog2:
1560 outputTriplet(out, visit, "log2(", "", ")");
1561 break;
1562 case EOpSqrt:
1563 outputTriplet(out, visit, "sqrt(", "", ")");
1564 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001565 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001566 outputTriplet(out, visit, "rsqrt(", "", ")");
1567 break;
1568 case EOpAbs:
1569 outputTriplet(out, visit, "abs(", "", ")");
1570 break;
1571 case EOpSign:
1572 outputTriplet(out, visit, "sign(", "", ")");
1573 break;
1574 case EOpFloor:
1575 outputTriplet(out, visit, "floor(", "", ")");
1576 break;
1577 case EOpTrunc:
1578 outputTriplet(out, visit, "trunc(", "", ")");
1579 break;
1580 case EOpRound:
1581 outputTriplet(out, visit, "round(", "", ")");
1582 break;
1583 case EOpRoundEven:
1584 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001585 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 break;
1587 case EOpCeil:
1588 outputTriplet(out, visit, "ceil(", "", ")");
1589 break;
1590 case EOpFract:
1591 outputTriplet(out, visit, "frac(", "", ")");
1592 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001593 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001595 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 else
1597 outputTriplet(out, visit, "isnan(", "", ")");
1598 mRequiresIEEEStrictCompiling = true;
1599 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001600 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 outputTriplet(out, visit, "isinf(", "", ")");
1602 break;
1603 case EOpFloatBitsToInt:
1604 outputTriplet(out, visit, "asint(", "", ")");
1605 break;
1606 case EOpFloatBitsToUint:
1607 outputTriplet(out, visit, "asuint(", "", ")");
1608 break;
1609 case EOpIntBitsToFloat:
1610 outputTriplet(out, visit, "asfloat(", "", ")");
1611 break;
1612 case EOpUintBitsToFloat:
1613 outputTriplet(out, visit, "asfloat(", "", ")");
1614 break;
1615 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001616 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001617 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001619 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001621 case EOpPackUnorm4x8:
1622 case EOpPackSnorm4x8:
1623 case EOpUnpackUnorm4x8:
1624 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001625 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001626 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001627 break;
1628 case EOpLength:
1629 outputTriplet(out, visit, "length(", "", ")");
1630 break;
1631 case EOpNormalize:
1632 outputTriplet(out, visit, "normalize(", "", ")");
1633 break;
1634 case EOpDFdx:
1635 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1636 {
1637 outputTriplet(out, visit, "(", "", ", 0.0)");
1638 }
1639 else
1640 {
1641 outputTriplet(out, visit, "ddx(", "", ")");
1642 }
1643 break;
1644 case EOpDFdy:
1645 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1646 {
1647 outputTriplet(out, visit, "(", "", ", 0.0)");
1648 }
1649 else
1650 {
1651 outputTriplet(out, visit, "ddy(", "", ")");
1652 }
1653 break;
1654 case EOpFwidth:
1655 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1656 {
1657 outputTriplet(out, visit, "(", "", ", 0.0)");
1658 }
1659 else
1660 {
1661 outputTriplet(out, visit, "fwidth(", "", ")");
1662 }
1663 break;
1664 case EOpTranspose:
1665 outputTriplet(out, visit, "transpose(", "", ")");
1666 break;
1667 case EOpDeterminant:
1668 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1669 break;
1670 case EOpInverse:
1671 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001672 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001673 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001674
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001675 case EOpAny:
1676 outputTriplet(out, visit, "any(", "", ")");
1677 break;
1678 case EOpAll:
1679 outputTriplet(out, visit, "all(", "", ")");
1680 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001681 case EOpLogicalNotComponentWise:
1682 outputTriplet(out, visit, "(!", "", ")");
1683 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001684 case EOpBitfieldReverse:
1685 outputTriplet(out, visit, "reversebits(", "", ")");
1686 break;
1687 case EOpBitCount:
1688 outputTriplet(out, visit, "countbits(", "", ")");
1689 break;
1690 case EOpFindLSB:
1691 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1692 // in GLSLTest and results are consistent with GL.
1693 outputTriplet(out, visit, "firstbitlow(", "", ")");
1694 break;
1695 case EOpFindMSB:
1696 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1697 // tested in GLSLTest and results are consistent with GL.
1698 outputTriplet(out, visit, "firstbithigh(", "", ")");
1699 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 default:
1701 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001702 }
1703
1704 return true;
1705}
1706
Olli Etuahofbb1c792018-01-19 16:26:59 +02001707ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001708{
1709 if (node->getAsSymbolNode())
1710 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001711 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1712 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001713 }
1714 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1715 switch (nodeBinary->getOp())
1716 {
1717 case EOpIndexDirect:
1718 {
1719 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1720
Olli Etuahofbb1c792018-01-19 16:26:59 +02001721 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001722 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001723 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001724 }
1725 case EOpIndexDirectStruct:
1726 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001727 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001728 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1729 const TField *field = s->fields()[index];
1730
Olli Etuahofbb1c792018-01-19 16:26:59 +02001731 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001732 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1733 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001734 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001735 }
1736 default:
1737 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001738 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001739 }
1740}
1741
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001742bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1743{
1744 TInfoSinkBase &out = getInfoSink();
1745
Olli Etuaho06235df2018-07-20 14:26:07 +03001746 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1747
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001748 if (mInsideFunction)
1749 {
1750 outputLineDirective(out, node->getLine().first_line);
1751 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001752 if (isMainBlock)
1753 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001754 if (mShaderType == GL_COMPUTE_SHADER)
1755 {
1756 out << "initGLBuiltins(input);\n";
1757 }
1758 else
1759 {
1760 out << "@@ MAIN PROLOGUE @@\n";
1761 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001762 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001763 }
1764
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001765 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001766 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001767 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001768
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001769 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001770
1771 // Don't output ; after case labels, they're terminated by :
1772 // This is needed especially since outputting a ; after a case statement would turn empty
1773 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001774 // Also the output code is clearer if we don't output ; after statements where it is not
1775 // needed:
1776 // * if statements
1777 // * switch statements
1778 // * blocks
1779 // * function definitions
1780 // * loops (do-while loops output the semicolon in VisitLoop)
1781 // * declarations that don't generate output.
1782 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1783 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1784 statement->getAsSwitchNode() == nullptr &&
1785 statement->getAsFunctionDefinition() == nullptr &&
1786 (statement->getAsDeclarationNode() == nullptr ||
1787 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1788 statement->getAsInvariantDeclarationNode() == nullptr)
1789 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001790 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001791 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001792 }
1793
1794 if (mInsideFunction)
1795 {
1796 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001797 if (isMainBlock && shaderNeedsGenerateOutput())
1798 {
1799 // We could have an empty main, a main function without a branch at the end, or a main
1800 // function with a discard statement at the end. In these cases we need to add a return
1801 // statement.
1802 bool needReturnStatement =
1803 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1804 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1805 if (needReturnStatement)
1806 {
1807 out << "return " << generateOutputCall() << ";\n";
1808 }
1809 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001810 out << "}\n";
1811 }
1812
1813 return false;
1814}
1815
Olli Etuaho336b1472016-10-05 16:37:55 +01001816bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1817{
1818 TInfoSinkBase &out = getInfoSink();
1819
1820 ASSERT(mCurrentFunctionMetadata == nullptr);
1821
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001822 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001823 ASSERT(index != CallDAG::InvalidIndex);
1824 mCurrentFunctionMetadata = &mASTMetadataList[index];
1825
Olli Etuahod4bd9632018-03-08 16:32:44 +02001826 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001827
Olli Etuahod4bd9632018-03-08 16:32:44 +02001828 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001829 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001830 // The stub strings below are replaced when shader is dynamically defined by its layout:
1831 switch (mShaderType)
1832 {
1833 case GL_VERTEX_SHADER:
1834 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1835 << "@@ VERTEX OUTPUT @@\n\n"
1836 << "VS_OUTPUT main(VS_INPUT input)";
1837 break;
1838 case GL_FRAGMENT_SHADER:
1839 out << "@@ PIXEL OUTPUT @@\n\n"
1840 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1841 break;
1842 case GL_COMPUTE_SHADER:
1843 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1844 << mWorkGroupSize[2] << ")]\n";
1845 out << "void main(CS_INPUT input)";
1846 break;
1847 default:
1848 UNREACHABLE();
1849 break;
1850 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001851 }
1852 else
1853 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001854 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001855 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001856 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001857
Olli Etuaho06235df2018-07-20 14:26:07 +03001858 size_t paramCount = func->getParamCount();
1859 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001860 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001861 const TVariable *param = func->getParam(i);
1862 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001863
Olli Etuaho06235df2018-07-20 14:26:07 +03001864 writeParameter(param, out);
1865
1866 if (i < paramCount - 1)
1867 {
1868 out << ", ";
1869 }
1870 }
1871
1872 out << ")\n";
1873 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001874
1875 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03001876 if (func->isMain())
1877 {
1878 mInsideMain = true;
1879 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001880 // The function body node will output braces.
1881 node->getBody()->traverse(this);
1882 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03001883 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01001884
1885 mCurrentFunctionMetadata = nullptr;
1886
1887 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1888 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1889 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001890 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001891 mOutputLod0Function = true;
1892 node->traverse(this);
1893 mOutputLod0Function = false;
1894 }
1895
1896 return false;
1897}
1898
Olli Etuaho13389b62016-10-16 11:48:18 +01001899bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1900{
Olli Etuaho13389b62016-10-16 11:48:18 +01001901 if (visit == PreVisit)
1902 {
1903 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001904 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001905 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001906 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001907
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001908 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001909 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001910 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001911 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001912
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001913 if (!declarator->getAsSymbolNode() ||
1914 declarator->getAsSymbolNode()->variable().symbolType() !=
1915 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001916 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001917 if (declarator->getQualifier() == EvqShared)
1918 {
1919 out << "groupshared ";
1920 }
1921 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001922 {
1923 out << "static ";
1924 }
1925
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001926 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001927
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001928 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001929
1930 if (symbol)
1931 {
1932 symbol->traverse(this);
1933 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001934 // We don't initialize shared variables because:
1935 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1936 // code to initialize a groupshared array variable with a large array size.
1937 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1938 // allow initializing shared variables at all.
1939 if (declarator->getQualifier() != EvqShared)
1940 {
1941 out << " = " + zeroInitializer(symbol->getType());
1942 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001943 }
1944 else
1945 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001946 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001947 }
1948 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001949 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001950 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001951 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001952 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001953 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001954
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001955 const TVariable &variable = symbol->variable();
1956
1957 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001958 {
1959 // Vertex outputs which are declared but not written to should still be declared to
1960 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001961 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001962 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001963 }
1964 }
1965 return false;
1966}
1967
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001968bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1969{
1970 // Do not do any translation
1971 return false;
1972}
1973
Olli Etuahod4bd9632018-03-08 16:32:44 +02001974void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001975{
1976 TInfoSinkBase &out = getInfoSink();
1977
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001978 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001979 // Skip the prototype if it is not implemented (and thus not used)
1980 if (index == CallDAG::InvalidIndex)
1981 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001982 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00001983 }
1984
Olli Etuahod4bd9632018-03-08 16:32:44 +02001985 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00001986
Olli Etuahod4bd9632018-03-08 16:32:44 +02001987 TString name = DecorateFunctionIfNeeded(func);
1988 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001989 << (mOutputLod0Function ? "Lod0(" : "(");
1990
Olli Etuahod4bd9632018-03-08 16:32:44 +02001991 size_t paramCount = func->getParamCount();
1992 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001993 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001994 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00001995
Olli Etuahod4bd9632018-03-08 16:32:44 +02001996 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001997 {
1998 out << ", ";
1999 }
2000 }
2001
2002 out << ");\n";
2003
2004 // Also prototype the Lod0 variant if needed
2005 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2006 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2007 {
2008 mOutputLod0Function = true;
2009 node->traverse(this);
2010 mOutputLod0Function = false;
2011 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002012}
2013
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002014bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2015{
Jamie Madill32aab012015-01-27 14:12:26 -05002016 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002017
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002018 switch (node->getOp())
2019 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002020 case EOpCallBuiltInFunction:
2021 case EOpCallFunctionInAST:
2022 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002024 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002025
Corentin Wallez1239ee92015-03-19 14:38:02 -07002026 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002027 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002028 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002029 if (node->isArray())
2030 {
2031 UNIMPLEMENTED();
2032 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002033 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002034 ASSERT(index != CallDAG::InvalidIndex);
2035 lod0 &= mASTMetadataList[index].mNeedsLod0;
2036
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002037 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002038 out << DisambiguateFunctionName(node->getSequence());
2039 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002040 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002041 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002042 {
2043 // This path is used for internal functions that don't have their definitions in the
2044 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002045 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002046 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002047 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002048 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002049 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002050 TType type = (*arguments)[0]->getAsTyped()->getType();
2051 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002052 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002053 type.getMemoryQualifier().readonly);
2054 out << imageFunctionName << "(";
2055 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002056 else
2057 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002058 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002059 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002060 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2061 if (arguments->size() > 1)
2062 {
2063 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2064 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002065 const ImmutableString &textureFunctionName =
2066 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2067 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002068 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002069 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002070
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002071 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002072 {
Olli Etuaho96963162016-03-21 11:54:33 +02002073 TIntermTyped *typedArg = (*arg)->getAsTyped();
2074 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002075 {
2076 out << "texture_";
2077 (*arg)->traverse(this);
2078 out << ", sampler_";
2079 }
2080
2081 (*arg)->traverse(this);
2082
Olli Etuaho96963162016-03-21 11:54:33 +02002083 if (typedArg->getType().isStructureContainingSamplers())
2084 {
2085 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002086 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002087 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2088 std::string namePrefix = "angle_";
2089 namePrefix += structName.data();
2090 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002091 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002092 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002093 {
2094 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2095 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002096 out << ", texture_" << sampler->name();
2097 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002098 }
2099 else
2100 {
2101 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2102 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002103 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002104 }
2105 }
2106 }
2107
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002108 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002109 {
2110 out << ", ";
2111 }
2112 }
2113
2114 out << ")";
2115
2116 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002117 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002118 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002119 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002120 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002121 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002122 outputTriplet(out, visit, "(", " == ", ")");
2123 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002124 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002125 outputTriplet(out, visit, "(", " != ", ")");
2126 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002127 case EOpLessThanComponentWise:
2128 outputTriplet(out, visit, "(", " < ", ")");
2129 break;
2130 case EOpGreaterThanComponentWise:
2131 outputTriplet(out, visit, "(", " > ", ")");
2132 break;
2133 case EOpLessThanEqualComponentWise:
2134 outputTriplet(out, visit, "(", " <= ", ")");
2135 break;
2136 case EOpGreaterThanEqualComponentWise:
2137 outputTriplet(out, visit, "(", " >= ", ")");
2138 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002139 case EOpMod:
2140 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002141 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002142 break;
2143 case EOpModf:
2144 outputTriplet(out, visit, "modf(", ", ", ")");
2145 break;
2146 case EOpPow:
2147 outputTriplet(out, visit, "pow(", ", ", ")");
2148 break;
2149 case EOpAtan:
2150 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2151 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002152 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002153 break;
2154 case EOpMin:
2155 outputTriplet(out, visit, "min(", ", ", ")");
2156 break;
2157 case EOpMax:
2158 outputTriplet(out, visit, "max(", ", ", ")");
2159 break;
2160 case EOpClamp:
2161 outputTriplet(out, visit, "clamp(", ", ", ")");
2162 break;
2163 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302164 {
2165 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2166 if (lastParamNode->getType().getBasicType() == EbtBool)
2167 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002168 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2169 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302170 // so use emulated version.
2171 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002172 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302173 }
2174 else
2175 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002176 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302177 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002178 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302179 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002180 case EOpStep:
2181 outputTriplet(out, visit, "step(", ", ", ")");
2182 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002183 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002184 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2185 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002186 case EOpFrexp:
2187 case EOpLdexp:
2188 ASSERT(node->getUseEmulatedFunction());
2189 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2190 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002191 case EOpDistance:
2192 outputTriplet(out, visit, "distance(", ", ", ")");
2193 break;
2194 case EOpDot:
2195 outputTriplet(out, visit, "dot(", ", ", ")");
2196 break;
2197 case EOpCross:
2198 outputTriplet(out, visit, "cross(", ", ", ")");
2199 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002200 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002201 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002202 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002203 break;
2204 case EOpReflect:
2205 outputTriplet(out, visit, "reflect(", ", ", ")");
2206 break;
2207 case EOpRefract:
2208 outputTriplet(out, visit, "refract(", ", ", ")");
2209 break;
2210 case EOpOuterProduct:
2211 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002212 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002213 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002214 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002215 outputTriplet(out, visit, "(", " * ", ")");
2216 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002217 case EOpBitfieldExtract:
2218 case EOpBitfieldInsert:
2219 case EOpUaddCarry:
2220 case EOpUsubBorrow:
2221 case EOpUmulExtended:
2222 case EOpImulExtended:
2223 ASSERT(node->getUseEmulatedFunction());
2224 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2225 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002226 case EOpBarrier:
2227 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2228 // cheapest *WithGroupSync() function, without any functionality loss, but
2229 // with the potential for severe performance loss.
2230 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2231 break;
2232 case EOpMemoryBarrierShared:
2233 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2234 break;
2235 case EOpMemoryBarrierAtomicCounter:
2236 case EOpMemoryBarrierBuffer:
2237 case EOpMemoryBarrierImage:
2238 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2239 break;
2240 case EOpGroupMemoryBarrier:
2241 case EOpMemoryBarrier:
2242 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2243 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002244
2245 // Single atomic function calls without return value.
2246 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2247 case EOpAtomicAdd:
2248 case EOpAtomicMin:
2249 case EOpAtomicMax:
2250 case EOpAtomicAnd:
2251 case EOpAtomicOr:
2252 case EOpAtomicXor:
2253 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2254 ",", ")");
2255 break;
2256
2257 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2258 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2259 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2260 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2261 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2262 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2263 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2264 // intermediate tree before traversing outputHLSL.
2265 case EOpAtomicExchange:
2266 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002267 default:
2268 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002269 }
2270
2271 return true;
2272}
2273
Olli Etuaho57961272016-09-14 13:57:46 +03002274void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002275{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002276 out << "if (";
2277
2278 node->getCondition()->traverse(this);
2279
2280 out << ")\n";
2281
Jamie Madill8c46ab12015-12-07 16:39:19 -05002282 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002283
2284 bool discard = false;
2285
2286 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002287 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002288 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002289 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002290
Olli Etuahoa6f22092015-05-08 18:31:10 +03002291 // Detect true discard
2292 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2293 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002294 else
2295 {
2296 // TODO(oetuaho): Check if the semicolon inside is necessary.
2297 // It's there as a result of conservative refactoring of the output.
2298 out << "{;}\n";
2299 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002300
Jamie Madill8c46ab12015-12-07 16:39:19 -05002301 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002302
Olli Etuahoa6f22092015-05-08 18:31:10 +03002303 if (node->getFalseBlock())
2304 {
2305 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002306
Jamie Madill8c46ab12015-12-07 16:39:19 -05002307 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002308
Olli Etuaho32db19b2016-10-04 14:43:16 +01002309 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002310 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002311
Jamie Madill8c46ab12015-12-07 16:39:19 -05002312 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002313
Olli Etuahoa6f22092015-05-08 18:31:10 +03002314 // Detect false discard
2315 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2316 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002317
Olli Etuahoa6f22092015-05-08 18:31:10 +03002318 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002319 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002320 {
2321 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002322 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002323}
2324
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002325bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2326{
2327 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2328 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2329 UNREACHABLE();
2330 return false;
2331}
2332
Olli Etuaho57961272016-09-14 13:57:46 +03002333bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002334{
2335 TInfoSinkBase &out = getInfoSink();
2336
Olli Etuaho3d932d82016-04-12 11:10:30 +03002337 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002338
2339 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002340 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002341 {
2342 out << "FLATTEN ";
2343 }
2344
Olli Etuaho57961272016-09-14 13:57:46 +03002345 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002346
2347 return false;
2348}
2349
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002350bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002351{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002352 TInfoSinkBase &out = getInfoSink();
2353
Olli Etuaho923ecef2017-10-11 12:01:38 +03002354 ASSERT(node->getStatementList());
2355 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002356 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002357 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002358 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002359 outputTriplet(out, visit, "switch (", ") ", "");
2360 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002361 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002362}
2363
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002364bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002365{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002366 TInfoSinkBase &out = getInfoSink();
2367
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002368 if (node->hasCondition())
2369 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002370 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002371 return true;
2372 }
2373 else
2374 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002375 out << "default:\n";
2376 return false;
2377 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002378}
2379
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002380void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2381{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002382 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002383 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002384}
2385
2386bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2387{
Nicolas Capens655fe362014-04-11 13:12:34 -04002388 mNestedLoopDepth++;
2389
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002390 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002391 mInsideDiscontinuousLoop =
2392 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002393
Jamie Madill8c46ab12015-12-07 16:39:19 -05002394 TInfoSinkBase &out = getInfoSink();
2395
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002396 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002397 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002398 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002399 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002400 mInsideDiscontinuousLoop = wasDiscontinuous;
2401 mNestedLoopDepth--;
2402
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002403 return false;
2404 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002405 }
2406
Corentin Wallez1239ee92015-03-19 14:38:02 -07002407 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002408 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002409 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002410 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002411
Jamie Madill8c46ab12015-12-07 16:39:19 -05002412 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002413 }
2414 else
2415 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002416 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002417
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002418 if (node->getInit())
2419 {
2420 node->getInit()->traverse(this);
2421 }
2422
2423 out << "; ";
2424
alokp@chromium.org52813552010-11-16 18:36:09 +00002425 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002426 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002427 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428 }
2429
2430 out << "; ";
2431
alokp@chromium.org52813552010-11-16 18:36:09 +00002432 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002433 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002434 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002435 }
2436
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002437 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002438
Jamie Madill8c46ab12015-12-07 16:39:19 -05002439 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002440 }
2441
2442 if (node->getBody())
2443 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002444 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002445 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002446 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002447 else
2448 {
2449 // TODO(oetuaho): Check if the semicolon inside is necessary.
2450 // It's there as a result of conservative refactoring of the output.
2451 out << "{;}\n";
2452 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002453
Jamie Madill8c46ab12015-12-07 16:39:19 -05002454 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002455
alokp@chromium.org52813552010-11-16 18:36:09 +00002456 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002457 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002458 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002459 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002460
alokp@chromium.org52813552010-11-16 18:36:09 +00002461 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002462
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002463 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002464 }
2465
daniel@transgaming.com73536982012-03-21 20:45:49 +00002466 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002467
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002468 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002469 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471 return false;
2472}
2473
2474bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2475{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002476 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002477 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002478 TInfoSinkBase &out = getInfoSink();
2479
2480 switch (node->getFlowOp())
2481 {
2482 case EOpKill:
2483 out << "discard";
2484 break;
2485 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002486 if (mNestedLoopDepth > 1)
2487 {
2488 mUsesNestedBreak = true;
2489 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002490
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002491 if (mExcessiveLoopIndex)
2492 {
2493 out << "{Break";
2494 mExcessiveLoopIndex->traverse(this);
2495 out << " = true; break;}\n";
2496 }
2497 else
2498 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002499 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002500 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002501 break;
2502 case EOpContinue:
2503 out << "continue";
2504 break;
2505 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002506 if (node->getExpression())
2507 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002508 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002509 out << "return ";
2510 }
2511 else
2512 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002513 if (mInsideMain && shaderNeedsGenerateOutput())
2514 {
2515 out << "return " << generateOutputCall();
2516 }
2517 else
2518 {
2519 out << "return";
2520 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002521 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002522 break;
2523 default:
2524 UNREACHABLE();
2525 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002526 }
2527
2528 return true;
2529}
2530
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002531// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002532// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2533// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002534bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002535{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002536 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002537
2538 // Parse loops of the form:
2539 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002540 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002541 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002542 int initial = 0;
2543 int limit = 0;
2544 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002545
2546 // Parse index name and intial value
2547 if (node->getInit())
2548 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002549 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002550
2551 if (init)
2552 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002553 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002554 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002555
2556 if (variable && variable->getQualifier() == EvqTemporary)
2557 {
2558 TIntermBinary *assign = variable->getAsBinaryNode();
2559
2560 if (assign->getOp() == EOpInitialize)
2561 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002562 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002563 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2564
2565 if (symbol && constant)
2566 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002567 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002568 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002569 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002570 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002571 }
2572 }
2573 }
2574 }
2575 }
2576 }
2577
2578 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002579 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002580 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002581 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002582
Olli Etuahob6af22b2017-12-15 14:05:44 +02002583 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002584 {
2585 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2586
2587 if (constant)
2588 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002589 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002590 {
2591 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002592 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002593 }
2594 }
2595 }
2596 }
2597
2598 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002599 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002600 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002601 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002602 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002603
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002604 if (binaryTerminal)
2605 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002606 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002607 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2608
2609 if (constant)
2610 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002611 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002612 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002613 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002614
2615 switch (op)
2616 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002617 case EOpAddAssign:
2618 increment = value;
2619 break;
2620 case EOpSubAssign:
2621 increment = -value;
2622 break;
2623 default:
2624 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002625 }
2626 }
2627 }
2628 }
2629 else if (unaryTerminal)
2630 {
2631 TOperator op = unaryTerminal->getOp();
2632
2633 switch (op)
2634 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002635 case EOpPostIncrement:
2636 increment = 1;
2637 break;
2638 case EOpPostDecrement:
2639 increment = -1;
2640 break;
2641 case EOpPreIncrement:
2642 increment = 1;
2643 break;
2644 case EOpPreDecrement:
2645 increment = -1;
2646 break;
2647 default:
2648 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002649 }
2650 }
2651 }
2652
Yunchao He4f285442017-04-21 12:15:49 +08002653 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002654 {
2655 if (comparator == EOpLessThanEqual)
2656 {
2657 comparator = EOpLessThan;
2658 limit += 1;
2659 }
2660
2661 if (comparator == EOpLessThan)
2662 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002663 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002664
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002665 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002666 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002667 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002668 }
2669
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002670 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002671 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002672
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002673 out << "{int ";
2674 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002675 out << ";\n"
2676 "bool Break";
2677 index->traverse(this);
2678 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002679
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002680 bool firstLoopFragment = true;
2681
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002682 while (iterations > 0)
2683 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002684 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002685
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002686 if (!firstLoopFragment)
2687 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002688 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002689 index->traverse(this);
2690 out << ") {\n";
2691 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002692
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002693 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002694 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002695 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002696 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002697
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002698 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002699 const char *unroll =
2700 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002701
Corentin Wallez1239ee92015-03-19 14:38:02 -07002702 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002703 index->traverse(this);
2704 out << " = ";
2705 out << initial;
2706
2707 out << "; ";
2708 index->traverse(this);
2709 out << " < ";
2710 out << clampedLimit;
2711
2712 out << "; ";
2713 index->traverse(this);
2714 out << " += ";
2715 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002716 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002717
Jamie Madill8c46ab12015-12-07 16:39:19 -05002718 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002719 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002720
2721 if (node->getBody())
2722 {
2723 node->getBody()->traverse(this);
2724 }
2725
Jamie Madill8c46ab12015-12-07 16:39:19 -05002726 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002727 out << ";}\n";
2728
2729 if (!firstLoopFragment)
2730 {
2731 out << "}\n";
2732 }
2733
2734 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002735
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002736 initial += MAX_LOOP_ITERATIONS * increment;
2737 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002738 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002739
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002740 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002741
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002742 mExcessiveLoopIndex = restoreIndex;
2743
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002744 return true;
2745 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 else
2747 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002748 }
2749
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002750 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002751}
2752
Jamie Madill8c46ab12015-12-07 16:39:19 -05002753void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2754 Visit visit,
2755 const char *preString,
2756 const char *inString,
2757 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002758{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002759 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002760 {
2761 out << preString;
2762 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002763 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002764 {
2765 out << inString;
2766 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002767 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002768 {
2769 out << postString;
2770 }
2771}
2772
Jamie Madill8c46ab12015-12-07 16:39:19 -05002773void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002774{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002775 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002776 {
Jamie Madill32aab012015-01-27 14:12:26 -05002777 out << "\n";
2778 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002779
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002780 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002781 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002782 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002783 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002784
Jamie Madill32aab012015-01-27 14:12:26 -05002785 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002786 }
2787}
2788
Olli Etuahod4bd9632018-03-08 16:32:44 +02002789void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002790{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002791 const TType &type = param->getType();
2792 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002793
Olli Etuahod4bd9632018-03-08 16:32:44 +02002794 TString nameStr = DecorateVariableIfNeeded(*param);
2795 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002796
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002797 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002798 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002799 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2800 {
2801 // Samplers are passed as indices to the sampler array.
2802 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002803 out << "const uint " << nameStr << ArrayString(type);
2804 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002805 }
2806 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2807 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002808 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2809 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2810 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2811 << ArrayString(type);
2812 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002813 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002814 }
2815
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002816 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2817 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002818
2819 // If the structure parameter contains samplers, they need to be passed into the function as
2820 // separate parameters. HLSL doesn't natively support samplers in structs.
2821 if (type.isStructureContainingSamplers())
2822 {
2823 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002824 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002825 std::string namePrefix = "angle";
2826 namePrefix += nameStr.c_str();
2827 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2828 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002829 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002830 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002831 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002832 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2833 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002834 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002835 }
2836 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2837 {
Olli Etuaho96963162016-03-21 11:54:33 +02002838 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002839 out << ", " << QualifierString(qualifier) << " "
2840 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2841 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2842 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2843 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002844 }
2845 else
2846 {
Olli Etuaho96963162016-03-21 11:54:33 +02002847 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002848 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2849 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002850 }
2851 }
2852 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002853}
2854
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002855TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002856{
2857 TString string;
2858
Jamie Madill94bf7f22013-07-08 13:31:15 -04002859 size_t size = type.getObjectSize();
2860 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002861 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002862 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002863
Jamie Madill94bf7f22013-07-08 13:31:15 -04002864 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002865 {
2866 string += ", ";
2867 }
2868 }
2869
daniel@transgaming.comead23042010-04-29 03:35:36 +00002870 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002871}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002872
Olli Etuahobd3cd502017-11-03 15:48:52 +02002873void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002874{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002875 // Array constructors should have been already pruned from the code.
2876 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002877
2878 if (visit == PreVisit)
2879 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002880 TString constructorName;
2881 if (node->getBasicType() == EbtStruct)
2882 {
2883 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2884 }
2885 else
2886 {
2887 constructorName =
2888 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2889 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002890 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002891 }
2892 else if (visit == InVisit)
2893 {
2894 out << ", ";
2895 }
2896 else if (visit == PostVisit)
2897 {
2898 out << ")";
2899 }
2900}
2901
Jamie Madill8c46ab12015-12-07 16:39:19 -05002902const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2903 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002904 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002905{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002906 ASSERT(!type.isArray());
2907
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002908 const TConstantUnion *constUnionIterated = constUnion;
2909
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002910 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002911 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002912 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002913 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002914
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002915 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002916
Jamie Madill98493dd2013-07-08 14:39:03 -04002917 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002918 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002919 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002920 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002921
Jamie Madill98493dd2013-07-08 14:39:03 -04002922 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002923 {
2924 out << ", ";
2925 }
2926 }
2927
2928 out << ")";
2929 }
2930 else
2931 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002932 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002933 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002934
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002935 if (writeType)
2936 {
Jamie Madill033dae62014-06-18 12:56:28 -04002937 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002938 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002939 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002940 if (writeType)
2941 {
2942 out << ")";
2943 }
2944 }
2945
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002946 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002947}
2948
Olli Etuahod68924e2017-01-02 17:34:40 +00002949void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002950{
Olli Etuahod68924e2017-01-02 17:34:40 +00002951 if (visit == PreVisit)
2952 {
2953 const char *opStr = GetOperatorString(op);
2954 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2955 out << "(";
2956 }
2957 else
2958 {
2959 outputTriplet(out, visit, nullptr, ", ", ")");
2960 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002961}
2962
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002963bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2964 TIntermSymbol *symbolNode,
2965 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002966{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002967 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2968 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002969
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002970 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002971 {
2972 // Type already printed
2973 out << "t" + str(mUniqueIndex) + " = ";
2974 expression->traverse(this);
2975 out << ", ";
2976 symbolNode->traverse(this);
2977 out << " = t" + str(mUniqueIndex);
2978
2979 mUniqueIndex++;
2980 return true;
2981 }
2982
2983 return false;
2984}
2985
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002986bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2987 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002988 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002989{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002990 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002991 {
2992 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002993 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002994 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002995 writeConstantUnionArray(out, initializer->getConstantValue(),
2996 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002997 out << "}";
2998 return true;
2999 }
3000 return false;
3001}
3002
Jamie Madill55e79e02015-02-09 15:35:00 -05003003TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3004{
3005 const TFieldList &fields = structure.fields();
3006
3007 for (const auto &eqFunction : mStructEqualityFunctions)
3008 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003009 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003010 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003011 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003012 }
3013 }
3014
3015 const TString &structNameString = StructNameString(structure);
3016
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003017 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003018 function->structure = &structure;
3019 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003020
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003021 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003022
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003023 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3024 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003025 << "{\n"
3026 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003027
3028 for (size_t i = 0; i < fields.size(); i++)
3029 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003030 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003031 const TType *fieldType = field->type();
3032
3033 const TString &fieldNameA = "a." + Decorate(field->name());
3034 const TString &fieldNameB = "b." + Decorate(field->name());
3035
3036 if (i > 0)
3037 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003038 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003039 }
3040
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003041 fnOut << "(";
3042 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3043 fnOut << fieldNameA;
3044 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3045 fnOut << fieldNameB;
3046 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3047 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003048 }
3049
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003050 fnOut << ";\n"
3051 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003052
3053 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003054
3055 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003056 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003057
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003058 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003059}
3060
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003061TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003062{
3063 for (const auto &eqFunction : mArrayEqualityFunctions)
3064 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003065 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003066 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003067 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003068 }
3069 }
3070
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003071 TType elementType(type);
3072 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003073
Olli Etuaho12690762015-03-31 12:55:28 +03003074 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003075 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003076
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003077 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003078
3079 TInfoSinkBase fnOut;
3080
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003081 const TString &typeName = TypeString(type);
3082 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3083 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003084 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003085 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003086 << type.getOutermostArraySize()
3087 << "; ++i)\n"
3088 " {\n"
3089 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003090
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003091 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003092 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003093 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003094 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003095 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003096
3097 fnOut << ") { return false; }\n"
3098 " }\n"
3099 " return true;\n"
3100 "}\n";
3101
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003102 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003103
3104 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003105 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003106
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003107 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003108}
3109
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003110TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003111{
3112 for (const auto &assignFunction : mArrayAssignmentFunctions)
3113 {
3114 if (assignFunction.type == type)
3115 {
3116 return assignFunction.functionName;
3117 }
3118 }
3119
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003120 TType elementType(type);
3121 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003122
3123 ArrayHelperFunction function;
3124 function.type = type;
3125
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003126 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003127
3128 TInfoSinkBase fnOut;
3129
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003130 const TString &typeName = TypeString(type);
3131 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3132 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003133 << "{\n"
3134 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003135 << type.getOutermostArraySize()
3136 << "; ++i)\n"
3137 " {\n"
3138 " ";
3139
3140 outputAssign(PreVisit, elementType, fnOut);
3141 fnOut << "a[i]";
3142 outputAssign(InVisit, elementType, fnOut);
3143 fnOut << "b[i]";
3144 outputAssign(PostVisit, elementType, fnOut);
3145
3146 fnOut << ";\n"
3147 " }\n"
3148 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003149
3150 function.functionDefinition = fnOut.c_str();
3151
3152 mArrayAssignmentFunctions.push_back(function);
3153
3154 return function.functionName;
3155}
3156
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003157TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003158{
3159 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3160 {
3161 if (constructIntoFunction.type == type)
3162 {
3163 return constructIntoFunction.functionName;
3164 }
3165 }
3166
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003167 TType elementType(type);
3168 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003169
3170 ArrayHelperFunction function;
3171 function.type = type;
3172
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003173 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003174
3175 TInfoSinkBase fnOut;
3176
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003177 const TString &typeName = TypeString(type);
3178 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3179 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003180 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003181 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003182 }
3183 fnOut << ")\n"
3184 "{\n";
3185
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003186 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003187 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003188 fnOut << " ";
3189 outputAssign(PreVisit, elementType, fnOut);
3190 fnOut << "a[" << i << "]";
3191 outputAssign(InVisit, elementType, fnOut);
3192 fnOut << "b" << i;
3193 outputAssign(PostVisit, elementType, fnOut);
3194 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003195 }
3196 fnOut << "}\n";
3197
3198 function.functionDefinition = fnOut.c_str();
3199
3200 mArrayConstructIntoFunctions.push_back(function);
3201
3202 return function.functionName;
3203}
3204
Jamie Madill2e295e22015-04-29 10:41:33 -04003205void OutputHLSL::ensureStructDefined(const TType &type)
3206{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003207 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003208 if (structure)
3209 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003210 ASSERT(type.getBasicType() == EbtStruct);
3211 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003212 }
3213}
3214
Olli Etuaho06235df2018-07-20 14:26:07 +03003215bool OutputHLSL::shaderNeedsGenerateOutput() const
3216{
3217 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3218}
3219
3220const char *OutputHLSL::generateOutputCall() const
3221{
3222 if (mShaderType == GL_VERTEX_SHADER)
3223 {
3224 return "generateOutput(input)";
3225 }
3226 else
3227 {
3228 return "generateOutput()";
3229 }
3230}
3231
Jamie Madill45bcc782016-11-07 13:58:48 -05003232} // namespace sh