blob: a9610f405bbf68055a89246777225fc7bff76fa4 [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 Etuaho89a69a02017-10-23 12:20:45 +0300185 TSymbolTable *symbolTable,
186 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300187 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200188 mShaderType(shaderType),
189 mShaderVersion(shaderVersion),
190 mExtensionBehavior(extensionBehavior),
191 mSourcePath(sourcePath),
192 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700193 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000194 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300195 mCurrentFunctionMetadata(nullptr),
196 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000198 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000199
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800200 mUsesFragColor = false;
201 mUsesFragData = false;
202 mUsesDepthRange = false;
203 mUsesFragCoord = false;
204 mUsesPointCoord = false;
205 mUsesFrontFacing = false;
206 mUsesPointSize = false;
207 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300208 mHasMultiviewExtensionEnabled =
209 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300210 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500211 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500212 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800213 mUsesNumWorkGroups = false;
214 mUsesWorkGroupID = false;
215 mUsesLocalInvocationID = false;
216 mUsesGlobalInvocationID = false;
217 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500218 mUsesXor = false;
219 mUsesDiscardRewriting = false;
220 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530221 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000222
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000223 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000224
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500225 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000226 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000228
Yunchao Hed7297bf2017-04-19 15:27:10 +0800229 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000230
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500231 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300232 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800233 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400234
Olli Etuahod8724a92017-12-29 18:40:36 +0200235 unsigned int firstUniformRegister =
236 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Xinghua Cao06a22622018-05-18 16:48:41 +0800237 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200238
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200239 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000240 {
Arun Patole63419392015-03-13 11:51:07 +0530241 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500242 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
243 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530244 // In both cases total 3 uniform registers need to be reserved.
245 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000246 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000247
Geoff Lang00140f42016-02-03 18:47:33 +0000248 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800249 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250}
251
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000252OutputHLSL::~OutputHLSL()
253{
Jamie Madill8daaba12014-06-13 10:04:33 -0400254 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400255 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300256 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800257 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200258 for (auto &eqFunction : mStructEqualityFunctions)
259 {
260 SafeDelete(eqFunction);
261 }
262 for (auto &eqFunction : mArrayEqualityFunctions)
263 {
264 SafeDelete(eqFunction);
265 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000266}
267
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200268void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000269{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200270 BuiltInFunctionEmulator builtInFunctionEmulator;
271 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800272 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
273 {
274 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
275 mShaderVersion);
276 }
277
Olli Etuahodfa75e82017-01-23 09:43:06 -0800278 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500279
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700280 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000281 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700282 ASSERT(success == CallDAG::INITDAG_SUCCESS);
283 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700284
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200285 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
286 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
287 // the shader code. When we add shader storage blocks we might also consider an alternative
288 // solution, since the struct mapping won't work very well for shader storage blocks.
289
Jamie Madill37997142015-01-28 10:06:34 -0500290 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500291 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200292 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500293 mInfoSinkStack.pop();
294
Jamie Madill37997142015-01-28 10:06:34 -0500295 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500296 mInfoSinkStack.pop();
297
Jamie Madill32aab012015-01-27 14:12:26 -0500298 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200299 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500300 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000301
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200302 objSink << mHeader.c_str();
303 objSink << mBody.c_str();
304 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200305
Olli Etuahodfa75e82017-01-23 09:43:06 -0800306 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000307}
308
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800309const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400310{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800311 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400312}
313
Jamie Madill9fe25e92014-07-18 10:33:08 -0400314const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
315{
316 return mUniformHLSL->getUniformRegisterMap();
317}
318
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200319TString OutputHLSL::structInitializerString(int indent,
320 const TType &type,
321 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400322{
323 TString init;
324
Olli Etuahoed049ab2017-06-30 17:38:33 +0300325 TString indentString;
326 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400327 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300328 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 }
330
Olli Etuahoed049ab2017-06-30 17:38:33 +0300331 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400332 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300333 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300334 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400335 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300336 TStringStream indexedString;
337 indexedString << name << "[" << arrayIndex << "]";
338 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300339 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300340 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300341 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300342 {
343 init += ",";
344 }
345 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400346 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300347 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 else if (type.getBasicType() == EbtStruct)
350 {
351 init += indentString + "{\n";
352 const TStructure &structure = *type.getStruct();
353 const TFieldList &fields = structure.fields();
354 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
355 {
356 const TField &field = *fields[fieldIndex];
357 const TString &fieldName = name + "." + Decorate(field.name());
358 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400359
Olli Etuahoed049ab2017-06-30 17:38:33 +0300360 init += structInitializerString(indent + 1, fieldType, fieldName);
361 if (fieldIndex < fields.size() - 1)
362 {
363 init += ",";
364 }
365 init += "\n";
366 }
367 init += indentString + "}";
368 }
369 else
370 {
371 init += indentString + name;
372 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400373
374 return init;
375}
376
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200377TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
378{
379 TString mappedStructs;
380
381 for (auto &mappedStruct : std140Structs)
382 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200383 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200384 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200385 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200386 {
387 continue;
388 }
389
390 unsigned int instanceCount = 1u;
391 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
392 if (isInstanceArray)
393 {
394 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
395 }
396
397 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
398 ++instanceArrayIndex)
399 {
400 TString originalName;
401 TString mappedName("map");
402
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200403 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200404 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200405 const ImmutableString &instanceName =
406 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200407 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
408 if (isInstanceArray)
409 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200410 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200411 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200412 originalName += instanceString;
413 mappedName += instanceString;
414 originalName += ".";
415 mappedName += "_";
416 }
417
418 TString fieldName = Decorate(mappedStruct.field->name());
419 originalName += fieldName;
420 mappedName += fieldName;
421
422 TType *structType = mappedStruct.field->type();
423 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200424 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200425
426 if (structType->isArray())
427 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300428 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200429 }
430
431 mappedStructs += " =\n";
432 mappedStructs += structInitializerString(0, *structType, originalName);
433 mappedStructs += ";\n";
434 }
435 }
436 return mappedStructs;
437}
438
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300439void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300441 for (const auto &attribute : mReferencedAttributes)
442 {
443 const TType &type = attribute.second->getType();
444 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400445
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300446 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
447 << zeroInitializer(type) << ";\n";
448 }
449}
450
451void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
452{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200453 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000454 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800455 const TType &type = varying.second->getType();
Olli Etuahofbb1c792018-01-19 16:26:59 +0200456 const ImmutableString &name = varying.second->name();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000457
458 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300459 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
460 << " " << Decorate(name) << ArrayString(type) << " = " << zeroInitializer(type)
461 << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000462 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300463}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000464
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300465void OutputHLSL::header(TInfoSinkBase &out,
466 const std::vector<MappedStruct> &std140Structs,
467 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
468{
469 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000470
Jamie Madill8daaba12014-06-13 10:04:33 -0400471 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400472
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300473 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800474 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400475
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200476 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500477 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200478 out << "\n// Equality functions\n\n";
479 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500480 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200481 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200482 }
483 }
Olli Etuaho12690762015-03-31 12:55:28 +0300484 if (!mArrayAssignmentFunctions.empty())
485 {
486 out << "\n// Assignment functions\n\n";
487 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
488 {
489 out << assignmentFunction.functionDefinition << "\n";
490 }
491 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300492 if (!mArrayConstructIntoFunctions.empty())
493 {
494 out << "\n// Array constructor functions\n\n";
495 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
496 {
497 out << constructIntoFunction.functionDefinition << "\n";
498 }
499 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200500
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500501 if (mUsesDiscardRewriting)
502 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400503 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500504 }
505
Nicolas Capens655fe362014-04-11 13:12:34 -0400506 if (mUsesNestedBreak)
507 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400508 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400509 }
510
Arun Patole44efa0b2015-03-04 17:11:05 +0530511 if (mRequiresIEEEStrictCompiling)
512 {
513 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
514 }
515
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400516 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
517 "#define LOOP [loop]\n"
518 "#define FLATTEN [flatten]\n"
519 "#else\n"
520 "#define LOOP\n"
521 "#define FLATTEN\n"
522 "#endif\n";
523
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200524 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000525 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300526 const bool usingMRTExtension =
527 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000528
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000529 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300530 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400531 out << "\n";
532
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200533 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000534 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200535 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000536 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200537 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800538 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400539
Olli Etuahofbb1c792018-01-19 16:26:59 +0200540 out << "static " << TypeString(variableType) << " out_" << variableName
541 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000542 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000543 }
Jamie Madill46131a32013-06-20 11:55:50 -0400544 else
545 {
546 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
547
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800548 out << "static float4 gl_Color[" << numColorValues
549 << "] =\n"
550 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400551 for (unsigned int i = 0; i < numColorValues; i++)
552 {
553 out << " float4(0, 0, 0, 0)";
554 if (i + 1 != numColorValues)
555 {
556 out << ",";
557 }
558 out << "\n";
559 }
560
561 out << "};\n";
562 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000563
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400564 if (mUsesFragDepth)
565 {
566 out << "static float gl_Depth = 0.0;\n";
567 }
568
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000569 if (mUsesFragCoord)
570 {
571 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
572 }
573
574 if (mUsesPointCoord)
575 {
576 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
577 }
578
579 if (mUsesFrontFacing)
580 {
581 out << "static bool gl_FrontFacing = false;\n";
582 }
583
584 out << "\n";
585
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000586 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000587 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000588 out << "struct gl_DepthRangeParameters\n"
589 "{\n"
590 " float near;\n"
591 " float far;\n"
592 " float diff;\n"
593 "};\n"
594 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000595 }
596
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200597 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000598 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000599 out << "cbuffer DriverConstants : register(b1)\n"
600 "{\n";
601
602 if (mUsesDepthRange)
603 {
604 out << " float3 dx_DepthRange : packoffset(c0);\n";
605 }
606
607 if (mUsesFragCoord)
608 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000609 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000610 }
611
612 if (mUsesFragCoord || mUsesFrontFacing)
613 {
614 out << " float3 dx_DepthFront : packoffset(c2);\n";
615 }
616
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800617 if (mUsesFragCoord)
618 {
619 // dx_ViewScale is only used in the fragment shader to correct
620 // the value for glFragCoord if necessary
621 out << " float2 dx_ViewScale : packoffset(c3);\n";
622 }
623
Martin Radev72b4e1e2017-08-31 15:42:56 +0300624 if (mHasMultiviewExtensionEnabled)
625 {
626 // We have to add a value which we can use to keep track of which multi-view code
627 // path is to be selected in the GS.
628 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
629 }
630
Olli Etuaho618bebc2016-01-15 16:40:00 +0200631 if (mOutputType == SH_HLSL_4_1_OUTPUT)
632 {
633 mUniformHLSL->samplerMetadataUniforms(out, "c4");
634 }
635
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000636 out << "};\n";
637 }
638 else
639 {
640 if (mUsesDepthRange)
641 {
642 out << "uniform float3 dx_DepthRange : register(c0);";
643 }
644
645 if (mUsesFragCoord)
646 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000647 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000648 }
649
650 if (mUsesFragCoord || mUsesFrontFacing)
651 {
652 out << "uniform float3 dx_DepthFront : register(c2);\n";
653 }
654 }
655
656 out << "\n";
657
658 if (mUsesDepthRange)
659 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500660 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
661 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000662 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000663 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000664
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000665 if (usingMRTExtension && mNumRenderTargets > 1)
666 {
667 out << "#define GL_USES_MRT\n";
668 }
669
670 if (mUsesFragColor)
671 {
672 out << "#define GL_USES_FRAG_COLOR\n";
673 }
674
675 if (mUsesFragData)
676 {
677 out << "#define GL_USES_FRAG_DATA\n";
678 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679 }
Xinghua Caob1239382016-12-13 15:07:05 +0800680 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000681 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000682 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300683 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000684 out << "\n"
685 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400686
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000687 if (mUsesPointSize)
688 {
689 out << "static float gl_PointSize = float(1);\n";
690 }
691
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000692 if (mUsesInstanceID)
693 {
694 out << "static int gl_InstanceID;";
695 }
696
Corentin Wallezb076add2016-01-11 16:45:46 -0500697 if (mUsesVertexID)
698 {
699 out << "static int gl_VertexID;";
700 }
701
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000702 out << "\n"
703 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300704 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000705 out << "\n";
706
707 if (mUsesDepthRange)
708 {
709 out << "struct gl_DepthRangeParameters\n"
710 "{\n"
711 " float near;\n"
712 " float far;\n"
713 " float diff;\n"
714 "};\n"
715 "\n";
716 }
717
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200718 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000719 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800720 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500721 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800722
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000723 if (mUsesDepthRange)
724 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800725 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000726 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800727
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800728 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
729 // shaders. However, we declare it for all shaders (including Feature Level 10+).
730 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
731 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800732 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800733 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800734 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800735
Martin Radev72b4e1e2017-08-31 15:42:56 +0300736 if (mHasMultiviewExtensionEnabled)
737 {
738 // We have to add a value which we can use to keep track of which multi-view code
739 // path is to be selected in the GS.
740 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
741 }
742
Olli Etuaho618bebc2016-01-15 16:40:00 +0200743 if (mOutputType == SH_HLSL_4_1_OUTPUT)
744 {
745 mUniformHLSL->samplerMetadataUniforms(out, "c4");
746 }
747
Austin Kinross4fd18b12014-12-22 12:32:05 -0800748 out << "};\n"
749 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000750 }
751 else
752 {
753 if (mUsesDepthRange)
754 {
755 out << "uniform float3 dx_DepthRange : register(c0);\n";
756 }
757
Cooper Partine6664f02015-01-09 16:22:24 -0800758 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
759 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000760 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000761 }
762
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000763 if (mUsesDepthRange)
764 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
766 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000767 "\n";
768 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400769 }
Xinghua Caob1239382016-12-13 15:07:05 +0800770 else // Compute shader
771 {
772 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800773
774 out << "cbuffer DriverConstants : register(b1)\n"
775 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800776 if (mUsesNumWorkGroups)
777 {
Xinghua Caob1239382016-12-13 15:07:05 +0800778 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800779 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800780 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
781 mUniformHLSL->samplerMetadataUniforms(out, "c1");
782 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800783
784 // Follow built-in variables would be initialized in
785 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
786 // are used in compute shader.
787 if (mUsesWorkGroupID)
788 {
789 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
790 }
791
792 if (mUsesLocalInvocationID)
793 {
794 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
795 }
796
797 if (mUsesGlobalInvocationID)
798 {
799 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
800 }
801
802 if (mUsesLocalInvocationIndex)
803 {
804 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
805 }
806 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000807
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800808 if (!mappedStructs.empty())
809 {
810 out << "// Structures from std140 blocks with padding removed\n";
811 out << "\n";
812 out << mappedStructs;
813 out << "\n";
814 }
815
Geoff Lang1fe74c72016-08-25 13:23:01 -0400816 bool getDimensionsIgnoresBaseLevel =
817 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
818 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800819 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000821 if (mUsesFragCoord)
822 {
823 out << "#define GL_USES_FRAG_COORD\n";
824 }
825
826 if (mUsesPointCoord)
827 {
828 out << "#define GL_USES_POINT_COORD\n";
829 }
830
831 if (mUsesFrontFacing)
832 {
833 out << "#define GL_USES_FRONT_FACING\n";
834 }
835
836 if (mUsesPointSize)
837 {
838 out << "#define GL_USES_POINT_SIZE\n";
839 }
840
Martin Radev41ac68e2017-06-06 12:16:58 +0300841 if (mHasMultiviewExtensionEnabled)
842 {
843 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
844 }
845
846 if (mUsesViewID)
847 {
848 out << "#define GL_USES_VIEW_ID\n";
849 }
850
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400851 if (mUsesFragDepth)
852 {
853 out << "#define GL_USES_FRAG_DEPTH\n";
854 }
855
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000856 if (mUsesDepthRange)
857 {
858 out << "#define GL_USES_DEPTH_RANGE\n";
859 }
860
Xinghua Caob1239382016-12-13 15:07:05 +0800861 if (mUsesNumWorkGroups)
862 {
863 out << "#define GL_USES_NUM_WORK_GROUPS\n";
864 }
865
866 if (mUsesWorkGroupID)
867 {
868 out << "#define GL_USES_WORK_GROUP_ID\n";
869 }
870
871 if (mUsesLocalInvocationID)
872 {
873 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
874 }
875
876 if (mUsesGlobalInvocationID)
877 {
878 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
879 }
880
881 if (mUsesLocalInvocationIndex)
882 {
883 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
884 }
885
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000886 if (mUsesXor)
887 {
888 out << "bool xor(bool p, bool q)\n"
889 "{\n"
890 " return (p || q) && !(p && q);\n"
891 "}\n"
892 "\n";
893 }
894
Olli Etuahodfa75e82017-01-23 09:43:06 -0800895 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896}
897
898void OutputHLSL::visitSymbol(TIntermSymbol *node)
899{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200900 const TVariable &variable = node->variable();
901
902 // Empty symbols can only appear in declarations and function arguments, and in either of those
903 // cases the symbol nodes are not visited.
904 ASSERT(variable.symbolType() != SymbolType::Empty);
905
Jamie Madill32aab012015-01-27 14:12:26 -0500906 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000907
Jamie Madill570e04d2013-06-21 09:15:33 -0400908 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200909 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400910 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200911 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400912 }
913
Olli Etuahofbb1c792018-01-19 16:26:59 +0200914 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200915 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200916
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000917 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000918 {
919 mUsesDepthRange = true;
920 out << name;
921 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922 else
923 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200924 const TType &variableType = variable.getType();
925 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000926
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200927 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200928
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000929 if (qualifier == EvqUniform)
930 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200931 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400932
933 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000934 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200935 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
936 {
937 const TVariable *instanceVariable = nullptr;
938 if (variableType.isInterfaceBlock())
939 {
940 instanceVariable = &variable;
941 }
942 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
943 new TReferencedBlock(interfaceBlock, instanceVariable);
944 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000945 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000946 else
947 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200948 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000949 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400950
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200951 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000952 }
Jamie Madill19571812013-08-12 15:26:34 -0700953 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000954 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200955 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400956 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000957 }
Jamie Madill033dae62014-06-18 12:56:28 -0400958 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000959 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200960 mReferencedVaryings[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400961 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300962 if (name == "ViewID_OVR")
963 {
964 mUsesViewID = true;
965 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000966 }
Jamie Madill19571812013-08-12 15:26:34 -0700967 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400968 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200969 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400970 out << "out_" << name;
971 }
972 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000973 {
974 out << "gl_Color[0]";
975 mUsesFragColor = true;
976 }
977 else if (qualifier == EvqFragData)
978 {
979 out << "gl_Color";
980 mUsesFragData = true;
981 }
982 else if (qualifier == EvqFragCoord)
983 {
984 mUsesFragCoord = true;
985 out << name;
986 }
987 else if (qualifier == EvqPointCoord)
988 {
989 mUsesPointCoord = true;
990 out << name;
991 }
992 else if (qualifier == EvqFrontFacing)
993 {
994 mUsesFrontFacing = true;
995 out << name;
996 }
997 else if (qualifier == EvqPointSize)
998 {
999 mUsesPointSize = true;
1000 out << name;
1001 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001002 else if (qualifier == EvqInstanceID)
1003 {
1004 mUsesInstanceID = true;
1005 out << name;
1006 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001007 else if (qualifier == EvqVertexID)
1008 {
1009 mUsesVertexID = true;
1010 out << name;
1011 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001012 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001013 {
1014 mUsesFragDepth = true;
1015 out << "gl_Depth";
1016 }
Xinghua Caob1239382016-12-13 15:07:05 +08001017 else if (qualifier == EvqNumWorkGroups)
1018 {
1019 mUsesNumWorkGroups = true;
1020 out << name;
1021 }
1022 else if (qualifier == EvqWorkGroupID)
1023 {
1024 mUsesWorkGroupID = true;
1025 out << name;
1026 }
1027 else if (qualifier == EvqLocalInvocationID)
1028 {
1029 mUsesLocalInvocationID = true;
1030 out << name;
1031 }
1032 else if (qualifier == EvqGlobalInvocationID)
1033 {
1034 mUsesGlobalInvocationID = true;
1035 out << name;
1036 }
1037 else if (qualifier == EvqLocalInvocationIndex)
1038 {
1039 mUsesLocalInvocationIndex = true;
1040 out << name;
1041 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001042 else
1043 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001044 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001045 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 }
1047}
1048
Olli Etuaho7fb49552015-03-18 17:27:44 +02001049void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1050{
1051 if (type.isScalar() && !type.isArray())
1052 {
1053 if (op == EOpEqual)
1054 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001055 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001056 }
1057 else
1058 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001059 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001060 }
1061 }
1062 else
1063 {
1064 if (visit == PreVisit && op == EOpNotEqual)
1065 {
1066 out << "!";
1067 }
1068
1069 if (type.isArray())
1070 {
1071 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001072 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001073 }
1074 else if (type.getBasicType() == EbtStruct)
1075 {
1076 const TStructure &structure = *type.getStruct();
1077 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001078 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001079 }
1080 else
1081 {
1082 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001083 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001084 }
1085 }
1086}
1087
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001088void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1089{
1090 if (type.isArray())
1091 {
1092 const TString &functionName = addArrayAssignmentFunction(type);
1093 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1094 }
1095 else
1096 {
1097 outputTriplet(out, visit, "(", " = ", ")");
1098 }
1099}
1100
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001101bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001102{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001103 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001104 {
1105 TIntermNode *ancestor = getAncestorNode(n);
1106 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1107 if (ancestorBinary == nullptr)
1108 {
1109 return false;
1110 }
1111 switch (ancestorBinary->getOp())
1112 {
1113 case EOpIndexDirectStruct:
1114 {
1115 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1116 const TIntermConstantUnion *index =
1117 ancestorBinary->getRight()->getAsConstantUnion();
1118 const TField *field = structure->fields()[index->getIConst(0)];
1119 if (IsSampler(field->type()->getBasicType()))
1120 {
1121 return true;
1122 }
1123 break;
1124 }
1125 case EOpIndexDirect:
1126 break;
1127 default:
1128 // Returning a sampler from indirect indexing is not supported.
1129 return false;
1130 }
1131 }
1132 return false;
1133}
1134
Olli Etuahob6fa0432016-09-28 16:28:05 +01001135bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1136{
1137 TInfoSinkBase &out = getInfoSink();
1138 if (visit == PostVisit)
1139 {
1140 out << ".";
1141 node->writeOffsetsAsXYZW(&out);
1142 }
1143 return true;
1144}
1145
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1147{
Jamie Madill32aab012015-01-27 14:12:26 -05001148 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001149
1150 switch (node->getOp())
1151 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001152 case EOpComma:
1153 outputTriplet(out, visit, "(", ", ", ")");
1154 break;
1155 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001156 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001157 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001158 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1159 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001160 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001161 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1162 out << functionName << "(";
1163 node->getLeft()->traverse(this);
1164 TIntermSequence *seq = rightAgg->getSequence();
1165 for (auto &arrayElement : *seq)
1166 {
1167 out << ", ";
1168 arrayElement->traverse(this);
1169 }
1170 out << ")";
1171 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001172 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001173 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1174 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001175 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001176 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001177 // Assignment expressions with atomic functions should be transformed into atomic
1178 // function calls in HLSL.
1179 // e.g. original_value = atomicAdd(dest, value) should be translated into
1180 // InterlockedAdd(dest, value, original_value);
1181 else if (IsAtomicFunctionDirectAssign(*node))
1182 {
1183 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1184 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1185 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1186 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1187 ASSERT(argumentSeq->size() >= 2u);
1188 for (auto &argument : *argumentSeq)
1189 {
1190 argument->traverse(this);
1191 out << ", ";
1192 }
1193 node->getLeft()->traverse(this);
1194 out << ")";
1195 return false;
1196 }
1197
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001198 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001199 break;
1200 case EOpInitialize:
1201 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001202 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001203 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1204 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001205 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001206
1207 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001208 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001209
1210 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1211 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1212 // new variable is created before the assignment is evaluated), so we need to
1213 // convert
1214 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001215 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001216 {
1217 // Skip initializing the rest of the expression
1218 return false;
1219 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001220 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001221 {
1222 return false;
1223 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001224 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001225 else if (visit == InVisit)
1226 {
1227 out << " = ";
1228 }
1229 break;
1230 case EOpAddAssign:
1231 outputTriplet(out, visit, "(", " += ", ")");
1232 break;
1233 case EOpSubAssign:
1234 outputTriplet(out, visit, "(", " -= ", ")");
1235 break;
1236 case EOpMulAssign:
1237 outputTriplet(out, visit, "(", " *= ", ")");
1238 break;
1239 case EOpVectorTimesScalarAssign:
1240 outputTriplet(out, visit, "(", " *= ", ")");
1241 break;
1242 case EOpMatrixTimesScalarAssign:
1243 outputTriplet(out, visit, "(", " *= ", ")");
1244 break;
1245 case EOpVectorTimesMatrixAssign:
1246 if (visit == PreVisit)
1247 {
1248 out << "(";
1249 }
1250 else if (visit == InVisit)
1251 {
1252 out << " = mul(";
1253 node->getLeft()->traverse(this);
1254 out << ", transpose(";
1255 }
1256 else
1257 {
1258 out << ")))";
1259 }
1260 break;
1261 case EOpMatrixTimesMatrixAssign:
1262 if (visit == PreVisit)
1263 {
1264 out << "(";
1265 }
1266 else if (visit == InVisit)
1267 {
1268 out << " = transpose(mul(transpose(";
1269 node->getLeft()->traverse(this);
1270 out << "), transpose(";
1271 }
1272 else
1273 {
1274 out << "))))";
1275 }
1276 break;
1277 case EOpDivAssign:
1278 outputTriplet(out, visit, "(", " /= ", ")");
1279 break;
1280 case EOpIModAssign:
1281 outputTriplet(out, visit, "(", " %= ", ")");
1282 break;
1283 case EOpBitShiftLeftAssign:
1284 outputTriplet(out, visit, "(", " <<= ", ")");
1285 break;
1286 case EOpBitShiftRightAssign:
1287 outputTriplet(out, visit, "(", " >>= ", ")");
1288 break;
1289 case EOpBitwiseAndAssign:
1290 outputTriplet(out, visit, "(", " &= ", ")");
1291 break;
1292 case EOpBitwiseXorAssign:
1293 outputTriplet(out, visit, "(", " ^= ", ")");
1294 break;
1295 case EOpBitwiseOrAssign:
1296 outputTriplet(out, visit, "(", " |= ", ")");
1297 break;
1298 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001299 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001300 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001301 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001302 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001303 if (visit == PreVisit)
1304 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001305 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001306 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuahoc71862a2017-12-21 12:58:29 +02001307 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1308 {
1309 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1310 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1311 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001312 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001313 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1314 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001315 return false;
1316 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001317 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001318 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001319 {
1320 // All parts of an expression that access a sampler in a struct need to use _ as
1321 // separator to access the sampler variable that has been moved out of the struct.
1322 outputTriplet(out, visit, "", "_", "");
1323 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001324 else
1325 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001326 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001327 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001328 }
1329 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001330 case EOpIndexIndirect:
1331 // We do not currently support indirect references to interface blocks
1332 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1333 outputTriplet(out, visit, "", "[", "]");
1334 break;
1335 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001336 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001337 const TStructure *structure = node->getLeft()->getType().getStruct();
1338 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1339 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001340
Olli Etuaho96963162016-03-21 11:54:33 +02001341 // In cases where indexing returns a sampler, we need to access the sampler variable
1342 // that has been moved out of the struct.
1343 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1344 if (visit == PreVisit && indexingReturnsSampler)
1345 {
1346 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1347 // This prefix is only output at the beginning of the indexing expression, which
1348 // may have multiple parts.
1349 out << "angle";
1350 }
1351 if (!indexingReturnsSampler)
1352 {
1353 // All parts of an expression that access a sampler in a struct need to use _ as
1354 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001355 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001356 }
1357 if (visit == InVisit)
1358 {
1359 if (indexingReturnsSampler)
1360 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001361 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001362 }
1363 else
1364 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001365 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001366 }
1367
1368 return false;
1369 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001370 }
1371 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001372 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001373 {
1374 bool structInStd140Block =
1375 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1376 if (visit == PreVisit && structInStd140Block)
1377 {
1378 out << "map";
1379 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001380 if (visit == InVisit)
1381 {
1382 const TInterfaceBlock *interfaceBlock =
1383 node->getLeft()->getType().getInterfaceBlock();
1384 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1385 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001386 if (structInStd140Block)
1387 {
1388 out << "_";
1389 }
1390 else
1391 {
1392 out << ".";
1393 }
1394 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001395
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001396 return false;
1397 }
1398 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001399 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001400 case EOpAdd:
1401 outputTriplet(out, visit, "(", " + ", ")");
1402 break;
1403 case EOpSub:
1404 outputTriplet(out, visit, "(", " - ", ")");
1405 break;
1406 case EOpMul:
1407 outputTriplet(out, visit, "(", " * ", ")");
1408 break;
1409 case EOpDiv:
1410 outputTriplet(out, visit, "(", " / ", ")");
1411 break;
1412 case EOpIMod:
1413 outputTriplet(out, visit, "(", " % ", ")");
1414 break;
1415 case EOpBitShiftLeft:
1416 outputTriplet(out, visit, "(", " << ", ")");
1417 break;
1418 case EOpBitShiftRight:
1419 outputTriplet(out, visit, "(", " >> ", ")");
1420 break;
1421 case EOpBitwiseAnd:
1422 outputTriplet(out, visit, "(", " & ", ")");
1423 break;
1424 case EOpBitwiseXor:
1425 outputTriplet(out, visit, "(", " ^ ", ")");
1426 break;
1427 case EOpBitwiseOr:
1428 outputTriplet(out, visit, "(", " | ", ")");
1429 break;
1430 case EOpEqual:
1431 case EOpNotEqual:
1432 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1433 break;
1434 case EOpLessThan:
1435 outputTriplet(out, visit, "(", " < ", ")");
1436 break;
1437 case EOpGreaterThan:
1438 outputTriplet(out, visit, "(", " > ", ")");
1439 break;
1440 case EOpLessThanEqual:
1441 outputTriplet(out, visit, "(", " <= ", ")");
1442 break;
1443 case EOpGreaterThanEqual:
1444 outputTriplet(out, visit, "(", " >= ", ")");
1445 break;
1446 case EOpVectorTimesScalar:
1447 outputTriplet(out, visit, "(", " * ", ")");
1448 break;
1449 case EOpMatrixTimesScalar:
1450 outputTriplet(out, visit, "(", " * ", ")");
1451 break;
1452 case EOpVectorTimesMatrix:
1453 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1454 break;
1455 case EOpMatrixTimesVector:
1456 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1457 break;
1458 case EOpMatrixTimesMatrix:
1459 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1460 break;
1461 case EOpLogicalOr:
1462 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1463 // been unfolded.
1464 ASSERT(!node->getRight()->hasSideEffects());
1465 outputTriplet(out, visit, "(", " || ", ")");
1466 return true;
1467 case EOpLogicalXor:
1468 mUsesXor = true;
1469 outputTriplet(out, visit, "xor(", ", ", ")");
1470 break;
1471 case EOpLogicalAnd:
1472 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1473 // been unfolded.
1474 ASSERT(!node->getRight()->hasSideEffects());
1475 outputTriplet(out, visit, "(", " && ", ")");
1476 return true;
1477 default:
1478 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479 }
1480
1481 return true;
1482}
1483
1484bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1485{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001486 TInfoSinkBase &out = getInfoSink();
1487
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001488 switch (node->getOp())
1489 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001490 case EOpNegative:
1491 outputTriplet(out, visit, "(-", "", ")");
1492 break;
1493 case EOpPositive:
1494 outputTriplet(out, visit, "(+", "", ")");
1495 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001496 case EOpLogicalNot:
1497 outputTriplet(out, visit, "(!", "", ")");
1498 break;
1499 case EOpBitwiseNot:
1500 outputTriplet(out, visit, "(~", "", ")");
1501 break;
1502 case EOpPostIncrement:
1503 outputTriplet(out, visit, "(", "", "++)");
1504 break;
1505 case EOpPostDecrement:
1506 outputTriplet(out, visit, "(", "", "--)");
1507 break;
1508 case EOpPreIncrement:
1509 outputTriplet(out, visit, "(++", "", ")");
1510 break;
1511 case EOpPreDecrement:
1512 outputTriplet(out, visit, "(--", "", ")");
1513 break;
1514 case EOpRadians:
1515 outputTriplet(out, visit, "radians(", "", ")");
1516 break;
1517 case EOpDegrees:
1518 outputTriplet(out, visit, "degrees(", "", ")");
1519 break;
1520 case EOpSin:
1521 outputTriplet(out, visit, "sin(", "", ")");
1522 break;
1523 case EOpCos:
1524 outputTriplet(out, visit, "cos(", "", ")");
1525 break;
1526 case EOpTan:
1527 outputTriplet(out, visit, "tan(", "", ")");
1528 break;
1529 case EOpAsin:
1530 outputTriplet(out, visit, "asin(", "", ")");
1531 break;
1532 case EOpAcos:
1533 outputTriplet(out, visit, "acos(", "", ")");
1534 break;
1535 case EOpAtan:
1536 outputTriplet(out, visit, "atan(", "", ")");
1537 break;
1538 case EOpSinh:
1539 outputTriplet(out, visit, "sinh(", "", ")");
1540 break;
1541 case EOpCosh:
1542 outputTriplet(out, visit, "cosh(", "", ")");
1543 break;
1544 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpAtanh:
1548 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001549 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001550 break;
1551 case EOpExp:
1552 outputTriplet(out, visit, "exp(", "", ")");
1553 break;
1554 case EOpLog:
1555 outputTriplet(out, visit, "log(", "", ")");
1556 break;
1557 case EOpExp2:
1558 outputTriplet(out, visit, "exp2(", "", ")");
1559 break;
1560 case EOpLog2:
1561 outputTriplet(out, visit, "log2(", "", ")");
1562 break;
1563 case EOpSqrt:
1564 outputTriplet(out, visit, "sqrt(", "", ")");
1565 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001566 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001567 outputTriplet(out, visit, "rsqrt(", "", ")");
1568 break;
1569 case EOpAbs:
1570 outputTriplet(out, visit, "abs(", "", ")");
1571 break;
1572 case EOpSign:
1573 outputTriplet(out, visit, "sign(", "", ")");
1574 break;
1575 case EOpFloor:
1576 outputTriplet(out, visit, "floor(", "", ")");
1577 break;
1578 case EOpTrunc:
1579 outputTriplet(out, visit, "trunc(", "", ")");
1580 break;
1581 case EOpRound:
1582 outputTriplet(out, visit, "round(", "", ")");
1583 break;
1584 case EOpRoundEven:
1585 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001586 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001587 break;
1588 case EOpCeil:
1589 outputTriplet(out, visit, "ceil(", "", ")");
1590 break;
1591 case EOpFract:
1592 outputTriplet(out, visit, "frac(", "", ")");
1593 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001594 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001595 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001596 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001597 else
1598 outputTriplet(out, visit, "isnan(", "", ")");
1599 mRequiresIEEEStrictCompiling = true;
1600 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001601 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 outputTriplet(out, visit, "isinf(", "", ")");
1603 break;
1604 case EOpFloatBitsToInt:
1605 outputTriplet(out, visit, "asint(", "", ")");
1606 break;
1607 case EOpFloatBitsToUint:
1608 outputTriplet(out, visit, "asuint(", "", ")");
1609 break;
1610 case EOpIntBitsToFloat:
1611 outputTriplet(out, visit, "asfloat(", "", ")");
1612 break;
1613 case EOpUintBitsToFloat:
1614 outputTriplet(out, visit, "asfloat(", "", ")");
1615 break;
1616 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001617 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001619 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001622 case EOpPackUnorm4x8:
1623 case EOpPackSnorm4x8:
1624 case EOpUnpackUnorm4x8:
1625 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001626 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001627 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001628 break;
1629 case EOpLength:
1630 outputTriplet(out, visit, "length(", "", ")");
1631 break;
1632 case EOpNormalize:
1633 outputTriplet(out, visit, "normalize(", "", ")");
1634 break;
1635 case EOpDFdx:
1636 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1637 {
1638 outputTriplet(out, visit, "(", "", ", 0.0)");
1639 }
1640 else
1641 {
1642 outputTriplet(out, visit, "ddx(", "", ")");
1643 }
1644 break;
1645 case EOpDFdy:
1646 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1647 {
1648 outputTriplet(out, visit, "(", "", ", 0.0)");
1649 }
1650 else
1651 {
1652 outputTriplet(out, visit, "ddy(", "", ")");
1653 }
1654 break;
1655 case EOpFwidth:
1656 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1657 {
1658 outputTriplet(out, visit, "(", "", ", 0.0)");
1659 }
1660 else
1661 {
1662 outputTriplet(out, visit, "fwidth(", "", ")");
1663 }
1664 break;
1665 case EOpTranspose:
1666 outputTriplet(out, visit, "transpose(", "", ")");
1667 break;
1668 case EOpDeterminant:
1669 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1670 break;
1671 case EOpInverse:
1672 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001673 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001675
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 case EOpAny:
1677 outputTriplet(out, visit, "any(", "", ")");
1678 break;
1679 case EOpAll:
1680 outputTriplet(out, visit, "all(", "", ")");
1681 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001682 case EOpLogicalNotComponentWise:
1683 outputTriplet(out, visit, "(!", "", ")");
1684 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001685 case EOpBitfieldReverse:
1686 outputTriplet(out, visit, "reversebits(", "", ")");
1687 break;
1688 case EOpBitCount:
1689 outputTriplet(out, visit, "countbits(", "", ")");
1690 break;
1691 case EOpFindLSB:
1692 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1693 // in GLSLTest and results are consistent with GL.
1694 outputTriplet(out, visit, "firstbitlow(", "", ")");
1695 break;
1696 case EOpFindMSB:
1697 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1698 // tested in GLSLTest and results are consistent with GL.
1699 outputTriplet(out, visit, "firstbithigh(", "", ")");
1700 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001701 default:
1702 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001703 }
1704
1705 return true;
1706}
1707
Olli Etuahofbb1c792018-01-19 16:26:59 +02001708ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001709{
1710 if (node->getAsSymbolNode())
1711 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001712 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1713 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001714 }
1715 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1716 switch (nodeBinary->getOp())
1717 {
1718 case EOpIndexDirect:
1719 {
1720 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1721
Olli Etuahofbb1c792018-01-19 16:26:59 +02001722 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001723 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001724 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001725 }
1726 case EOpIndexDirectStruct:
1727 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001728 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001729 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1730 const TField *field = s->fields()[index];
1731
Olli Etuahofbb1c792018-01-19 16:26:59 +02001732 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001733 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1734 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001735 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001736 }
1737 default:
1738 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001739 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001740 }
1741}
1742
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001743bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1744{
1745 TInfoSinkBase &out = getInfoSink();
1746
1747 if (mInsideFunction)
1748 {
1749 outputLineDirective(out, node->getLine().first_line);
1750 out << "{\n";
1751 }
1752
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001753 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001754 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001755 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001756
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001757 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001758
1759 // Don't output ; after case labels, they're terminated by :
1760 // This is needed especially since outputting a ; after a case statement would turn empty
1761 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001762 // Also the output code is clearer if we don't output ; after statements where it is not
1763 // needed:
1764 // * if statements
1765 // * switch statements
1766 // * blocks
1767 // * function definitions
1768 // * loops (do-while loops output the semicolon in VisitLoop)
1769 // * declarations that don't generate output.
1770 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1771 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1772 statement->getAsSwitchNode() == nullptr &&
1773 statement->getAsFunctionDefinition() == nullptr &&
1774 (statement->getAsDeclarationNode() == nullptr ||
1775 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1776 statement->getAsInvariantDeclarationNode() == nullptr)
1777 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001778 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001779 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001780 }
1781
1782 if (mInsideFunction)
1783 {
1784 outputLineDirective(out, node->getLine().last_line);
1785 out << "}\n";
1786 }
1787
1788 return false;
1789}
1790
Olli Etuaho336b1472016-10-05 16:37:55 +01001791bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1792{
1793 TInfoSinkBase &out = getInfoSink();
1794
1795 ASSERT(mCurrentFunctionMetadata == nullptr);
1796
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001797 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001798 ASSERT(index != CallDAG::InvalidIndex);
1799 mCurrentFunctionMetadata = &mASTMetadataList[index];
1800
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001801 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001802
Olli Etuahod4bd9632018-03-08 16:32:44 +02001803 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001804
Olli Etuahod4bd9632018-03-08 16:32:44 +02001805 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001806 {
1807 out << "gl_main(";
1808 }
1809 else
1810 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001811 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001812 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001813 }
1814
Olli Etuahod4bd9632018-03-08 16:32:44 +02001815 size_t paramCount = func->getParamCount();
1816 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001817 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001818 const TVariable *param = func->getParam(i);
1819 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001820
Olli Etuahod4bd9632018-03-08 16:32:44 +02001821 writeParameter(param, out);
1822
1823 if (i < paramCount - 1)
Olli Etuaho336b1472016-10-05 16:37:55 +01001824 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001825 out << ", ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001826 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001827 }
1828
1829 out << ")\n";
1830
1831 mInsideFunction = true;
1832 // The function body node will output braces.
1833 node->getBody()->traverse(this);
1834 mInsideFunction = false;
1835
1836 mCurrentFunctionMetadata = nullptr;
1837
1838 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1839 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1840 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001841 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001842 mOutputLod0Function = true;
1843 node->traverse(this);
1844 mOutputLod0Function = false;
1845 }
1846
1847 return false;
1848}
1849
Olli Etuaho13389b62016-10-16 11:48:18 +01001850bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1851{
Olli Etuaho13389b62016-10-16 11:48:18 +01001852 if (visit == PreVisit)
1853 {
1854 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001855 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001856 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001857 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001858
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001859 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001860 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001861 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001862 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001863
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001864 if (!declarator->getAsSymbolNode() ||
1865 declarator->getAsSymbolNode()->variable().symbolType() !=
1866 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001867 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001868 if (declarator->getQualifier() == EvqShared)
1869 {
1870 out << "groupshared ";
1871 }
1872 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001873 {
1874 out << "static ";
1875 }
1876
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001877 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001878
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001879 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001880
1881 if (symbol)
1882 {
1883 symbol->traverse(this);
1884 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001885 // We don't initialize shared variables because:
1886 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1887 // code to initialize a groupshared array variable with a large array size.
1888 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1889 // allow initializing shared variables at all.
1890 if (declarator->getQualifier() != EvqShared)
1891 {
1892 out << " = " + zeroInitializer(symbol->getType());
1893 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001894 }
1895 else
1896 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001897 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001898 }
1899 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001900 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001901 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001902 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001903 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001904 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001905
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001906 const TVariable &variable = symbol->variable();
1907
1908 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001909 {
1910 // Vertex outputs which are declared but not written to should still be declared to
1911 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001912 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001913 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001914 }
1915 }
1916 return false;
1917}
1918
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001919bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1920{
1921 // Do not do any translation
1922 return false;
1923}
1924
Olli Etuahod4bd9632018-03-08 16:32:44 +02001925void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001926{
1927 TInfoSinkBase &out = getInfoSink();
1928
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001929 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001930 // Skip the prototype if it is not implemented (and thus not used)
1931 if (index == CallDAG::InvalidIndex)
1932 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001933 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00001934 }
1935
Olli Etuahod4bd9632018-03-08 16:32:44 +02001936 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00001937
Olli Etuahod4bd9632018-03-08 16:32:44 +02001938 TString name = DecorateFunctionIfNeeded(func);
1939 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001940 << (mOutputLod0Function ? "Lod0(" : "(");
1941
Olli Etuahod4bd9632018-03-08 16:32:44 +02001942 size_t paramCount = func->getParamCount();
1943 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001944 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001945 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00001946
Olli Etuahod4bd9632018-03-08 16:32:44 +02001947 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001948 {
1949 out << ", ";
1950 }
1951 }
1952
1953 out << ");\n";
1954
1955 // Also prototype the Lod0 variant if needed
1956 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1957 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1958 {
1959 mOutputLod0Function = true;
1960 node->traverse(this);
1961 mOutputLod0Function = false;
1962 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00001963}
1964
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001965bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1966{
Jamie Madill32aab012015-01-27 14:12:26 -05001967 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001968
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001969 switch (node->getOp())
1970 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001971 case EOpCallBuiltInFunction:
1972 case EOpCallFunctionInAST:
1973 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001974 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001975 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001976
Corentin Wallez1239ee92015-03-19 14:38:02 -07001977 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001978 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001979 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001980 if (node->isArray())
1981 {
1982 UNIMPLEMENTED();
1983 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001984 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001985 ASSERT(index != CallDAG::InvalidIndex);
1986 lod0 &= mASTMetadataList[index].mNeedsLod0;
1987
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001988 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001989 out << DisambiguateFunctionName(node->getSequence());
1990 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001991 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001992 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001993 {
1994 // This path is used for internal functions that don't have their definitions in the
1995 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001996 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001997 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001998 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08001999 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002000 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002001 TType type = (*arguments)[0]->getAsTyped()->getType();
2002 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002003 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002004 type.getMemoryQualifier().readonly);
2005 out << imageFunctionName << "(";
2006 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002007 else
2008 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002009 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002010 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002011 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2012 if (arguments->size() > 1)
2013 {
2014 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2015 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002016 const ImmutableString &textureFunctionName =
2017 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2018 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002019 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002020 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002021
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002022 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002023 {
Olli Etuaho96963162016-03-21 11:54:33 +02002024 TIntermTyped *typedArg = (*arg)->getAsTyped();
2025 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002026 {
2027 out << "texture_";
2028 (*arg)->traverse(this);
2029 out << ", sampler_";
2030 }
2031
2032 (*arg)->traverse(this);
2033
Olli Etuaho96963162016-03-21 11:54:33 +02002034 if (typedArg->getType().isStructureContainingSamplers())
2035 {
2036 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002037 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002038 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2039 std::string namePrefix = "angle_";
2040 namePrefix += structName.data();
2041 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002042 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002043 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002044 {
2045 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2046 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002047 out << ", texture_" << sampler->name();
2048 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002049 }
2050 else
2051 {
2052 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2053 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002054 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002055 }
2056 }
2057 }
2058
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002059 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002060 {
2061 out << ", ";
2062 }
2063 }
2064
2065 out << ")";
2066
2067 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002068 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002069 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002070 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002071 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002072 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002073 outputTriplet(out, visit, "(", " == ", ")");
2074 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002075 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002076 outputTriplet(out, visit, "(", " != ", ")");
2077 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002078 case EOpLessThanComponentWise:
2079 outputTriplet(out, visit, "(", " < ", ")");
2080 break;
2081 case EOpGreaterThanComponentWise:
2082 outputTriplet(out, visit, "(", " > ", ")");
2083 break;
2084 case EOpLessThanEqualComponentWise:
2085 outputTriplet(out, visit, "(", " <= ", ")");
2086 break;
2087 case EOpGreaterThanEqualComponentWise:
2088 outputTriplet(out, visit, "(", " >= ", ")");
2089 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002090 case EOpMod:
2091 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002092 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002093 break;
2094 case EOpModf:
2095 outputTriplet(out, visit, "modf(", ", ", ")");
2096 break;
2097 case EOpPow:
2098 outputTriplet(out, visit, "pow(", ", ", ")");
2099 break;
2100 case EOpAtan:
2101 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2102 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002103 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002104 break;
2105 case EOpMin:
2106 outputTriplet(out, visit, "min(", ", ", ")");
2107 break;
2108 case EOpMax:
2109 outputTriplet(out, visit, "max(", ", ", ")");
2110 break;
2111 case EOpClamp:
2112 outputTriplet(out, visit, "clamp(", ", ", ")");
2113 break;
2114 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302115 {
2116 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2117 if (lastParamNode->getType().getBasicType() == EbtBool)
2118 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002119 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2120 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302121 // so use emulated version.
2122 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002123 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302124 }
2125 else
2126 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002127 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302128 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002129 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302130 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002131 case EOpStep:
2132 outputTriplet(out, visit, "step(", ", ", ")");
2133 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002134 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002135 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2136 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002137 case EOpFrexp:
2138 case EOpLdexp:
2139 ASSERT(node->getUseEmulatedFunction());
2140 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2141 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002142 case EOpDistance:
2143 outputTriplet(out, visit, "distance(", ", ", ")");
2144 break;
2145 case EOpDot:
2146 outputTriplet(out, visit, "dot(", ", ", ")");
2147 break;
2148 case EOpCross:
2149 outputTriplet(out, visit, "cross(", ", ", ")");
2150 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002151 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002152 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002153 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002154 break;
2155 case EOpReflect:
2156 outputTriplet(out, visit, "reflect(", ", ", ")");
2157 break;
2158 case EOpRefract:
2159 outputTriplet(out, visit, "refract(", ", ", ")");
2160 break;
2161 case EOpOuterProduct:
2162 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002163 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002164 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002165 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002166 outputTriplet(out, visit, "(", " * ", ")");
2167 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002168 case EOpBitfieldExtract:
2169 case EOpBitfieldInsert:
2170 case EOpUaddCarry:
2171 case EOpUsubBorrow:
2172 case EOpUmulExtended:
2173 case EOpImulExtended:
2174 ASSERT(node->getUseEmulatedFunction());
2175 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2176 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002177 case EOpBarrier:
2178 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2179 // cheapest *WithGroupSync() function, without any functionality loss, but
2180 // with the potential for severe performance loss.
2181 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2182 break;
2183 case EOpMemoryBarrierShared:
2184 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2185 break;
2186 case EOpMemoryBarrierAtomicCounter:
2187 case EOpMemoryBarrierBuffer:
2188 case EOpMemoryBarrierImage:
2189 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2190 break;
2191 case EOpGroupMemoryBarrier:
2192 case EOpMemoryBarrier:
2193 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2194 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002195
2196 // Single atomic function calls without return value.
2197 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2198 case EOpAtomicAdd:
2199 case EOpAtomicMin:
2200 case EOpAtomicMax:
2201 case EOpAtomicAnd:
2202 case EOpAtomicOr:
2203 case EOpAtomicXor:
2204 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2205 ",", ")");
2206 break;
2207
2208 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2209 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2210 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2211 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2212 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2213 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2214 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2215 // intermediate tree before traversing outputHLSL.
2216 case EOpAtomicExchange:
2217 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002218 default:
2219 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002220 }
2221
2222 return true;
2223}
2224
Olli Etuaho57961272016-09-14 13:57:46 +03002225void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002226{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002227 out << "if (";
2228
2229 node->getCondition()->traverse(this);
2230
2231 out << ")\n";
2232
Jamie Madill8c46ab12015-12-07 16:39:19 -05002233 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002234
2235 bool discard = false;
2236
2237 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002239 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002240 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002241
Olli Etuahoa6f22092015-05-08 18:31:10 +03002242 // Detect true discard
2243 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2244 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002245 else
2246 {
2247 // TODO(oetuaho): Check if the semicolon inside is necessary.
2248 // It's there as a result of conservative refactoring of the output.
2249 out << "{;}\n";
2250 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002251
Jamie Madill8c46ab12015-12-07 16:39:19 -05002252 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002253
Olli Etuahoa6f22092015-05-08 18:31:10 +03002254 if (node->getFalseBlock())
2255 {
2256 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002257
Jamie Madill8c46ab12015-12-07 16:39:19 -05002258 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002259
Olli Etuaho32db19b2016-10-04 14:43:16 +01002260 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002261 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002262
Jamie Madill8c46ab12015-12-07 16:39:19 -05002263 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002264
Olli Etuahoa6f22092015-05-08 18:31:10 +03002265 // Detect false discard
2266 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2267 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002268
Olli Etuahoa6f22092015-05-08 18:31:10 +03002269 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002270 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002271 {
2272 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002273 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002274}
2275
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002276bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2277{
2278 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2279 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2280 UNREACHABLE();
2281 return false;
2282}
2283
Olli Etuaho57961272016-09-14 13:57:46 +03002284bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002285{
2286 TInfoSinkBase &out = getInfoSink();
2287
Olli Etuaho3d932d82016-04-12 11:10:30 +03002288 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002289
2290 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002291 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002292 {
2293 out << "FLATTEN ";
2294 }
2295
Olli Etuaho57961272016-09-14 13:57:46 +03002296 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002297
2298 return false;
2299}
2300
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002301bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002302{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002303 TInfoSinkBase &out = getInfoSink();
2304
Olli Etuaho923ecef2017-10-11 12:01:38 +03002305 ASSERT(node->getStatementList());
2306 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002307 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002308 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002309 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002310 outputTriplet(out, visit, "switch (", ") ", "");
2311 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002312 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002313}
2314
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002315bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002316{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002317 TInfoSinkBase &out = getInfoSink();
2318
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002319 if (node->hasCondition())
2320 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002321 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002322 return true;
2323 }
2324 else
2325 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002326 out << "default:\n";
2327 return false;
2328 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002329}
2330
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002331void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2332{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002333 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002334 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002335}
2336
2337bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2338{
Nicolas Capens655fe362014-04-11 13:12:34 -04002339 mNestedLoopDepth++;
2340
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002341 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002342 mInsideDiscontinuousLoop =
2343 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002344
Jamie Madill8c46ab12015-12-07 16:39:19 -05002345 TInfoSinkBase &out = getInfoSink();
2346
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002347 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002348 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002349 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002350 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002351 mInsideDiscontinuousLoop = wasDiscontinuous;
2352 mNestedLoopDepth--;
2353
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002354 return false;
2355 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002356 }
2357
Corentin Wallez1239ee92015-03-19 14:38:02 -07002358 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002359 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002360 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002361 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002362
Jamie Madill8c46ab12015-12-07 16:39:19 -05002363 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002364 }
2365 else
2366 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002367 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002368
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002369 if (node->getInit())
2370 {
2371 node->getInit()->traverse(this);
2372 }
2373
2374 out << "; ";
2375
alokp@chromium.org52813552010-11-16 18:36:09 +00002376 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002377 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002378 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002379 }
2380
2381 out << "; ";
2382
alokp@chromium.org52813552010-11-16 18:36:09 +00002383 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002384 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002385 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002386 }
2387
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002388 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002389
Jamie Madill8c46ab12015-12-07 16:39:19 -05002390 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002391 }
2392
2393 if (node->getBody())
2394 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002395 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002396 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002397 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002398 else
2399 {
2400 // TODO(oetuaho): Check if the semicolon inside is necessary.
2401 // It's there as a result of conservative refactoring of the output.
2402 out << "{;}\n";
2403 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404
Jamie Madill8c46ab12015-12-07 16:39:19 -05002405 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002406
alokp@chromium.org52813552010-11-16 18:36:09 +00002407 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002408 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002409 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002410 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002411
alokp@chromium.org52813552010-11-16 18:36:09 +00002412 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002413
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002414 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002415 }
2416
daniel@transgaming.com73536982012-03-21 20:45:49 +00002417 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002418
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002419 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002420 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002421
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002422 return false;
2423}
2424
2425bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2426{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002427 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002429 TInfoSinkBase &out = getInfoSink();
2430
2431 switch (node->getFlowOp())
2432 {
2433 case EOpKill:
2434 out << "discard";
2435 break;
2436 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002437 if (mNestedLoopDepth > 1)
2438 {
2439 mUsesNestedBreak = true;
2440 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002441
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002442 if (mExcessiveLoopIndex)
2443 {
2444 out << "{Break";
2445 mExcessiveLoopIndex->traverse(this);
2446 out << " = true; break;}\n";
2447 }
2448 else
2449 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002450 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002451 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002452 break;
2453 case EOpContinue:
2454 out << "continue";
2455 break;
2456 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002457 if (node->getExpression())
2458 {
2459 out << "return ";
2460 }
2461 else
2462 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002463 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002464 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002465 break;
2466 default:
2467 UNREACHABLE();
2468 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002469 }
2470
2471 return true;
2472}
2473
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002474// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002475// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2476// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002477bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002478{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002479 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002480
2481 // Parse loops of the form:
2482 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002483 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002484 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002485 int initial = 0;
2486 int limit = 0;
2487 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002488
2489 // Parse index name and intial value
2490 if (node->getInit())
2491 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002492 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002493
2494 if (init)
2495 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002496 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002497 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498
2499 if (variable && variable->getQualifier() == EvqTemporary)
2500 {
2501 TIntermBinary *assign = variable->getAsBinaryNode();
2502
2503 if (assign->getOp() == EOpInitialize)
2504 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002505 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002506 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2507
2508 if (symbol && constant)
2509 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002510 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002511 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002512 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002513 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002514 }
2515 }
2516 }
2517 }
2518 }
2519 }
2520
2521 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002522 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002523 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002524 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002525
Olli Etuahob6af22b2017-12-15 14:05:44 +02002526 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002527 {
2528 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2529
2530 if (constant)
2531 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002532 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533 {
2534 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002535 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002536 }
2537 }
2538 }
2539 }
2540
2541 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002542 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002543 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002544 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002545 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002546
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002547 if (binaryTerminal)
2548 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002549 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002550 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2551
2552 if (constant)
2553 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002554 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002555 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002556 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002557
2558 switch (op)
2559 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002560 case EOpAddAssign:
2561 increment = value;
2562 break;
2563 case EOpSubAssign:
2564 increment = -value;
2565 break;
2566 default:
2567 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002568 }
2569 }
2570 }
2571 }
2572 else if (unaryTerminal)
2573 {
2574 TOperator op = unaryTerminal->getOp();
2575
2576 switch (op)
2577 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002578 case EOpPostIncrement:
2579 increment = 1;
2580 break;
2581 case EOpPostDecrement:
2582 increment = -1;
2583 break;
2584 case EOpPreIncrement:
2585 increment = 1;
2586 break;
2587 case EOpPreDecrement:
2588 increment = -1;
2589 break;
2590 default:
2591 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002592 }
2593 }
2594 }
2595
Yunchao He4f285442017-04-21 12:15:49 +08002596 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002597 {
2598 if (comparator == EOpLessThanEqual)
2599 {
2600 comparator = EOpLessThan;
2601 limit += 1;
2602 }
2603
2604 if (comparator == EOpLessThan)
2605 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002606 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002607
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002608 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002609 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002610 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002611 }
2612
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002613 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002614 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002615
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002616 out << "{int ";
2617 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002618 out << ";\n"
2619 "bool Break";
2620 index->traverse(this);
2621 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002622
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002623 bool firstLoopFragment = true;
2624
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002625 while (iterations > 0)
2626 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002627 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002628
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002629 if (!firstLoopFragment)
2630 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002631 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002632 index->traverse(this);
2633 out << ") {\n";
2634 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002635
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002636 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002637 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002638 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002639 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002640
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002641 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002642 const char *unroll =
2643 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002644
Corentin Wallez1239ee92015-03-19 14:38:02 -07002645 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002646 index->traverse(this);
2647 out << " = ";
2648 out << initial;
2649
2650 out << "; ";
2651 index->traverse(this);
2652 out << " < ";
2653 out << clampedLimit;
2654
2655 out << "; ";
2656 index->traverse(this);
2657 out << " += ";
2658 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002659 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002660
Jamie Madill8c46ab12015-12-07 16:39:19 -05002661 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002662 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002663
2664 if (node->getBody())
2665 {
2666 node->getBody()->traverse(this);
2667 }
2668
Jamie Madill8c46ab12015-12-07 16:39:19 -05002669 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002670 out << ";}\n";
2671
2672 if (!firstLoopFragment)
2673 {
2674 out << "}\n";
2675 }
2676
2677 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002678
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002679 initial += MAX_LOOP_ITERATIONS * increment;
2680 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002681 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002682
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002683 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002684
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002685 mExcessiveLoopIndex = restoreIndex;
2686
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002687 return true;
2688 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002689 else
2690 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002691 }
2692
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002693 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002694}
2695
Jamie Madill8c46ab12015-12-07 16:39:19 -05002696void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2697 Visit visit,
2698 const char *preString,
2699 const char *inString,
2700 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002701{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002702 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002703 {
2704 out << preString;
2705 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002706 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002707 {
2708 out << inString;
2709 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002710 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002711 {
2712 out << postString;
2713 }
2714}
2715
Jamie Madill8c46ab12015-12-07 16:39:19 -05002716void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002717{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002718 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002719 {
Jamie Madill32aab012015-01-27 14:12:26 -05002720 out << "\n";
2721 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002722
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002723 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002724 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002725 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002726 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002727
Jamie Madill32aab012015-01-27 14:12:26 -05002728 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002729 }
2730}
2731
Olli Etuahod4bd9632018-03-08 16:32:44 +02002732void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002733{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002734 const TType &type = param->getType();
2735 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002736
Olli Etuahod4bd9632018-03-08 16:32:44 +02002737 TString nameStr = DecorateVariableIfNeeded(*param);
2738 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002739
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002740 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002741 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002742 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2743 {
2744 // Samplers are passed as indices to the sampler array.
2745 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002746 out << "const uint " << nameStr << ArrayString(type);
2747 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002748 }
2749 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2750 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002751 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2752 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2753 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2754 << ArrayString(type);
2755 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002756 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002757 }
2758
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002759 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2760 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002761
2762 // If the structure parameter contains samplers, they need to be passed into the function as
2763 // separate parameters. HLSL doesn't natively support samplers in structs.
2764 if (type.isStructureContainingSamplers())
2765 {
2766 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002767 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002768 std::string namePrefix = "angle";
2769 namePrefix += nameStr.c_str();
2770 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2771 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002772 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002773 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002774 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002775 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2776 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002777 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002778 }
2779 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2780 {
Olli Etuaho96963162016-03-21 11:54:33 +02002781 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002782 out << ", " << QualifierString(qualifier) << " "
2783 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2784 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2785 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2786 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002787 }
2788 else
2789 {
Olli Etuaho96963162016-03-21 11:54:33 +02002790 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002791 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2792 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002793 }
2794 }
2795 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002796}
2797
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002798TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002799{
2800 TString string;
2801
Jamie Madill94bf7f22013-07-08 13:31:15 -04002802 size_t size = type.getObjectSize();
2803 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002804 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002805 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002806
Jamie Madill94bf7f22013-07-08 13:31:15 -04002807 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002808 {
2809 string += ", ";
2810 }
2811 }
2812
daniel@transgaming.comead23042010-04-29 03:35:36 +00002813 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002814}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002815
Olli Etuahobd3cd502017-11-03 15:48:52 +02002816void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002817{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002818 // Array constructors should have been already pruned from the code.
2819 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002820
2821 if (visit == PreVisit)
2822 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002823 TString constructorName;
2824 if (node->getBasicType() == EbtStruct)
2825 {
2826 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2827 }
2828 else
2829 {
2830 constructorName =
2831 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2832 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002833 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002834 }
2835 else if (visit == InVisit)
2836 {
2837 out << ", ";
2838 }
2839 else if (visit == PostVisit)
2840 {
2841 out << ")";
2842 }
2843}
2844
Jamie Madill8c46ab12015-12-07 16:39:19 -05002845const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2846 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002847 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002848{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002849 ASSERT(!type.isArray());
2850
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002851 const TConstantUnion *constUnionIterated = constUnion;
2852
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002853 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002854 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002855 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002856 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002857
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002858 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002859
Jamie Madill98493dd2013-07-08 14:39:03 -04002860 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002861 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002862 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002863 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002864
Jamie Madill98493dd2013-07-08 14:39:03 -04002865 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002866 {
2867 out << ", ";
2868 }
2869 }
2870
2871 out << ")";
2872 }
2873 else
2874 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002875 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002876 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002877
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002878 if (writeType)
2879 {
Jamie Madill033dae62014-06-18 12:56:28 -04002880 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002881 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002882 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002883 if (writeType)
2884 {
2885 out << ")";
2886 }
2887 }
2888
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002889 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002890}
2891
Olli Etuahod68924e2017-01-02 17:34:40 +00002892void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002893{
Olli Etuahod68924e2017-01-02 17:34:40 +00002894 if (visit == PreVisit)
2895 {
2896 const char *opStr = GetOperatorString(op);
2897 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2898 out << "(";
2899 }
2900 else
2901 {
2902 outputTriplet(out, visit, nullptr, ", ", ")");
2903 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002904}
2905
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002906bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2907 TIntermSymbol *symbolNode,
2908 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002909{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002910 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2911 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002912
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002913 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002914 {
2915 // Type already printed
2916 out << "t" + str(mUniqueIndex) + " = ";
2917 expression->traverse(this);
2918 out << ", ";
2919 symbolNode->traverse(this);
2920 out << " = t" + str(mUniqueIndex);
2921
2922 mUniqueIndex++;
2923 return true;
2924 }
2925
2926 return false;
2927}
2928
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002929bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2930 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002931 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002932{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002933 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002934 {
2935 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002936 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002937 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002938 writeConstantUnionArray(out, initializer->getConstantValue(),
2939 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002940 out << "}";
2941 return true;
2942 }
2943 return false;
2944}
2945
Jamie Madill55e79e02015-02-09 15:35:00 -05002946TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2947{
2948 const TFieldList &fields = structure.fields();
2949
2950 for (const auto &eqFunction : mStructEqualityFunctions)
2951 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002952 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002953 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002954 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002955 }
2956 }
2957
2958 const TString &structNameString = StructNameString(structure);
2959
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002960 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002961 function->structure = &structure;
2962 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002963
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002964 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002965
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002966 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2967 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002968 << "{\n"
2969 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002970
2971 for (size_t i = 0; i < fields.size(); i++)
2972 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002973 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002974 const TType *fieldType = field->type();
2975
2976 const TString &fieldNameA = "a." + Decorate(field->name());
2977 const TString &fieldNameB = "b." + Decorate(field->name());
2978
2979 if (i > 0)
2980 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002981 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002982 }
2983
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002984 fnOut << "(";
2985 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2986 fnOut << fieldNameA;
2987 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2988 fnOut << fieldNameB;
2989 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2990 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002991 }
2992
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002993 fnOut << ";\n"
2994 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002995
2996 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002997
2998 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002999 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003000
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003001 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003002}
3003
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003004TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003005{
3006 for (const auto &eqFunction : mArrayEqualityFunctions)
3007 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003008 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003009 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003010 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003011 }
3012 }
3013
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003014 TType elementType(type);
3015 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003016
Olli Etuaho12690762015-03-31 12:55:28 +03003017 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003018 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003019
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003020 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003021
3022 TInfoSinkBase fnOut;
3023
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003024 const TString &typeName = TypeString(type);
3025 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3026 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003027 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003028 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003029 << type.getOutermostArraySize()
3030 << "; ++i)\n"
3031 " {\n"
3032 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003033
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003034 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003035 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003036 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003037 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003038 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003039
3040 fnOut << ") { return false; }\n"
3041 " }\n"
3042 " return true;\n"
3043 "}\n";
3044
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003045 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003046
3047 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003048 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003049
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003050 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003051}
3052
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003053TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003054{
3055 for (const auto &assignFunction : mArrayAssignmentFunctions)
3056 {
3057 if (assignFunction.type == type)
3058 {
3059 return assignFunction.functionName;
3060 }
3061 }
3062
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003063 TType elementType(type);
3064 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003065
3066 ArrayHelperFunction function;
3067 function.type = type;
3068
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003069 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003070
3071 TInfoSinkBase fnOut;
3072
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003073 const TString &typeName = TypeString(type);
3074 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3075 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003076 << "{\n"
3077 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003078 << type.getOutermostArraySize()
3079 << "; ++i)\n"
3080 " {\n"
3081 " ";
3082
3083 outputAssign(PreVisit, elementType, fnOut);
3084 fnOut << "a[i]";
3085 outputAssign(InVisit, elementType, fnOut);
3086 fnOut << "b[i]";
3087 outputAssign(PostVisit, elementType, fnOut);
3088
3089 fnOut << ";\n"
3090 " }\n"
3091 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003092
3093 function.functionDefinition = fnOut.c_str();
3094
3095 mArrayAssignmentFunctions.push_back(function);
3096
3097 return function.functionName;
3098}
3099
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003100TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003101{
3102 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3103 {
3104 if (constructIntoFunction.type == type)
3105 {
3106 return constructIntoFunction.functionName;
3107 }
3108 }
3109
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003110 TType elementType(type);
3111 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003112
3113 ArrayHelperFunction function;
3114 function.type = type;
3115
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003116 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003117
3118 TInfoSinkBase fnOut;
3119
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003120 const TString &typeName = TypeString(type);
3121 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3122 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003123 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003124 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003125 }
3126 fnOut << ")\n"
3127 "{\n";
3128
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003129 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003130 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003131 fnOut << " ";
3132 outputAssign(PreVisit, elementType, fnOut);
3133 fnOut << "a[" << i << "]";
3134 outputAssign(InVisit, elementType, fnOut);
3135 fnOut << "b" << i;
3136 outputAssign(PostVisit, elementType, fnOut);
3137 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003138 }
3139 fnOut << "}\n";
3140
3141 function.functionDefinition = fnOut.c_str();
3142
3143 mArrayConstructIntoFunctions.push_back(function);
3144
3145 return function.functionName;
3146}
3147
Jamie Madill2e295e22015-04-29 10:41:33 -04003148void OutputHLSL::ensureStructDefined(const TType &type)
3149{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003150 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003151 if (structure)
3152 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003153 ASSERT(type.getBasicType() == EbtStruct);
3154 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003155 }
3156}
3157
Jamie Madill45bcc782016-11-07 13:58:48 -05003158} // namespace sh