blob: 5e858244dd45a005adfaa2d59e24e57ec0fe6dcb [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08009#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000010#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000011#include <cfloat>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000012
Jamie Madill9e0478f2015-01-13 11:13:54 -050013#include "common/angleutils.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030014#include "common/debug.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/utilities.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020016#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050017#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080018#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/InfoSink.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030021#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/UniformHLSL.h"
24#include "compiler/translator/UtilsHLSL.h"
25#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020026#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020027#include "compiler/translator/tree_util/FindSymbolNode.h"
28#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080041 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030042 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080043 for (unsigned int arraySize : *type.getArraySizes())
44 {
45 fnName << arraySize << "_";
46 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030047 }
48 fnName << TypeString(type);
49 return fnName.str();
50}
51
Olli Etuaho40dbdd62017-10-13 13:34:19 +030052bool IsDeclarationWrittenOut(TIntermDeclaration *node)
53{
54 TIntermSequence *sequence = node->getSequence();
55 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
56 ASSERT(sequence->size() == 1);
57 ASSERT(variable);
58 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080059 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030060}
61
Olli Etuaho2ef23e22017-11-01 16:39:11 +020062bool IsInStd140InterfaceBlock(TIntermTyped *node)
63{
64 TIntermBinary *binaryNode = node->getAsBinaryNode();
65
66 if (binaryNode)
67 {
68 return IsInStd140InterfaceBlock(binaryNode->getLeft());
69 }
70
71 const TType &type = node->getType();
72
73 // determine if we are in the standard layout
74 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
75 if (interfaceBlock)
76 {
77 return (interfaceBlock->blockStorage() == EbsStd140);
78 }
79
80 return false;
81}
82
Jiawei Shaoa6a78422018-06-28 08:32:54 +080083const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
84{
85 switch (op)
86 {
87 case EOpAtomicAdd:
88 return "InterlockedAdd(";
89 case EOpAtomicMin:
90 return "InterlockedMin(";
91 case EOpAtomicMax:
92 return "InterlockedMax(";
93 case EOpAtomicAnd:
94 return "InterlockedAnd(";
95 case EOpAtomicOr:
96 return "InterlockedOr(";
97 case EOpAtomicXor:
98 return "InterlockedXor(";
99 case EOpAtomicExchange:
100 return "InterlockedExchange(";
101 case EOpAtomicCompSwap:
102 return "InterlockedCompareExchange(";
103 default:
104 UNREACHABLE();
105 return "";
106 }
107}
108
109bool IsAtomicFunctionDirectAssign(const TIntermBinary &node)
110{
111 return node.getOp() == EOpAssign && node.getRight()->getAsAggregate() &&
112 IsAtomicFunction(node.getRight()->getAsAggregate()->getOp());
113}
114
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300115} // anonymous namespace
116
Olli Etuahoc71862a2017-12-21 12:58:29 +0200117TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
118 const TVariable *aInstanceVariable)
119 : block(aBlock), instanceVariable(aInstanceVariable)
120{
121}
122
Olli Etuaho56a2f952016-12-08 12:16:27 +0000123void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300124{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000125 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
126 // regardless.
127 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
128 mOutputType == SH_HLSL_4_1_OUTPUT)
129 {
130 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
131 }
132 else
133 {
134 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
135 }
136}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300137
Olli Etuaho56a2f952016-12-08 12:16:27 +0000138void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200139{
140 ASSERT(constUnion != nullptr);
141 switch (constUnion->getType())
142 {
143 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000144 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200145 break;
146 case EbtInt:
147 out << constUnion->getIConst();
148 break;
149 case EbtUInt:
150 out << constUnion->getUConst();
151 break;
152 case EbtBool:
153 out << constUnion->getBConst();
154 break;
155 default:
156 UNREACHABLE();
157 }
158}
159
Olli Etuaho56a2f952016-12-08 12:16:27 +0000160const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
161 const TConstantUnion *const constUnion,
162 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200163{
164 const TConstantUnion *constUnionIterated = constUnion;
165 for (size_t i = 0; i < size; i++, constUnionIterated++)
166 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000167 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200168
169 if (i != size - 1)
170 {
171 out << ", ";
172 }
173 }
174 return constUnionIterated;
175}
176
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800177OutputHLSL::OutputHLSL(sh::GLenum shaderType,
178 int shaderVersion,
179 const TExtensionBehavior &extensionBehavior,
180 const char *sourcePath,
181 ShShaderOutput outputType,
182 int numRenderTargets,
183 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300184 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300185 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300186 TSymbolTable *symbolTable,
187 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300188 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200189 mShaderType(shaderType),
190 mShaderVersion(shaderVersion),
191 mExtensionBehavior(extensionBehavior),
192 mSourcePath(sourcePath),
193 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700194 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300195 mInsideFunction(false),
196 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000197 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300198 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300199 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300200 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800202 mUsesFragColor = false;
203 mUsesFragData = false;
204 mUsesDepthRange = false;
205 mUsesFragCoord = false;
206 mUsesPointCoord = false;
207 mUsesFrontFacing = false;
208 mUsesPointSize = false;
209 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300210 mHasMultiviewExtensionEnabled =
211 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300212 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500213 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500214 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800215 mUsesNumWorkGroups = false;
216 mUsesWorkGroupID = false;
217 mUsesLocalInvocationID = false;
218 mUsesGlobalInvocationID = false;
219 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500220 mUsesXor = false;
221 mUsesDiscardRewriting = false;
222 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530223 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000224
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000225 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000228 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500229 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000230
Yunchao Hed7297bf2017-04-19 15:27:10 +0800231 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000232
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500233 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300234 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800235 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400236
Olli Etuahod8724a92017-12-29 18:40:36 +0200237 unsigned int firstUniformRegister =
238 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Xinghua Cao06a22622018-05-18 16:48:41 +0800239 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200240
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200241 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000242 {
Arun Patole63419392015-03-13 11:51:07 +0530243 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500244 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
245 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530246 // In both cases total 3 uniform registers need to be reserved.
247 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000248 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000249
Geoff Lang00140f42016-02-03 18:47:33 +0000250 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800251 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252}
253
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000254OutputHLSL::~OutputHLSL()
255{
Jamie Madill8daaba12014-06-13 10:04:33 -0400256 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400257 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300258 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800259 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200260 for (auto &eqFunction : mStructEqualityFunctions)
261 {
262 SafeDelete(eqFunction);
263 }
264 for (auto &eqFunction : mArrayEqualityFunctions)
265 {
266 SafeDelete(eqFunction);
267 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000268}
269
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200270void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000271{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200272 BuiltInFunctionEmulator builtInFunctionEmulator;
273 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800274 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
275 {
276 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
277 mShaderVersion);
278 }
279
Olli Etuahodfa75e82017-01-23 09:43:06 -0800280 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500281
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700282 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000283 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700284 ASSERT(success == CallDAG::INITDAG_SUCCESS);
285 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700286
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200287 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
288 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
289 // the shader code. When we add shader storage blocks we might also consider an alternative
290 // solution, since the struct mapping won't work very well for shader storage blocks.
291
Jamie Madill37997142015-01-28 10:06:34 -0500292 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500293 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200294 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500295 mInfoSinkStack.pop();
296
Jamie Madill37997142015-01-28 10:06:34 -0500297 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500298 mInfoSinkStack.pop();
299
Jamie Madill32aab012015-01-27 14:12:26 -0500300 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200301 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500302 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000303
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200304 objSink << mHeader.c_str();
305 objSink << mBody.c_str();
306 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200307
Olli Etuahodfa75e82017-01-23 09:43:06 -0800308 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000309}
310
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800311const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400312{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800313 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400314}
315
Jamie Madill9fe25e92014-07-18 10:33:08 -0400316const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
317{
318 return mUniformHLSL->getUniformRegisterMap();
319}
320
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200321TString OutputHLSL::structInitializerString(int indent,
322 const TType &type,
323 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400324{
325 TString init;
326
Olli Etuahoed049ab2017-06-30 17:38:33 +0300327 TString indentString;
328 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300330 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400331 }
332
Olli Etuahoed049ab2017-06-30 17:38:33 +0300333 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400334 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300335 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300336 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400337 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300338 TStringStream indexedString;
339 indexedString << name << "[" << arrayIndex << "]";
340 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300341 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300342 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300343 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300344 {
345 init += ",";
346 }
347 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400350 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300351 else if (type.getBasicType() == EbtStruct)
352 {
353 init += indentString + "{\n";
354 const TStructure &structure = *type.getStruct();
355 const TFieldList &fields = structure.fields();
356 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
357 {
358 const TField &field = *fields[fieldIndex];
359 const TString &fieldName = name + "." + Decorate(field.name());
360 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400361
Olli Etuahoed049ab2017-06-30 17:38:33 +0300362 init += structInitializerString(indent + 1, fieldType, fieldName);
363 if (fieldIndex < fields.size() - 1)
364 {
365 init += ",";
366 }
367 init += "\n";
368 }
369 init += indentString + "}";
370 }
371 else
372 {
373 init += indentString + name;
374 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400375
376 return init;
377}
378
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200379TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
380{
381 TString mappedStructs;
382
383 for (auto &mappedStruct : std140Structs)
384 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200385 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200386 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200387 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200388 {
389 continue;
390 }
391
392 unsigned int instanceCount = 1u;
393 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
394 if (isInstanceArray)
395 {
396 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
397 }
398
399 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
400 ++instanceArrayIndex)
401 {
402 TString originalName;
403 TString mappedName("map");
404
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200405 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200406 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200407 const ImmutableString &instanceName =
408 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200409 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
410 if (isInstanceArray)
411 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200412 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200413 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200414 originalName += instanceString;
415 mappedName += instanceString;
416 originalName += ".";
417 mappedName += "_";
418 }
419
420 TString fieldName = Decorate(mappedStruct.field->name());
421 originalName += fieldName;
422 mappedName += fieldName;
423
424 TType *structType = mappedStruct.field->type();
425 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200426 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200427
428 if (structType->isArray())
429 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300430 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431 }
432
433 mappedStructs += " =\n";
434 mappedStructs += structInitializerString(0, *structType, originalName);
435 mappedStructs += ";\n";
436 }
437 }
438 return mappedStructs;
439}
440
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300441void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300443 for (const auto &attribute : mReferencedAttributes)
444 {
445 const TType &type = attribute.second->getType();
446 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400447
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300448 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
449 << zeroInitializer(type) << ";\n";
450 }
451}
452
453void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
454{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200455 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000456 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800457 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000458
459 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300460 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300461 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
462 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000463 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300464}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000465
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300466void OutputHLSL::header(TInfoSinkBase &out,
467 const std::vector<MappedStruct> &std140Structs,
468 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
469{
470 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000471
Jamie Madill8daaba12014-06-13 10:04:33 -0400472 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400473
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300474 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800475 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400476
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200477 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500478 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200479 out << "\n// Equality functions\n\n";
480 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500481 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200482 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200483 }
484 }
Olli Etuaho12690762015-03-31 12:55:28 +0300485 if (!mArrayAssignmentFunctions.empty())
486 {
487 out << "\n// Assignment functions\n\n";
488 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
489 {
490 out << assignmentFunction.functionDefinition << "\n";
491 }
492 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300493 if (!mArrayConstructIntoFunctions.empty())
494 {
495 out << "\n// Array constructor functions\n\n";
496 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
497 {
498 out << constructIntoFunction.functionDefinition << "\n";
499 }
500 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200501
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500502 if (mUsesDiscardRewriting)
503 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400504 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500505 }
506
Nicolas Capens655fe362014-04-11 13:12:34 -0400507 if (mUsesNestedBreak)
508 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400509 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400510 }
511
Arun Patole44efa0b2015-03-04 17:11:05 +0530512 if (mRequiresIEEEStrictCompiling)
513 {
514 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
515 }
516
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400517 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
518 "#define LOOP [loop]\n"
519 "#define FLATTEN [flatten]\n"
520 "#else\n"
521 "#define LOOP\n"
522 "#define FLATTEN\n"
523 "#endif\n";
524
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200525 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300527 const bool usingMRTExtension =
528 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000529
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000530 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300531 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400532 out << "\n";
533
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200534 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000535 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200536 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000537 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200538 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800539 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400540
Olli Etuahofbb1c792018-01-19 16:26:59 +0200541 out << "static " << TypeString(variableType) << " out_" << variableName
542 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000543 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000544 }
Jamie Madill46131a32013-06-20 11:55:50 -0400545 else
546 {
547 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
548
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800549 out << "static float4 gl_Color[" << numColorValues
550 << "] =\n"
551 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400552 for (unsigned int i = 0; i < numColorValues; i++)
553 {
554 out << " float4(0, 0, 0, 0)";
555 if (i + 1 != numColorValues)
556 {
557 out << ",";
558 }
559 out << "\n";
560 }
561
562 out << "};\n";
563 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000564
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400565 if (mUsesFragDepth)
566 {
567 out << "static float gl_Depth = 0.0;\n";
568 }
569
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000570 if (mUsesFragCoord)
571 {
572 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
573 }
574
575 if (mUsesPointCoord)
576 {
577 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
578 }
579
580 if (mUsesFrontFacing)
581 {
582 out << "static bool gl_FrontFacing = false;\n";
583 }
584
585 out << "\n";
586
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000587 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000589 out << "struct gl_DepthRangeParameters\n"
590 "{\n"
591 " float near;\n"
592 " float far;\n"
593 " float diff;\n"
594 "};\n"
595 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000596 }
597
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200598 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000599 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000600 out << "cbuffer DriverConstants : register(b1)\n"
601 "{\n";
602
603 if (mUsesDepthRange)
604 {
605 out << " float3 dx_DepthRange : packoffset(c0);\n";
606 }
607
608 if (mUsesFragCoord)
609 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000610 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000611 }
612
613 if (mUsesFragCoord || mUsesFrontFacing)
614 {
615 out << " float3 dx_DepthFront : packoffset(c2);\n";
616 }
617
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800618 if (mUsesFragCoord)
619 {
620 // dx_ViewScale is only used in the fragment shader to correct
621 // the value for glFragCoord if necessary
622 out << " float2 dx_ViewScale : packoffset(c3);\n";
623 }
624
Martin Radev72b4e1e2017-08-31 15:42:56 +0300625 if (mHasMultiviewExtensionEnabled)
626 {
627 // We have to add a value which we can use to keep track of which multi-view code
628 // path is to be selected in the GS.
629 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
630 }
631
Olli Etuaho618bebc2016-01-15 16:40:00 +0200632 if (mOutputType == SH_HLSL_4_1_OUTPUT)
633 {
634 mUniformHLSL->samplerMetadataUniforms(out, "c4");
635 }
636
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000637 out << "};\n";
638 }
639 else
640 {
641 if (mUsesDepthRange)
642 {
643 out << "uniform float3 dx_DepthRange : register(c0);";
644 }
645
646 if (mUsesFragCoord)
647 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000648 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000649 }
650
651 if (mUsesFragCoord || mUsesFrontFacing)
652 {
653 out << "uniform float3 dx_DepthFront : register(c2);\n";
654 }
655 }
656
657 out << "\n";
658
659 if (mUsesDepthRange)
660 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500661 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
662 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000663 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000664 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000665
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000666 if (usingMRTExtension && mNumRenderTargets > 1)
667 {
668 out << "#define GL_USES_MRT\n";
669 }
670
671 if (mUsesFragColor)
672 {
673 out << "#define GL_USES_FRAG_COLOR\n";
674 }
675
676 if (mUsesFragData)
677 {
678 out << "#define GL_USES_FRAG_DATA\n";
679 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680 }
Xinghua Caob1239382016-12-13 15:07:05 +0800681 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000683 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300684 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000685 out << "\n"
686 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400687
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000688 if (mUsesPointSize)
689 {
690 out << "static float gl_PointSize = float(1);\n";
691 }
692
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000693 if (mUsesInstanceID)
694 {
695 out << "static int gl_InstanceID;";
696 }
697
Corentin Wallezb076add2016-01-11 16:45:46 -0500698 if (mUsesVertexID)
699 {
700 out << "static int gl_VertexID;";
701 }
702
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000703 out << "\n"
704 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300705 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000706 out << "\n";
707
708 if (mUsesDepthRange)
709 {
710 out << "struct gl_DepthRangeParameters\n"
711 "{\n"
712 " float near;\n"
713 " float far;\n"
714 " float diff;\n"
715 "};\n"
716 "\n";
717 }
718
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200719 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000720 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800721 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800723
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000724 if (mUsesDepthRange)
725 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800726 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000727 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800728
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800729 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
730 // shaders. However, we declare it for all shaders (including Feature Level 10+).
731 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
732 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800733 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800734 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800735 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800736
Martin Radev72b4e1e2017-08-31 15:42:56 +0300737 if (mHasMultiviewExtensionEnabled)
738 {
739 // We have to add a value which we can use to keep track of which multi-view code
740 // path is to be selected in the GS.
741 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
742 }
743
Olli Etuaho618bebc2016-01-15 16:40:00 +0200744 if (mOutputType == SH_HLSL_4_1_OUTPUT)
745 {
746 mUniformHLSL->samplerMetadataUniforms(out, "c4");
747 }
748
Austin Kinross4fd18b12014-12-22 12:32:05 -0800749 out << "};\n"
750 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000751 }
752 else
753 {
754 if (mUsesDepthRange)
755 {
756 out << "uniform float3 dx_DepthRange : register(c0);\n";
757 }
758
Cooper Partine6664f02015-01-09 16:22:24 -0800759 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
760 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000761 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000762 }
763
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000764 if (mUsesDepthRange)
765 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
767 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000768 "\n";
769 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400770 }
Xinghua Caob1239382016-12-13 15:07:05 +0800771 else // Compute shader
772 {
773 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800774
775 out << "cbuffer DriverConstants : register(b1)\n"
776 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800777 if (mUsesNumWorkGroups)
778 {
Xinghua Caob1239382016-12-13 15:07:05 +0800779 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800780 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800781 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
782 mUniformHLSL->samplerMetadataUniforms(out, "c1");
783 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800784
785 // Follow built-in variables would be initialized in
786 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
787 // are used in compute shader.
788 if (mUsesWorkGroupID)
789 {
790 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
791 }
792
793 if (mUsesLocalInvocationID)
794 {
795 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
796 }
797
798 if (mUsesGlobalInvocationID)
799 {
800 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
801 }
802
803 if (mUsesLocalInvocationIndex)
804 {
805 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
806 }
807 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000808
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800809 if (!mappedStructs.empty())
810 {
811 out << "// Structures from std140 blocks with padding removed\n";
812 out << "\n";
813 out << mappedStructs;
814 out << "\n";
815 }
816
Geoff Lang1fe74c72016-08-25 13:23:01 -0400817 bool getDimensionsIgnoresBaseLevel =
818 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
819 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800820 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000821
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000822 if (mUsesFragCoord)
823 {
824 out << "#define GL_USES_FRAG_COORD\n";
825 }
826
827 if (mUsesPointCoord)
828 {
829 out << "#define GL_USES_POINT_COORD\n";
830 }
831
832 if (mUsesFrontFacing)
833 {
834 out << "#define GL_USES_FRONT_FACING\n";
835 }
836
837 if (mUsesPointSize)
838 {
839 out << "#define GL_USES_POINT_SIZE\n";
840 }
841
Martin Radev41ac68e2017-06-06 12:16:58 +0300842 if (mHasMultiviewExtensionEnabled)
843 {
844 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
845 }
846
847 if (mUsesViewID)
848 {
849 out << "#define GL_USES_VIEW_ID\n";
850 }
851
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400852 if (mUsesFragDepth)
853 {
854 out << "#define GL_USES_FRAG_DEPTH\n";
855 }
856
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000857 if (mUsesDepthRange)
858 {
859 out << "#define GL_USES_DEPTH_RANGE\n";
860 }
861
Xinghua Caob1239382016-12-13 15:07:05 +0800862 if (mUsesNumWorkGroups)
863 {
864 out << "#define GL_USES_NUM_WORK_GROUPS\n";
865 }
866
867 if (mUsesWorkGroupID)
868 {
869 out << "#define GL_USES_WORK_GROUP_ID\n";
870 }
871
872 if (mUsesLocalInvocationID)
873 {
874 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
875 }
876
877 if (mUsesGlobalInvocationID)
878 {
879 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
880 }
881
882 if (mUsesLocalInvocationIndex)
883 {
884 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
885 }
886
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000887 if (mUsesXor)
888 {
889 out << "bool xor(bool p, bool q)\n"
890 "{\n"
891 " return (p || q) && !(p && q);\n"
892 "}\n"
893 "\n";
894 }
895
Olli Etuahodfa75e82017-01-23 09:43:06 -0800896 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000897}
898
899void OutputHLSL::visitSymbol(TIntermSymbol *node)
900{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200901 const TVariable &variable = node->variable();
902
903 // Empty symbols can only appear in declarations and function arguments, and in either of those
904 // cases the symbol nodes are not visited.
905 ASSERT(variable.symbolType() != SymbolType::Empty);
906
Jamie Madill32aab012015-01-27 14:12:26 -0500907 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000908
Jamie Madill570e04d2013-06-21 09:15:33 -0400909 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200910 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400911 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200912 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400913 }
914
Olli Etuahofbb1c792018-01-19 16:26:59 +0200915 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200916 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200917
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000918 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000919 {
920 mUsesDepthRange = true;
921 out << name;
922 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000923 else
924 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200925 const TType &variableType = variable.getType();
926 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000927
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200928 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200929
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000930 if (qualifier == EvqUniform)
931 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200932 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400933
934 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000935 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200936 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
937 {
938 const TVariable *instanceVariable = nullptr;
939 if (variableType.isInterfaceBlock())
940 {
941 instanceVariable = &variable;
942 }
943 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
944 new TReferencedBlock(interfaceBlock, instanceVariable);
945 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000946 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000947 else
948 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200949 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000950 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400951
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200952 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000953 }
Jamie Madill19571812013-08-12 15:26:34 -0700954 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000955 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200956 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400957 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000958 }
Jamie Madill033dae62014-06-18 12:56:28 -0400959 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000960 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200961 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +0300962 out << DecorateVariableIfNeeded(variable);
963 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +0300964 {
965 mUsesViewID = true;
966 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000967 }
Jamie Madill19571812013-08-12 15:26:34 -0700968 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400969 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200970 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400971 out << "out_" << name;
972 }
973 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000974 {
975 out << "gl_Color[0]";
976 mUsesFragColor = true;
977 }
978 else if (qualifier == EvqFragData)
979 {
980 out << "gl_Color";
981 mUsesFragData = true;
982 }
983 else if (qualifier == EvqFragCoord)
984 {
985 mUsesFragCoord = true;
986 out << name;
987 }
988 else if (qualifier == EvqPointCoord)
989 {
990 mUsesPointCoord = true;
991 out << name;
992 }
993 else if (qualifier == EvqFrontFacing)
994 {
995 mUsesFrontFacing = true;
996 out << name;
997 }
998 else if (qualifier == EvqPointSize)
999 {
1000 mUsesPointSize = true;
1001 out << name;
1002 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001003 else if (qualifier == EvqInstanceID)
1004 {
1005 mUsesInstanceID = true;
1006 out << name;
1007 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001008 else if (qualifier == EvqVertexID)
1009 {
1010 mUsesVertexID = true;
1011 out << name;
1012 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001013 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001014 {
1015 mUsesFragDepth = true;
1016 out << "gl_Depth";
1017 }
Xinghua Caob1239382016-12-13 15:07:05 +08001018 else if (qualifier == EvqNumWorkGroups)
1019 {
1020 mUsesNumWorkGroups = true;
1021 out << name;
1022 }
1023 else if (qualifier == EvqWorkGroupID)
1024 {
1025 mUsesWorkGroupID = true;
1026 out << name;
1027 }
1028 else if (qualifier == EvqLocalInvocationID)
1029 {
1030 mUsesLocalInvocationID = true;
1031 out << name;
1032 }
1033 else if (qualifier == EvqGlobalInvocationID)
1034 {
1035 mUsesGlobalInvocationID = true;
1036 out << name;
1037 }
1038 else if (qualifier == EvqLocalInvocationIndex)
1039 {
1040 mUsesLocalInvocationIndex = true;
1041 out << name;
1042 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001043 else
1044 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001045 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001046 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001047 }
1048}
1049
Olli Etuaho7fb49552015-03-18 17:27:44 +02001050void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1051{
1052 if (type.isScalar() && !type.isArray())
1053 {
1054 if (op == EOpEqual)
1055 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001056 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001057 }
1058 else
1059 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001060 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001061 }
1062 }
1063 else
1064 {
1065 if (visit == PreVisit && op == EOpNotEqual)
1066 {
1067 out << "!";
1068 }
1069
1070 if (type.isArray())
1071 {
1072 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001073 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001074 }
1075 else if (type.getBasicType() == EbtStruct)
1076 {
1077 const TStructure &structure = *type.getStruct();
1078 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001079 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001080 }
1081 else
1082 {
1083 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001084 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001085 }
1086 }
1087}
1088
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001089void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1090{
1091 if (type.isArray())
1092 {
1093 const TString &functionName = addArrayAssignmentFunction(type);
1094 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1095 }
1096 else
1097 {
1098 outputTriplet(out, visit, "(", " = ", ")");
1099 }
1100}
1101
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001102bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001103{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001104 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001105 {
1106 TIntermNode *ancestor = getAncestorNode(n);
1107 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1108 if (ancestorBinary == nullptr)
1109 {
1110 return false;
1111 }
1112 switch (ancestorBinary->getOp())
1113 {
1114 case EOpIndexDirectStruct:
1115 {
1116 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1117 const TIntermConstantUnion *index =
1118 ancestorBinary->getRight()->getAsConstantUnion();
1119 const TField *field = structure->fields()[index->getIConst(0)];
1120 if (IsSampler(field->type()->getBasicType()))
1121 {
1122 return true;
1123 }
1124 break;
1125 }
1126 case EOpIndexDirect:
1127 break;
1128 default:
1129 // Returning a sampler from indirect indexing is not supported.
1130 return false;
1131 }
1132 }
1133 return false;
1134}
1135
Olli Etuahob6fa0432016-09-28 16:28:05 +01001136bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1137{
1138 TInfoSinkBase &out = getInfoSink();
1139 if (visit == PostVisit)
1140 {
1141 out << ".";
1142 node->writeOffsetsAsXYZW(&out);
1143 }
1144 return true;
1145}
1146
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1148{
Jamie Madill32aab012015-01-27 14:12:26 -05001149 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150
1151 switch (node->getOp())
1152 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001153 case EOpComma:
1154 outputTriplet(out, visit, "(", ", ", ")");
1155 break;
1156 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001157 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001158 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001159 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1160 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001161 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001162 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1163 out << functionName << "(";
1164 node->getLeft()->traverse(this);
1165 TIntermSequence *seq = rightAgg->getSequence();
1166 for (auto &arrayElement : *seq)
1167 {
1168 out << ", ";
1169 arrayElement->traverse(this);
1170 }
1171 out << ")";
1172 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001173 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001174 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1175 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001176 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001177 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001178 // Assignment expressions with atomic functions should be transformed into atomic
1179 // function calls in HLSL.
1180 // e.g. original_value = atomicAdd(dest, value) should be translated into
1181 // InterlockedAdd(dest, value, original_value);
1182 else if (IsAtomicFunctionDirectAssign(*node))
1183 {
1184 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1185 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1186 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1187 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1188 ASSERT(argumentSeq->size() >= 2u);
1189 for (auto &argument : *argumentSeq)
1190 {
1191 argument->traverse(this);
1192 out << ", ";
1193 }
1194 node->getLeft()->traverse(this);
1195 out << ")";
1196 return false;
1197 }
1198
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001199 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001200 break;
1201 case EOpInitialize:
1202 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001203 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001204 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1205 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001206 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001207
1208 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001209 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001210
1211 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1212 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1213 // new variable is created before the assignment is evaluated), so we need to
1214 // convert
1215 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001216 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001217 {
1218 // Skip initializing the rest of the expression
1219 return false;
1220 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001221 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001222 {
1223 return false;
1224 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001225 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001226 else if (visit == InVisit)
1227 {
1228 out << " = ";
1229 }
1230 break;
1231 case EOpAddAssign:
1232 outputTriplet(out, visit, "(", " += ", ")");
1233 break;
1234 case EOpSubAssign:
1235 outputTriplet(out, visit, "(", " -= ", ")");
1236 break;
1237 case EOpMulAssign:
1238 outputTriplet(out, visit, "(", " *= ", ")");
1239 break;
1240 case EOpVectorTimesScalarAssign:
1241 outputTriplet(out, visit, "(", " *= ", ")");
1242 break;
1243 case EOpMatrixTimesScalarAssign:
1244 outputTriplet(out, visit, "(", " *= ", ")");
1245 break;
1246 case EOpVectorTimesMatrixAssign:
1247 if (visit == PreVisit)
1248 {
1249 out << "(";
1250 }
1251 else if (visit == InVisit)
1252 {
1253 out << " = mul(";
1254 node->getLeft()->traverse(this);
1255 out << ", transpose(";
1256 }
1257 else
1258 {
1259 out << ")))";
1260 }
1261 break;
1262 case EOpMatrixTimesMatrixAssign:
1263 if (visit == PreVisit)
1264 {
1265 out << "(";
1266 }
1267 else if (visit == InVisit)
1268 {
1269 out << " = transpose(mul(transpose(";
1270 node->getLeft()->traverse(this);
1271 out << "), transpose(";
1272 }
1273 else
1274 {
1275 out << "))))";
1276 }
1277 break;
1278 case EOpDivAssign:
1279 outputTriplet(out, visit, "(", " /= ", ")");
1280 break;
1281 case EOpIModAssign:
1282 outputTriplet(out, visit, "(", " %= ", ")");
1283 break;
1284 case EOpBitShiftLeftAssign:
1285 outputTriplet(out, visit, "(", " <<= ", ")");
1286 break;
1287 case EOpBitShiftRightAssign:
1288 outputTriplet(out, visit, "(", " >>= ", ")");
1289 break;
1290 case EOpBitwiseAndAssign:
1291 outputTriplet(out, visit, "(", " &= ", ")");
1292 break;
1293 case EOpBitwiseXorAssign:
1294 outputTriplet(out, visit, "(", " ^= ", ")");
1295 break;
1296 case EOpBitwiseOrAssign:
1297 outputTriplet(out, visit, "(", " |= ", ")");
1298 break;
1299 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001300 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001301 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001302 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001303 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001304 if (visit == PreVisit)
1305 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001306 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001307 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuahoc71862a2017-12-21 12:58:29 +02001308 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1309 {
1310 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1311 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1312 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001313 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001314 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1315 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001316 return false;
1317 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001318 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001319 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001320 {
1321 // All parts of an expression that access a sampler in a struct need to use _ as
1322 // separator to access the sampler variable that has been moved out of the struct.
1323 outputTriplet(out, visit, "", "_", "");
1324 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001325 else
1326 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001327 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001328 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001329 }
1330 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001331 case EOpIndexIndirect:
1332 // We do not currently support indirect references to interface blocks
1333 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1334 outputTriplet(out, visit, "", "[", "]");
1335 break;
1336 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001337 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001338 const TStructure *structure = node->getLeft()->getType().getStruct();
1339 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1340 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001341
Olli Etuaho96963162016-03-21 11:54:33 +02001342 // In cases where indexing returns a sampler, we need to access the sampler variable
1343 // that has been moved out of the struct.
1344 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1345 if (visit == PreVisit && indexingReturnsSampler)
1346 {
1347 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1348 // This prefix is only output at the beginning of the indexing expression, which
1349 // may have multiple parts.
1350 out << "angle";
1351 }
1352 if (!indexingReturnsSampler)
1353 {
1354 // All parts of an expression that access a sampler in a struct need to use _ as
1355 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001356 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001357 }
1358 if (visit == InVisit)
1359 {
1360 if (indexingReturnsSampler)
1361 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001362 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001363 }
1364 else
1365 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001366 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001367 }
1368
1369 return false;
1370 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001371 }
1372 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001373 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001374 {
1375 bool structInStd140Block =
1376 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1377 if (visit == PreVisit && structInStd140Block)
1378 {
1379 out << "map";
1380 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001381 if (visit == InVisit)
1382 {
1383 const TInterfaceBlock *interfaceBlock =
1384 node->getLeft()->getType().getInterfaceBlock();
1385 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1386 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001387 if (structInStd140Block)
1388 {
1389 out << "_";
1390 }
1391 else
1392 {
1393 out << ".";
1394 }
1395 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001396
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001397 return false;
1398 }
1399 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001400 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001401 case EOpAdd:
1402 outputTriplet(out, visit, "(", " + ", ")");
1403 break;
1404 case EOpSub:
1405 outputTriplet(out, visit, "(", " - ", ")");
1406 break;
1407 case EOpMul:
1408 outputTriplet(out, visit, "(", " * ", ")");
1409 break;
1410 case EOpDiv:
1411 outputTriplet(out, visit, "(", " / ", ")");
1412 break;
1413 case EOpIMod:
1414 outputTriplet(out, visit, "(", " % ", ")");
1415 break;
1416 case EOpBitShiftLeft:
1417 outputTriplet(out, visit, "(", " << ", ")");
1418 break;
1419 case EOpBitShiftRight:
1420 outputTriplet(out, visit, "(", " >> ", ")");
1421 break;
1422 case EOpBitwiseAnd:
1423 outputTriplet(out, visit, "(", " & ", ")");
1424 break;
1425 case EOpBitwiseXor:
1426 outputTriplet(out, visit, "(", " ^ ", ")");
1427 break;
1428 case EOpBitwiseOr:
1429 outputTriplet(out, visit, "(", " | ", ")");
1430 break;
1431 case EOpEqual:
1432 case EOpNotEqual:
1433 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1434 break;
1435 case EOpLessThan:
1436 outputTriplet(out, visit, "(", " < ", ")");
1437 break;
1438 case EOpGreaterThan:
1439 outputTriplet(out, visit, "(", " > ", ")");
1440 break;
1441 case EOpLessThanEqual:
1442 outputTriplet(out, visit, "(", " <= ", ")");
1443 break;
1444 case EOpGreaterThanEqual:
1445 outputTriplet(out, visit, "(", " >= ", ")");
1446 break;
1447 case EOpVectorTimesScalar:
1448 outputTriplet(out, visit, "(", " * ", ")");
1449 break;
1450 case EOpMatrixTimesScalar:
1451 outputTriplet(out, visit, "(", " * ", ")");
1452 break;
1453 case EOpVectorTimesMatrix:
1454 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1455 break;
1456 case EOpMatrixTimesVector:
1457 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1458 break;
1459 case EOpMatrixTimesMatrix:
1460 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1461 break;
1462 case EOpLogicalOr:
1463 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1464 // been unfolded.
1465 ASSERT(!node->getRight()->hasSideEffects());
1466 outputTriplet(out, visit, "(", " || ", ")");
1467 return true;
1468 case EOpLogicalXor:
1469 mUsesXor = true;
1470 outputTriplet(out, visit, "xor(", ", ", ")");
1471 break;
1472 case EOpLogicalAnd:
1473 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1474 // been unfolded.
1475 ASSERT(!node->getRight()->hasSideEffects());
1476 outputTriplet(out, visit, "(", " && ", ")");
1477 return true;
1478 default:
1479 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001480 }
1481
1482 return true;
1483}
1484
1485bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1486{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001487 TInfoSinkBase &out = getInfoSink();
1488
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001489 switch (node->getOp())
1490 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001491 case EOpNegative:
1492 outputTriplet(out, visit, "(-", "", ")");
1493 break;
1494 case EOpPositive:
1495 outputTriplet(out, visit, "(+", "", ")");
1496 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001497 case EOpLogicalNot:
1498 outputTriplet(out, visit, "(!", "", ")");
1499 break;
1500 case EOpBitwiseNot:
1501 outputTriplet(out, visit, "(~", "", ")");
1502 break;
1503 case EOpPostIncrement:
1504 outputTriplet(out, visit, "(", "", "++)");
1505 break;
1506 case EOpPostDecrement:
1507 outputTriplet(out, visit, "(", "", "--)");
1508 break;
1509 case EOpPreIncrement:
1510 outputTriplet(out, visit, "(++", "", ")");
1511 break;
1512 case EOpPreDecrement:
1513 outputTriplet(out, visit, "(--", "", ")");
1514 break;
1515 case EOpRadians:
1516 outputTriplet(out, visit, "radians(", "", ")");
1517 break;
1518 case EOpDegrees:
1519 outputTriplet(out, visit, "degrees(", "", ")");
1520 break;
1521 case EOpSin:
1522 outputTriplet(out, visit, "sin(", "", ")");
1523 break;
1524 case EOpCos:
1525 outputTriplet(out, visit, "cos(", "", ")");
1526 break;
1527 case EOpTan:
1528 outputTriplet(out, visit, "tan(", "", ")");
1529 break;
1530 case EOpAsin:
1531 outputTriplet(out, visit, "asin(", "", ")");
1532 break;
1533 case EOpAcos:
1534 outputTriplet(out, visit, "acos(", "", ")");
1535 break;
1536 case EOpAtan:
1537 outputTriplet(out, visit, "atan(", "", ")");
1538 break;
1539 case EOpSinh:
1540 outputTriplet(out, visit, "sinh(", "", ")");
1541 break;
1542 case EOpCosh:
1543 outputTriplet(out, visit, "cosh(", "", ")");
1544 break;
1545 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 case EOpAtanh:
1549 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001550 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 break;
1552 case EOpExp:
1553 outputTriplet(out, visit, "exp(", "", ")");
1554 break;
1555 case EOpLog:
1556 outputTriplet(out, visit, "log(", "", ")");
1557 break;
1558 case EOpExp2:
1559 outputTriplet(out, visit, "exp2(", "", ")");
1560 break;
1561 case EOpLog2:
1562 outputTriplet(out, visit, "log2(", "", ")");
1563 break;
1564 case EOpSqrt:
1565 outputTriplet(out, visit, "sqrt(", "", ")");
1566 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001567 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001568 outputTriplet(out, visit, "rsqrt(", "", ")");
1569 break;
1570 case EOpAbs:
1571 outputTriplet(out, visit, "abs(", "", ")");
1572 break;
1573 case EOpSign:
1574 outputTriplet(out, visit, "sign(", "", ")");
1575 break;
1576 case EOpFloor:
1577 outputTriplet(out, visit, "floor(", "", ")");
1578 break;
1579 case EOpTrunc:
1580 outputTriplet(out, visit, "trunc(", "", ")");
1581 break;
1582 case EOpRound:
1583 outputTriplet(out, visit, "round(", "", ")");
1584 break;
1585 case EOpRoundEven:
1586 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001587 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001588 break;
1589 case EOpCeil:
1590 outputTriplet(out, visit, "ceil(", "", ")");
1591 break;
1592 case EOpFract:
1593 outputTriplet(out, visit, "frac(", "", ")");
1594 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001595 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001596 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001597 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 else
1599 outputTriplet(out, visit, "isnan(", "", ")");
1600 mRequiresIEEEStrictCompiling = true;
1601 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001602 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001603 outputTriplet(out, visit, "isinf(", "", ")");
1604 break;
1605 case EOpFloatBitsToInt:
1606 outputTriplet(out, visit, "asint(", "", ")");
1607 break;
1608 case EOpFloatBitsToUint:
1609 outputTriplet(out, visit, "asuint(", "", ")");
1610 break;
1611 case EOpIntBitsToFloat:
1612 outputTriplet(out, visit, "asfloat(", "", ")");
1613 break;
1614 case EOpUintBitsToFloat:
1615 outputTriplet(out, visit, "asfloat(", "", ")");
1616 break;
1617 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001618 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001619 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001620 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001622 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001623 case EOpPackUnorm4x8:
1624 case EOpPackSnorm4x8:
1625 case EOpUnpackUnorm4x8:
1626 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001627 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001628 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001629 break;
1630 case EOpLength:
1631 outputTriplet(out, visit, "length(", "", ")");
1632 break;
1633 case EOpNormalize:
1634 outputTriplet(out, visit, "normalize(", "", ")");
1635 break;
1636 case EOpDFdx:
1637 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1638 {
1639 outputTriplet(out, visit, "(", "", ", 0.0)");
1640 }
1641 else
1642 {
1643 outputTriplet(out, visit, "ddx(", "", ")");
1644 }
1645 break;
1646 case EOpDFdy:
1647 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1648 {
1649 outputTriplet(out, visit, "(", "", ", 0.0)");
1650 }
1651 else
1652 {
1653 outputTriplet(out, visit, "ddy(", "", ")");
1654 }
1655 break;
1656 case EOpFwidth:
1657 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1658 {
1659 outputTriplet(out, visit, "(", "", ", 0.0)");
1660 }
1661 else
1662 {
1663 outputTriplet(out, visit, "fwidth(", "", ")");
1664 }
1665 break;
1666 case EOpTranspose:
1667 outputTriplet(out, visit, "transpose(", "", ")");
1668 break;
1669 case EOpDeterminant:
1670 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1671 break;
1672 case EOpInverse:
1673 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001674 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001675 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001676
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001677 case EOpAny:
1678 outputTriplet(out, visit, "any(", "", ")");
1679 break;
1680 case EOpAll:
1681 outputTriplet(out, visit, "all(", "", ")");
1682 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001683 case EOpLogicalNotComponentWise:
1684 outputTriplet(out, visit, "(!", "", ")");
1685 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001686 case EOpBitfieldReverse:
1687 outputTriplet(out, visit, "reversebits(", "", ")");
1688 break;
1689 case EOpBitCount:
1690 outputTriplet(out, visit, "countbits(", "", ")");
1691 break;
1692 case EOpFindLSB:
1693 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1694 // in GLSLTest and results are consistent with GL.
1695 outputTriplet(out, visit, "firstbitlow(", "", ")");
1696 break;
1697 case EOpFindMSB:
1698 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1699 // tested in GLSLTest and results are consistent with GL.
1700 outputTriplet(out, visit, "firstbithigh(", "", ")");
1701 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001702 default:
1703 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001704 }
1705
1706 return true;
1707}
1708
Olli Etuahofbb1c792018-01-19 16:26:59 +02001709ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001710{
1711 if (node->getAsSymbolNode())
1712 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001713 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1714 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001715 }
1716 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1717 switch (nodeBinary->getOp())
1718 {
1719 case EOpIndexDirect:
1720 {
1721 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1722
Olli Etuahofbb1c792018-01-19 16:26:59 +02001723 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001724 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001725 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001726 }
1727 case EOpIndexDirectStruct:
1728 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001729 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001730 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1731 const TField *field = s->fields()[index];
1732
Olli Etuahofbb1c792018-01-19 16:26:59 +02001733 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001734 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1735 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001736 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001737 }
1738 default:
1739 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001740 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001741 }
1742}
1743
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001744bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1745{
1746 TInfoSinkBase &out = getInfoSink();
1747
Olli Etuaho06235df2018-07-20 14:26:07 +03001748 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1749
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001750 if (mInsideFunction)
1751 {
1752 outputLineDirective(out, node->getLine().first_line);
1753 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001754 if (isMainBlock)
1755 {
1756 out << "@@ MAIN PROLOGUE @@\n";
1757 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001758 }
1759
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001760 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001761 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001762 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001763
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001764 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001765
1766 // Don't output ; after case labels, they're terminated by :
1767 // This is needed especially since outputting a ; after a case statement would turn empty
1768 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001769 // Also the output code is clearer if we don't output ; after statements where it is not
1770 // needed:
1771 // * if statements
1772 // * switch statements
1773 // * blocks
1774 // * function definitions
1775 // * loops (do-while loops output the semicolon in VisitLoop)
1776 // * declarations that don't generate output.
1777 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1778 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1779 statement->getAsSwitchNode() == nullptr &&
1780 statement->getAsFunctionDefinition() == nullptr &&
1781 (statement->getAsDeclarationNode() == nullptr ||
1782 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1783 statement->getAsInvariantDeclarationNode() == nullptr)
1784 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001785 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001786 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001787 }
1788
1789 if (mInsideFunction)
1790 {
1791 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001792 if (isMainBlock && shaderNeedsGenerateOutput())
1793 {
1794 // We could have an empty main, a main function without a branch at the end, or a main
1795 // function with a discard statement at the end. In these cases we need to add a return
1796 // statement.
1797 bool needReturnStatement =
1798 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1799 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1800 if (needReturnStatement)
1801 {
1802 out << "return " << generateOutputCall() << ";\n";
1803 }
1804 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001805 out << "}\n";
1806 }
1807
1808 return false;
1809}
1810
Olli Etuaho336b1472016-10-05 16:37:55 +01001811bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1812{
1813 TInfoSinkBase &out = getInfoSink();
1814
1815 ASSERT(mCurrentFunctionMetadata == nullptr);
1816
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001817 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001818 ASSERT(index != CallDAG::InvalidIndex);
1819 mCurrentFunctionMetadata = &mASTMetadataList[index];
1820
Olli Etuahod4bd9632018-03-08 16:32:44 +02001821 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001822
Olli Etuahod4bd9632018-03-08 16:32:44 +02001823 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001824 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001825 // The stub strings below are replaced when shader is dynamically defined by its layout:
1826 switch (mShaderType)
1827 {
1828 case GL_VERTEX_SHADER:
1829 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1830 << "@@ VERTEX OUTPUT @@\n\n"
1831 << "VS_OUTPUT main(VS_INPUT input)";
1832 break;
1833 case GL_FRAGMENT_SHADER:
1834 out << "@@ PIXEL OUTPUT @@\n\n"
1835 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1836 break;
1837 case GL_COMPUTE_SHADER:
1838 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1839 << mWorkGroupSize[2] << ")]\n";
1840 out << "void main(CS_INPUT input)";
1841 break;
1842 default:
1843 UNREACHABLE();
1844 break;
1845 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001846 }
1847 else
1848 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001849 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001850 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001851 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001852
Olli Etuaho06235df2018-07-20 14:26:07 +03001853 size_t paramCount = func->getParamCount();
1854 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001855 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001856 const TVariable *param = func->getParam(i);
1857 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001858
Olli Etuaho06235df2018-07-20 14:26:07 +03001859 writeParameter(param, out);
1860
1861 if (i < paramCount - 1)
1862 {
1863 out << ", ";
1864 }
1865 }
1866
1867 out << ")\n";
1868 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001869
1870 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03001871 if (func->isMain())
1872 {
1873 mInsideMain = true;
1874 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001875 // The function body node will output braces.
1876 node->getBody()->traverse(this);
1877 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03001878 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01001879
1880 mCurrentFunctionMetadata = nullptr;
1881
1882 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1883 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1884 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001885 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001886 mOutputLod0Function = true;
1887 node->traverse(this);
1888 mOutputLod0Function = false;
1889 }
1890
1891 return false;
1892}
1893
Olli Etuaho13389b62016-10-16 11:48:18 +01001894bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1895{
Olli Etuaho13389b62016-10-16 11:48:18 +01001896 if (visit == PreVisit)
1897 {
1898 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001899 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001900 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001901 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001902
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001903 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001904 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001905 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001906 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001907
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001908 if (!declarator->getAsSymbolNode() ||
1909 declarator->getAsSymbolNode()->variable().symbolType() !=
1910 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001911 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001912 if (declarator->getQualifier() == EvqShared)
1913 {
1914 out << "groupshared ";
1915 }
1916 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001917 {
1918 out << "static ";
1919 }
1920
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001921 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001922
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001923 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001924
1925 if (symbol)
1926 {
1927 symbol->traverse(this);
1928 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001929 // We don't initialize shared variables because:
1930 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1931 // code to initialize a groupshared array variable with a large array size.
1932 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1933 // allow initializing shared variables at all.
1934 if (declarator->getQualifier() != EvqShared)
1935 {
1936 out << " = " + zeroInitializer(symbol->getType());
1937 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001938 }
1939 else
1940 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001941 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001942 }
1943 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001944 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001945 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001946 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001947 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001948 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001949
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001950 const TVariable &variable = symbol->variable();
1951
1952 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001953 {
1954 // Vertex outputs which are declared but not written to should still be declared to
1955 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001956 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001957 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001958 }
1959 }
1960 return false;
1961}
1962
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001963bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1964{
1965 // Do not do any translation
1966 return false;
1967}
1968
Olli Etuahod4bd9632018-03-08 16:32:44 +02001969void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001970{
1971 TInfoSinkBase &out = getInfoSink();
1972
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001973 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001974 // Skip the prototype if it is not implemented (and thus not used)
1975 if (index == CallDAG::InvalidIndex)
1976 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001977 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00001978 }
1979
Olli Etuahod4bd9632018-03-08 16:32:44 +02001980 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00001981
Olli Etuahod4bd9632018-03-08 16:32:44 +02001982 TString name = DecorateFunctionIfNeeded(func);
1983 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001984 << (mOutputLod0Function ? "Lod0(" : "(");
1985
Olli Etuahod4bd9632018-03-08 16:32:44 +02001986 size_t paramCount = func->getParamCount();
1987 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001988 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001989 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00001990
Olli Etuahod4bd9632018-03-08 16:32:44 +02001991 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001992 {
1993 out << ", ";
1994 }
1995 }
1996
1997 out << ");\n";
1998
1999 // Also prototype the Lod0 variant if needed
2000 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2001 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2002 {
2003 mOutputLod0Function = true;
2004 node->traverse(this);
2005 mOutputLod0Function = false;
2006 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002007}
2008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002009bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2010{
Jamie Madill32aab012015-01-27 14:12:26 -05002011 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002012
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002013 switch (node->getOp())
2014 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002015 case EOpCallBuiltInFunction:
2016 case EOpCallFunctionInAST:
2017 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002018 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002019 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002020
Corentin Wallez1239ee92015-03-19 14:38:02 -07002021 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002022 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002024 if (node->isArray())
2025 {
2026 UNIMPLEMENTED();
2027 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002028 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002029 ASSERT(index != CallDAG::InvalidIndex);
2030 lod0 &= mASTMetadataList[index].mNeedsLod0;
2031
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002032 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002033 out << DisambiguateFunctionName(node->getSequence());
2034 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002035 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002036 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002037 {
2038 // This path is used for internal functions that don't have their definitions in the
2039 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002040 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002041 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002042 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002043 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002044 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002045 TType type = (*arguments)[0]->getAsTyped()->getType();
2046 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002047 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002048 type.getMemoryQualifier().readonly);
2049 out << imageFunctionName << "(";
2050 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002051 else
2052 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002053 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002054 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002055 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2056 if (arguments->size() > 1)
2057 {
2058 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2059 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002060 const ImmutableString &textureFunctionName =
2061 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2062 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002063 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002064 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002065
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002066 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002067 {
Olli Etuaho96963162016-03-21 11:54:33 +02002068 TIntermTyped *typedArg = (*arg)->getAsTyped();
2069 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002070 {
2071 out << "texture_";
2072 (*arg)->traverse(this);
2073 out << ", sampler_";
2074 }
2075
2076 (*arg)->traverse(this);
2077
Olli Etuaho96963162016-03-21 11:54:33 +02002078 if (typedArg->getType().isStructureContainingSamplers())
2079 {
2080 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002081 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002082 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2083 std::string namePrefix = "angle_";
2084 namePrefix += structName.data();
2085 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002086 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002087 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002088 {
2089 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2090 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002091 out << ", texture_" << sampler->name();
2092 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002093 }
2094 else
2095 {
2096 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2097 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002098 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002099 }
2100 }
2101 }
2102
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002103 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002104 {
2105 out << ", ";
2106 }
2107 }
2108
2109 out << ")";
2110
2111 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002112 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002113 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002114 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002115 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002116 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002117 outputTriplet(out, visit, "(", " == ", ")");
2118 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002119 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002120 outputTriplet(out, visit, "(", " != ", ")");
2121 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002122 case EOpLessThanComponentWise:
2123 outputTriplet(out, visit, "(", " < ", ")");
2124 break;
2125 case EOpGreaterThanComponentWise:
2126 outputTriplet(out, visit, "(", " > ", ")");
2127 break;
2128 case EOpLessThanEqualComponentWise:
2129 outputTriplet(out, visit, "(", " <= ", ")");
2130 break;
2131 case EOpGreaterThanEqualComponentWise:
2132 outputTriplet(out, visit, "(", " >= ", ")");
2133 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002134 case EOpMod:
2135 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002136 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002137 break;
2138 case EOpModf:
2139 outputTriplet(out, visit, "modf(", ", ", ")");
2140 break;
2141 case EOpPow:
2142 outputTriplet(out, visit, "pow(", ", ", ")");
2143 break;
2144 case EOpAtan:
2145 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2146 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002147 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002148 break;
2149 case EOpMin:
2150 outputTriplet(out, visit, "min(", ", ", ")");
2151 break;
2152 case EOpMax:
2153 outputTriplet(out, visit, "max(", ", ", ")");
2154 break;
2155 case EOpClamp:
2156 outputTriplet(out, visit, "clamp(", ", ", ")");
2157 break;
2158 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302159 {
2160 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2161 if (lastParamNode->getType().getBasicType() == EbtBool)
2162 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002163 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2164 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302165 // so use emulated version.
2166 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002167 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302168 }
2169 else
2170 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002171 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302172 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002173 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302174 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002175 case EOpStep:
2176 outputTriplet(out, visit, "step(", ", ", ")");
2177 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002178 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002179 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2180 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002181 case EOpFrexp:
2182 case EOpLdexp:
2183 ASSERT(node->getUseEmulatedFunction());
2184 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2185 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002186 case EOpDistance:
2187 outputTriplet(out, visit, "distance(", ", ", ")");
2188 break;
2189 case EOpDot:
2190 outputTriplet(out, visit, "dot(", ", ", ")");
2191 break;
2192 case EOpCross:
2193 outputTriplet(out, visit, "cross(", ", ", ")");
2194 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002195 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002196 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002197 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002198 break;
2199 case EOpReflect:
2200 outputTriplet(out, visit, "reflect(", ", ", ")");
2201 break;
2202 case EOpRefract:
2203 outputTriplet(out, visit, "refract(", ", ", ")");
2204 break;
2205 case EOpOuterProduct:
2206 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002207 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002208 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002209 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002210 outputTriplet(out, visit, "(", " * ", ")");
2211 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002212 case EOpBitfieldExtract:
2213 case EOpBitfieldInsert:
2214 case EOpUaddCarry:
2215 case EOpUsubBorrow:
2216 case EOpUmulExtended:
2217 case EOpImulExtended:
2218 ASSERT(node->getUseEmulatedFunction());
2219 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2220 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002221 case EOpBarrier:
2222 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2223 // cheapest *WithGroupSync() function, without any functionality loss, but
2224 // with the potential for severe performance loss.
2225 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2226 break;
2227 case EOpMemoryBarrierShared:
2228 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2229 break;
2230 case EOpMemoryBarrierAtomicCounter:
2231 case EOpMemoryBarrierBuffer:
2232 case EOpMemoryBarrierImage:
2233 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2234 break;
2235 case EOpGroupMemoryBarrier:
2236 case EOpMemoryBarrier:
2237 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2238 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002239
2240 // Single atomic function calls without return value.
2241 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2242 case EOpAtomicAdd:
2243 case EOpAtomicMin:
2244 case EOpAtomicMax:
2245 case EOpAtomicAnd:
2246 case EOpAtomicOr:
2247 case EOpAtomicXor:
2248 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2249 ",", ")");
2250 break;
2251
2252 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2253 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2254 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2255 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2256 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2257 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2258 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2259 // intermediate tree before traversing outputHLSL.
2260 case EOpAtomicExchange:
2261 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002262 default:
2263 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002264 }
2265
2266 return true;
2267}
2268
Olli Etuaho57961272016-09-14 13:57:46 +03002269void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002270{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002271 out << "if (";
2272
2273 node->getCondition()->traverse(this);
2274
2275 out << ")\n";
2276
Jamie Madill8c46ab12015-12-07 16:39:19 -05002277 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002278
2279 bool discard = false;
2280
2281 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002282 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002283 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002284 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002285
Olli Etuahoa6f22092015-05-08 18:31:10 +03002286 // Detect true discard
2287 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2288 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002289 else
2290 {
2291 // TODO(oetuaho): Check if the semicolon inside is necessary.
2292 // It's there as a result of conservative refactoring of the output.
2293 out << "{;}\n";
2294 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002295
Jamie Madill8c46ab12015-12-07 16:39:19 -05002296 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002297
Olli Etuahoa6f22092015-05-08 18:31:10 +03002298 if (node->getFalseBlock())
2299 {
2300 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002301
Jamie Madill8c46ab12015-12-07 16:39:19 -05002302 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002303
Olli Etuaho32db19b2016-10-04 14:43:16 +01002304 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002305 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002306
Jamie Madill8c46ab12015-12-07 16:39:19 -05002307 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002308
Olli Etuahoa6f22092015-05-08 18:31:10 +03002309 // Detect false discard
2310 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2311 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002312
Olli Etuahoa6f22092015-05-08 18:31:10 +03002313 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002314 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002315 {
2316 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002317 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002318}
2319
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002320bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2321{
2322 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2323 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2324 UNREACHABLE();
2325 return false;
2326}
2327
Olli Etuaho57961272016-09-14 13:57:46 +03002328bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002329{
2330 TInfoSinkBase &out = getInfoSink();
2331
Olli Etuaho3d932d82016-04-12 11:10:30 +03002332 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002333
2334 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002335 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002336 {
2337 out << "FLATTEN ";
2338 }
2339
Olli Etuaho57961272016-09-14 13:57:46 +03002340 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002341
2342 return false;
2343}
2344
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002345bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002346{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002347 TInfoSinkBase &out = getInfoSink();
2348
Olli Etuaho923ecef2017-10-11 12:01:38 +03002349 ASSERT(node->getStatementList());
2350 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002351 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002352 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002353 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002354 outputTriplet(out, visit, "switch (", ") ", "");
2355 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002356 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002357}
2358
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002359bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002360{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002361 TInfoSinkBase &out = getInfoSink();
2362
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002363 if (node->hasCondition())
2364 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002365 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002366 return true;
2367 }
2368 else
2369 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002370 out << "default:\n";
2371 return false;
2372 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002373}
2374
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002375void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2376{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002377 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002378 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002379}
2380
2381bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2382{
Nicolas Capens655fe362014-04-11 13:12:34 -04002383 mNestedLoopDepth++;
2384
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002385 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002386 mInsideDiscontinuousLoop =
2387 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002388
Jamie Madill8c46ab12015-12-07 16:39:19 -05002389 TInfoSinkBase &out = getInfoSink();
2390
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002391 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002392 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002393 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002394 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002395 mInsideDiscontinuousLoop = wasDiscontinuous;
2396 mNestedLoopDepth--;
2397
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002398 return false;
2399 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002400 }
2401
Corentin Wallez1239ee92015-03-19 14:38:02 -07002402 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002403 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002405 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002406
Jamie Madill8c46ab12015-12-07 16:39:19 -05002407 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002408 }
2409 else
2410 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002411 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002412
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002413 if (node->getInit())
2414 {
2415 node->getInit()->traverse(this);
2416 }
2417
2418 out << "; ";
2419
alokp@chromium.org52813552010-11-16 18:36:09 +00002420 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002421 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002422 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002423 }
2424
2425 out << "; ";
2426
alokp@chromium.org52813552010-11-16 18:36:09 +00002427 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002429 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002430 }
2431
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002432 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002433
Jamie Madill8c46ab12015-12-07 16:39:19 -05002434 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002435 }
2436
2437 if (node->getBody())
2438 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002439 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002440 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002441 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002442 else
2443 {
2444 // TODO(oetuaho): Check if the semicolon inside is necessary.
2445 // It's there as a result of conservative refactoring of the output.
2446 out << "{;}\n";
2447 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002448
Jamie Madill8c46ab12015-12-07 16:39:19 -05002449 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002450
alokp@chromium.org52813552010-11-16 18:36:09 +00002451 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002452 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002453 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002454 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002455
alokp@chromium.org52813552010-11-16 18:36:09 +00002456 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002457
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002458 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002459 }
2460
daniel@transgaming.com73536982012-03-21 20:45:49 +00002461 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002462
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002463 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002464 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002465
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002466 return false;
2467}
2468
2469bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2470{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002471 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002472 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002473 TInfoSinkBase &out = getInfoSink();
2474
2475 switch (node->getFlowOp())
2476 {
2477 case EOpKill:
2478 out << "discard";
2479 break;
2480 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002481 if (mNestedLoopDepth > 1)
2482 {
2483 mUsesNestedBreak = true;
2484 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002485
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002486 if (mExcessiveLoopIndex)
2487 {
2488 out << "{Break";
2489 mExcessiveLoopIndex->traverse(this);
2490 out << " = true; break;}\n";
2491 }
2492 else
2493 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002494 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002495 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002496 break;
2497 case EOpContinue:
2498 out << "continue";
2499 break;
2500 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002501 if (node->getExpression())
2502 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002503 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002504 out << "return ";
2505 }
2506 else
2507 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002508 if (mInsideMain && shaderNeedsGenerateOutput())
2509 {
2510 out << "return " << generateOutputCall();
2511 }
2512 else
2513 {
2514 out << "return";
2515 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002516 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002517 break;
2518 default:
2519 UNREACHABLE();
2520 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002521 }
2522
2523 return true;
2524}
2525
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002526// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002527// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2528// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002529bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002530{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002531 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002532
2533 // Parse loops of the form:
2534 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002535 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002536 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002537 int initial = 0;
2538 int limit = 0;
2539 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002540
2541 // Parse index name and intial value
2542 if (node->getInit())
2543 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002544 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002545
2546 if (init)
2547 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002548 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002549 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002550
2551 if (variable && variable->getQualifier() == EvqTemporary)
2552 {
2553 TIntermBinary *assign = variable->getAsBinaryNode();
2554
2555 if (assign->getOp() == EOpInitialize)
2556 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002557 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002558 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2559
2560 if (symbol && constant)
2561 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002562 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002563 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002564 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002565 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002566 }
2567 }
2568 }
2569 }
2570 }
2571 }
2572
2573 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002574 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002575 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002576 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002577
Olli Etuahob6af22b2017-12-15 14:05:44 +02002578 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002579 {
2580 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2581
2582 if (constant)
2583 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002584 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002585 {
2586 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002587 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002588 }
2589 }
2590 }
2591 }
2592
2593 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002594 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002595 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002596 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002597 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002598
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002599 if (binaryTerminal)
2600 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002601 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002602 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2603
2604 if (constant)
2605 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002606 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002607 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002608 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002609
2610 switch (op)
2611 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002612 case EOpAddAssign:
2613 increment = value;
2614 break;
2615 case EOpSubAssign:
2616 increment = -value;
2617 break;
2618 default:
2619 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002620 }
2621 }
2622 }
2623 }
2624 else if (unaryTerminal)
2625 {
2626 TOperator op = unaryTerminal->getOp();
2627
2628 switch (op)
2629 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002630 case EOpPostIncrement:
2631 increment = 1;
2632 break;
2633 case EOpPostDecrement:
2634 increment = -1;
2635 break;
2636 case EOpPreIncrement:
2637 increment = 1;
2638 break;
2639 case EOpPreDecrement:
2640 increment = -1;
2641 break;
2642 default:
2643 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002644 }
2645 }
2646 }
2647
Yunchao He4f285442017-04-21 12:15:49 +08002648 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002649 {
2650 if (comparator == EOpLessThanEqual)
2651 {
2652 comparator = EOpLessThan;
2653 limit += 1;
2654 }
2655
2656 if (comparator == EOpLessThan)
2657 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002658 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002659
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002660 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002661 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002662 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002663 }
2664
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002665 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002666 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002667
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002668 out << "{int ";
2669 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002670 out << ";\n"
2671 "bool Break";
2672 index->traverse(this);
2673 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002674
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002675 bool firstLoopFragment = true;
2676
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002677 while (iterations > 0)
2678 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002679 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002680
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002681 if (!firstLoopFragment)
2682 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002683 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002684 index->traverse(this);
2685 out << ") {\n";
2686 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002687
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002688 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002689 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002690 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002691 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002692
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002693 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002694 const char *unroll =
2695 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002696
Corentin Wallez1239ee92015-03-19 14:38:02 -07002697 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002698 index->traverse(this);
2699 out << " = ";
2700 out << initial;
2701
2702 out << "; ";
2703 index->traverse(this);
2704 out << " < ";
2705 out << clampedLimit;
2706
2707 out << "; ";
2708 index->traverse(this);
2709 out << " += ";
2710 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002711 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002712
Jamie Madill8c46ab12015-12-07 16:39:19 -05002713 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002714 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002715
2716 if (node->getBody())
2717 {
2718 node->getBody()->traverse(this);
2719 }
2720
Jamie Madill8c46ab12015-12-07 16:39:19 -05002721 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002722 out << ";}\n";
2723
2724 if (!firstLoopFragment)
2725 {
2726 out << "}\n";
2727 }
2728
2729 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002730
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002731 initial += MAX_LOOP_ITERATIONS * increment;
2732 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002733 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002734
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002735 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002736
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002737 mExcessiveLoopIndex = restoreIndex;
2738
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002739 return true;
2740 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002741 else
2742 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002743 }
2744
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002745 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002746}
2747
Jamie Madill8c46ab12015-12-07 16:39:19 -05002748void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2749 Visit visit,
2750 const char *preString,
2751 const char *inString,
2752 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002753{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002754 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002755 {
2756 out << preString;
2757 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002758 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002759 {
2760 out << inString;
2761 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002762 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002763 {
2764 out << postString;
2765 }
2766}
2767
Jamie Madill8c46ab12015-12-07 16:39:19 -05002768void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002769{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002770 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002771 {
Jamie Madill32aab012015-01-27 14:12:26 -05002772 out << "\n";
2773 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002774
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002775 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002776 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002777 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002778 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002779
Jamie Madill32aab012015-01-27 14:12:26 -05002780 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002781 }
2782}
2783
Olli Etuahod4bd9632018-03-08 16:32:44 +02002784void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002785{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002786 const TType &type = param->getType();
2787 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002788
Olli Etuahod4bd9632018-03-08 16:32:44 +02002789 TString nameStr = DecorateVariableIfNeeded(*param);
2790 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002791
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002792 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002793 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002794 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2795 {
2796 // Samplers are passed as indices to the sampler array.
2797 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002798 out << "const uint " << nameStr << ArrayString(type);
2799 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002800 }
2801 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2802 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002803 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2804 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2805 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2806 << ArrayString(type);
2807 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002808 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002809 }
2810
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002811 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2812 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002813
2814 // If the structure parameter contains samplers, they need to be passed into the function as
2815 // separate parameters. HLSL doesn't natively support samplers in structs.
2816 if (type.isStructureContainingSamplers())
2817 {
2818 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002819 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002820 std::string namePrefix = "angle";
2821 namePrefix += nameStr.c_str();
2822 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2823 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002824 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002825 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002826 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002827 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2828 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002829 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002830 }
2831 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2832 {
Olli Etuaho96963162016-03-21 11:54:33 +02002833 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002834 out << ", " << QualifierString(qualifier) << " "
2835 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2836 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2837 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2838 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002839 }
2840 else
2841 {
Olli Etuaho96963162016-03-21 11:54:33 +02002842 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002843 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2844 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002845 }
2846 }
2847 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002848}
2849
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002850TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002851{
2852 TString string;
2853
Jamie Madill94bf7f22013-07-08 13:31:15 -04002854 size_t size = type.getObjectSize();
2855 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002856 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002857 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002858
Jamie Madill94bf7f22013-07-08 13:31:15 -04002859 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002860 {
2861 string += ", ";
2862 }
2863 }
2864
daniel@transgaming.comead23042010-04-29 03:35:36 +00002865 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002866}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002867
Olli Etuahobd3cd502017-11-03 15:48:52 +02002868void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002869{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002870 // Array constructors should have been already pruned from the code.
2871 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002872
2873 if (visit == PreVisit)
2874 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002875 TString constructorName;
2876 if (node->getBasicType() == EbtStruct)
2877 {
2878 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2879 }
2880 else
2881 {
2882 constructorName =
2883 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2884 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002885 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002886 }
2887 else if (visit == InVisit)
2888 {
2889 out << ", ";
2890 }
2891 else if (visit == PostVisit)
2892 {
2893 out << ")";
2894 }
2895}
2896
Jamie Madill8c46ab12015-12-07 16:39:19 -05002897const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2898 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002899 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002900{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002901 ASSERT(!type.isArray());
2902
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002903 const TConstantUnion *constUnionIterated = constUnion;
2904
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002905 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002906 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002907 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002908 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002909
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002910 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002911
Jamie Madill98493dd2013-07-08 14:39:03 -04002912 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002913 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002914 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002915 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002916
Jamie Madill98493dd2013-07-08 14:39:03 -04002917 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002918 {
2919 out << ", ";
2920 }
2921 }
2922
2923 out << ")";
2924 }
2925 else
2926 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002927 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002928 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002929
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002930 if (writeType)
2931 {
Jamie Madill033dae62014-06-18 12:56:28 -04002932 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002933 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002934 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002935 if (writeType)
2936 {
2937 out << ")";
2938 }
2939 }
2940
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002941 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002942}
2943
Olli Etuahod68924e2017-01-02 17:34:40 +00002944void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002945{
Olli Etuahod68924e2017-01-02 17:34:40 +00002946 if (visit == PreVisit)
2947 {
2948 const char *opStr = GetOperatorString(op);
2949 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2950 out << "(";
2951 }
2952 else
2953 {
2954 outputTriplet(out, visit, nullptr, ", ", ")");
2955 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002956}
2957
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002958bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2959 TIntermSymbol *symbolNode,
2960 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002961{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002962 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2963 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002964
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002965 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002966 {
2967 // Type already printed
2968 out << "t" + str(mUniqueIndex) + " = ";
2969 expression->traverse(this);
2970 out << ", ";
2971 symbolNode->traverse(this);
2972 out << " = t" + str(mUniqueIndex);
2973
2974 mUniqueIndex++;
2975 return true;
2976 }
2977
2978 return false;
2979}
2980
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002981bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2982 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002983 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002984{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002985 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002986 {
2987 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002988 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002989 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002990 writeConstantUnionArray(out, initializer->getConstantValue(),
2991 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002992 out << "}";
2993 return true;
2994 }
2995 return false;
2996}
2997
Jamie Madill55e79e02015-02-09 15:35:00 -05002998TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2999{
3000 const TFieldList &fields = structure.fields();
3001
3002 for (const auto &eqFunction : mStructEqualityFunctions)
3003 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003004 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003005 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003006 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003007 }
3008 }
3009
3010 const TString &structNameString = StructNameString(structure);
3011
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003012 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003013 function->structure = &structure;
3014 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003015
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003016 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003017
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003018 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3019 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003020 << "{\n"
3021 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003022
3023 for (size_t i = 0; i < fields.size(); i++)
3024 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003025 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003026 const TType *fieldType = field->type();
3027
3028 const TString &fieldNameA = "a." + Decorate(field->name());
3029 const TString &fieldNameB = "b." + Decorate(field->name());
3030
3031 if (i > 0)
3032 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003033 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003034 }
3035
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003036 fnOut << "(";
3037 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3038 fnOut << fieldNameA;
3039 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3040 fnOut << fieldNameB;
3041 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3042 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003043 }
3044
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003045 fnOut << ";\n"
3046 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003047
3048 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003049
3050 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003051 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003052
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003053 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003054}
3055
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003056TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003057{
3058 for (const auto &eqFunction : mArrayEqualityFunctions)
3059 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003060 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003061 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003062 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003063 }
3064 }
3065
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003066 TType elementType(type);
3067 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003068
Olli Etuaho12690762015-03-31 12:55:28 +03003069 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003070 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003071
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003072 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003073
3074 TInfoSinkBase fnOut;
3075
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003076 const TString &typeName = TypeString(type);
3077 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3078 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003079 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003080 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003081 << type.getOutermostArraySize()
3082 << "; ++i)\n"
3083 " {\n"
3084 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003085
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003086 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003087 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003088 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003089 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003090 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003091
3092 fnOut << ") { return false; }\n"
3093 " }\n"
3094 " return true;\n"
3095 "}\n";
3096
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003097 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003098
3099 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003100 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003101
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003102 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003103}
3104
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003105TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003106{
3107 for (const auto &assignFunction : mArrayAssignmentFunctions)
3108 {
3109 if (assignFunction.type == type)
3110 {
3111 return assignFunction.functionName;
3112 }
3113 }
3114
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003115 TType elementType(type);
3116 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003117
3118 ArrayHelperFunction function;
3119 function.type = type;
3120
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003121 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003122
3123 TInfoSinkBase fnOut;
3124
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003125 const TString &typeName = TypeString(type);
3126 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3127 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003128 << "{\n"
3129 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003130 << type.getOutermostArraySize()
3131 << "; ++i)\n"
3132 " {\n"
3133 " ";
3134
3135 outputAssign(PreVisit, elementType, fnOut);
3136 fnOut << "a[i]";
3137 outputAssign(InVisit, elementType, fnOut);
3138 fnOut << "b[i]";
3139 outputAssign(PostVisit, elementType, fnOut);
3140
3141 fnOut << ";\n"
3142 " }\n"
3143 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003144
3145 function.functionDefinition = fnOut.c_str();
3146
3147 mArrayAssignmentFunctions.push_back(function);
3148
3149 return function.functionName;
3150}
3151
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003152TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003153{
3154 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3155 {
3156 if (constructIntoFunction.type == type)
3157 {
3158 return constructIntoFunction.functionName;
3159 }
3160 }
3161
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003162 TType elementType(type);
3163 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003164
3165 ArrayHelperFunction function;
3166 function.type = type;
3167
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003168 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003169
3170 TInfoSinkBase fnOut;
3171
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003172 const TString &typeName = TypeString(type);
3173 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3174 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003175 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003176 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003177 }
3178 fnOut << ")\n"
3179 "{\n";
3180
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003181 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003182 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003183 fnOut << " ";
3184 outputAssign(PreVisit, elementType, fnOut);
3185 fnOut << "a[" << i << "]";
3186 outputAssign(InVisit, elementType, fnOut);
3187 fnOut << "b" << i;
3188 outputAssign(PostVisit, elementType, fnOut);
3189 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003190 }
3191 fnOut << "}\n";
3192
3193 function.functionDefinition = fnOut.c_str();
3194
3195 mArrayConstructIntoFunctions.push_back(function);
3196
3197 return function.functionName;
3198}
3199
Jamie Madill2e295e22015-04-29 10:41:33 -04003200void OutputHLSL::ensureStructDefined(const TType &type)
3201{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003202 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003203 if (structure)
3204 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003205 ASSERT(type.getBasicType() == EbtStruct);
3206 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003207 }
3208}
3209
Olli Etuaho06235df2018-07-20 14:26:07 +03003210bool OutputHLSL::shaderNeedsGenerateOutput() const
3211{
3212 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3213}
3214
3215const char *OutputHLSL::generateOutputCall() const
3216{
3217 if (mShaderType == GL_VERTEX_SHADER)
3218 {
3219 return "generateOutput(input)";
3220 }
3221 else
3222 {
3223 return "generateOutput()";
3224 }
3225}
3226
Jamie Madill45bcc782016-11-07 13:58:48 -05003227} // namespace sh