blob: 5e8e2cb59a8e2e387003db8bb6fdbfbfc9bcc4ad [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();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000456
457 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300458 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300459 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
460 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000461 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300462}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000463
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300464void OutputHLSL::header(TInfoSinkBase &out,
465 const std::vector<MappedStruct> &std140Structs,
466 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
467{
468 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000469
Jamie Madill8daaba12014-06-13 10:04:33 -0400470 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400471
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300472 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800473 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400474
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200475 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500476 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200477 out << "\n// Equality functions\n\n";
478 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500479 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200480 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200481 }
482 }
Olli Etuaho12690762015-03-31 12:55:28 +0300483 if (!mArrayAssignmentFunctions.empty())
484 {
485 out << "\n// Assignment functions\n\n";
486 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
487 {
488 out << assignmentFunction.functionDefinition << "\n";
489 }
490 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300491 if (!mArrayConstructIntoFunctions.empty())
492 {
493 out << "\n// Array constructor functions\n\n";
494 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
495 {
496 out << constructIntoFunction.functionDefinition << "\n";
497 }
498 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200499
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500500 if (mUsesDiscardRewriting)
501 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400502 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500503 }
504
Nicolas Capens655fe362014-04-11 13:12:34 -0400505 if (mUsesNestedBreak)
506 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400507 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400508 }
509
Arun Patole44efa0b2015-03-04 17:11:05 +0530510 if (mRequiresIEEEStrictCompiling)
511 {
512 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
513 }
514
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400515 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
516 "#define LOOP [loop]\n"
517 "#define FLATTEN [flatten]\n"
518 "#else\n"
519 "#define LOOP\n"
520 "#define FLATTEN\n"
521 "#endif\n";
522
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200523 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300525 const bool usingMRTExtension =
526 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000527
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000528 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300529 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400530 out << "\n";
531
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200532 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000533 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200534 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000535 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200536 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800537 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400538
Olli Etuahofbb1c792018-01-19 16:26:59 +0200539 out << "static " << TypeString(variableType) << " out_" << variableName
540 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000541 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000542 }
Jamie Madill46131a32013-06-20 11:55:50 -0400543 else
544 {
545 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
546
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800547 out << "static float4 gl_Color[" << numColorValues
548 << "] =\n"
549 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400550 for (unsigned int i = 0; i < numColorValues; i++)
551 {
552 out << " float4(0, 0, 0, 0)";
553 if (i + 1 != numColorValues)
554 {
555 out << ",";
556 }
557 out << "\n";
558 }
559
560 out << "};\n";
561 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000562
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400563 if (mUsesFragDepth)
564 {
565 out << "static float gl_Depth = 0.0;\n";
566 }
567
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000568 if (mUsesFragCoord)
569 {
570 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
571 }
572
573 if (mUsesPointCoord)
574 {
575 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
576 }
577
578 if (mUsesFrontFacing)
579 {
580 out << "static bool gl_FrontFacing = false;\n";
581 }
582
583 out << "\n";
584
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000585 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000586 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000587 out << "struct gl_DepthRangeParameters\n"
588 "{\n"
589 " float near;\n"
590 " float far;\n"
591 " float diff;\n"
592 "};\n"
593 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000594 }
595
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200596 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000597 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000598 out << "cbuffer DriverConstants : register(b1)\n"
599 "{\n";
600
601 if (mUsesDepthRange)
602 {
603 out << " float3 dx_DepthRange : packoffset(c0);\n";
604 }
605
606 if (mUsesFragCoord)
607 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000608 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000609 }
610
611 if (mUsesFragCoord || mUsesFrontFacing)
612 {
613 out << " float3 dx_DepthFront : packoffset(c2);\n";
614 }
615
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800616 if (mUsesFragCoord)
617 {
618 // dx_ViewScale is only used in the fragment shader to correct
619 // the value for glFragCoord if necessary
620 out << " float2 dx_ViewScale : packoffset(c3);\n";
621 }
622
Martin Radev72b4e1e2017-08-31 15:42:56 +0300623 if (mHasMultiviewExtensionEnabled)
624 {
625 // We have to add a value which we can use to keep track of which multi-view code
626 // path is to be selected in the GS.
627 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
628 }
629
Olli Etuaho618bebc2016-01-15 16:40:00 +0200630 if (mOutputType == SH_HLSL_4_1_OUTPUT)
631 {
632 mUniformHLSL->samplerMetadataUniforms(out, "c4");
633 }
634
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000635 out << "};\n";
636 }
637 else
638 {
639 if (mUsesDepthRange)
640 {
641 out << "uniform float3 dx_DepthRange : register(c0);";
642 }
643
644 if (mUsesFragCoord)
645 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000646 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000647 }
648
649 if (mUsesFragCoord || mUsesFrontFacing)
650 {
651 out << "uniform float3 dx_DepthFront : register(c2);\n";
652 }
653 }
654
655 out << "\n";
656
657 if (mUsesDepthRange)
658 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500659 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
660 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000661 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000662 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000663
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000664 if (usingMRTExtension && mNumRenderTargets > 1)
665 {
666 out << "#define GL_USES_MRT\n";
667 }
668
669 if (mUsesFragColor)
670 {
671 out << "#define GL_USES_FRAG_COLOR\n";
672 }
673
674 if (mUsesFragData)
675 {
676 out << "#define GL_USES_FRAG_DATA\n";
677 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678 }
Xinghua Caob1239382016-12-13 15:07:05 +0800679 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000681 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300682 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000683 out << "\n"
684 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400685
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000686 if (mUsesPointSize)
687 {
688 out << "static float gl_PointSize = float(1);\n";
689 }
690
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000691 if (mUsesInstanceID)
692 {
693 out << "static int gl_InstanceID;";
694 }
695
Corentin Wallezb076add2016-01-11 16:45:46 -0500696 if (mUsesVertexID)
697 {
698 out << "static int gl_VertexID;";
699 }
700
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000701 out << "\n"
702 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300703 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000704 out << "\n";
705
706 if (mUsesDepthRange)
707 {
708 out << "struct gl_DepthRangeParameters\n"
709 "{\n"
710 " float near;\n"
711 " float far;\n"
712 " float diff;\n"
713 "};\n"
714 "\n";
715 }
716
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200717 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000718 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800719 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500720 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800721
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000722 if (mUsesDepthRange)
723 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800724 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000725 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800726
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800727 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
728 // shaders. However, we declare it for all shaders (including Feature Level 10+).
729 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
730 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800731 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800732 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800733 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800734
Martin Radev72b4e1e2017-08-31 15:42:56 +0300735 if (mHasMultiviewExtensionEnabled)
736 {
737 // We have to add a value which we can use to keep track of which multi-view code
738 // path is to be selected in the GS.
739 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
740 }
741
Olli Etuaho618bebc2016-01-15 16:40:00 +0200742 if (mOutputType == SH_HLSL_4_1_OUTPUT)
743 {
744 mUniformHLSL->samplerMetadataUniforms(out, "c4");
745 }
746
Austin Kinross4fd18b12014-12-22 12:32:05 -0800747 out << "};\n"
748 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000749 }
750 else
751 {
752 if (mUsesDepthRange)
753 {
754 out << "uniform float3 dx_DepthRange : register(c0);\n";
755 }
756
Cooper Partine6664f02015-01-09 16:22:24 -0800757 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
758 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000759 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000760 }
761
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000762 if (mUsesDepthRange)
763 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
765 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000766 "\n";
767 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400768 }
Xinghua Caob1239382016-12-13 15:07:05 +0800769 else // Compute shader
770 {
771 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800772
773 out << "cbuffer DriverConstants : register(b1)\n"
774 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800775 if (mUsesNumWorkGroups)
776 {
Xinghua Caob1239382016-12-13 15:07:05 +0800777 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800778 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800779 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
780 mUniformHLSL->samplerMetadataUniforms(out, "c1");
781 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800782
783 // Follow built-in variables would be initialized in
784 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
785 // are used in compute shader.
786 if (mUsesWorkGroupID)
787 {
788 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
789 }
790
791 if (mUsesLocalInvocationID)
792 {
793 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
794 }
795
796 if (mUsesGlobalInvocationID)
797 {
798 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
799 }
800
801 if (mUsesLocalInvocationIndex)
802 {
803 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
804 }
805 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000806
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800807 if (!mappedStructs.empty())
808 {
809 out << "// Structures from std140 blocks with padding removed\n";
810 out << "\n";
811 out << mappedStructs;
812 out << "\n";
813 }
814
Geoff Lang1fe74c72016-08-25 13:23:01 -0400815 bool getDimensionsIgnoresBaseLevel =
816 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
817 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800818 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000819
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000820 if (mUsesFragCoord)
821 {
822 out << "#define GL_USES_FRAG_COORD\n";
823 }
824
825 if (mUsesPointCoord)
826 {
827 out << "#define GL_USES_POINT_COORD\n";
828 }
829
830 if (mUsesFrontFacing)
831 {
832 out << "#define GL_USES_FRONT_FACING\n";
833 }
834
835 if (mUsesPointSize)
836 {
837 out << "#define GL_USES_POINT_SIZE\n";
838 }
839
Martin Radev41ac68e2017-06-06 12:16:58 +0300840 if (mHasMultiviewExtensionEnabled)
841 {
842 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
843 }
844
845 if (mUsesViewID)
846 {
847 out << "#define GL_USES_VIEW_ID\n";
848 }
849
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400850 if (mUsesFragDepth)
851 {
852 out << "#define GL_USES_FRAG_DEPTH\n";
853 }
854
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000855 if (mUsesDepthRange)
856 {
857 out << "#define GL_USES_DEPTH_RANGE\n";
858 }
859
Xinghua Caob1239382016-12-13 15:07:05 +0800860 if (mUsesNumWorkGroups)
861 {
862 out << "#define GL_USES_NUM_WORK_GROUPS\n";
863 }
864
865 if (mUsesWorkGroupID)
866 {
867 out << "#define GL_USES_WORK_GROUP_ID\n";
868 }
869
870 if (mUsesLocalInvocationID)
871 {
872 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
873 }
874
875 if (mUsesGlobalInvocationID)
876 {
877 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
878 }
879
880 if (mUsesLocalInvocationIndex)
881 {
882 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
883 }
884
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000885 if (mUsesXor)
886 {
887 out << "bool xor(bool p, bool q)\n"
888 "{\n"
889 " return (p || q) && !(p && q);\n"
890 "}\n"
891 "\n";
892 }
893
Olli Etuahodfa75e82017-01-23 09:43:06 -0800894 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000895}
896
897void OutputHLSL::visitSymbol(TIntermSymbol *node)
898{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200899 const TVariable &variable = node->variable();
900
901 // Empty symbols can only appear in declarations and function arguments, and in either of those
902 // cases the symbol nodes are not visited.
903 ASSERT(variable.symbolType() != SymbolType::Empty);
904
Jamie Madill32aab012015-01-27 14:12:26 -0500905 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906
Jamie Madill570e04d2013-06-21 09:15:33 -0400907 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200908 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400909 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200910 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400911 }
912
Olli Etuahofbb1c792018-01-19 16:26:59 +0200913 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200914 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200915
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000916 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000917 {
918 mUsesDepthRange = true;
919 out << name;
920 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921 else
922 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200923 const TType &variableType = variable.getType();
924 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000925
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200926 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200927
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000928 if (qualifier == EvqUniform)
929 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200930 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400931
932 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000933 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200934 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
935 {
936 const TVariable *instanceVariable = nullptr;
937 if (variableType.isInterfaceBlock())
938 {
939 instanceVariable = &variable;
940 }
941 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
942 new TReferencedBlock(interfaceBlock, instanceVariable);
943 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000944 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000945 else
946 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200947 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000948 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400949
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200950 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000951 }
Jamie Madill19571812013-08-12 15:26:34 -0700952 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000953 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200954 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400955 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000956 }
Jamie Madill033dae62014-06-18 12:56:28 -0400957 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000958 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200959 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +0300960 out << DecorateVariableIfNeeded(variable);
961 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +0300962 {
963 mUsesViewID = true;
964 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000965 }
Jamie Madill19571812013-08-12 15:26:34 -0700966 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400967 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200968 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400969 out << "out_" << name;
970 }
971 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000972 {
973 out << "gl_Color[0]";
974 mUsesFragColor = true;
975 }
976 else if (qualifier == EvqFragData)
977 {
978 out << "gl_Color";
979 mUsesFragData = true;
980 }
981 else if (qualifier == EvqFragCoord)
982 {
983 mUsesFragCoord = true;
984 out << name;
985 }
986 else if (qualifier == EvqPointCoord)
987 {
988 mUsesPointCoord = true;
989 out << name;
990 }
991 else if (qualifier == EvqFrontFacing)
992 {
993 mUsesFrontFacing = true;
994 out << name;
995 }
996 else if (qualifier == EvqPointSize)
997 {
998 mUsesPointSize = true;
999 out << name;
1000 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001001 else if (qualifier == EvqInstanceID)
1002 {
1003 mUsesInstanceID = true;
1004 out << name;
1005 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001006 else if (qualifier == EvqVertexID)
1007 {
1008 mUsesVertexID = true;
1009 out << name;
1010 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001011 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001012 {
1013 mUsesFragDepth = true;
1014 out << "gl_Depth";
1015 }
Xinghua Caob1239382016-12-13 15:07:05 +08001016 else if (qualifier == EvqNumWorkGroups)
1017 {
1018 mUsesNumWorkGroups = true;
1019 out << name;
1020 }
1021 else if (qualifier == EvqWorkGroupID)
1022 {
1023 mUsesWorkGroupID = true;
1024 out << name;
1025 }
1026 else if (qualifier == EvqLocalInvocationID)
1027 {
1028 mUsesLocalInvocationID = true;
1029 out << name;
1030 }
1031 else if (qualifier == EvqGlobalInvocationID)
1032 {
1033 mUsesGlobalInvocationID = true;
1034 out << name;
1035 }
1036 else if (qualifier == EvqLocalInvocationIndex)
1037 {
1038 mUsesLocalInvocationIndex = true;
1039 out << name;
1040 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001041 else
1042 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001043 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001044 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045 }
1046}
1047
Olli Etuaho7fb49552015-03-18 17:27:44 +02001048void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1049{
1050 if (type.isScalar() && !type.isArray())
1051 {
1052 if (op == EOpEqual)
1053 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001054 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001055 }
1056 else
1057 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001058 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001059 }
1060 }
1061 else
1062 {
1063 if (visit == PreVisit && op == EOpNotEqual)
1064 {
1065 out << "!";
1066 }
1067
1068 if (type.isArray())
1069 {
1070 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001071 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001072 }
1073 else if (type.getBasicType() == EbtStruct)
1074 {
1075 const TStructure &structure = *type.getStruct();
1076 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001077 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001078 }
1079 else
1080 {
1081 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001082 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001083 }
1084 }
1085}
1086
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001087void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1088{
1089 if (type.isArray())
1090 {
1091 const TString &functionName = addArrayAssignmentFunction(type);
1092 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1093 }
1094 else
1095 {
1096 outputTriplet(out, visit, "(", " = ", ")");
1097 }
1098}
1099
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001100bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001101{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001102 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001103 {
1104 TIntermNode *ancestor = getAncestorNode(n);
1105 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1106 if (ancestorBinary == nullptr)
1107 {
1108 return false;
1109 }
1110 switch (ancestorBinary->getOp())
1111 {
1112 case EOpIndexDirectStruct:
1113 {
1114 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1115 const TIntermConstantUnion *index =
1116 ancestorBinary->getRight()->getAsConstantUnion();
1117 const TField *field = structure->fields()[index->getIConst(0)];
1118 if (IsSampler(field->type()->getBasicType()))
1119 {
1120 return true;
1121 }
1122 break;
1123 }
1124 case EOpIndexDirect:
1125 break;
1126 default:
1127 // Returning a sampler from indirect indexing is not supported.
1128 return false;
1129 }
1130 }
1131 return false;
1132}
1133
Olli Etuahob6fa0432016-09-28 16:28:05 +01001134bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1135{
1136 TInfoSinkBase &out = getInfoSink();
1137 if (visit == PostVisit)
1138 {
1139 out << ".";
1140 node->writeOffsetsAsXYZW(&out);
1141 }
1142 return true;
1143}
1144
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1146{
Jamie Madill32aab012015-01-27 14:12:26 -05001147 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148
1149 switch (node->getOp())
1150 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001151 case EOpComma:
1152 outputTriplet(out, visit, "(", ", ", ")");
1153 break;
1154 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001155 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001156 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001157 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1158 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001159 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001160 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1161 out << functionName << "(";
1162 node->getLeft()->traverse(this);
1163 TIntermSequence *seq = rightAgg->getSequence();
1164 for (auto &arrayElement : *seq)
1165 {
1166 out << ", ";
1167 arrayElement->traverse(this);
1168 }
1169 out << ")";
1170 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001171 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001172 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1173 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001174 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001175 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001176 // Assignment expressions with atomic functions should be transformed into atomic
1177 // function calls in HLSL.
1178 // e.g. original_value = atomicAdd(dest, value) should be translated into
1179 // InterlockedAdd(dest, value, original_value);
1180 else if (IsAtomicFunctionDirectAssign(*node))
1181 {
1182 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1183 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1184 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1185 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1186 ASSERT(argumentSeq->size() >= 2u);
1187 for (auto &argument : *argumentSeq)
1188 {
1189 argument->traverse(this);
1190 out << ", ";
1191 }
1192 node->getLeft()->traverse(this);
1193 out << ")";
1194 return false;
1195 }
1196
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001197 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001198 break;
1199 case EOpInitialize:
1200 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001201 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001202 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1203 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001204 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001205
1206 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001207 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001208
1209 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1210 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1211 // new variable is created before the assignment is evaluated), so we need to
1212 // convert
1213 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001214 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001215 {
1216 // Skip initializing the rest of the expression
1217 return false;
1218 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001219 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001220 {
1221 return false;
1222 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001223 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001224 else if (visit == InVisit)
1225 {
1226 out << " = ";
1227 }
1228 break;
1229 case EOpAddAssign:
1230 outputTriplet(out, visit, "(", " += ", ")");
1231 break;
1232 case EOpSubAssign:
1233 outputTriplet(out, visit, "(", " -= ", ")");
1234 break;
1235 case EOpMulAssign:
1236 outputTriplet(out, visit, "(", " *= ", ")");
1237 break;
1238 case EOpVectorTimesScalarAssign:
1239 outputTriplet(out, visit, "(", " *= ", ")");
1240 break;
1241 case EOpMatrixTimesScalarAssign:
1242 outputTriplet(out, visit, "(", " *= ", ")");
1243 break;
1244 case EOpVectorTimesMatrixAssign:
1245 if (visit == PreVisit)
1246 {
1247 out << "(";
1248 }
1249 else if (visit == InVisit)
1250 {
1251 out << " = mul(";
1252 node->getLeft()->traverse(this);
1253 out << ", transpose(";
1254 }
1255 else
1256 {
1257 out << ")))";
1258 }
1259 break;
1260 case EOpMatrixTimesMatrixAssign:
1261 if (visit == PreVisit)
1262 {
1263 out << "(";
1264 }
1265 else if (visit == InVisit)
1266 {
1267 out << " = transpose(mul(transpose(";
1268 node->getLeft()->traverse(this);
1269 out << "), transpose(";
1270 }
1271 else
1272 {
1273 out << "))))";
1274 }
1275 break;
1276 case EOpDivAssign:
1277 outputTriplet(out, visit, "(", " /= ", ")");
1278 break;
1279 case EOpIModAssign:
1280 outputTriplet(out, visit, "(", " %= ", ")");
1281 break;
1282 case EOpBitShiftLeftAssign:
1283 outputTriplet(out, visit, "(", " <<= ", ")");
1284 break;
1285 case EOpBitShiftRightAssign:
1286 outputTriplet(out, visit, "(", " >>= ", ")");
1287 break;
1288 case EOpBitwiseAndAssign:
1289 outputTriplet(out, visit, "(", " &= ", ")");
1290 break;
1291 case EOpBitwiseXorAssign:
1292 outputTriplet(out, visit, "(", " ^= ", ")");
1293 break;
1294 case EOpBitwiseOrAssign:
1295 outputTriplet(out, visit, "(", " |= ", ")");
1296 break;
1297 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001298 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001299 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001300 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001301 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001302 if (visit == PreVisit)
1303 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001304 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001305 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuahoc71862a2017-12-21 12:58:29 +02001306 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1307 {
1308 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1309 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1310 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001311 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001312 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1313 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001314 return false;
1315 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001316 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001317 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001318 {
1319 // All parts of an expression that access a sampler in a struct need to use _ as
1320 // separator to access the sampler variable that has been moved out of the struct.
1321 outputTriplet(out, visit, "", "_", "");
1322 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001323 else
1324 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001325 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001326 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001327 }
1328 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001329 case EOpIndexIndirect:
1330 // We do not currently support indirect references to interface blocks
1331 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1332 outputTriplet(out, visit, "", "[", "]");
1333 break;
1334 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001335 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001336 const TStructure *structure = node->getLeft()->getType().getStruct();
1337 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1338 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001339
Olli Etuaho96963162016-03-21 11:54:33 +02001340 // In cases where indexing returns a sampler, we need to access the sampler variable
1341 // that has been moved out of the struct.
1342 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1343 if (visit == PreVisit && indexingReturnsSampler)
1344 {
1345 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1346 // This prefix is only output at the beginning of the indexing expression, which
1347 // may have multiple parts.
1348 out << "angle";
1349 }
1350 if (!indexingReturnsSampler)
1351 {
1352 // All parts of an expression that access a sampler in a struct need to use _ as
1353 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001354 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001355 }
1356 if (visit == InVisit)
1357 {
1358 if (indexingReturnsSampler)
1359 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001360 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001361 }
1362 else
1363 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001364 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001365 }
1366
1367 return false;
1368 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001369 }
1370 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001371 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001372 {
1373 bool structInStd140Block =
1374 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1375 if (visit == PreVisit && structInStd140Block)
1376 {
1377 out << "map";
1378 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001379 if (visit == InVisit)
1380 {
1381 const TInterfaceBlock *interfaceBlock =
1382 node->getLeft()->getType().getInterfaceBlock();
1383 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1384 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001385 if (structInStd140Block)
1386 {
1387 out << "_";
1388 }
1389 else
1390 {
1391 out << ".";
1392 }
1393 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001394
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001395 return false;
1396 }
1397 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001398 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001399 case EOpAdd:
1400 outputTriplet(out, visit, "(", " + ", ")");
1401 break;
1402 case EOpSub:
1403 outputTriplet(out, visit, "(", " - ", ")");
1404 break;
1405 case EOpMul:
1406 outputTriplet(out, visit, "(", " * ", ")");
1407 break;
1408 case EOpDiv:
1409 outputTriplet(out, visit, "(", " / ", ")");
1410 break;
1411 case EOpIMod:
1412 outputTriplet(out, visit, "(", " % ", ")");
1413 break;
1414 case EOpBitShiftLeft:
1415 outputTriplet(out, visit, "(", " << ", ")");
1416 break;
1417 case EOpBitShiftRight:
1418 outputTriplet(out, visit, "(", " >> ", ")");
1419 break;
1420 case EOpBitwiseAnd:
1421 outputTriplet(out, visit, "(", " & ", ")");
1422 break;
1423 case EOpBitwiseXor:
1424 outputTriplet(out, visit, "(", " ^ ", ")");
1425 break;
1426 case EOpBitwiseOr:
1427 outputTriplet(out, visit, "(", " | ", ")");
1428 break;
1429 case EOpEqual:
1430 case EOpNotEqual:
1431 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1432 break;
1433 case EOpLessThan:
1434 outputTriplet(out, visit, "(", " < ", ")");
1435 break;
1436 case EOpGreaterThan:
1437 outputTriplet(out, visit, "(", " > ", ")");
1438 break;
1439 case EOpLessThanEqual:
1440 outputTriplet(out, visit, "(", " <= ", ")");
1441 break;
1442 case EOpGreaterThanEqual:
1443 outputTriplet(out, visit, "(", " >= ", ")");
1444 break;
1445 case EOpVectorTimesScalar:
1446 outputTriplet(out, visit, "(", " * ", ")");
1447 break;
1448 case EOpMatrixTimesScalar:
1449 outputTriplet(out, visit, "(", " * ", ")");
1450 break;
1451 case EOpVectorTimesMatrix:
1452 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1453 break;
1454 case EOpMatrixTimesVector:
1455 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1456 break;
1457 case EOpMatrixTimesMatrix:
1458 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1459 break;
1460 case EOpLogicalOr:
1461 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1462 // been unfolded.
1463 ASSERT(!node->getRight()->hasSideEffects());
1464 outputTriplet(out, visit, "(", " || ", ")");
1465 return true;
1466 case EOpLogicalXor:
1467 mUsesXor = true;
1468 outputTriplet(out, visit, "xor(", ", ", ")");
1469 break;
1470 case EOpLogicalAnd:
1471 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1472 // been unfolded.
1473 ASSERT(!node->getRight()->hasSideEffects());
1474 outputTriplet(out, visit, "(", " && ", ")");
1475 return true;
1476 default:
1477 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001478 }
1479
1480 return true;
1481}
1482
1483bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1484{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001485 TInfoSinkBase &out = getInfoSink();
1486
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001487 switch (node->getOp())
1488 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001489 case EOpNegative:
1490 outputTriplet(out, visit, "(-", "", ")");
1491 break;
1492 case EOpPositive:
1493 outputTriplet(out, visit, "(+", "", ")");
1494 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001495 case EOpLogicalNot:
1496 outputTriplet(out, visit, "(!", "", ")");
1497 break;
1498 case EOpBitwiseNot:
1499 outputTriplet(out, visit, "(~", "", ")");
1500 break;
1501 case EOpPostIncrement:
1502 outputTriplet(out, visit, "(", "", "++)");
1503 break;
1504 case EOpPostDecrement:
1505 outputTriplet(out, visit, "(", "", "--)");
1506 break;
1507 case EOpPreIncrement:
1508 outputTriplet(out, visit, "(++", "", ")");
1509 break;
1510 case EOpPreDecrement:
1511 outputTriplet(out, visit, "(--", "", ")");
1512 break;
1513 case EOpRadians:
1514 outputTriplet(out, visit, "radians(", "", ")");
1515 break;
1516 case EOpDegrees:
1517 outputTriplet(out, visit, "degrees(", "", ")");
1518 break;
1519 case EOpSin:
1520 outputTriplet(out, visit, "sin(", "", ")");
1521 break;
1522 case EOpCos:
1523 outputTriplet(out, visit, "cos(", "", ")");
1524 break;
1525 case EOpTan:
1526 outputTriplet(out, visit, "tan(", "", ")");
1527 break;
1528 case EOpAsin:
1529 outputTriplet(out, visit, "asin(", "", ")");
1530 break;
1531 case EOpAcos:
1532 outputTriplet(out, visit, "acos(", "", ")");
1533 break;
1534 case EOpAtan:
1535 outputTriplet(out, visit, "atan(", "", ")");
1536 break;
1537 case EOpSinh:
1538 outputTriplet(out, visit, "sinh(", "", ")");
1539 break;
1540 case EOpCosh:
1541 outputTriplet(out, visit, "cosh(", "", ")");
1542 break;
1543 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpAtanh:
1547 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001548 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 break;
1550 case EOpExp:
1551 outputTriplet(out, visit, "exp(", "", ")");
1552 break;
1553 case EOpLog:
1554 outputTriplet(out, visit, "log(", "", ")");
1555 break;
1556 case EOpExp2:
1557 outputTriplet(out, visit, "exp2(", "", ")");
1558 break;
1559 case EOpLog2:
1560 outputTriplet(out, visit, "log2(", "", ")");
1561 break;
1562 case EOpSqrt:
1563 outputTriplet(out, visit, "sqrt(", "", ")");
1564 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001565 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001566 outputTriplet(out, visit, "rsqrt(", "", ")");
1567 break;
1568 case EOpAbs:
1569 outputTriplet(out, visit, "abs(", "", ")");
1570 break;
1571 case EOpSign:
1572 outputTriplet(out, visit, "sign(", "", ")");
1573 break;
1574 case EOpFloor:
1575 outputTriplet(out, visit, "floor(", "", ")");
1576 break;
1577 case EOpTrunc:
1578 outputTriplet(out, visit, "trunc(", "", ")");
1579 break;
1580 case EOpRound:
1581 outputTriplet(out, visit, "round(", "", ")");
1582 break;
1583 case EOpRoundEven:
1584 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001585 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001586 break;
1587 case EOpCeil:
1588 outputTriplet(out, visit, "ceil(", "", ")");
1589 break;
1590 case EOpFract:
1591 outputTriplet(out, visit, "frac(", "", ")");
1592 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001593 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001594 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001595 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 else
1597 outputTriplet(out, visit, "isnan(", "", ")");
1598 mRequiresIEEEStrictCompiling = true;
1599 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001600 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001601 outputTriplet(out, visit, "isinf(", "", ")");
1602 break;
1603 case EOpFloatBitsToInt:
1604 outputTriplet(out, visit, "asint(", "", ")");
1605 break;
1606 case EOpFloatBitsToUint:
1607 outputTriplet(out, visit, "asuint(", "", ")");
1608 break;
1609 case EOpIntBitsToFloat:
1610 outputTriplet(out, visit, "asfloat(", "", ")");
1611 break;
1612 case EOpUintBitsToFloat:
1613 outputTriplet(out, visit, "asfloat(", "", ")");
1614 break;
1615 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001616 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001617 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001619 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001621 case EOpPackUnorm4x8:
1622 case EOpPackSnorm4x8:
1623 case EOpUnpackUnorm4x8:
1624 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001625 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001626 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001627 break;
1628 case EOpLength:
1629 outputTriplet(out, visit, "length(", "", ")");
1630 break;
1631 case EOpNormalize:
1632 outputTriplet(out, visit, "normalize(", "", ")");
1633 break;
1634 case EOpDFdx:
1635 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1636 {
1637 outputTriplet(out, visit, "(", "", ", 0.0)");
1638 }
1639 else
1640 {
1641 outputTriplet(out, visit, "ddx(", "", ")");
1642 }
1643 break;
1644 case EOpDFdy:
1645 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1646 {
1647 outputTriplet(out, visit, "(", "", ", 0.0)");
1648 }
1649 else
1650 {
1651 outputTriplet(out, visit, "ddy(", "", ")");
1652 }
1653 break;
1654 case EOpFwidth:
1655 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1656 {
1657 outputTriplet(out, visit, "(", "", ", 0.0)");
1658 }
1659 else
1660 {
1661 outputTriplet(out, visit, "fwidth(", "", ")");
1662 }
1663 break;
1664 case EOpTranspose:
1665 outputTriplet(out, visit, "transpose(", "", ")");
1666 break;
1667 case EOpDeterminant:
1668 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1669 break;
1670 case EOpInverse:
1671 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001672 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001673 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001674
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001675 case EOpAny:
1676 outputTriplet(out, visit, "any(", "", ")");
1677 break;
1678 case EOpAll:
1679 outputTriplet(out, visit, "all(", "", ")");
1680 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001681 case EOpLogicalNotComponentWise:
1682 outputTriplet(out, visit, "(!", "", ")");
1683 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001684 case EOpBitfieldReverse:
1685 outputTriplet(out, visit, "reversebits(", "", ")");
1686 break;
1687 case EOpBitCount:
1688 outputTriplet(out, visit, "countbits(", "", ")");
1689 break;
1690 case EOpFindLSB:
1691 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1692 // in GLSLTest and results are consistent with GL.
1693 outputTriplet(out, visit, "firstbitlow(", "", ")");
1694 break;
1695 case EOpFindMSB:
1696 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1697 // tested in GLSLTest and results are consistent with GL.
1698 outputTriplet(out, visit, "firstbithigh(", "", ")");
1699 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001700 default:
1701 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001702 }
1703
1704 return true;
1705}
1706
Olli Etuahofbb1c792018-01-19 16:26:59 +02001707ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001708{
1709 if (node->getAsSymbolNode())
1710 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001711 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1712 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001713 }
1714 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1715 switch (nodeBinary->getOp())
1716 {
1717 case EOpIndexDirect:
1718 {
1719 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1720
Olli Etuahofbb1c792018-01-19 16:26:59 +02001721 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001722 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001723 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001724 }
1725 case EOpIndexDirectStruct:
1726 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001727 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001728 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1729 const TField *field = s->fields()[index];
1730
Olli Etuahofbb1c792018-01-19 16:26:59 +02001731 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001732 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1733 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001734 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001735 }
1736 default:
1737 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001738 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001739 }
1740}
1741
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001742bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1743{
1744 TInfoSinkBase &out = getInfoSink();
1745
1746 if (mInsideFunction)
1747 {
1748 outputLineDirective(out, node->getLine().first_line);
1749 out << "{\n";
1750 }
1751
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001752 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001753 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001754 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001755
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001756 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001757
1758 // Don't output ; after case labels, they're terminated by :
1759 // This is needed especially since outputting a ; after a case statement would turn empty
1760 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001761 // Also the output code is clearer if we don't output ; after statements where it is not
1762 // needed:
1763 // * if statements
1764 // * switch statements
1765 // * blocks
1766 // * function definitions
1767 // * loops (do-while loops output the semicolon in VisitLoop)
1768 // * declarations that don't generate output.
1769 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1770 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1771 statement->getAsSwitchNode() == nullptr &&
1772 statement->getAsFunctionDefinition() == nullptr &&
1773 (statement->getAsDeclarationNode() == nullptr ||
1774 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1775 statement->getAsInvariantDeclarationNode() == nullptr)
1776 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001777 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001778 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001779 }
1780
1781 if (mInsideFunction)
1782 {
1783 outputLineDirective(out, node->getLine().last_line);
1784 out << "}\n";
1785 }
1786
1787 return false;
1788}
1789
Olli Etuaho336b1472016-10-05 16:37:55 +01001790bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1791{
1792 TInfoSinkBase &out = getInfoSink();
1793
1794 ASSERT(mCurrentFunctionMetadata == nullptr);
1795
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001796 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001797 ASSERT(index != CallDAG::InvalidIndex);
1798 mCurrentFunctionMetadata = &mASTMetadataList[index];
1799
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001800 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001801
Olli Etuahod4bd9632018-03-08 16:32:44 +02001802 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001803
Olli Etuahod4bd9632018-03-08 16:32:44 +02001804 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001805 {
1806 out << "gl_main(";
1807 }
1808 else
1809 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001810 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001811 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001812 }
1813
Olli Etuahod4bd9632018-03-08 16:32:44 +02001814 size_t paramCount = func->getParamCount();
1815 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001816 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001817 const TVariable *param = func->getParam(i);
1818 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001819
Olli Etuahod4bd9632018-03-08 16:32:44 +02001820 writeParameter(param, out);
1821
1822 if (i < paramCount - 1)
Olli Etuaho336b1472016-10-05 16:37:55 +01001823 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001824 out << ", ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001825 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001826 }
1827
1828 out << ")\n";
1829
1830 mInsideFunction = true;
1831 // The function body node will output braces.
1832 node->getBody()->traverse(this);
1833 mInsideFunction = false;
1834
1835 mCurrentFunctionMetadata = nullptr;
1836
1837 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1838 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1839 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001840 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001841 mOutputLod0Function = true;
1842 node->traverse(this);
1843 mOutputLod0Function = false;
1844 }
1845
1846 return false;
1847}
1848
Olli Etuaho13389b62016-10-16 11:48:18 +01001849bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1850{
Olli Etuaho13389b62016-10-16 11:48:18 +01001851 if (visit == PreVisit)
1852 {
1853 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001854 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001855 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001856 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001857
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001858 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001859 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001860 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001861 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001862
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001863 if (!declarator->getAsSymbolNode() ||
1864 declarator->getAsSymbolNode()->variable().symbolType() !=
1865 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001866 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001867 if (declarator->getQualifier() == EvqShared)
1868 {
1869 out << "groupshared ";
1870 }
1871 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001872 {
1873 out << "static ";
1874 }
1875
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001876 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001877
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001878 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001879
1880 if (symbol)
1881 {
1882 symbol->traverse(this);
1883 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001884 // We don't initialize shared variables because:
1885 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1886 // code to initialize a groupshared array variable with a large array size.
1887 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1888 // allow initializing shared variables at all.
1889 if (declarator->getQualifier() != EvqShared)
1890 {
1891 out << " = " + zeroInitializer(symbol->getType());
1892 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001893 }
1894 else
1895 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001896 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001897 }
1898 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001899 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001900 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001901 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001902 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001903 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001904
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001905 const TVariable &variable = symbol->variable();
1906
1907 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001908 {
1909 // Vertex outputs which are declared but not written to should still be declared to
1910 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001911 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001912 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001913 }
1914 }
1915 return false;
1916}
1917
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001918bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1919{
1920 // Do not do any translation
1921 return false;
1922}
1923
Olli Etuahod4bd9632018-03-08 16:32:44 +02001924void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001925{
1926 TInfoSinkBase &out = getInfoSink();
1927
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001928 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001929 // Skip the prototype if it is not implemented (and thus not used)
1930 if (index == CallDAG::InvalidIndex)
1931 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001932 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00001933 }
1934
Olli Etuahod4bd9632018-03-08 16:32:44 +02001935 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00001936
Olli Etuahod4bd9632018-03-08 16:32:44 +02001937 TString name = DecorateFunctionIfNeeded(func);
1938 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001939 << (mOutputLod0Function ? "Lod0(" : "(");
1940
Olli Etuahod4bd9632018-03-08 16:32:44 +02001941 size_t paramCount = func->getParamCount();
1942 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001943 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001944 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00001945
Olli Etuahod4bd9632018-03-08 16:32:44 +02001946 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001947 {
1948 out << ", ";
1949 }
1950 }
1951
1952 out << ");\n";
1953
1954 // Also prototype the Lod0 variant if needed
1955 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1956 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1957 {
1958 mOutputLod0Function = true;
1959 node->traverse(this);
1960 mOutputLod0Function = false;
1961 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00001962}
1963
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001964bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1965{
Jamie Madill32aab012015-01-27 14:12:26 -05001966 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001967
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001968 switch (node->getOp())
1969 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001970 case EOpCallBuiltInFunction:
1971 case EOpCallFunctionInAST:
1972 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001973 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001974 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001975
Corentin Wallez1239ee92015-03-19 14:38:02 -07001976 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001977 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001978 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001979 if (node->isArray())
1980 {
1981 UNIMPLEMENTED();
1982 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001983 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001984 ASSERT(index != CallDAG::InvalidIndex);
1985 lod0 &= mASTMetadataList[index].mNeedsLod0;
1986
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001987 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001988 out << DisambiguateFunctionName(node->getSequence());
1989 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001990 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001991 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001992 {
1993 // This path is used for internal functions that don't have their definitions in the
1994 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001995 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001996 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001997 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08001998 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001999 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002000 TType type = (*arguments)[0]->getAsTyped()->getType();
2001 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002002 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002003 type.getMemoryQualifier().readonly);
2004 out << imageFunctionName << "(";
2005 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002006 else
2007 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002008 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002009 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002010 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2011 if (arguments->size() > 1)
2012 {
2013 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2014 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002015 const ImmutableString &textureFunctionName =
2016 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2017 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002018 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002019 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002020
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002021 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002022 {
Olli Etuaho96963162016-03-21 11:54:33 +02002023 TIntermTyped *typedArg = (*arg)->getAsTyped();
2024 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002025 {
2026 out << "texture_";
2027 (*arg)->traverse(this);
2028 out << ", sampler_";
2029 }
2030
2031 (*arg)->traverse(this);
2032
Olli Etuaho96963162016-03-21 11:54:33 +02002033 if (typedArg->getType().isStructureContainingSamplers())
2034 {
2035 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002036 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002037 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2038 std::string namePrefix = "angle_";
2039 namePrefix += structName.data();
2040 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002041 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002042 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002043 {
2044 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2045 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002046 out << ", texture_" << sampler->name();
2047 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002048 }
2049 else
2050 {
2051 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2052 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002053 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002054 }
2055 }
2056 }
2057
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002058 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002059 {
2060 out << ", ";
2061 }
2062 }
2063
2064 out << ")";
2065
2066 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002067 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002068 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002069 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002070 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002071 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002072 outputTriplet(out, visit, "(", " == ", ")");
2073 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002074 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002075 outputTriplet(out, visit, "(", " != ", ")");
2076 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002077 case EOpLessThanComponentWise:
2078 outputTriplet(out, visit, "(", " < ", ")");
2079 break;
2080 case EOpGreaterThanComponentWise:
2081 outputTriplet(out, visit, "(", " > ", ")");
2082 break;
2083 case EOpLessThanEqualComponentWise:
2084 outputTriplet(out, visit, "(", " <= ", ")");
2085 break;
2086 case EOpGreaterThanEqualComponentWise:
2087 outputTriplet(out, visit, "(", " >= ", ")");
2088 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002089 case EOpMod:
2090 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002091 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002092 break;
2093 case EOpModf:
2094 outputTriplet(out, visit, "modf(", ", ", ")");
2095 break;
2096 case EOpPow:
2097 outputTriplet(out, visit, "pow(", ", ", ")");
2098 break;
2099 case EOpAtan:
2100 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2101 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002102 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002103 break;
2104 case EOpMin:
2105 outputTriplet(out, visit, "min(", ", ", ")");
2106 break;
2107 case EOpMax:
2108 outputTriplet(out, visit, "max(", ", ", ")");
2109 break;
2110 case EOpClamp:
2111 outputTriplet(out, visit, "clamp(", ", ", ")");
2112 break;
2113 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302114 {
2115 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2116 if (lastParamNode->getType().getBasicType() == EbtBool)
2117 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002118 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2119 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302120 // so use emulated version.
2121 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002122 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302123 }
2124 else
2125 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002126 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302127 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002128 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302129 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002130 case EOpStep:
2131 outputTriplet(out, visit, "step(", ", ", ")");
2132 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002133 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002134 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2135 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002136 case EOpFrexp:
2137 case EOpLdexp:
2138 ASSERT(node->getUseEmulatedFunction());
2139 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2140 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002141 case EOpDistance:
2142 outputTriplet(out, visit, "distance(", ", ", ")");
2143 break;
2144 case EOpDot:
2145 outputTriplet(out, visit, "dot(", ", ", ")");
2146 break;
2147 case EOpCross:
2148 outputTriplet(out, visit, "cross(", ", ", ")");
2149 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002150 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002151 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002152 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002153 break;
2154 case EOpReflect:
2155 outputTriplet(out, visit, "reflect(", ", ", ")");
2156 break;
2157 case EOpRefract:
2158 outputTriplet(out, visit, "refract(", ", ", ")");
2159 break;
2160 case EOpOuterProduct:
2161 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002162 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002163 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002164 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002165 outputTriplet(out, visit, "(", " * ", ")");
2166 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002167 case EOpBitfieldExtract:
2168 case EOpBitfieldInsert:
2169 case EOpUaddCarry:
2170 case EOpUsubBorrow:
2171 case EOpUmulExtended:
2172 case EOpImulExtended:
2173 ASSERT(node->getUseEmulatedFunction());
2174 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2175 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002176 case EOpBarrier:
2177 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2178 // cheapest *WithGroupSync() function, without any functionality loss, but
2179 // with the potential for severe performance loss.
2180 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2181 break;
2182 case EOpMemoryBarrierShared:
2183 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2184 break;
2185 case EOpMemoryBarrierAtomicCounter:
2186 case EOpMemoryBarrierBuffer:
2187 case EOpMemoryBarrierImage:
2188 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2189 break;
2190 case EOpGroupMemoryBarrier:
2191 case EOpMemoryBarrier:
2192 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2193 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002194
2195 // Single atomic function calls without return value.
2196 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2197 case EOpAtomicAdd:
2198 case EOpAtomicMin:
2199 case EOpAtomicMax:
2200 case EOpAtomicAnd:
2201 case EOpAtomicOr:
2202 case EOpAtomicXor:
2203 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2204 ",", ")");
2205 break;
2206
2207 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2208 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2209 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2210 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2211 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2212 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2213 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2214 // intermediate tree before traversing outputHLSL.
2215 case EOpAtomicExchange:
2216 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002217 default:
2218 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
2220
2221 return true;
2222}
2223
Olli Etuaho57961272016-09-14 13:57:46 +03002224void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002225{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002226 out << "if (";
2227
2228 node->getCondition()->traverse(this);
2229
2230 out << ")\n";
2231
Jamie Madill8c46ab12015-12-07 16:39:19 -05002232 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002233
2234 bool discard = false;
2235
2236 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002237 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002238 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002239 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002240
Olli Etuahoa6f22092015-05-08 18:31:10 +03002241 // Detect true discard
2242 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2243 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002244 else
2245 {
2246 // TODO(oetuaho): Check if the semicolon inside is necessary.
2247 // It's there as a result of conservative refactoring of the output.
2248 out << "{;}\n";
2249 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002250
Jamie Madill8c46ab12015-12-07 16:39:19 -05002251 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002252
Olli Etuahoa6f22092015-05-08 18:31:10 +03002253 if (node->getFalseBlock())
2254 {
2255 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002256
Jamie Madill8c46ab12015-12-07 16:39:19 -05002257 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002258
Olli Etuaho32db19b2016-10-04 14:43:16 +01002259 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002260 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002261
Jamie Madill8c46ab12015-12-07 16:39:19 -05002262 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002263
Olli Etuahoa6f22092015-05-08 18:31:10 +03002264 // Detect false discard
2265 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2266 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002267
Olli Etuahoa6f22092015-05-08 18:31:10 +03002268 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002269 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002270 {
2271 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002272 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002273}
2274
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002275bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2276{
2277 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2278 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2279 UNREACHABLE();
2280 return false;
2281}
2282
Olli Etuaho57961272016-09-14 13:57:46 +03002283bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002284{
2285 TInfoSinkBase &out = getInfoSink();
2286
Olli Etuaho3d932d82016-04-12 11:10:30 +03002287 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002288
2289 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002290 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002291 {
2292 out << "FLATTEN ";
2293 }
2294
Olli Etuaho57961272016-09-14 13:57:46 +03002295 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002296
2297 return false;
2298}
2299
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002300bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002301{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002302 TInfoSinkBase &out = getInfoSink();
2303
Olli Etuaho923ecef2017-10-11 12:01:38 +03002304 ASSERT(node->getStatementList());
2305 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002306 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002307 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002308 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002309 outputTriplet(out, visit, "switch (", ") ", "");
2310 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002311 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002312}
2313
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002314bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002315{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002316 TInfoSinkBase &out = getInfoSink();
2317
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002318 if (node->hasCondition())
2319 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002320 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002321 return true;
2322 }
2323 else
2324 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002325 out << "default:\n";
2326 return false;
2327 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002328}
2329
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002330void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2331{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002332 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002333 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002334}
2335
2336bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2337{
Nicolas Capens655fe362014-04-11 13:12:34 -04002338 mNestedLoopDepth++;
2339
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002340 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002341 mInsideDiscontinuousLoop =
2342 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002343
Jamie Madill8c46ab12015-12-07 16:39:19 -05002344 TInfoSinkBase &out = getInfoSink();
2345
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002346 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002347 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002348 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002349 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002350 mInsideDiscontinuousLoop = wasDiscontinuous;
2351 mNestedLoopDepth--;
2352
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002353 return false;
2354 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002355 }
2356
Corentin Wallez1239ee92015-03-19 14:38:02 -07002357 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002358 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002359 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002360 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002361
Jamie Madill8c46ab12015-12-07 16:39:19 -05002362 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002363 }
2364 else
2365 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002366 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002367
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002368 if (node->getInit())
2369 {
2370 node->getInit()->traverse(this);
2371 }
2372
2373 out << "; ";
2374
alokp@chromium.org52813552010-11-16 18:36:09 +00002375 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002376 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002377 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002378 }
2379
2380 out << "; ";
2381
alokp@chromium.org52813552010-11-16 18:36:09 +00002382 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002383 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002384 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002385 }
2386
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002387 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002388
Jamie Madill8c46ab12015-12-07 16:39:19 -05002389 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002390 }
2391
2392 if (node->getBody())
2393 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002394 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002395 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002396 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002397 else
2398 {
2399 // TODO(oetuaho): Check if the semicolon inside is necessary.
2400 // It's there as a result of conservative refactoring of the output.
2401 out << "{;}\n";
2402 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002403
Jamie Madill8c46ab12015-12-07 16:39:19 -05002404 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002405
alokp@chromium.org52813552010-11-16 18:36:09 +00002406 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002407 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002408 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002409 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002410
alokp@chromium.org52813552010-11-16 18:36:09 +00002411 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002412
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002413 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002414 }
2415
daniel@transgaming.com73536982012-03-21 20:45:49 +00002416 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002417
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002418 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002419 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002420
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002421 return false;
2422}
2423
2424bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2425{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002426 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002427 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002428 TInfoSinkBase &out = getInfoSink();
2429
2430 switch (node->getFlowOp())
2431 {
2432 case EOpKill:
2433 out << "discard";
2434 break;
2435 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002436 if (mNestedLoopDepth > 1)
2437 {
2438 mUsesNestedBreak = true;
2439 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002440
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002441 if (mExcessiveLoopIndex)
2442 {
2443 out << "{Break";
2444 mExcessiveLoopIndex->traverse(this);
2445 out << " = true; break;}\n";
2446 }
2447 else
2448 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002449 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002450 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002451 break;
2452 case EOpContinue:
2453 out << "continue";
2454 break;
2455 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002456 if (node->getExpression())
2457 {
2458 out << "return ";
2459 }
2460 else
2461 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002462 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002463 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002464 break;
2465 default:
2466 UNREACHABLE();
2467 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002468 }
2469
2470 return true;
2471}
2472
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002473// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002474// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2475// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002476bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002478 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479
2480 // Parse loops of the form:
2481 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002482 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002483 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002484 int initial = 0;
2485 int limit = 0;
2486 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002487
2488 // Parse index name and intial value
2489 if (node->getInit())
2490 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002491 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002492
2493 if (init)
2494 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002495 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002496 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002497
2498 if (variable && variable->getQualifier() == EvqTemporary)
2499 {
2500 TIntermBinary *assign = variable->getAsBinaryNode();
2501
2502 if (assign->getOp() == EOpInitialize)
2503 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002504 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002505 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2506
2507 if (symbol && constant)
2508 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002509 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002510 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002511 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002512 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002513 }
2514 }
2515 }
2516 }
2517 }
2518 }
2519
2520 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002521 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002522 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002523 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002524
Olli Etuahob6af22b2017-12-15 14:05:44 +02002525 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002526 {
2527 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2528
2529 if (constant)
2530 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002531 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002532 {
2533 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002534 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002535 }
2536 }
2537 }
2538 }
2539
2540 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002541 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002542 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002543 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002544 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002545
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002546 if (binaryTerminal)
2547 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002548 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002549 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2550
2551 if (constant)
2552 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002553 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002554 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002555 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002556
2557 switch (op)
2558 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002559 case EOpAddAssign:
2560 increment = value;
2561 break;
2562 case EOpSubAssign:
2563 increment = -value;
2564 break;
2565 default:
2566 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002567 }
2568 }
2569 }
2570 }
2571 else if (unaryTerminal)
2572 {
2573 TOperator op = unaryTerminal->getOp();
2574
2575 switch (op)
2576 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002577 case EOpPostIncrement:
2578 increment = 1;
2579 break;
2580 case EOpPostDecrement:
2581 increment = -1;
2582 break;
2583 case EOpPreIncrement:
2584 increment = 1;
2585 break;
2586 case EOpPreDecrement:
2587 increment = -1;
2588 break;
2589 default:
2590 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002591 }
2592 }
2593 }
2594
Yunchao He4f285442017-04-21 12:15:49 +08002595 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002596 {
2597 if (comparator == EOpLessThanEqual)
2598 {
2599 comparator = EOpLessThan;
2600 limit += 1;
2601 }
2602
2603 if (comparator == EOpLessThan)
2604 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002605 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002606
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002607 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002608 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002609 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002610 }
2611
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002612 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002613 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002614
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002615 out << "{int ";
2616 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002617 out << ";\n"
2618 "bool Break";
2619 index->traverse(this);
2620 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002621
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002622 bool firstLoopFragment = true;
2623
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002624 while (iterations > 0)
2625 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002626 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002627
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002628 if (!firstLoopFragment)
2629 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002630 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002631 index->traverse(this);
2632 out << ") {\n";
2633 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002634
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002635 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002636 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002637 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002638 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002639
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002640 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002641 const char *unroll =
2642 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002643
Corentin Wallez1239ee92015-03-19 14:38:02 -07002644 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002645 index->traverse(this);
2646 out << " = ";
2647 out << initial;
2648
2649 out << "; ";
2650 index->traverse(this);
2651 out << " < ";
2652 out << clampedLimit;
2653
2654 out << "; ";
2655 index->traverse(this);
2656 out << " += ";
2657 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002658 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002659
Jamie Madill8c46ab12015-12-07 16:39:19 -05002660 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002661 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002662
2663 if (node->getBody())
2664 {
2665 node->getBody()->traverse(this);
2666 }
2667
Jamie Madill8c46ab12015-12-07 16:39:19 -05002668 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002669 out << ";}\n";
2670
2671 if (!firstLoopFragment)
2672 {
2673 out << "}\n";
2674 }
2675
2676 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002677
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002678 initial += MAX_LOOP_ITERATIONS * increment;
2679 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002680 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002681
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002682 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002683
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002684 mExcessiveLoopIndex = restoreIndex;
2685
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002686 return true;
2687 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002688 else
2689 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002690 }
2691
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002692 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002693}
2694
Jamie Madill8c46ab12015-12-07 16:39:19 -05002695void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2696 Visit visit,
2697 const char *preString,
2698 const char *inString,
2699 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002700{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002701 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002702 {
2703 out << preString;
2704 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002705 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002706 {
2707 out << inString;
2708 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002709 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002710 {
2711 out << postString;
2712 }
2713}
2714
Jamie Madill8c46ab12015-12-07 16:39:19 -05002715void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002716{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002717 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002718 {
Jamie Madill32aab012015-01-27 14:12:26 -05002719 out << "\n";
2720 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002721
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002722 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002723 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002724 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002725 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002726
Jamie Madill32aab012015-01-27 14:12:26 -05002727 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002728 }
2729}
2730
Olli Etuahod4bd9632018-03-08 16:32:44 +02002731void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002732{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002733 const TType &type = param->getType();
2734 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002735
Olli Etuahod4bd9632018-03-08 16:32:44 +02002736 TString nameStr = DecorateVariableIfNeeded(*param);
2737 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002738
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002739 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002740 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002741 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2742 {
2743 // Samplers are passed as indices to the sampler array.
2744 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002745 out << "const uint " << nameStr << ArrayString(type);
2746 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002747 }
2748 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2749 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002750 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2751 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2752 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2753 << ArrayString(type);
2754 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002755 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002756 }
2757
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002758 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2759 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002760
2761 // If the structure parameter contains samplers, they need to be passed into the function as
2762 // separate parameters. HLSL doesn't natively support samplers in structs.
2763 if (type.isStructureContainingSamplers())
2764 {
2765 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002766 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002767 std::string namePrefix = "angle";
2768 namePrefix += nameStr.c_str();
2769 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2770 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002771 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002772 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002773 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002774 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2775 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002776 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002777 }
2778 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2779 {
Olli Etuaho96963162016-03-21 11:54:33 +02002780 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002781 out << ", " << QualifierString(qualifier) << " "
2782 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2783 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2784 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2785 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002786 }
2787 else
2788 {
Olli Etuaho96963162016-03-21 11:54:33 +02002789 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002790 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2791 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002792 }
2793 }
2794 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002795}
2796
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002797TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002798{
2799 TString string;
2800
Jamie Madill94bf7f22013-07-08 13:31:15 -04002801 size_t size = type.getObjectSize();
2802 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002803 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002804 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002805
Jamie Madill94bf7f22013-07-08 13:31:15 -04002806 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002807 {
2808 string += ", ";
2809 }
2810 }
2811
daniel@transgaming.comead23042010-04-29 03:35:36 +00002812 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002813}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002814
Olli Etuahobd3cd502017-11-03 15:48:52 +02002815void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002816{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002817 // Array constructors should have been already pruned from the code.
2818 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002819
2820 if (visit == PreVisit)
2821 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002822 TString constructorName;
2823 if (node->getBasicType() == EbtStruct)
2824 {
2825 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2826 }
2827 else
2828 {
2829 constructorName =
2830 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2831 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002832 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002833 }
2834 else if (visit == InVisit)
2835 {
2836 out << ", ";
2837 }
2838 else if (visit == PostVisit)
2839 {
2840 out << ")";
2841 }
2842}
2843
Jamie Madill8c46ab12015-12-07 16:39:19 -05002844const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2845 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002846 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002847{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002848 ASSERT(!type.isArray());
2849
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002850 const TConstantUnion *constUnionIterated = constUnion;
2851
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002852 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002853 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002854 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002855 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002856
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002857 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002858
Jamie Madill98493dd2013-07-08 14:39:03 -04002859 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002860 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002861 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002862 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002863
Jamie Madill98493dd2013-07-08 14:39:03 -04002864 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002865 {
2866 out << ", ";
2867 }
2868 }
2869
2870 out << ")";
2871 }
2872 else
2873 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002874 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002875 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002876
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002877 if (writeType)
2878 {
Jamie Madill033dae62014-06-18 12:56:28 -04002879 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002880 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002881 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002882 if (writeType)
2883 {
2884 out << ")";
2885 }
2886 }
2887
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002888 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002889}
2890
Olli Etuahod68924e2017-01-02 17:34:40 +00002891void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002892{
Olli Etuahod68924e2017-01-02 17:34:40 +00002893 if (visit == PreVisit)
2894 {
2895 const char *opStr = GetOperatorString(op);
2896 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2897 out << "(";
2898 }
2899 else
2900 {
2901 outputTriplet(out, visit, nullptr, ", ", ")");
2902 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002903}
2904
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002905bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2906 TIntermSymbol *symbolNode,
2907 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002908{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002909 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2910 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002911
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002912 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002913 {
2914 // Type already printed
2915 out << "t" + str(mUniqueIndex) + " = ";
2916 expression->traverse(this);
2917 out << ", ";
2918 symbolNode->traverse(this);
2919 out << " = t" + str(mUniqueIndex);
2920
2921 mUniqueIndex++;
2922 return true;
2923 }
2924
2925 return false;
2926}
2927
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002928bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2929 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002930 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002931{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002932 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002933 {
2934 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002935 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002936 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002937 writeConstantUnionArray(out, initializer->getConstantValue(),
2938 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002939 out << "}";
2940 return true;
2941 }
2942 return false;
2943}
2944
Jamie Madill55e79e02015-02-09 15:35:00 -05002945TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2946{
2947 const TFieldList &fields = structure.fields();
2948
2949 for (const auto &eqFunction : mStructEqualityFunctions)
2950 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002951 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002952 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002953 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002954 }
2955 }
2956
2957 const TString &structNameString = StructNameString(structure);
2958
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002959 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002960 function->structure = &structure;
2961 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002962
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002963 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002964
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002965 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2966 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002967 << "{\n"
2968 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002969
2970 for (size_t i = 0; i < fields.size(); i++)
2971 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002972 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002973 const TType *fieldType = field->type();
2974
2975 const TString &fieldNameA = "a." + Decorate(field->name());
2976 const TString &fieldNameB = "b." + Decorate(field->name());
2977
2978 if (i > 0)
2979 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002980 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002981 }
2982
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002983 fnOut << "(";
2984 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2985 fnOut << fieldNameA;
2986 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2987 fnOut << fieldNameB;
2988 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2989 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002990 }
2991
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002992 fnOut << ";\n"
2993 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002994
2995 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002996
2997 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002998 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002999
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003000 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003001}
3002
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003003TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003004{
3005 for (const auto &eqFunction : mArrayEqualityFunctions)
3006 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003007 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003008 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003009 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003010 }
3011 }
3012
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003013 TType elementType(type);
3014 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003015
Olli Etuaho12690762015-03-31 12:55:28 +03003016 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003017 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003018
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003019 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003020
3021 TInfoSinkBase fnOut;
3022
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003023 const TString &typeName = TypeString(type);
3024 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3025 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003026 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003027 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003028 << type.getOutermostArraySize()
3029 << "; ++i)\n"
3030 " {\n"
3031 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003032
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003033 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003034 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003035 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003036 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003037 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003038
3039 fnOut << ") { return false; }\n"
3040 " }\n"
3041 " return true;\n"
3042 "}\n";
3043
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003044 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003045
3046 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003047 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003048
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003049 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003050}
3051
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003052TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003053{
3054 for (const auto &assignFunction : mArrayAssignmentFunctions)
3055 {
3056 if (assignFunction.type == type)
3057 {
3058 return assignFunction.functionName;
3059 }
3060 }
3061
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003062 TType elementType(type);
3063 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003064
3065 ArrayHelperFunction function;
3066 function.type = type;
3067
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003068 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003069
3070 TInfoSinkBase fnOut;
3071
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003072 const TString &typeName = TypeString(type);
3073 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3074 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003075 << "{\n"
3076 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003077 << type.getOutermostArraySize()
3078 << "; ++i)\n"
3079 " {\n"
3080 " ";
3081
3082 outputAssign(PreVisit, elementType, fnOut);
3083 fnOut << "a[i]";
3084 outputAssign(InVisit, elementType, fnOut);
3085 fnOut << "b[i]";
3086 outputAssign(PostVisit, elementType, fnOut);
3087
3088 fnOut << ";\n"
3089 " }\n"
3090 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003091
3092 function.functionDefinition = fnOut.c_str();
3093
3094 mArrayAssignmentFunctions.push_back(function);
3095
3096 return function.functionName;
3097}
3098
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003099TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003100{
3101 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3102 {
3103 if (constructIntoFunction.type == type)
3104 {
3105 return constructIntoFunction.functionName;
3106 }
3107 }
3108
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003109 TType elementType(type);
3110 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003111
3112 ArrayHelperFunction function;
3113 function.type = type;
3114
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003115 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003116
3117 TInfoSinkBase fnOut;
3118
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003119 const TString &typeName = TypeString(type);
3120 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3121 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003122 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003123 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003124 }
3125 fnOut << ")\n"
3126 "{\n";
3127
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003128 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003129 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003130 fnOut << " ";
3131 outputAssign(PreVisit, elementType, fnOut);
3132 fnOut << "a[" << i << "]";
3133 outputAssign(InVisit, elementType, fnOut);
3134 fnOut << "b" << i;
3135 outputAssign(PostVisit, elementType, fnOut);
3136 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003137 }
3138 fnOut << "}\n";
3139
3140 function.functionDefinition = fnOut.c_str();
3141
3142 mArrayConstructIntoFunctions.push_back(function);
3143
3144 return function.functionName;
3145}
3146
Jamie Madill2e295e22015-04-29 10:41:33 -04003147void OutputHLSL::ensureStructDefined(const TType &type)
3148{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003149 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003150 if (structure)
3151 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003152 ASSERT(type.getBasicType() == EbtStruct);
3153 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003154 }
3155}
3156
Jamie Madill45bcc782016-11-07 13:58:48 -05003157} // namespace sh