blob: 5995a15a58dac7282bdf64e211d649baa81152fc [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
Olli Etuaho96f6adf2017-08-16 11:18:54 +030083} // anonymous namespace
84
Olli Etuahoc71862a2017-12-21 12:58:29 +020085TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
86 const TVariable *aInstanceVariable)
87 : block(aBlock), instanceVariable(aInstanceVariable)
88{
89}
90
Olli Etuaho56a2f952016-12-08 12:16:27 +000091void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030092{
Olli Etuaho56a2f952016-12-08 12:16:27 +000093 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
94 // regardless.
95 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
96 mOutputType == SH_HLSL_4_1_OUTPUT)
97 {
98 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
99 }
100 else
101 {
102 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
103 }
104}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300105
Olli Etuaho56a2f952016-12-08 12:16:27 +0000106void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200107{
108 ASSERT(constUnion != nullptr);
109 switch (constUnion->getType())
110 {
111 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000112 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200113 break;
114 case EbtInt:
115 out << constUnion->getIConst();
116 break;
117 case EbtUInt:
118 out << constUnion->getUConst();
119 break;
120 case EbtBool:
121 out << constUnion->getBConst();
122 break;
123 default:
124 UNREACHABLE();
125 }
126}
127
Olli Etuaho56a2f952016-12-08 12:16:27 +0000128const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
129 const TConstantUnion *const constUnion,
130 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200131{
132 const TConstantUnion *constUnionIterated = constUnion;
133 for (size_t i = 0; i < size; i++, constUnionIterated++)
134 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000135 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200136
137 if (i != size - 1)
138 {
139 out << ", ";
140 }
141 }
142 return constUnionIterated;
143}
144
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800145OutputHLSL::OutputHLSL(sh::GLenum shaderType,
146 int shaderVersion,
147 const TExtensionBehavior &extensionBehavior,
148 const char *sourcePath,
149 ShShaderOutput outputType,
150 int numRenderTargets,
151 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300152 ShCompileOptions compileOptions,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300153 TSymbolTable *symbolTable,
154 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300155 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200156 mShaderType(shaderType),
157 mShaderVersion(shaderVersion),
158 mExtensionBehavior(extensionBehavior),
159 mSourcePath(sourcePath),
160 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700161 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000162 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300163 mCurrentFunctionMetadata(nullptr),
164 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000165{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000166 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000167
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800168 mUsesFragColor = false;
169 mUsesFragData = false;
170 mUsesDepthRange = false;
171 mUsesFragCoord = false;
172 mUsesPointCoord = false;
173 mUsesFrontFacing = false;
174 mUsesPointSize = false;
175 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300176 mHasMultiviewExtensionEnabled =
177 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300178 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500179 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500180 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800181 mUsesNumWorkGroups = false;
182 mUsesWorkGroupID = false;
183 mUsesLocalInvocationID = false;
184 mUsesGlobalInvocationID = false;
185 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500186 mUsesXor = false;
187 mUsesDiscardRewriting = false;
188 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530189 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000190
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000191 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000192
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000194 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500195 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000196
Yunchao Hed7297bf2017-04-19 15:27:10 +0800197 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000198
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500199 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300200 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800201 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400202
Olli Etuahod8724a92017-12-29 18:40:36 +0200203 unsigned int firstUniformRegister =
204 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Xinghua Cao06a22622018-05-18 16:48:41 +0800205 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200206
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200207 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000208 {
Arun Patole63419392015-03-13 11:51:07 +0530209 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500210 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
211 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530212 // In both cases total 3 uniform registers need to be reserved.
213 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000214 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000215
Geoff Lang00140f42016-02-03 18:47:33 +0000216 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800217 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000218}
219
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000220OutputHLSL::~OutputHLSL()
221{
Jamie Madill8daaba12014-06-13 10:04:33 -0400222 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400223 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300224 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800225 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200226 for (auto &eqFunction : mStructEqualityFunctions)
227 {
228 SafeDelete(eqFunction);
229 }
230 for (auto &eqFunction : mArrayEqualityFunctions)
231 {
232 SafeDelete(eqFunction);
233 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000234}
235
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200236void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000237{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200238 BuiltInFunctionEmulator builtInFunctionEmulator;
239 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800240 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
241 {
242 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
243 mShaderVersion);
244 }
245
Olli Etuahodfa75e82017-01-23 09:43:06 -0800246 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500247
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700248 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000249 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700250 ASSERT(success == CallDAG::INITDAG_SUCCESS);
251 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700252
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200253 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
254 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
255 // the shader code. When we add shader storage blocks we might also consider an alternative
256 // solution, since the struct mapping won't work very well for shader storage blocks.
257
Jamie Madill37997142015-01-28 10:06:34 -0500258 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500259 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200260 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500261 mInfoSinkStack.pop();
262
Jamie Madill37997142015-01-28 10:06:34 -0500263 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500264 mInfoSinkStack.pop();
265
Jamie Madill32aab012015-01-27 14:12:26 -0500266 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200267 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500268 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000269
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200270 objSink << mHeader.c_str();
271 objSink << mBody.c_str();
272 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200273
Olli Etuahodfa75e82017-01-23 09:43:06 -0800274 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000275}
276
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800277const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400278{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800279 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400280}
281
Jamie Madill9fe25e92014-07-18 10:33:08 -0400282const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
283{
284 return mUniformHLSL->getUniformRegisterMap();
285}
286
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200287TString OutputHLSL::structInitializerString(int indent,
288 const TType &type,
289 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400290{
291 TString init;
292
Olli Etuahoed049ab2017-06-30 17:38:33 +0300293 TString indentString;
294 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400295 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300296 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400297 }
298
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400300 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300301 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300302 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400303 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300304 TStringStream indexedString;
305 indexedString << name << "[" << arrayIndex << "]";
306 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300307 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300308 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300309 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300310 {
311 init += ",";
312 }
313 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400314 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300315 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400316 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300317 else if (type.getBasicType() == EbtStruct)
318 {
319 init += indentString + "{\n";
320 const TStructure &structure = *type.getStruct();
321 const TFieldList &fields = structure.fields();
322 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
323 {
324 const TField &field = *fields[fieldIndex];
325 const TString &fieldName = name + "." + Decorate(field.name());
326 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400327
Olli Etuahoed049ab2017-06-30 17:38:33 +0300328 init += structInitializerString(indent + 1, fieldType, fieldName);
329 if (fieldIndex < fields.size() - 1)
330 {
331 init += ",";
332 }
333 init += "\n";
334 }
335 init += indentString + "}";
336 }
337 else
338 {
339 init += indentString + name;
340 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400341
342 return init;
343}
344
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200345TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
346{
347 TString mappedStructs;
348
349 for (auto &mappedStruct : std140Structs)
350 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200351 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200352 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200353 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200354 {
355 continue;
356 }
357
358 unsigned int instanceCount = 1u;
359 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
360 if (isInstanceArray)
361 {
362 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
363 }
364
365 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
366 ++instanceArrayIndex)
367 {
368 TString originalName;
369 TString mappedName("map");
370
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200371 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200372 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200373 const ImmutableString &instanceName =
374 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200375 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
376 if (isInstanceArray)
377 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200378 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200379 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200380 originalName += instanceString;
381 mappedName += instanceString;
382 originalName += ".";
383 mappedName += "_";
384 }
385
386 TString fieldName = Decorate(mappedStruct.field->name());
387 originalName += fieldName;
388 mappedName += fieldName;
389
390 TType *structType = mappedStruct.field->type();
391 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200392 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200393
394 if (structType->isArray())
395 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300396 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200397 }
398
399 mappedStructs += " =\n";
400 mappedStructs += structInitializerString(0, *structType, originalName);
401 mappedStructs += ";\n";
402 }
403 }
404 return mappedStructs;
405}
406
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300407void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000408{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300409 for (const auto &attribute : mReferencedAttributes)
410 {
411 const TType &type = attribute.second->getType();
412 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400413
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300414 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
415 << zeroInitializer(type) << ";\n";
416 }
417}
418
419void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
420{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200421 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000422 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800423 const TType &type = varying.second->getType();
Olli Etuahofbb1c792018-01-19 16:26:59 +0200424 const ImmutableString &name = varying.second->name();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000425
426 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300427 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
428 << " " << Decorate(name) << ArrayString(type) << " = " << zeroInitializer(type)
429 << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000430 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300431}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000432
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300433void OutputHLSL::header(TInfoSinkBase &out,
434 const std::vector<MappedStruct> &std140Structs,
435 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
436{
437 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000438
Jamie Madill8daaba12014-06-13 10:04:33 -0400439 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400440
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300441 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800442 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400443
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200444 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500445 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200446 out << "\n// Equality functions\n\n";
447 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500448 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200449 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200450 }
451 }
Olli Etuaho12690762015-03-31 12:55:28 +0300452 if (!mArrayAssignmentFunctions.empty())
453 {
454 out << "\n// Assignment functions\n\n";
455 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
456 {
457 out << assignmentFunction.functionDefinition << "\n";
458 }
459 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300460 if (!mArrayConstructIntoFunctions.empty())
461 {
462 out << "\n// Array constructor functions\n\n";
463 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
464 {
465 out << constructIntoFunction.functionDefinition << "\n";
466 }
467 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200468
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500469 if (mUsesDiscardRewriting)
470 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400471 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500472 }
473
Nicolas Capens655fe362014-04-11 13:12:34 -0400474 if (mUsesNestedBreak)
475 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400476 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400477 }
478
Arun Patole44efa0b2015-03-04 17:11:05 +0530479 if (mRequiresIEEEStrictCompiling)
480 {
481 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
482 }
483
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400484 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
485 "#define LOOP [loop]\n"
486 "#define FLATTEN [flatten]\n"
487 "#else\n"
488 "#define LOOP\n"
489 "#define FLATTEN\n"
490 "#endif\n";
491
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200492 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300494 const bool usingMRTExtension =
495 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000496
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000497 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300498 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400499 out << "\n";
500
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200501 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000502 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200503 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000504 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200505 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800506 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400507
Olli Etuahofbb1c792018-01-19 16:26:59 +0200508 out << "static " << TypeString(variableType) << " out_" << variableName
509 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000510 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000511 }
Jamie Madill46131a32013-06-20 11:55:50 -0400512 else
513 {
514 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
515
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800516 out << "static float4 gl_Color[" << numColorValues
517 << "] =\n"
518 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400519 for (unsigned int i = 0; i < numColorValues; i++)
520 {
521 out << " float4(0, 0, 0, 0)";
522 if (i + 1 != numColorValues)
523 {
524 out << ",";
525 }
526 out << "\n";
527 }
528
529 out << "};\n";
530 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000531
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400532 if (mUsesFragDepth)
533 {
534 out << "static float gl_Depth = 0.0;\n";
535 }
536
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000537 if (mUsesFragCoord)
538 {
539 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
540 }
541
542 if (mUsesPointCoord)
543 {
544 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
545 }
546
547 if (mUsesFrontFacing)
548 {
549 out << "static bool gl_FrontFacing = false;\n";
550 }
551
552 out << "\n";
553
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000554 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000555 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000556 out << "struct gl_DepthRangeParameters\n"
557 "{\n"
558 " float near;\n"
559 " float far;\n"
560 " float diff;\n"
561 "};\n"
562 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000563 }
564
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200565 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000566 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000567 out << "cbuffer DriverConstants : register(b1)\n"
568 "{\n";
569
570 if (mUsesDepthRange)
571 {
572 out << " float3 dx_DepthRange : packoffset(c0);\n";
573 }
574
575 if (mUsesFragCoord)
576 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000577 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000578 }
579
580 if (mUsesFragCoord || mUsesFrontFacing)
581 {
582 out << " float3 dx_DepthFront : packoffset(c2);\n";
583 }
584
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800585 if (mUsesFragCoord)
586 {
587 // dx_ViewScale is only used in the fragment shader to correct
588 // the value for glFragCoord if necessary
589 out << " float2 dx_ViewScale : packoffset(c3);\n";
590 }
591
Martin Radev72b4e1e2017-08-31 15:42:56 +0300592 if (mHasMultiviewExtensionEnabled)
593 {
594 // We have to add a value which we can use to keep track of which multi-view code
595 // path is to be selected in the GS.
596 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
597 }
598
Olli Etuaho618bebc2016-01-15 16:40:00 +0200599 if (mOutputType == SH_HLSL_4_1_OUTPUT)
600 {
601 mUniformHLSL->samplerMetadataUniforms(out, "c4");
602 }
603
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000604 out << "};\n";
605 }
606 else
607 {
608 if (mUsesDepthRange)
609 {
610 out << "uniform float3 dx_DepthRange : register(c0);";
611 }
612
613 if (mUsesFragCoord)
614 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000615 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000616 }
617
618 if (mUsesFragCoord || mUsesFrontFacing)
619 {
620 out << "uniform float3 dx_DepthFront : register(c2);\n";
621 }
622 }
623
624 out << "\n";
625
626 if (mUsesDepthRange)
627 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500628 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
629 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000630 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000631 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000632
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000633 if (usingMRTExtension && mNumRenderTargets > 1)
634 {
635 out << "#define GL_USES_MRT\n";
636 }
637
638 if (mUsesFragColor)
639 {
640 out << "#define GL_USES_FRAG_COLOR\n";
641 }
642
643 if (mUsesFragData)
644 {
645 out << "#define GL_USES_FRAG_DATA\n";
646 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647 }
Xinghua Caob1239382016-12-13 15:07:05 +0800648 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000650 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300651 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000652 out << "\n"
653 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400654
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000655 if (mUsesPointSize)
656 {
657 out << "static float gl_PointSize = float(1);\n";
658 }
659
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000660 if (mUsesInstanceID)
661 {
662 out << "static int gl_InstanceID;";
663 }
664
Corentin Wallezb076add2016-01-11 16:45:46 -0500665 if (mUsesVertexID)
666 {
667 out << "static int gl_VertexID;";
668 }
669
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000670 out << "\n"
671 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300672 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000673 out << "\n";
674
675 if (mUsesDepthRange)
676 {
677 out << "struct gl_DepthRangeParameters\n"
678 "{\n"
679 " float near;\n"
680 " float far;\n"
681 " float diff;\n"
682 "};\n"
683 "\n";
684 }
685
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200686 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000687 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800688 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500689 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800690
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000691 if (mUsesDepthRange)
692 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800693 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000694 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800695
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800696 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
697 // shaders. However, we declare it for all shaders (including Feature Level 10+).
698 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
699 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800700 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800701 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800702 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800703
Martin Radev72b4e1e2017-08-31 15:42:56 +0300704 if (mHasMultiviewExtensionEnabled)
705 {
706 // We have to add a value which we can use to keep track of which multi-view code
707 // path is to be selected in the GS.
708 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
709 }
710
Olli Etuaho618bebc2016-01-15 16:40:00 +0200711 if (mOutputType == SH_HLSL_4_1_OUTPUT)
712 {
713 mUniformHLSL->samplerMetadataUniforms(out, "c4");
714 }
715
Austin Kinross4fd18b12014-12-22 12:32:05 -0800716 out << "};\n"
717 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000718 }
719 else
720 {
721 if (mUsesDepthRange)
722 {
723 out << "uniform float3 dx_DepthRange : register(c0);\n";
724 }
725
Cooper Partine6664f02015-01-09 16:22:24 -0800726 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
727 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000728 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000729 }
730
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000731 if (mUsesDepthRange)
732 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
734 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000735 "\n";
736 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400737 }
Xinghua Caob1239382016-12-13 15:07:05 +0800738 else // Compute shader
739 {
740 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800741
742 out << "cbuffer DriverConstants : register(b1)\n"
743 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800744 if (mUsesNumWorkGroups)
745 {
Xinghua Caob1239382016-12-13 15:07:05 +0800746 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800747 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800748 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
749 mUniformHLSL->samplerMetadataUniforms(out, "c1");
750 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800751
752 // Follow built-in variables would be initialized in
753 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
754 // are used in compute shader.
755 if (mUsesWorkGroupID)
756 {
757 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
758 }
759
760 if (mUsesLocalInvocationID)
761 {
762 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
763 }
764
765 if (mUsesGlobalInvocationID)
766 {
767 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
768 }
769
770 if (mUsesLocalInvocationIndex)
771 {
772 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
773 }
774 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000775
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800776 if (!mappedStructs.empty())
777 {
778 out << "// Structures from std140 blocks with padding removed\n";
779 out << "\n";
780 out << mappedStructs;
781 out << "\n";
782 }
783
Geoff Lang1fe74c72016-08-25 13:23:01 -0400784 bool getDimensionsIgnoresBaseLevel =
785 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
786 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800787 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000789 if (mUsesFragCoord)
790 {
791 out << "#define GL_USES_FRAG_COORD\n";
792 }
793
794 if (mUsesPointCoord)
795 {
796 out << "#define GL_USES_POINT_COORD\n";
797 }
798
799 if (mUsesFrontFacing)
800 {
801 out << "#define GL_USES_FRONT_FACING\n";
802 }
803
804 if (mUsesPointSize)
805 {
806 out << "#define GL_USES_POINT_SIZE\n";
807 }
808
Martin Radev41ac68e2017-06-06 12:16:58 +0300809 if (mHasMultiviewExtensionEnabled)
810 {
811 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
812 }
813
814 if (mUsesViewID)
815 {
816 out << "#define GL_USES_VIEW_ID\n";
817 }
818
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400819 if (mUsesFragDepth)
820 {
821 out << "#define GL_USES_FRAG_DEPTH\n";
822 }
823
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000824 if (mUsesDepthRange)
825 {
826 out << "#define GL_USES_DEPTH_RANGE\n";
827 }
828
Xinghua Caob1239382016-12-13 15:07:05 +0800829 if (mUsesNumWorkGroups)
830 {
831 out << "#define GL_USES_NUM_WORK_GROUPS\n";
832 }
833
834 if (mUsesWorkGroupID)
835 {
836 out << "#define GL_USES_WORK_GROUP_ID\n";
837 }
838
839 if (mUsesLocalInvocationID)
840 {
841 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
842 }
843
844 if (mUsesGlobalInvocationID)
845 {
846 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
847 }
848
849 if (mUsesLocalInvocationIndex)
850 {
851 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
852 }
853
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000854 if (mUsesXor)
855 {
856 out << "bool xor(bool p, bool q)\n"
857 "{\n"
858 " return (p || q) && !(p && q);\n"
859 "}\n"
860 "\n";
861 }
862
Olli Etuahodfa75e82017-01-23 09:43:06 -0800863 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000864}
865
866void OutputHLSL::visitSymbol(TIntermSymbol *node)
867{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200868 const TVariable &variable = node->variable();
869
870 // Empty symbols can only appear in declarations and function arguments, and in either of those
871 // cases the symbol nodes are not visited.
872 ASSERT(variable.symbolType() != SymbolType::Empty);
873
Jamie Madill32aab012015-01-27 14:12:26 -0500874 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000875
Jamie Madill570e04d2013-06-21 09:15:33 -0400876 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200877 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400878 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200879 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400880 }
881
Olli Etuahofbb1c792018-01-19 16:26:59 +0200882 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200883 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200884
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000885 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000886 {
887 mUsesDepthRange = true;
888 out << name;
889 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000890 else
891 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200892 const TType &variableType = variable.getType();
893 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000894
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200895 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200896
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000897 if (qualifier == EvqUniform)
898 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200899 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400900
901 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000902 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200903 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
904 {
905 const TVariable *instanceVariable = nullptr;
906 if (variableType.isInterfaceBlock())
907 {
908 instanceVariable = &variable;
909 }
910 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
911 new TReferencedBlock(interfaceBlock, instanceVariable);
912 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000913 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000914 else
915 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200916 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000917 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400918
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200919 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000920 }
Jamie Madill19571812013-08-12 15:26:34 -0700921 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000922 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200923 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400924 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000925 }
Jamie Madill033dae62014-06-18 12:56:28 -0400926 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000927 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200928 mReferencedVaryings[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400929 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300930 if (name == "ViewID_OVR")
931 {
932 mUsesViewID = true;
933 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000934 }
Jamie Madill19571812013-08-12 15:26:34 -0700935 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400936 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200937 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400938 out << "out_" << name;
939 }
940 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000941 {
942 out << "gl_Color[0]";
943 mUsesFragColor = true;
944 }
945 else if (qualifier == EvqFragData)
946 {
947 out << "gl_Color";
948 mUsesFragData = true;
949 }
950 else if (qualifier == EvqFragCoord)
951 {
952 mUsesFragCoord = true;
953 out << name;
954 }
955 else if (qualifier == EvqPointCoord)
956 {
957 mUsesPointCoord = true;
958 out << name;
959 }
960 else if (qualifier == EvqFrontFacing)
961 {
962 mUsesFrontFacing = true;
963 out << name;
964 }
965 else if (qualifier == EvqPointSize)
966 {
967 mUsesPointSize = true;
968 out << name;
969 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000970 else if (qualifier == EvqInstanceID)
971 {
972 mUsesInstanceID = true;
973 out << name;
974 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500975 else if (qualifier == EvqVertexID)
976 {
977 mUsesVertexID = true;
978 out << name;
979 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300980 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400981 {
982 mUsesFragDepth = true;
983 out << "gl_Depth";
984 }
Xinghua Caob1239382016-12-13 15:07:05 +0800985 else if (qualifier == EvqNumWorkGroups)
986 {
987 mUsesNumWorkGroups = true;
988 out << name;
989 }
990 else if (qualifier == EvqWorkGroupID)
991 {
992 mUsesWorkGroupID = true;
993 out << name;
994 }
995 else if (qualifier == EvqLocalInvocationID)
996 {
997 mUsesLocalInvocationID = true;
998 out << name;
999 }
1000 else if (qualifier == EvqGlobalInvocationID)
1001 {
1002 mUsesGlobalInvocationID = true;
1003 out << name;
1004 }
1005 else if (qualifier == EvqLocalInvocationIndex)
1006 {
1007 mUsesLocalInvocationIndex = true;
1008 out << name;
1009 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001010 else
1011 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001012 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001013 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014 }
1015}
1016
Olli Etuaho7fb49552015-03-18 17:27:44 +02001017void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1018{
1019 if (type.isScalar() && !type.isArray())
1020 {
1021 if (op == EOpEqual)
1022 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001023 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001024 }
1025 else
1026 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001027 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001028 }
1029 }
1030 else
1031 {
1032 if (visit == PreVisit && op == EOpNotEqual)
1033 {
1034 out << "!";
1035 }
1036
1037 if (type.isArray())
1038 {
1039 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001040 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001041 }
1042 else if (type.getBasicType() == EbtStruct)
1043 {
1044 const TStructure &structure = *type.getStruct();
1045 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001046 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001047 }
1048 else
1049 {
1050 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001051 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001052 }
1053 }
1054}
1055
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001056void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1057{
1058 if (type.isArray())
1059 {
1060 const TString &functionName = addArrayAssignmentFunction(type);
1061 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1062 }
1063 else
1064 {
1065 outputTriplet(out, visit, "(", " = ", ")");
1066 }
1067}
1068
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001069bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001070{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001071 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001072 {
1073 TIntermNode *ancestor = getAncestorNode(n);
1074 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1075 if (ancestorBinary == nullptr)
1076 {
1077 return false;
1078 }
1079 switch (ancestorBinary->getOp())
1080 {
1081 case EOpIndexDirectStruct:
1082 {
1083 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1084 const TIntermConstantUnion *index =
1085 ancestorBinary->getRight()->getAsConstantUnion();
1086 const TField *field = structure->fields()[index->getIConst(0)];
1087 if (IsSampler(field->type()->getBasicType()))
1088 {
1089 return true;
1090 }
1091 break;
1092 }
1093 case EOpIndexDirect:
1094 break;
1095 default:
1096 // Returning a sampler from indirect indexing is not supported.
1097 return false;
1098 }
1099 }
1100 return false;
1101}
1102
Olli Etuahob6fa0432016-09-28 16:28:05 +01001103bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1104{
1105 TInfoSinkBase &out = getInfoSink();
1106 if (visit == PostVisit)
1107 {
1108 out << ".";
1109 node->writeOffsetsAsXYZW(&out);
1110 }
1111 return true;
1112}
1113
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001114bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1115{
Jamie Madill32aab012015-01-27 14:12:26 -05001116 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001117
1118 switch (node->getOp())
1119 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001120 case EOpComma:
1121 outputTriplet(out, visit, "(", ", ", ")");
1122 break;
1123 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001124 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001125 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001126 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1127 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001128 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001129 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1130 out << functionName << "(";
1131 node->getLeft()->traverse(this);
1132 TIntermSequence *seq = rightAgg->getSequence();
1133 for (auto &arrayElement : *seq)
1134 {
1135 out << ", ";
1136 arrayElement->traverse(this);
1137 }
1138 out << ")";
1139 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001140 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001141 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1142 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001143 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001144 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001145 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001146 break;
1147 case EOpInitialize:
1148 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001149 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001150 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1151 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001152 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001153
1154 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001155 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001156
1157 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1158 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1159 // new variable is created before the assignment is evaluated), so we need to
1160 // convert
1161 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001162 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001163 {
1164 // Skip initializing the rest of the expression
1165 return false;
1166 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001167 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001168 {
1169 return false;
1170 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001171 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001172 else if (visit == InVisit)
1173 {
1174 out << " = ";
1175 }
1176 break;
1177 case EOpAddAssign:
1178 outputTriplet(out, visit, "(", " += ", ")");
1179 break;
1180 case EOpSubAssign:
1181 outputTriplet(out, visit, "(", " -= ", ")");
1182 break;
1183 case EOpMulAssign:
1184 outputTriplet(out, visit, "(", " *= ", ")");
1185 break;
1186 case EOpVectorTimesScalarAssign:
1187 outputTriplet(out, visit, "(", " *= ", ")");
1188 break;
1189 case EOpMatrixTimesScalarAssign:
1190 outputTriplet(out, visit, "(", " *= ", ")");
1191 break;
1192 case EOpVectorTimesMatrixAssign:
1193 if (visit == PreVisit)
1194 {
1195 out << "(";
1196 }
1197 else if (visit == InVisit)
1198 {
1199 out << " = mul(";
1200 node->getLeft()->traverse(this);
1201 out << ", transpose(";
1202 }
1203 else
1204 {
1205 out << ")))";
1206 }
1207 break;
1208 case EOpMatrixTimesMatrixAssign:
1209 if (visit == PreVisit)
1210 {
1211 out << "(";
1212 }
1213 else if (visit == InVisit)
1214 {
1215 out << " = transpose(mul(transpose(";
1216 node->getLeft()->traverse(this);
1217 out << "), transpose(";
1218 }
1219 else
1220 {
1221 out << "))))";
1222 }
1223 break;
1224 case EOpDivAssign:
1225 outputTriplet(out, visit, "(", " /= ", ")");
1226 break;
1227 case EOpIModAssign:
1228 outputTriplet(out, visit, "(", " %= ", ")");
1229 break;
1230 case EOpBitShiftLeftAssign:
1231 outputTriplet(out, visit, "(", " <<= ", ")");
1232 break;
1233 case EOpBitShiftRightAssign:
1234 outputTriplet(out, visit, "(", " >>= ", ")");
1235 break;
1236 case EOpBitwiseAndAssign:
1237 outputTriplet(out, visit, "(", " &= ", ")");
1238 break;
1239 case EOpBitwiseXorAssign:
1240 outputTriplet(out, visit, "(", " ^= ", ")");
1241 break;
1242 case EOpBitwiseOrAssign:
1243 outputTriplet(out, visit, "(", " |= ", ")");
1244 break;
1245 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001246 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001247 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001248 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001249 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001250 if (visit == PreVisit)
1251 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001252 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001253 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuahoc71862a2017-12-21 12:58:29 +02001254 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1255 {
1256 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1257 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1258 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001259 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001260 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1261 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001262 return false;
1263 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001264 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001265 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001266 {
1267 // All parts of an expression that access a sampler in a struct need to use _ as
1268 // separator to access the sampler variable that has been moved out of the struct.
1269 outputTriplet(out, visit, "", "_", "");
1270 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001271 else
1272 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001273 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001274 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001275 }
1276 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001277 case EOpIndexIndirect:
1278 // We do not currently support indirect references to interface blocks
1279 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1280 outputTriplet(out, visit, "", "[", "]");
1281 break;
1282 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001283 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001284 const TStructure *structure = node->getLeft()->getType().getStruct();
1285 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1286 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001287
Olli Etuaho96963162016-03-21 11:54:33 +02001288 // In cases where indexing returns a sampler, we need to access the sampler variable
1289 // that has been moved out of the struct.
1290 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1291 if (visit == PreVisit && indexingReturnsSampler)
1292 {
1293 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1294 // This prefix is only output at the beginning of the indexing expression, which
1295 // may have multiple parts.
1296 out << "angle";
1297 }
1298 if (!indexingReturnsSampler)
1299 {
1300 // All parts of an expression that access a sampler in a struct need to use _ as
1301 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001302 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001303 }
1304 if (visit == InVisit)
1305 {
1306 if (indexingReturnsSampler)
1307 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001308 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001309 }
1310 else
1311 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001312 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001313 }
1314
1315 return false;
1316 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001317 }
1318 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001319 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001320 {
1321 bool structInStd140Block =
1322 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1323 if (visit == PreVisit && structInStd140Block)
1324 {
1325 out << "map";
1326 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001327 if (visit == InVisit)
1328 {
1329 const TInterfaceBlock *interfaceBlock =
1330 node->getLeft()->getType().getInterfaceBlock();
1331 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1332 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001333 if (structInStd140Block)
1334 {
1335 out << "_";
1336 }
1337 else
1338 {
1339 out << ".";
1340 }
1341 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001342
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001343 return false;
1344 }
1345 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001346 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 case EOpAdd:
1348 outputTriplet(out, visit, "(", " + ", ")");
1349 break;
1350 case EOpSub:
1351 outputTriplet(out, visit, "(", " - ", ")");
1352 break;
1353 case EOpMul:
1354 outputTriplet(out, visit, "(", " * ", ")");
1355 break;
1356 case EOpDiv:
1357 outputTriplet(out, visit, "(", " / ", ")");
1358 break;
1359 case EOpIMod:
1360 outputTriplet(out, visit, "(", " % ", ")");
1361 break;
1362 case EOpBitShiftLeft:
1363 outputTriplet(out, visit, "(", " << ", ")");
1364 break;
1365 case EOpBitShiftRight:
1366 outputTriplet(out, visit, "(", " >> ", ")");
1367 break;
1368 case EOpBitwiseAnd:
1369 outputTriplet(out, visit, "(", " & ", ")");
1370 break;
1371 case EOpBitwiseXor:
1372 outputTriplet(out, visit, "(", " ^ ", ")");
1373 break;
1374 case EOpBitwiseOr:
1375 outputTriplet(out, visit, "(", " | ", ")");
1376 break;
1377 case EOpEqual:
1378 case EOpNotEqual:
1379 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1380 break;
1381 case EOpLessThan:
1382 outputTriplet(out, visit, "(", " < ", ")");
1383 break;
1384 case EOpGreaterThan:
1385 outputTriplet(out, visit, "(", " > ", ")");
1386 break;
1387 case EOpLessThanEqual:
1388 outputTriplet(out, visit, "(", " <= ", ")");
1389 break;
1390 case EOpGreaterThanEqual:
1391 outputTriplet(out, visit, "(", " >= ", ")");
1392 break;
1393 case EOpVectorTimesScalar:
1394 outputTriplet(out, visit, "(", " * ", ")");
1395 break;
1396 case EOpMatrixTimesScalar:
1397 outputTriplet(out, visit, "(", " * ", ")");
1398 break;
1399 case EOpVectorTimesMatrix:
1400 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1401 break;
1402 case EOpMatrixTimesVector:
1403 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1404 break;
1405 case EOpMatrixTimesMatrix:
1406 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1407 break;
1408 case EOpLogicalOr:
1409 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1410 // been unfolded.
1411 ASSERT(!node->getRight()->hasSideEffects());
1412 outputTriplet(out, visit, "(", " || ", ")");
1413 return true;
1414 case EOpLogicalXor:
1415 mUsesXor = true;
1416 outputTriplet(out, visit, "xor(", ", ", ")");
1417 break;
1418 case EOpLogicalAnd:
1419 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1420 // been unfolded.
1421 ASSERT(!node->getRight()->hasSideEffects());
1422 outputTriplet(out, visit, "(", " && ", ")");
1423 return true;
1424 default:
1425 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001426 }
1427
1428 return true;
1429}
1430
1431bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1432{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001433 TInfoSinkBase &out = getInfoSink();
1434
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001435 switch (node->getOp())
1436 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001437 case EOpNegative:
1438 outputTriplet(out, visit, "(-", "", ")");
1439 break;
1440 case EOpPositive:
1441 outputTriplet(out, visit, "(+", "", ")");
1442 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001443 case EOpLogicalNot:
1444 outputTriplet(out, visit, "(!", "", ")");
1445 break;
1446 case EOpBitwiseNot:
1447 outputTriplet(out, visit, "(~", "", ")");
1448 break;
1449 case EOpPostIncrement:
1450 outputTriplet(out, visit, "(", "", "++)");
1451 break;
1452 case EOpPostDecrement:
1453 outputTriplet(out, visit, "(", "", "--)");
1454 break;
1455 case EOpPreIncrement:
1456 outputTriplet(out, visit, "(++", "", ")");
1457 break;
1458 case EOpPreDecrement:
1459 outputTriplet(out, visit, "(--", "", ")");
1460 break;
1461 case EOpRadians:
1462 outputTriplet(out, visit, "radians(", "", ")");
1463 break;
1464 case EOpDegrees:
1465 outputTriplet(out, visit, "degrees(", "", ")");
1466 break;
1467 case EOpSin:
1468 outputTriplet(out, visit, "sin(", "", ")");
1469 break;
1470 case EOpCos:
1471 outputTriplet(out, visit, "cos(", "", ")");
1472 break;
1473 case EOpTan:
1474 outputTriplet(out, visit, "tan(", "", ")");
1475 break;
1476 case EOpAsin:
1477 outputTriplet(out, visit, "asin(", "", ")");
1478 break;
1479 case EOpAcos:
1480 outputTriplet(out, visit, "acos(", "", ")");
1481 break;
1482 case EOpAtan:
1483 outputTriplet(out, visit, "atan(", "", ")");
1484 break;
1485 case EOpSinh:
1486 outputTriplet(out, visit, "sinh(", "", ")");
1487 break;
1488 case EOpCosh:
1489 outputTriplet(out, visit, "cosh(", "", ")");
1490 break;
1491 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001493 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 case EOpAtanh:
1495 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001496 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001497 break;
1498 case EOpExp:
1499 outputTriplet(out, visit, "exp(", "", ")");
1500 break;
1501 case EOpLog:
1502 outputTriplet(out, visit, "log(", "", ")");
1503 break;
1504 case EOpExp2:
1505 outputTriplet(out, visit, "exp2(", "", ")");
1506 break;
1507 case EOpLog2:
1508 outputTriplet(out, visit, "log2(", "", ")");
1509 break;
1510 case EOpSqrt:
1511 outputTriplet(out, visit, "sqrt(", "", ")");
1512 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001513 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001514 outputTriplet(out, visit, "rsqrt(", "", ")");
1515 break;
1516 case EOpAbs:
1517 outputTriplet(out, visit, "abs(", "", ")");
1518 break;
1519 case EOpSign:
1520 outputTriplet(out, visit, "sign(", "", ")");
1521 break;
1522 case EOpFloor:
1523 outputTriplet(out, visit, "floor(", "", ")");
1524 break;
1525 case EOpTrunc:
1526 outputTriplet(out, visit, "trunc(", "", ")");
1527 break;
1528 case EOpRound:
1529 outputTriplet(out, visit, "round(", "", ")");
1530 break;
1531 case EOpRoundEven:
1532 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001533 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001534 break;
1535 case EOpCeil:
1536 outputTriplet(out, visit, "ceil(", "", ")");
1537 break;
1538 case EOpFract:
1539 outputTriplet(out, visit, "frac(", "", ")");
1540 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001541 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001542 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001543 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001544 else
1545 outputTriplet(out, visit, "isnan(", "", ")");
1546 mRequiresIEEEStrictCompiling = true;
1547 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001548 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 outputTriplet(out, visit, "isinf(", "", ")");
1550 break;
1551 case EOpFloatBitsToInt:
1552 outputTriplet(out, visit, "asint(", "", ")");
1553 break;
1554 case EOpFloatBitsToUint:
1555 outputTriplet(out, visit, "asuint(", "", ")");
1556 break;
1557 case EOpIntBitsToFloat:
1558 outputTriplet(out, visit, "asfloat(", "", ")");
1559 break;
1560 case EOpUintBitsToFloat:
1561 outputTriplet(out, visit, "asfloat(", "", ")");
1562 break;
1563 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001564 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001566 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001567 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001568 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001569 case EOpPackUnorm4x8:
1570 case EOpPackSnorm4x8:
1571 case EOpUnpackUnorm4x8:
1572 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001574 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001575 break;
1576 case EOpLength:
1577 outputTriplet(out, visit, "length(", "", ")");
1578 break;
1579 case EOpNormalize:
1580 outputTriplet(out, visit, "normalize(", "", ")");
1581 break;
1582 case EOpDFdx:
1583 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1584 {
1585 outputTriplet(out, visit, "(", "", ", 0.0)");
1586 }
1587 else
1588 {
1589 outputTriplet(out, visit, "ddx(", "", ")");
1590 }
1591 break;
1592 case EOpDFdy:
1593 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1594 {
1595 outputTriplet(out, visit, "(", "", ", 0.0)");
1596 }
1597 else
1598 {
1599 outputTriplet(out, visit, "ddy(", "", ")");
1600 }
1601 break;
1602 case EOpFwidth:
1603 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1604 {
1605 outputTriplet(out, visit, "(", "", ", 0.0)");
1606 }
1607 else
1608 {
1609 outputTriplet(out, visit, "fwidth(", "", ")");
1610 }
1611 break;
1612 case EOpTranspose:
1613 outputTriplet(out, visit, "transpose(", "", ")");
1614 break;
1615 case EOpDeterminant:
1616 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1617 break;
1618 case EOpInverse:
1619 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001620 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001621 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001622
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001623 case EOpAny:
1624 outputTriplet(out, visit, "any(", "", ")");
1625 break;
1626 case EOpAll:
1627 outputTriplet(out, visit, "all(", "", ")");
1628 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001629 case EOpLogicalNotComponentWise:
1630 outputTriplet(out, visit, "(!", "", ")");
1631 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001632 case EOpBitfieldReverse:
1633 outputTriplet(out, visit, "reversebits(", "", ")");
1634 break;
1635 case EOpBitCount:
1636 outputTriplet(out, visit, "countbits(", "", ")");
1637 break;
1638 case EOpFindLSB:
1639 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1640 // in GLSLTest and results are consistent with GL.
1641 outputTriplet(out, visit, "firstbitlow(", "", ")");
1642 break;
1643 case EOpFindMSB:
1644 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1645 // tested in GLSLTest and results are consistent with GL.
1646 outputTriplet(out, visit, "firstbithigh(", "", ")");
1647 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001648 default:
1649 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001650 }
1651
1652 return true;
1653}
1654
Olli Etuahofbb1c792018-01-19 16:26:59 +02001655ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001656{
1657 if (node->getAsSymbolNode())
1658 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001659 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1660 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001661 }
1662 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1663 switch (nodeBinary->getOp())
1664 {
1665 case EOpIndexDirect:
1666 {
1667 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1668
Olli Etuahofbb1c792018-01-19 16:26:59 +02001669 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001670 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001671 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001672 }
1673 case EOpIndexDirectStruct:
1674 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001675 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001676 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1677 const TField *field = s->fields()[index];
1678
Olli Etuahofbb1c792018-01-19 16:26:59 +02001679 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001680 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1681 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001682 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001683 }
1684 default:
1685 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001686 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001687 }
1688}
1689
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001690bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1691{
1692 TInfoSinkBase &out = getInfoSink();
1693
1694 if (mInsideFunction)
1695 {
1696 outputLineDirective(out, node->getLine().first_line);
1697 out << "{\n";
1698 }
1699
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001700 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001701 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001702 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001703
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001704 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001705
1706 // Don't output ; after case labels, they're terminated by :
1707 // This is needed especially since outputting a ; after a case statement would turn empty
1708 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001709 // Also the output code is clearer if we don't output ; after statements where it is not
1710 // needed:
1711 // * if statements
1712 // * switch statements
1713 // * blocks
1714 // * function definitions
1715 // * loops (do-while loops output the semicolon in VisitLoop)
1716 // * declarations that don't generate output.
1717 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1718 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1719 statement->getAsSwitchNode() == nullptr &&
1720 statement->getAsFunctionDefinition() == nullptr &&
1721 (statement->getAsDeclarationNode() == nullptr ||
1722 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1723 statement->getAsInvariantDeclarationNode() == nullptr)
1724 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001725 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001726 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001727 }
1728
1729 if (mInsideFunction)
1730 {
1731 outputLineDirective(out, node->getLine().last_line);
1732 out << "}\n";
1733 }
1734
1735 return false;
1736}
1737
Olli Etuaho336b1472016-10-05 16:37:55 +01001738bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1739{
1740 TInfoSinkBase &out = getInfoSink();
1741
1742 ASSERT(mCurrentFunctionMetadata == nullptr);
1743
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001744 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001745 ASSERT(index != CallDAG::InvalidIndex);
1746 mCurrentFunctionMetadata = &mASTMetadataList[index];
1747
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001748 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001749
Olli Etuahod4bd9632018-03-08 16:32:44 +02001750 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001751
Olli Etuahod4bd9632018-03-08 16:32:44 +02001752 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001753 {
1754 out << "gl_main(";
1755 }
1756 else
1757 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001758 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001759 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001760 }
1761
Olli Etuahod4bd9632018-03-08 16:32:44 +02001762 size_t paramCount = func->getParamCount();
1763 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001764 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001765 const TVariable *param = func->getParam(i);
1766 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001767
Olli Etuahod4bd9632018-03-08 16:32:44 +02001768 writeParameter(param, out);
1769
1770 if (i < paramCount - 1)
Olli Etuaho336b1472016-10-05 16:37:55 +01001771 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001772 out << ", ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001773 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001774 }
1775
1776 out << ")\n";
1777
1778 mInsideFunction = true;
1779 // The function body node will output braces.
1780 node->getBody()->traverse(this);
1781 mInsideFunction = false;
1782
1783 mCurrentFunctionMetadata = nullptr;
1784
1785 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1786 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1787 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001788 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001789 mOutputLod0Function = true;
1790 node->traverse(this);
1791 mOutputLod0Function = false;
1792 }
1793
1794 return false;
1795}
1796
Olli Etuaho13389b62016-10-16 11:48:18 +01001797bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1798{
Olli Etuaho13389b62016-10-16 11:48:18 +01001799 if (visit == PreVisit)
1800 {
1801 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001802 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001803 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001804 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001805
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001806 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001807 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001808 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001809 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001810
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001811 if (!declarator->getAsSymbolNode() ||
1812 declarator->getAsSymbolNode()->variable().symbolType() !=
1813 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001814 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001815 if (declarator->getQualifier() == EvqShared)
1816 {
1817 out << "groupshared ";
1818 }
1819 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001820 {
1821 out << "static ";
1822 }
1823
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001824 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001825
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001826 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001827
1828 if (symbol)
1829 {
1830 symbol->traverse(this);
1831 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001832 // We don't initialize shared variables because:
1833 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1834 // code to initialize a groupshared array variable with a large array size.
1835 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1836 // allow initializing shared variables at all.
1837 if (declarator->getQualifier() != EvqShared)
1838 {
1839 out << " = " + zeroInitializer(symbol->getType());
1840 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001841 }
1842 else
1843 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001844 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001845 }
1846 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001847 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001848 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001849 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001850 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001851 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001852
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001853 const TVariable &variable = symbol->variable();
1854
1855 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001856 {
1857 // Vertex outputs which are declared but not written to should still be declared to
1858 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001859 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001860 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001861 }
1862 }
1863 return false;
1864}
1865
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001866bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1867{
1868 // Do not do any translation
1869 return false;
1870}
1871
Olli Etuahod4bd9632018-03-08 16:32:44 +02001872void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001873{
1874 TInfoSinkBase &out = getInfoSink();
1875
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001876 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001877 // Skip the prototype if it is not implemented (and thus not used)
1878 if (index == CallDAG::InvalidIndex)
1879 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001880 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00001881 }
1882
Olli Etuahod4bd9632018-03-08 16:32:44 +02001883 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00001884
Olli Etuahod4bd9632018-03-08 16:32:44 +02001885 TString name = DecorateFunctionIfNeeded(func);
1886 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001887 << (mOutputLod0Function ? "Lod0(" : "(");
1888
Olli Etuahod4bd9632018-03-08 16:32:44 +02001889 size_t paramCount = func->getParamCount();
1890 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001891 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02001892 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00001893
Olli Etuahod4bd9632018-03-08 16:32:44 +02001894 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00001895 {
1896 out << ", ";
1897 }
1898 }
1899
1900 out << ");\n";
1901
1902 // Also prototype the Lod0 variant if needed
1903 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1904 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1905 {
1906 mOutputLod0Function = true;
1907 node->traverse(this);
1908 mOutputLod0Function = false;
1909 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00001910}
1911
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001912bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1913{
Jamie Madill32aab012015-01-27 14:12:26 -05001914 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001915
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001916 switch (node->getOp())
1917 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001918 case EOpCallBuiltInFunction:
1919 case EOpCallFunctionInAST:
1920 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001921 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001922 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001923
Corentin Wallez1239ee92015-03-19 14:38:02 -07001924 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001925 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001926 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001927 if (node->isArray())
1928 {
1929 UNIMPLEMENTED();
1930 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001931 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001932 ASSERT(index != CallDAG::InvalidIndex);
1933 lod0 &= mASTMetadataList[index].mNeedsLod0;
1934
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001935 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001936 out << DisambiguateFunctionName(node->getSequence());
1937 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001938 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001939 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001940 {
1941 // This path is used for internal functions that don't have their definitions in the
1942 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001943 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001944 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001945 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08001946 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001947 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03001948 TType type = (*arguments)[0]->getAsTyped()->getType();
1949 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02001950 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08001951 type.getMemoryQualifier().readonly);
1952 out << imageFunctionName << "(";
1953 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001954 else
1955 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001956 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001957 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001958 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1959 if (arguments->size() > 1)
1960 {
1961 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1962 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001963 const ImmutableString &textureFunctionName =
1964 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
1965 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001966 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001967 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001968
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001969 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001970 {
Olli Etuaho96963162016-03-21 11:54:33 +02001971 TIntermTyped *typedArg = (*arg)->getAsTyped();
1972 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001973 {
1974 out << "texture_";
1975 (*arg)->traverse(this);
1976 out << ", sampler_";
1977 }
1978
1979 (*arg)->traverse(this);
1980
Olli Etuaho96963162016-03-21 11:54:33 +02001981 if (typedArg->getType().isStructureContainingSamplers())
1982 {
1983 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001984 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001985 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
1986 std::string namePrefix = "angle_";
1987 namePrefix += structName.data();
1988 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001989 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001990 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02001991 {
1992 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1993 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001994 out << ", texture_" << sampler->name();
1995 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001996 }
1997 else
1998 {
1999 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2000 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002001 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002002 }
2003 }
2004 }
2005
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002006 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002007 {
2008 out << ", ";
2009 }
2010 }
2011
2012 out << ")";
2013
2014 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002015 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002016 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002017 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002018 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002019 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002020 outputTriplet(out, visit, "(", " == ", ")");
2021 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002022 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002023 outputTriplet(out, visit, "(", " != ", ")");
2024 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002025 case EOpLessThanComponentWise:
2026 outputTriplet(out, visit, "(", " < ", ")");
2027 break;
2028 case EOpGreaterThanComponentWise:
2029 outputTriplet(out, visit, "(", " > ", ")");
2030 break;
2031 case EOpLessThanEqualComponentWise:
2032 outputTriplet(out, visit, "(", " <= ", ")");
2033 break;
2034 case EOpGreaterThanEqualComponentWise:
2035 outputTriplet(out, visit, "(", " >= ", ")");
2036 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002037 case EOpMod:
2038 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002039 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002040 break;
2041 case EOpModf:
2042 outputTriplet(out, visit, "modf(", ", ", ")");
2043 break;
2044 case EOpPow:
2045 outputTriplet(out, visit, "pow(", ", ", ")");
2046 break;
2047 case EOpAtan:
2048 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2049 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002050 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002051 break;
2052 case EOpMin:
2053 outputTriplet(out, visit, "min(", ", ", ")");
2054 break;
2055 case EOpMax:
2056 outputTriplet(out, visit, "max(", ", ", ")");
2057 break;
2058 case EOpClamp:
2059 outputTriplet(out, visit, "clamp(", ", ", ")");
2060 break;
2061 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302062 {
2063 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2064 if (lastParamNode->getType().getBasicType() == EbtBool)
2065 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002066 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2067 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302068 // so use emulated version.
2069 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002070 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302071 }
2072 else
2073 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002074 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302075 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002076 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302077 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002078 case EOpStep:
2079 outputTriplet(out, visit, "step(", ", ", ")");
2080 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002081 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002082 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2083 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002084 case EOpFrexp:
2085 case EOpLdexp:
2086 ASSERT(node->getUseEmulatedFunction());
2087 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2088 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002089 case EOpDistance:
2090 outputTriplet(out, visit, "distance(", ", ", ")");
2091 break;
2092 case EOpDot:
2093 outputTriplet(out, visit, "dot(", ", ", ")");
2094 break;
2095 case EOpCross:
2096 outputTriplet(out, visit, "cross(", ", ", ")");
2097 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002098 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002099 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002100 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002101 break;
2102 case EOpReflect:
2103 outputTriplet(out, visit, "reflect(", ", ", ")");
2104 break;
2105 case EOpRefract:
2106 outputTriplet(out, visit, "refract(", ", ", ")");
2107 break;
2108 case EOpOuterProduct:
2109 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002110 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002111 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002112 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002113 outputTriplet(out, visit, "(", " * ", ")");
2114 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002115 case EOpBitfieldExtract:
2116 case EOpBitfieldInsert:
2117 case EOpUaddCarry:
2118 case EOpUsubBorrow:
2119 case EOpUmulExtended:
2120 case EOpImulExtended:
2121 ASSERT(node->getUseEmulatedFunction());
2122 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2123 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002124 case EOpBarrier:
2125 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2126 // cheapest *WithGroupSync() function, without any functionality loss, but
2127 // with the potential for severe performance loss.
2128 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2129 break;
2130 case EOpMemoryBarrierShared:
2131 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2132 break;
2133 case EOpMemoryBarrierAtomicCounter:
2134 case EOpMemoryBarrierBuffer:
2135 case EOpMemoryBarrierImage:
2136 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2137 break;
2138 case EOpGroupMemoryBarrier:
2139 case EOpMemoryBarrier:
2140 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2141 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002142 default:
2143 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002144 }
2145
2146 return true;
2147}
2148
Olli Etuaho57961272016-09-14 13:57:46 +03002149void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002150{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002151 out << "if (";
2152
2153 node->getCondition()->traverse(this);
2154
2155 out << ")\n";
2156
Jamie Madill8c46ab12015-12-07 16:39:19 -05002157 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002158
2159 bool discard = false;
2160
2161 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002162 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002163 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002164 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002165
Olli Etuahoa6f22092015-05-08 18:31:10 +03002166 // Detect true discard
2167 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2168 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002169 else
2170 {
2171 // TODO(oetuaho): Check if the semicolon inside is necessary.
2172 // It's there as a result of conservative refactoring of the output.
2173 out << "{;}\n";
2174 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002175
Jamie Madill8c46ab12015-12-07 16:39:19 -05002176 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002177
Olli Etuahoa6f22092015-05-08 18:31:10 +03002178 if (node->getFalseBlock())
2179 {
2180 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002181
Jamie Madill8c46ab12015-12-07 16:39:19 -05002182 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183
Olli Etuaho32db19b2016-10-04 14:43:16 +01002184 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002185 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002186
Jamie Madill8c46ab12015-12-07 16:39:19 -05002187 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002188
Olli Etuahoa6f22092015-05-08 18:31:10 +03002189 // Detect false discard
2190 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2191 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002192
Olli Etuahoa6f22092015-05-08 18:31:10 +03002193 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002194 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002195 {
2196 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002197 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002198}
2199
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002200bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2201{
2202 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2203 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2204 UNREACHABLE();
2205 return false;
2206}
2207
Olli Etuaho57961272016-09-14 13:57:46 +03002208bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002209{
2210 TInfoSinkBase &out = getInfoSink();
2211
Olli Etuaho3d932d82016-04-12 11:10:30 +03002212 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002213
2214 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002215 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002216 {
2217 out << "FLATTEN ";
2218 }
2219
Olli Etuaho57961272016-09-14 13:57:46 +03002220 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002221
2222 return false;
2223}
2224
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002225bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002226{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002227 TInfoSinkBase &out = getInfoSink();
2228
Olli Etuaho923ecef2017-10-11 12:01:38 +03002229 ASSERT(node->getStatementList());
2230 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002231 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002232 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002233 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002234 outputTriplet(out, visit, "switch (", ") ", "");
2235 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002236 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002237}
2238
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002239bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002240{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002241 TInfoSinkBase &out = getInfoSink();
2242
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002243 if (node->hasCondition())
2244 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002245 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002246 return true;
2247 }
2248 else
2249 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002250 out << "default:\n";
2251 return false;
2252 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002253}
2254
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002255void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2256{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002257 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002258 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002259}
2260
2261bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2262{
Nicolas Capens655fe362014-04-11 13:12:34 -04002263 mNestedLoopDepth++;
2264
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002265 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002266 mInsideDiscontinuousLoop =
2267 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002268
Jamie Madill8c46ab12015-12-07 16:39:19 -05002269 TInfoSinkBase &out = getInfoSink();
2270
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002271 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002272 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002273 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002274 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002275 mInsideDiscontinuousLoop = wasDiscontinuous;
2276 mNestedLoopDepth--;
2277
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002278 return false;
2279 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002280 }
2281
Corentin Wallez1239ee92015-03-19 14:38:02 -07002282 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002283 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002284 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002285 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002286
Jamie Madill8c46ab12015-12-07 16:39:19 -05002287 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002288 }
2289 else
2290 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002291 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002292
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002293 if (node->getInit())
2294 {
2295 node->getInit()->traverse(this);
2296 }
2297
2298 out << "; ";
2299
alokp@chromium.org52813552010-11-16 18:36:09 +00002300 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002301 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002302 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002303 }
2304
2305 out << "; ";
2306
alokp@chromium.org52813552010-11-16 18:36:09 +00002307 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002308 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002309 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002310 }
2311
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002312 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002313
Jamie Madill8c46ab12015-12-07 16:39:19 -05002314 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002315 }
2316
2317 if (node->getBody())
2318 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002319 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002320 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002321 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002322 else
2323 {
2324 // TODO(oetuaho): Check if the semicolon inside is necessary.
2325 // It's there as a result of conservative refactoring of the output.
2326 out << "{;}\n";
2327 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002328
Jamie Madill8c46ab12015-12-07 16:39:19 -05002329 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002330
alokp@chromium.org52813552010-11-16 18:36:09 +00002331 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002332 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002333 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002334 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002335
alokp@chromium.org52813552010-11-16 18:36:09 +00002336 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002337
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002338 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002339 }
2340
daniel@transgaming.com73536982012-03-21 20:45:49 +00002341 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002342
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002343 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002344 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002345
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002346 return false;
2347}
2348
2349bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2350{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002351 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002352 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002353 TInfoSinkBase &out = getInfoSink();
2354
2355 switch (node->getFlowOp())
2356 {
2357 case EOpKill:
2358 out << "discard";
2359 break;
2360 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002361 if (mNestedLoopDepth > 1)
2362 {
2363 mUsesNestedBreak = true;
2364 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002365
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002366 if (mExcessiveLoopIndex)
2367 {
2368 out << "{Break";
2369 mExcessiveLoopIndex->traverse(this);
2370 out << " = true; break;}\n";
2371 }
2372 else
2373 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002374 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002375 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002376 break;
2377 case EOpContinue:
2378 out << "continue";
2379 break;
2380 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002381 if (node->getExpression())
2382 {
2383 out << "return ";
2384 }
2385 else
2386 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002387 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002388 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002389 break;
2390 default:
2391 UNREACHABLE();
2392 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002393 }
2394
2395 return true;
2396}
2397
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002398// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002399// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2400// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002401bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002402{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002403 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002404
2405 // Parse loops of the form:
2406 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002407 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002408 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002409 int initial = 0;
2410 int limit = 0;
2411 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002412
2413 // Parse index name and intial value
2414 if (node->getInit())
2415 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002416 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002417
2418 if (init)
2419 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002420 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002421 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002422
2423 if (variable && variable->getQualifier() == EvqTemporary)
2424 {
2425 TIntermBinary *assign = variable->getAsBinaryNode();
2426
2427 if (assign->getOp() == EOpInitialize)
2428 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002429 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002430 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2431
2432 if (symbol && constant)
2433 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002434 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002435 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002436 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002437 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002438 }
2439 }
2440 }
2441 }
2442 }
2443 }
2444
2445 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002446 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002447 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002448 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002449
Olli Etuahob6af22b2017-12-15 14:05:44 +02002450 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002451 {
2452 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2453
2454 if (constant)
2455 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002456 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002457 {
2458 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002459 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002460 }
2461 }
2462 }
2463 }
2464
2465 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002466 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002467 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002468 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002469 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002470
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002471 if (binaryTerminal)
2472 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002473 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002474 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2475
2476 if (constant)
2477 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002478 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002480 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002481
2482 switch (op)
2483 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002484 case EOpAddAssign:
2485 increment = value;
2486 break;
2487 case EOpSubAssign:
2488 increment = -value;
2489 break;
2490 default:
2491 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002492 }
2493 }
2494 }
2495 }
2496 else if (unaryTerminal)
2497 {
2498 TOperator op = unaryTerminal->getOp();
2499
2500 switch (op)
2501 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002502 case EOpPostIncrement:
2503 increment = 1;
2504 break;
2505 case EOpPostDecrement:
2506 increment = -1;
2507 break;
2508 case EOpPreIncrement:
2509 increment = 1;
2510 break;
2511 case EOpPreDecrement:
2512 increment = -1;
2513 break;
2514 default:
2515 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002516 }
2517 }
2518 }
2519
Yunchao He4f285442017-04-21 12:15:49 +08002520 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002521 {
2522 if (comparator == EOpLessThanEqual)
2523 {
2524 comparator = EOpLessThan;
2525 limit += 1;
2526 }
2527
2528 if (comparator == EOpLessThan)
2529 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002530 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002531
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002532 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002534 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002535 }
2536
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002537 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002538 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002539
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002540 out << "{int ";
2541 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002542 out << ";\n"
2543 "bool Break";
2544 index->traverse(this);
2545 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002546
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002547 bool firstLoopFragment = true;
2548
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002549 while (iterations > 0)
2550 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002551 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002552
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002553 if (!firstLoopFragment)
2554 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002555 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002556 index->traverse(this);
2557 out << ") {\n";
2558 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002559
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002560 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002561 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002562 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002563 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002564
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002565 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002566 const char *unroll =
2567 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002568
Corentin Wallez1239ee92015-03-19 14:38:02 -07002569 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002570 index->traverse(this);
2571 out << " = ";
2572 out << initial;
2573
2574 out << "; ";
2575 index->traverse(this);
2576 out << " < ";
2577 out << clampedLimit;
2578
2579 out << "; ";
2580 index->traverse(this);
2581 out << " += ";
2582 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002583 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002584
Jamie Madill8c46ab12015-12-07 16:39:19 -05002585 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002586 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002587
2588 if (node->getBody())
2589 {
2590 node->getBody()->traverse(this);
2591 }
2592
Jamie Madill8c46ab12015-12-07 16:39:19 -05002593 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002594 out << ";}\n";
2595
2596 if (!firstLoopFragment)
2597 {
2598 out << "}\n";
2599 }
2600
2601 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002602
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002603 initial += MAX_LOOP_ITERATIONS * increment;
2604 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002605 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002606
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002607 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002608
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002609 mExcessiveLoopIndex = restoreIndex;
2610
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002611 return true;
2612 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002613 else
2614 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002615 }
2616
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002617 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002618}
2619
Jamie Madill8c46ab12015-12-07 16:39:19 -05002620void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2621 Visit visit,
2622 const char *preString,
2623 const char *inString,
2624 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002625{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002626 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002627 {
2628 out << preString;
2629 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002630 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002631 {
2632 out << inString;
2633 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002634 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002635 {
2636 out << postString;
2637 }
2638}
2639
Jamie Madill8c46ab12015-12-07 16:39:19 -05002640void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002641{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002642 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002643 {
Jamie Madill32aab012015-01-27 14:12:26 -05002644 out << "\n";
2645 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002646
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002647 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002648 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002649 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002650 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002651
Jamie Madill32aab012015-01-27 14:12:26 -05002652 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002653 }
2654}
2655
Olli Etuahod4bd9632018-03-08 16:32:44 +02002656void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002657{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002658 const TType &type = param->getType();
2659 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002660
Olli Etuahod4bd9632018-03-08 16:32:44 +02002661 TString nameStr = DecorateVariableIfNeeded(*param);
2662 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002663
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002664 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002665 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002666 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2667 {
2668 // Samplers are passed as indices to the sampler array.
2669 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002670 out << "const uint " << nameStr << ArrayString(type);
2671 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002672 }
2673 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2674 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002675 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2676 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2677 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2678 << ArrayString(type);
2679 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002680 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002681 }
2682
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002683 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2684 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002685
2686 // If the structure parameter contains samplers, they need to be passed into the function as
2687 // separate parameters. HLSL doesn't natively support samplers in structs.
2688 if (type.isStructureContainingSamplers())
2689 {
2690 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002691 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002692 std::string namePrefix = "angle";
2693 namePrefix += nameStr.c_str();
2694 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2695 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002696 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002697 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002698 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002699 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2700 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002701 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002702 }
2703 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2704 {
Olli Etuaho96963162016-03-21 11:54:33 +02002705 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002706 out << ", " << QualifierString(qualifier) << " "
2707 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2708 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2709 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2710 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002711 }
2712 else
2713 {
Olli Etuaho96963162016-03-21 11:54:33 +02002714 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002715 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2716 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002717 }
2718 }
2719 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002720}
2721
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002722TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002723{
2724 TString string;
2725
Jamie Madill94bf7f22013-07-08 13:31:15 -04002726 size_t size = type.getObjectSize();
2727 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002728 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002729 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002730
Jamie Madill94bf7f22013-07-08 13:31:15 -04002731 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002732 {
2733 string += ", ";
2734 }
2735 }
2736
daniel@transgaming.comead23042010-04-29 03:35:36 +00002737 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002738}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002739
Olli Etuahobd3cd502017-11-03 15:48:52 +02002740void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002741{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002742 // Array constructors should have been already pruned from the code.
2743 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002744
2745 if (visit == PreVisit)
2746 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002747 TString constructorName;
2748 if (node->getBasicType() == EbtStruct)
2749 {
2750 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2751 }
2752 else
2753 {
2754 constructorName =
2755 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2756 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002757 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002758 }
2759 else if (visit == InVisit)
2760 {
2761 out << ", ";
2762 }
2763 else if (visit == PostVisit)
2764 {
2765 out << ")";
2766 }
2767}
2768
Jamie Madill8c46ab12015-12-07 16:39:19 -05002769const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2770 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002771 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002772{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002773 ASSERT(!type.isArray());
2774
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002775 const TConstantUnion *constUnionIterated = constUnion;
2776
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002777 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002778 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002779 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002780 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002781
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002782 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002783
Jamie Madill98493dd2013-07-08 14:39:03 -04002784 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002785 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002786 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002787 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002788
Jamie Madill98493dd2013-07-08 14:39:03 -04002789 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002790 {
2791 out << ", ";
2792 }
2793 }
2794
2795 out << ")";
2796 }
2797 else
2798 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002799 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002800 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002801
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002802 if (writeType)
2803 {
Jamie Madill033dae62014-06-18 12:56:28 -04002804 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002805 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002806 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002807 if (writeType)
2808 {
2809 out << ")";
2810 }
2811 }
2812
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002813 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002814}
2815
Olli Etuahod68924e2017-01-02 17:34:40 +00002816void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002817{
Olli Etuahod68924e2017-01-02 17:34:40 +00002818 if (visit == PreVisit)
2819 {
2820 const char *opStr = GetOperatorString(op);
2821 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2822 out << "(";
2823 }
2824 else
2825 {
2826 outputTriplet(out, visit, nullptr, ", ", ")");
2827 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002828}
2829
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002830bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2831 TIntermSymbol *symbolNode,
2832 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002833{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002834 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2835 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002836
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002837 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002838 {
2839 // Type already printed
2840 out << "t" + str(mUniqueIndex) + " = ";
2841 expression->traverse(this);
2842 out << ", ";
2843 symbolNode->traverse(this);
2844 out << " = t" + str(mUniqueIndex);
2845
2846 mUniqueIndex++;
2847 return true;
2848 }
2849
2850 return false;
2851}
2852
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002853bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2854 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002855 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002856{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002857 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002858 {
2859 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002860 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002861 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002862 writeConstantUnionArray(out, initializer->getConstantValue(),
2863 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002864 out << "}";
2865 return true;
2866 }
2867 return false;
2868}
2869
Jamie Madill55e79e02015-02-09 15:35:00 -05002870TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2871{
2872 const TFieldList &fields = structure.fields();
2873
2874 for (const auto &eqFunction : mStructEqualityFunctions)
2875 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002876 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002877 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002878 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002879 }
2880 }
2881
2882 const TString &structNameString = StructNameString(structure);
2883
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002885 function->structure = &structure;
2886 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002887
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002888 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002889
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002890 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2891 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002892 << "{\n"
2893 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002894
2895 for (size_t i = 0; i < fields.size(); i++)
2896 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002897 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002898 const TType *fieldType = field->type();
2899
2900 const TString &fieldNameA = "a." + Decorate(field->name());
2901 const TString &fieldNameB = "b." + Decorate(field->name());
2902
2903 if (i > 0)
2904 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002905 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002906 }
2907
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002908 fnOut << "(";
2909 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2910 fnOut << fieldNameA;
2911 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2912 fnOut << fieldNameB;
2913 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2914 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002915 }
2916
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002917 fnOut << ";\n"
2918 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002919
2920 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002921
2922 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002923 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002924
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002925 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002926}
2927
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002928TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002929{
2930 for (const auto &eqFunction : mArrayEqualityFunctions)
2931 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002932 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002933 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002934 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002935 }
2936 }
2937
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002938 TType elementType(type);
2939 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002940
Olli Etuaho12690762015-03-31 12:55:28 +03002941 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002942 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002943
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002944 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002945
2946 TInfoSinkBase fnOut;
2947
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002948 const TString &typeName = TypeString(type);
2949 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2950 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002951 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002952 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002953 << type.getOutermostArraySize()
2954 << "; ++i)\n"
2955 " {\n"
2956 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002957
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002958 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002959 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002960 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002961 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002962 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002963
2964 fnOut << ") { return false; }\n"
2965 " }\n"
2966 " return true;\n"
2967 "}\n";
2968
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002969 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002970
2971 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002972 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002973
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002974 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002975}
2976
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002977TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002978{
2979 for (const auto &assignFunction : mArrayAssignmentFunctions)
2980 {
2981 if (assignFunction.type == type)
2982 {
2983 return assignFunction.functionName;
2984 }
2985 }
2986
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002987 TType elementType(type);
2988 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002989
2990 ArrayHelperFunction function;
2991 function.type = type;
2992
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002993 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002994
2995 TInfoSinkBase fnOut;
2996
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002997 const TString &typeName = TypeString(type);
2998 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2999 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003000 << "{\n"
3001 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003002 << type.getOutermostArraySize()
3003 << "; ++i)\n"
3004 " {\n"
3005 " ";
3006
3007 outputAssign(PreVisit, elementType, fnOut);
3008 fnOut << "a[i]";
3009 outputAssign(InVisit, elementType, fnOut);
3010 fnOut << "b[i]";
3011 outputAssign(PostVisit, elementType, fnOut);
3012
3013 fnOut << ";\n"
3014 " }\n"
3015 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003016
3017 function.functionDefinition = fnOut.c_str();
3018
3019 mArrayAssignmentFunctions.push_back(function);
3020
3021 return function.functionName;
3022}
3023
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003024TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003025{
3026 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3027 {
3028 if (constructIntoFunction.type == type)
3029 {
3030 return constructIntoFunction.functionName;
3031 }
3032 }
3033
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003034 TType elementType(type);
3035 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003036
3037 ArrayHelperFunction function;
3038 function.type = type;
3039
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003040 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003041
3042 TInfoSinkBase fnOut;
3043
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003044 const TString &typeName = TypeString(type);
3045 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3046 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003047 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003048 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003049 }
3050 fnOut << ")\n"
3051 "{\n";
3052
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003053 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003054 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003055 fnOut << " ";
3056 outputAssign(PreVisit, elementType, fnOut);
3057 fnOut << "a[" << i << "]";
3058 outputAssign(InVisit, elementType, fnOut);
3059 fnOut << "b" << i;
3060 outputAssign(PostVisit, elementType, fnOut);
3061 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003062 }
3063 fnOut << "}\n";
3064
3065 function.functionDefinition = fnOut.c_str();
3066
3067 mArrayConstructIntoFunctions.push_back(function);
3068
3069 return function.functionName;
3070}
3071
Jamie Madill2e295e22015-04-29 10:41:33 -04003072void OutputHLSL::ensureStructDefined(const TType &type)
3073{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003074 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003075 if (structure)
3076 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003077 ASSERT(type.getBasicType() == EbtStruct);
3078 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003079 }
3080}
3081
Jamie Madill45bcc782016-11-07 13:58:48 -05003082} // namespace sh