blob: ccd60377891ce38200fd89c90ea156ded744b457 [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
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00009#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000010#include <cfloat>
11#include <stdio.h>
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"
Olli Etuaho4728bdc2017-12-20 17:51:08 +020018#include "compiler/translator/FindSymbolNode.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080019#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/InfoSink.h"
21#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020022#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030024#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/UniformHLSL.h"
27#include "compiler/translator/UtilsHLSL.h"
28#include "compiler/translator/blocklayout.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 ||
59 variable->getQualifier() == EvqConst);
60}
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 Etuaho56a2f952016-12-08 12:16:27 +000085void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030086{
Olli Etuaho56a2f952016-12-08 12:16:27 +000087 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
88 // regardless.
89 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
90 mOutputType == SH_HLSL_4_1_OUTPUT)
91 {
92 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
93 }
94 else
95 {
96 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
97 }
98}
Olli Etuaho4785fec2015-05-18 16:09:37 +030099
Olli Etuaho56a2f952016-12-08 12:16:27 +0000100void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200101{
102 ASSERT(constUnion != nullptr);
103 switch (constUnion->getType())
104 {
105 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000106 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200107 break;
108 case EbtInt:
109 out << constUnion->getIConst();
110 break;
111 case EbtUInt:
112 out << constUnion->getUConst();
113 break;
114 case EbtBool:
115 out << constUnion->getBConst();
116 break;
117 default:
118 UNREACHABLE();
119 }
120}
121
Olli Etuaho56a2f952016-12-08 12:16:27 +0000122const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
123 const TConstantUnion *const constUnion,
124 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200125{
126 const TConstantUnion *constUnionIterated = constUnion;
127 for (size_t i = 0; i < size; i++, constUnionIterated++)
128 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000129 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200130
131 if (i != size - 1)
132 {
133 out << ", ";
134 }
135 }
136 return constUnionIterated;
137}
138
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800139OutputHLSL::OutputHLSL(sh::GLenum shaderType,
140 int shaderVersion,
141 const TExtensionBehavior &extensionBehavior,
142 const char *sourcePath,
143 ShShaderOutput outputType,
144 int numRenderTargets,
145 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300146 ShCompileOptions compileOptions,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300147 TSymbolTable *symbolTable,
148 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300149 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200150 mShaderType(shaderType),
151 mShaderVersion(shaderVersion),
152 mExtensionBehavior(extensionBehavior),
153 mSourcePath(sourcePath),
154 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700155 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000156 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300157 mCurrentFunctionMetadata(nullptr),
158 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000160 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000161
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 mUsesFragColor = false;
163 mUsesFragData = false;
164 mUsesDepthRange = false;
165 mUsesFragCoord = false;
166 mUsesPointCoord = false;
167 mUsesFrontFacing = false;
168 mUsesPointSize = false;
169 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300170 mHasMultiviewExtensionEnabled =
171 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300172 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500173 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800175 mUsesNumWorkGroups = false;
176 mUsesWorkGroupID = false;
177 mUsesLocalInvocationID = false;
178 mUsesGlobalInvocationID = false;
179 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500180 mUsesXor = false;
181 mUsesDiscardRewriting = false;
182 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530183 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000184
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000185 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000186
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000188 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500189 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000190
Yunchao Hed7297bf2017-04-19 15:27:10 +0800191 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000192
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300194 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800195 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400196
Olli Etuahod8724a92017-12-29 18:40:36 +0200197 unsigned int firstUniformRegister =
198 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
199 mUniformHLSL =
200 new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms, firstUniformRegister);
201
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200202 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000203 {
Arun Patole63419392015-03-13 11:51:07 +0530204 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500205 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
206 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530207 // In both cases total 3 uniform registers need to be reserved.
208 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000209 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000210
Geoff Lang00140f42016-02-03 18:47:33 +0000211 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800212 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213}
214
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000215OutputHLSL::~OutputHLSL()
216{
Jamie Madill8daaba12014-06-13 10:04:33 -0400217 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400218 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300219 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800220 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200221 for (auto &eqFunction : mStructEqualityFunctions)
222 {
223 SafeDelete(eqFunction);
224 }
225 for (auto &eqFunction : mArrayEqualityFunctions)
226 {
227 SafeDelete(eqFunction);
228 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000229}
230
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200231void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000232{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200233 BuiltInFunctionEmulator builtInFunctionEmulator;
234 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800235 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
236 {
237 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
238 mShaderVersion);
239 }
240
Olli Etuahodfa75e82017-01-23 09:43:06 -0800241 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500242
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700243 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000244 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700245 ASSERT(success == CallDAG::INITDAG_SUCCESS);
246 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700247
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200248 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
249 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
250 // the shader code. When we add shader storage blocks we might also consider an alternative
251 // solution, since the struct mapping won't work very well for shader storage blocks.
252
Jamie Madill37997142015-01-28 10:06:34 -0500253 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500254 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200255 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500256 mInfoSinkStack.pop();
257
Jamie Madill37997142015-01-28 10:06:34 -0500258 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500259 mInfoSinkStack.pop();
260
Jamie Madill32aab012015-01-27 14:12:26 -0500261 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200262 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500263 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000264
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200265 objSink << mHeader.c_str();
266 objSink << mBody.c_str();
267 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200268
Olli Etuahodfa75e82017-01-23 09:43:06 -0800269 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000270}
271
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800272const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400273{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800274 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400275}
276
Jamie Madill9fe25e92014-07-18 10:33:08 -0400277const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
278{
279 return mUniformHLSL->getUniformRegisterMap();
280}
281
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200282TString OutputHLSL::structInitializerString(int indent,
283 const TType &type,
284 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400285{
286 TString init;
287
Olli Etuahoed049ab2017-06-30 17:38:33 +0300288 TString indentString;
289 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400290 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300291 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400292 }
293
Olli Etuahoed049ab2017-06-30 17:38:33 +0300294 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400295 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300296 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300297 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400298 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 TStringStream indexedString;
300 indexedString << name << "[" << arrayIndex << "]";
301 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300302 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300303 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300304 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300305 {
306 init += ",";
307 }
308 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400309 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300310 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400311 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300312 else if (type.getBasicType() == EbtStruct)
313 {
314 init += indentString + "{\n";
315 const TStructure &structure = *type.getStruct();
316 const TFieldList &fields = structure.fields();
317 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
318 {
319 const TField &field = *fields[fieldIndex];
320 const TString &fieldName = name + "." + Decorate(field.name());
321 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400322
Olli Etuahoed049ab2017-06-30 17:38:33 +0300323 init += structInitializerString(indent + 1, fieldType, fieldName);
324 if (fieldIndex < fields.size() - 1)
325 {
326 init += ",";
327 }
328 init += "\n";
329 }
330 init += indentString + "}";
331 }
332 else
333 {
334 init += indentString + name;
335 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400336
337 return init;
338}
339
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200340TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
341{
342 TString mappedStructs;
343
344 for (auto &mappedStruct : std140Structs)
345 {
346 TInterfaceBlock *interfaceBlock =
347 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200348 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200349 {
350 continue;
351 }
352
353 unsigned int instanceCount = 1u;
354 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
355 if (isInstanceArray)
356 {
357 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
358 }
359
360 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
361 ++instanceArrayIndex)
362 {
363 TString originalName;
364 TString mappedName("map");
365
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200366 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200367 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200368 const TString &instanceName = mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200369 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
370 if (isInstanceArray)
371 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200372 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200373 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200374 originalName += instanceString;
375 mappedName += instanceString;
376 originalName += ".";
377 mappedName += "_";
378 }
379
380 TString fieldName = Decorate(mappedStruct.field->name());
381 originalName += fieldName;
382 mappedName += fieldName;
383
384 TType *structType = mappedStruct.field->type();
385 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200386 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200387
388 if (structType->isArray())
389 {
390 mappedStructs += ArrayString(*mappedStruct.field->type());
391 }
392
393 mappedStructs += " =\n";
394 mappedStructs += structInitializerString(0, *structType, originalName);
395 mappedStructs += ";\n";
396 }
397 }
398 return mappedStructs;
399}
400
401void OutputHLSL::header(TInfoSinkBase &out,
402 const std::vector<MappedStruct> &std140Structs,
403 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000404{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000405 TString varyings;
406 TString attributes;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200407 TString mappedStructs = generateStructMapping(std140Structs);
Jamie Madill570e04d2013-06-21 09:15:33 -0400408
Olli Etuahob8cb9392017-12-20 14:23:19 +0200409 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000410 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200411 const TType &type = varying.second->getType();
412 const TString &name = varying.second->name();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000413
414 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500415 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
416 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000417 }
418
Olli Etuaho93b059d2017-12-20 12:46:58 +0200419 for (const auto &attribute : mReferencedAttributes)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000420 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200421 const TType &type = attribute.second->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200422 const TString &name = attribute.second->name();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000423
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500424 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
425 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000426 }
427
Jamie Madill8daaba12014-06-13 10:04:33 -0400428 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400429
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300430 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800431 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400432
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200433 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500434 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200435 out << "\n// Equality functions\n\n";
436 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500437 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200438 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200439 }
440 }
Olli Etuaho12690762015-03-31 12:55:28 +0300441 if (!mArrayAssignmentFunctions.empty())
442 {
443 out << "\n// Assignment functions\n\n";
444 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
445 {
446 out << assignmentFunction.functionDefinition << "\n";
447 }
448 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300449 if (!mArrayConstructIntoFunctions.empty())
450 {
451 out << "\n// Array constructor functions\n\n";
452 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
453 {
454 out << constructIntoFunction.functionDefinition << "\n";
455 }
456 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200457
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500458 if (mUsesDiscardRewriting)
459 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400460 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500461 }
462
Nicolas Capens655fe362014-04-11 13:12:34 -0400463 if (mUsesNestedBreak)
464 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400465 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400466 }
467
Arun Patole44efa0b2015-03-04 17:11:05 +0530468 if (mRequiresIEEEStrictCompiling)
469 {
470 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
471 }
472
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400473 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
474 "#define LOOP [loop]\n"
475 "#define FLATTEN [flatten]\n"
476 "#else\n"
477 "#define LOOP\n"
478 "#define FLATTEN\n"
479 "#endif\n";
480
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200481 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300483 const bool usingMRTExtension =
484 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000485
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000486 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500487 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400488 out << "\n";
489
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200490 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000491 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200492 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000493 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200494 const TString &variableName = outputVariable.second->name();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200495 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400496
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500497 out << "static " + TypeString(variableType) + " out_" + variableName +
498 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000499 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000500 }
Jamie Madill46131a32013-06-20 11:55:50 -0400501 else
502 {
503 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
504
505 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500506 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400507 for (unsigned int i = 0; i < numColorValues; i++)
508 {
509 out << " float4(0, 0, 0, 0)";
510 if (i + 1 != numColorValues)
511 {
512 out << ",";
513 }
514 out << "\n";
515 }
516
517 out << "};\n";
518 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000519
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400520 if (mUsesFragDepth)
521 {
522 out << "static float gl_Depth = 0.0;\n";
523 }
524
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000525 if (mUsesFragCoord)
526 {
527 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
528 }
529
530 if (mUsesPointCoord)
531 {
532 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
533 }
534
535 if (mUsesFrontFacing)
536 {
537 out << "static bool gl_FrontFacing = false;\n";
538 }
539
540 out << "\n";
541
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000542 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000543 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000544 out << "struct gl_DepthRangeParameters\n"
545 "{\n"
546 " float near;\n"
547 " float far;\n"
548 " float diff;\n"
549 "};\n"
550 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000551 }
552
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200553 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000554 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000555 out << "cbuffer DriverConstants : register(b1)\n"
556 "{\n";
557
558 if (mUsesDepthRange)
559 {
560 out << " float3 dx_DepthRange : packoffset(c0);\n";
561 }
562
563 if (mUsesFragCoord)
564 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000565 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000566 }
567
568 if (mUsesFragCoord || mUsesFrontFacing)
569 {
570 out << " float3 dx_DepthFront : packoffset(c2);\n";
571 }
572
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800573 if (mUsesFragCoord)
574 {
575 // dx_ViewScale is only used in the fragment shader to correct
576 // the value for glFragCoord if necessary
577 out << " float2 dx_ViewScale : packoffset(c3);\n";
578 }
579
Martin Radev72b4e1e2017-08-31 15:42:56 +0300580 if (mHasMultiviewExtensionEnabled)
581 {
582 // We have to add a value which we can use to keep track of which multi-view code
583 // path is to be selected in the GS.
584 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
585 }
586
Olli Etuaho618bebc2016-01-15 16:40:00 +0200587 if (mOutputType == SH_HLSL_4_1_OUTPUT)
588 {
589 mUniformHLSL->samplerMetadataUniforms(out, "c4");
590 }
591
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000592 out << "};\n";
593 }
594 else
595 {
596 if (mUsesDepthRange)
597 {
598 out << "uniform float3 dx_DepthRange : register(c0);";
599 }
600
601 if (mUsesFragCoord)
602 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000603 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000604 }
605
606 if (mUsesFragCoord || mUsesFrontFacing)
607 {
608 out << "uniform float3 dx_DepthFront : register(c2);\n";
609 }
610 }
611
612 out << "\n";
613
614 if (mUsesDepthRange)
615 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500616 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
617 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000618 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000619 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000620
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200621 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000622 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200623 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000624 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200625 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400626 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000627 }
628
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000629 if (usingMRTExtension && mNumRenderTargets > 1)
630 {
631 out << "#define GL_USES_MRT\n";
632 }
633
634 if (mUsesFragColor)
635 {
636 out << "#define GL_USES_FRAG_COLOR\n";
637 }
638
639 if (mUsesFragData)
640 {
641 out << "#define GL_USES_FRAG_DATA\n";
642 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643 }
Xinghua Caob1239382016-12-13 15:07:05 +0800644 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000646 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500647 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000648 out << "\n"
649 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400650
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000651 if (mUsesPointSize)
652 {
653 out << "static float gl_PointSize = float(1);\n";
654 }
655
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000656 if (mUsesInstanceID)
657 {
658 out << "static int gl_InstanceID;";
659 }
660
Corentin Wallezb076add2016-01-11 16:45:46 -0500661 if (mUsesVertexID)
662 {
663 out << "static int gl_VertexID;";
664 }
665
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000666 out << "\n"
667 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500668 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000669 out << "\n";
670
671 if (mUsesDepthRange)
672 {
673 out << "struct gl_DepthRangeParameters\n"
674 "{\n"
675 " float near;\n"
676 " float far;\n"
677 " float diff;\n"
678 "};\n"
679 "\n";
680 }
681
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200682 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000683 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800684 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500685 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800686
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000687 if (mUsesDepthRange)
688 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800689 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000690 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800691
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800692 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
693 // shaders. However, we declare it for all shaders (including Feature Level 10+).
694 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
695 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800696 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800697 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800698 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800699
Martin Radev72b4e1e2017-08-31 15:42:56 +0300700 if (mHasMultiviewExtensionEnabled)
701 {
702 // We have to add a value which we can use to keep track of which multi-view code
703 // path is to be selected in the GS.
704 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
705 }
706
Olli Etuaho618bebc2016-01-15 16:40:00 +0200707 if (mOutputType == SH_HLSL_4_1_OUTPUT)
708 {
709 mUniformHLSL->samplerMetadataUniforms(out, "c4");
710 }
711
Austin Kinross4fd18b12014-12-22 12:32:05 -0800712 out << "};\n"
713 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000714 }
715 else
716 {
717 if (mUsesDepthRange)
718 {
719 out << "uniform float3 dx_DepthRange : register(c0);\n";
720 }
721
Cooper Partine6664f02015-01-09 16:22:24 -0800722 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
723 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000724 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000725 }
726
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000727 if (mUsesDepthRange)
728 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500729 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
730 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000731 "\n";
732 }
733
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200734 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000735 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200736 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000737 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200738 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400739 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000740 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400741 }
Xinghua Caob1239382016-12-13 15:07:05 +0800742 else // Compute shader
743 {
744 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800745
746 out << "cbuffer DriverConstants : register(b1)\n"
747 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800748 if (mUsesNumWorkGroups)
749 {
Xinghua Caob1239382016-12-13 15:07:05 +0800750 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800751 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800752 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
753 mUniformHLSL->samplerMetadataUniforms(out, "c1");
754 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800755
756 // Follow built-in variables would be initialized in
757 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
758 // are used in compute shader.
759 if (mUsesWorkGroupID)
760 {
761 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
762 }
763
764 if (mUsesLocalInvocationID)
765 {
766 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
767 }
768
769 if (mUsesGlobalInvocationID)
770 {
771 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
772 }
773
774 if (mUsesLocalInvocationIndex)
775 {
776 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
777 }
778 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000779
Geoff Lang1fe74c72016-08-25 13:23:01 -0400780 bool getDimensionsIgnoresBaseLevel =
781 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
782 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800783 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000785 if (mUsesFragCoord)
786 {
787 out << "#define GL_USES_FRAG_COORD\n";
788 }
789
790 if (mUsesPointCoord)
791 {
792 out << "#define GL_USES_POINT_COORD\n";
793 }
794
795 if (mUsesFrontFacing)
796 {
797 out << "#define GL_USES_FRONT_FACING\n";
798 }
799
800 if (mUsesPointSize)
801 {
802 out << "#define GL_USES_POINT_SIZE\n";
803 }
804
Martin Radev41ac68e2017-06-06 12:16:58 +0300805 if (mHasMultiviewExtensionEnabled)
806 {
807 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
808 }
809
810 if (mUsesViewID)
811 {
812 out << "#define GL_USES_VIEW_ID\n";
813 }
814
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400815 if (mUsesFragDepth)
816 {
817 out << "#define GL_USES_FRAG_DEPTH\n";
818 }
819
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000820 if (mUsesDepthRange)
821 {
822 out << "#define GL_USES_DEPTH_RANGE\n";
823 }
824
Xinghua Caob1239382016-12-13 15:07:05 +0800825 if (mUsesNumWorkGroups)
826 {
827 out << "#define GL_USES_NUM_WORK_GROUPS\n";
828 }
829
830 if (mUsesWorkGroupID)
831 {
832 out << "#define GL_USES_WORK_GROUP_ID\n";
833 }
834
835 if (mUsesLocalInvocationID)
836 {
837 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
838 }
839
840 if (mUsesGlobalInvocationID)
841 {
842 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
843 }
844
845 if (mUsesLocalInvocationIndex)
846 {
847 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
848 }
849
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000850 if (mUsesXor)
851 {
852 out << "bool xor(bool p, bool q)\n"
853 "{\n"
854 " return (p || q) && !(p && q);\n"
855 "}\n"
856 "\n";
857 }
858
Olli Etuahodfa75e82017-01-23 09:43:06 -0800859 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000860}
861
862void OutputHLSL::visitSymbol(TIntermSymbol *node)
863{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200864 const TVariable &variable = node->variable();
865
866 // Empty symbols can only appear in declarations and function arguments, and in either of those
867 // cases the symbol nodes are not visited.
868 ASSERT(variable.symbolType() != SymbolType::Empty);
869
Jamie Madill32aab012015-01-27 14:12:26 -0500870 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871
Jamie Madill570e04d2013-06-21 09:15:33 -0400872 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200873 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400874 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200875 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400876 }
877
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200878 const TString &name = variable.name();
879 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200880
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000881 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000882 {
883 mUsesDepthRange = true;
884 out << name;
885 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000886 else
887 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200888 const TType &variableType = variable.getType();
889 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000890
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200891 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200892
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000893 if (qualifier == EvqUniform)
894 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200895 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400896
897 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000898 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200899 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000900 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000901 else
902 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200903 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000904 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400905
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200906 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000907 }
Jamie Madill19571812013-08-12 15:26:34 -0700908 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000909 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200910 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400911 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000912 }
Jamie Madill033dae62014-06-18 12:56:28 -0400913 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000914 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200915 mReferencedVaryings[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400916 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300917 if (name == "ViewID_OVR")
918 {
919 mUsesViewID = true;
920 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000921 }
Jamie Madill19571812013-08-12 15:26:34 -0700922 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400923 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200924 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400925 out << "out_" << name;
926 }
927 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000928 {
929 out << "gl_Color[0]";
930 mUsesFragColor = true;
931 }
932 else if (qualifier == EvqFragData)
933 {
934 out << "gl_Color";
935 mUsesFragData = true;
936 }
937 else if (qualifier == EvqFragCoord)
938 {
939 mUsesFragCoord = true;
940 out << name;
941 }
942 else if (qualifier == EvqPointCoord)
943 {
944 mUsesPointCoord = true;
945 out << name;
946 }
947 else if (qualifier == EvqFrontFacing)
948 {
949 mUsesFrontFacing = true;
950 out << name;
951 }
952 else if (qualifier == EvqPointSize)
953 {
954 mUsesPointSize = true;
955 out << name;
956 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000957 else if (qualifier == EvqInstanceID)
958 {
959 mUsesInstanceID = true;
960 out << name;
961 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500962 else if (qualifier == EvqVertexID)
963 {
964 mUsesVertexID = true;
965 out << name;
966 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300967 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400968 {
969 mUsesFragDepth = true;
970 out << "gl_Depth";
971 }
Xinghua Caob1239382016-12-13 15:07:05 +0800972 else if (qualifier == EvqNumWorkGroups)
973 {
974 mUsesNumWorkGroups = true;
975 out << name;
976 }
977 else if (qualifier == EvqWorkGroupID)
978 {
979 mUsesWorkGroupID = true;
980 out << name;
981 }
982 else if (qualifier == EvqLocalInvocationID)
983 {
984 mUsesLocalInvocationID = true;
985 out << name;
986 }
987 else if (qualifier == EvqGlobalInvocationID)
988 {
989 mUsesGlobalInvocationID = true;
990 out << name;
991 }
992 else if (qualifier == EvqLocalInvocationIndex)
993 {
994 mUsesLocalInvocationIndex = true;
995 out << name;
996 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000997 else
998 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200999 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001000 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001001 }
1002}
1003
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001004void OutputHLSL::visitRaw(TIntermRaw *node)
1005{
Jamie Madill32aab012015-01-27 14:12:26 -05001006 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001007}
1008
Olli Etuaho7fb49552015-03-18 17:27:44 +02001009void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1010{
1011 if (type.isScalar() && !type.isArray())
1012 {
1013 if (op == EOpEqual)
1014 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001015 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001016 }
1017 else
1018 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001019 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001020 }
1021 }
1022 else
1023 {
1024 if (visit == PreVisit && op == EOpNotEqual)
1025 {
1026 out << "!";
1027 }
1028
1029 if (type.isArray())
1030 {
1031 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001032 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001033 }
1034 else if (type.getBasicType() == EbtStruct)
1035 {
1036 const TStructure &structure = *type.getStruct();
1037 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001038 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001039 }
1040 else
1041 {
1042 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001043 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001044 }
1045 }
1046}
1047
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001048void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1049{
1050 if (type.isArray())
1051 {
1052 const TString &functionName = addArrayAssignmentFunction(type);
1053 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1054 }
1055 else
1056 {
1057 outputTriplet(out, visit, "(", " = ", ")");
1058 }
1059}
1060
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001061bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001062{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001063 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001064 {
1065 TIntermNode *ancestor = getAncestorNode(n);
1066 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1067 if (ancestorBinary == nullptr)
1068 {
1069 return false;
1070 }
1071 switch (ancestorBinary->getOp())
1072 {
1073 case EOpIndexDirectStruct:
1074 {
1075 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1076 const TIntermConstantUnion *index =
1077 ancestorBinary->getRight()->getAsConstantUnion();
1078 const TField *field = structure->fields()[index->getIConst(0)];
1079 if (IsSampler(field->type()->getBasicType()))
1080 {
1081 return true;
1082 }
1083 break;
1084 }
1085 case EOpIndexDirect:
1086 break;
1087 default:
1088 // Returning a sampler from indirect indexing is not supported.
1089 return false;
1090 }
1091 }
1092 return false;
1093}
1094
Olli Etuahob6fa0432016-09-28 16:28:05 +01001095bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1096{
1097 TInfoSinkBase &out = getInfoSink();
1098 if (visit == PostVisit)
1099 {
1100 out << ".";
1101 node->writeOffsetsAsXYZW(&out);
1102 }
1103 return true;
1104}
1105
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001106bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1107{
Jamie Madill32aab012015-01-27 14:12:26 -05001108 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001109
1110 switch (node->getOp())
1111 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001112 case EOpComma:
1113 outputTriplet(out, visit, "(", ", ", ")");
1114 break;
1115 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001116 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001117 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001118 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1119 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001120 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001121 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1122 out << functionName << "(";
1123 node->getLeft()->traverse(this);
1124 TIntermSequence *seq = rightAgg->getSequence();
1125 for (auto &arrayElement : *seq)
1126 {
1127 out << ", ";
1128 arrayElement->traverse(this);
1129 }
1130 out << ")";
1131 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001132 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001133 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1134 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001135 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001136 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001137 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001138 break;
1139 case EOpInitialize:
1140 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001141 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001142 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1143 ASSERT(symbolNode);
1144 TIntermTyped *expression = node->getRight();
1145
1146 // Global initializers must be constant at this point.
1147 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1148 canWriteAsHLSLLiteral(expression));
1149
1150 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1151 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1152 // new variable is created before the assignment is evaluated), so we need to
1153 // convert
1154 // this to "float t = x, x = t;".
1155 if (writeSameSymbolInitializer(out, symbolNode, expression))
1156 {
1157 // Skip initializing the rest of the expression
1158 return false;
1159 }
1160 else if (writeConstantInitialization(out, symbolNode, expression))
1161 {
1162 return false;
1163 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001164 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001165 else if (visit == InVisit)
1166 {
1167 out << " = ";
1168 }
1169 break;
1170 case EOpAddAssign:
1171 outputTriplet(out, visit, "(", " += ", ")");
1172 break;
1173 case EOpSubAssign:
1174 outputTriplet(out, visit, "(", " -= ", ")");
1175 break;
1176 case EOpMulAssign:
1177 outputTriplet(out, visit, "(", " *= ", ")");
1178 break;
1179 case EOpVectorTimesScalarAssign:
1180 outputTriplet(out, visit, "(", " *= ", ")");
1181 break;
1182 case EOpMatrixTimesScalarAssign:
1183 outputTriplet(out, visit, "(", " *= ", ")");
1184 break;
1185 case EOpVectorTimesMatrixAssign:
1186 if (visit == PreVisit)
1187 {
1188 out << "(";
1189 }
1190 else if (visit == InVisit)
1191 {
1192 out << " = mul(";
1193 node->getLeft()->traverse(this);
1194 out << ", transpose(";
1195 }
1196 else
1197 {
1198 out << ")))";
1199 }
1200 break;
1201 case EOpMatrixTimesMatrixAssign:
1202 if (visit == PreVisit)
1203 {
1204 out << "(";
1205 }
1206 else if (visit == InVisit)
1207 {
1208 out << " = transpose(mul(transpose(";
1209 node->getLeft()->traverse(this);
1210 out << "), transpose(";
1211 }
1212 else
1213 {
1214 out << "))))";
1215 }
1216 break;
1217 case EOpDivAssign:
1218 outputTriplet(out, visit, "(", " /= ", ")");
1219 break;
1220 case EOpIModAssign:
1221 outputTriplet(out, visit, "(", " %= ", ")");
1222 break;
1223 case EOpBitShiftLeftAssign:
1224 outputTriplet(out, visit, "(", " <<= ", ")");
1225 break;
1226 case EOpBitShiftRightAssign:
1227 outputTriplet(out, visit, "(", " >>= ", ")");
1228 break;
1229 case EOpBitwiseAndAssign:
1230 outputTriplet(out, visit, "(", " &= ", ")");
1231 break;
1232 case EOpBitwiseXorAssign:
1233 outputTriplet(out, visit, "(", " ^= ", ")");
1234 break;
1235 case EOpBitwiseOrAssign:
1236 outputTriplet(out, visit, "(", " |= ", ")");
1237 break;
1238 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001239 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001240 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001241 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001242 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001243 if (visit == PreVisit)
1244 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001245 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuaho12a18ad2017-12-01 16:59:47 +02001246 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuaho93b059d2017-12-20 12:46:58 +02001247 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1248 instanceArraySymbol;
Jamie Madill98493dd2013-07-08 14:39:03 -04001249 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001250 out << mUniformHLSL->UniformBlockInstanceString(instanceArraySymbol->getName(),
1251 arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001252 return false;
1253 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001254 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001255 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001256 {
1257 // All parts of an expression that access a sampler in a struct need to use _ as
1258 // separator to access the sampler variable that has been moved out of the struct.
1259 outputTriplet(out, visit, "", "_", "");
1260 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001261 else
1262 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001263 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001264 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001265 }
1266 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001267 case EOpIndexIndirect:
1268 // We do not currently support indirect references to interface blocks
1269 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1270 outputTriplet(out, visit, "", "[", "]");
1271 break;
1272 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001273 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001274 const TStructure *structure = node->getLeft()->getType().getStruct();
1275 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1276 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001277
Olli Etuaho96963162016-03-21 11:54:33 +02001278 // In cases where indexing returns a sampler, we need to access the sampler variable
1279 // that has been moved out of the struct.
1280 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1281 if (visit == PreVisit && indexingReturnsSampler)
1282 {
1283 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1284 // This prefix is only output at the beginning of the indexing expression, which
1285 // may have multiple parts.
1286 out << "angle";
1287 }
1288 if (!indexingReturnsSampler)
1289 {
1290 // All parts of an expression that access a sampler in a struct need to use _ as
1291 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001292 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001293 }
1294 if (visit == InVisit)
1295 {
1296 if (indexingReturnsSampler)
1297 {
1298 out << "_" + field->name();
1299 }
1300 else
1301 {
1302 out << "." + DecorateField(field->name(), *structure);
1303 }
1304
1305 return false;
1306 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001307 }
1308 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001309 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001310 {
1311 bool structInStd140Block =
1312 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1313 if (visit == PreVisit && structInStd140Block)
1314 {
1315 out << "map";
1316 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001317 if (visit == InVisit)
1318 {
1319 const TInterfaceBlock *interfaceBlock =
1320 node->getLeft()->getType().getInterfaceBlock();
1321 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1322 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001323 if (structInStd140Block)
1324 {
1325 out << "_";
1326 }
1327 else
1328 {
1329 out << ".";
1330 }
1331 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001332
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001333 return false;
1334 }
1335 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001336 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001337 case EOpAdd:
1338 outputTriplet(out, visit, "(", " + ", ")");
1339 break;
1340 case EOpSub:
1341 outputTriplet(out, visit, "(", " - ", ")");
1342 break;
1343 case EOpMul:
1344 outputTriplet(out, visit, "(", " * ", ")");
1345 break;
1346 case EOpDiv:
1347 outputTriplet(out, visit, "(", " / ", ")");
1348 break;
1349 case EOpIMod:
1350 outputTriplet(out, visit, "(", " % ", ")");
1351 break;
1352 case EOpBitShiftLeft:
1353 outputTriplet(out, visit, "(", " << ", ")");
1354 break;
1355 case EOpBitShiftRight:
1356 outputTriplet(out, visit, "(", " >> ", ")");
1357 break;
1358 case EOpBitwiseAnd:
1359 outputTriplet(out, visit, "(", " & ", ")");
1360 break;
1361 case EOpBitwiseXor:
1362 outputTriplet(out, visit, "(", " ^ ", ")");
1363 break;
1364 case EOpBitwiseOr:
1365 outputTriplet(out, visit, "(", " | ", ")");
1366 break;
1367 case EOpEqual:
1368 case EOpNotEqual:
1369 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1370 break;
1371 case EOpLessThan:
1372 outputTriplet(out, visit, "(", " < ", ")");
1373 break;
1374 case EOpGreaterThan:
1375 outputTriplet(out, visit, "(", " > ", ")");
1376 break;
1377 case EOpLessThanEqual:
1378 outputTriplet(out, visit, "(", " <= ", ")");
1379 break;
1380 case EOpGreaterThanEqual:
1381 outputTriplet(out, visit, "(", " >= ", ")");
1382 break;
1383 case EOpVectorTimesScalar:
1384 outputTriplet(out, visit, "(", " * ", ")");
1385 break;
1386 case EOpMatrixTimesScalar:
1387 outputTriplet(out, visit, "(", " * ", ")");
1388 break;
1389 case EOpVectorTimesMatrix:
1390 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1391 break;
1392 case EOpMatrixTimesVector:
1393 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1394 break;
1395 case EOpMatrixTimesMatrix:
1396 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1397 break;
1398 case EOpLogicalOr:
1399 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1400 // been unfolded.
1401 ASSERT(!node->getRight()->hasSideEffects());
1402 outputTriplet(out, visit, "(", " || ", ")");
1403 return true;
1404 case EOpLogicalXor:
1405 mUsesXor = true;
1406 outputTriplet(out, visit, "xor(", ", ", ")");
1407 break;
1408 case EOpLogicalAnd:
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 default:
1415 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001416 }
1417
1418 return true;
1419}
1420
1421bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1422{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001423 TInfoSinkBase &out = getInfoSink();
1424
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001425 switch (node->getOp())
1426 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001427 case EOpNegative:
1428 outputTriplet(out, visit, "(-", "", ")");
1429 break;
1430 case EOpPositive:
1431 outputTriplet(out, visit, "(+", "", ")");
1432 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001433 case EOpLogicalNot:
1434 outputTriplet(out, visit, "(!", "", ")");
1435 break;
1436 case EOpBitwiseNot:
1437 outputTriplet(out, visit, "(~", "", ")");
1438 break;
1439 case EOpPostIncrement:
1440 outputTriplet(out, visit, "(", "", "++)");
1441 break;
1442 case EOpPostDecrement:
1443 outputTriplet(out, visit, "(", "", "--)");
1444 break;
1445 case EOpPreIncrement:
1446 outputTriplet(out, visit, "(++", "", ")");
1447 break;
1448 case EOpPreDecrement:
1449 outputTriplet(out, visit, "(--", "", ")");
1450 break;
1451 case EOpRadians:
1452 outputTriplet(out, visit, "radians(", "", ")");
1453 break;
1454 case EOpDegrees:
1455 outputTriplet(out, visit, "degrees(", "", ")");
1456 break;
1457 case EOpSin:
1458 outputTriplet(out, visit, "sin(", "", ")");
1459 break;
1460 case EOpCos:
1461 outputTriplet(out, visit, "cos(", "", ")");
1462 break;
1463 case EOpTan:
1464 outputTriplet(out, visit, "tan(", "", ")");
1465 break;
1466 case EOpAsin:
1467 outputTriplet(out, visit, "asin(", "", ")");
1468 break;
1469 case EOpAcos:
1470 outputTriplet(out, visit, "acos(", "", ")");
1471 break;
1472 case EOpAtan:
1473 outputTriplet(out, visit, "atan(", "", ")");
1474 break;
1475 case EOpSinh:
1476 outputTriplet(out, visit, "sinh(", "", ")");
1477 break;
1478 case EOpCosh:
1479 outputTriplet(out, visit, "cosh(", "", ")");
1480 break;
1481 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001483 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001484 case EOpAtanh:
1485 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001486 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 break;
1488 case EOpExp:
1489 outputTriplet(out, visit, "exp(", "", ")");
1490 break;
1491 case EOpLog:
1492 outputTriplet(out, visit, "log(", "", ")");
1493 break;
1494 case EOpExp2:
1495 outputTriplet(out, visit, "exp2(", "", ")");
1496 break;
1497 case EOpLog2:
1498 outputTriplet(out, visit, "log2(", "", ")");
1499 break;
1500 case EOpSqrt:
1501 outputTriplet(out, visit, "sqrt(", "", ")");
1502 break;
1503 case EOpInverseSqrt:
1504 outputTriplet(out, visit, "rsqrt(", "", ")");
1505 break;
1506 case EOpAbs:
1507 outputTriplet(out, visit, "abs(", "", ")");
1508 break;
1509 case EOpSign:
1510 outputTriplet(out, visit, "sign(", "", ")");
1511 break;
1512 case EOpFloor:
1513 outputTriplet(out, visit, "floor(", "", ")");
1514 break;
1515 case EOpTrunc:
1516 outputTriplet(out, visit, "trunc(", "", ")");
1517 break;
1518 case EOpRound:
1519 outputTriplet(out, visit, "round(", "", ")");
1520 break;
1521 case EOpRoundEven:
1522 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001523 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 break;
1525 case EOpCeil:
1526 outputTriplet(out, visit, "ceil(", "", ")");
1527 break;
1528 case EOpFract:
1529 outputTriplet(out, visit, "frac(", "", ")");
1530 break;
1531 case EOpIsNan:
1532 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001533 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001534 else
1535 outputTriplet(out, visit, "isnan(", "", ")");
1536 mRequiresIEEEStrictCompiling = true;
1537 break;
1538 case EOpIsInf:
1539 outputTriplet(out, visit, "isinf(", "", ")");
1540 break;
1541 case EOpFloatBitsToInt:
1542 outputTriplet(out, visit, "asint(", "", ")");
1543 break;
1544 case EOpFloatBitsToUint:
1545 outputTriplet(out, visit, "asuint(", "", ")");
1546 break;
1547 case EOpIntBitsToFloat:
1548 outputTriplet(out, visit, "asfloat(", "", ")");
1549 break;
1550 case EOpUintBitsToFloat:
1551 outputTriplet(out, visit, "asfloat(", "", ")");
1552 break;
1553 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001555 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001557 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001559 case EOpPackUnorm4x8:
1560 case EOpPackSnorm4x8:
1561 case EOpUnpackUnorm4x8:
1562 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001564 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001565 break;
1566 case EOpLength:
1567 outputTriplet(out, visit, "length(", "", ")");
1568 break;
1569 case EOpNormalize:
1570 outputTriplet(out, visit, "normalize(", "", ")");
1571 break;
1572 case EOpDFdx:
1573 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1574 {
1575 outputTriplet(out, visit, "(", "", ", 0.0)");
1576 }
1577 else
1578 {
1579 outputTriplet(out, visit, "ddx(", "", ")");
1580 }
1581 break;
1582 case EOpDFdy:
1583 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1584 {
1585 outputTriplet(out, visit, "(", "", ", 0.0)");
1586 }
1587 else
1588 {
1589 outputTriplet(out, visit, "ddy(", "", ")");
1590 }
1591 break;
1592 case EOpFwidth:
1593 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1594 {
1595 outputTriplet(out, visit, "(", "", ", 0.0)");
1596 }
1597 else
1598 {
1599 outputTriplet(out, visit, "fwidth(", "", ")");
1600 }
1601 break;
1602 case EOpTranspose:
1603 outputTriplet(out, visit, "transpose(", "", ")");
1604 break;
1605 case EOpDeterminant:
1606 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1607 break;
1608 case EOpInverse:
1609 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001610 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001611 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001612
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001613 case EOpAny:
1614 outputTriplet(out, visit, "any(", "", ")");
1615 break;
1616 case EOpAll:
1617 outputTriplet(out, visit, "all(", "", ")");
1618 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001619 case EOpLogicalNotComponentWise:
1620 outputTriplet(out, visit, "(!", "", ")");
1621 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001622 case EOpBitfieldReverse:
1623 outputTriplet(out, visit, "reversebits(", "", ")");
1624 break;
1625 case EOpBitCount:
1626 outputTriplet(out, visit, "countbits(", "", ")");
1627 break;
1628 case EOpFindLSB:
1629 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1630 // in GLSLTest and results are consistent with GL.
1631 outputTriplet(out, visit, "firstbitlow(", "", ")");
1632 break;
1633 case EOpFindMSB:
1634 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1635 // tested in GLSLTest and results are consistent with GL.
1636 outputTriplet(out, visit, "firstbithigh(", "", ")");
1637 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001638 default:
1639 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 }
1641
1642 return true;
1643}
1644
Olli Etuaho96963162016-03-21 11:54:33 +02001645TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1646{
1647 if (node->getAsSymbolNode())
1648 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001649 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1650 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001651 }
1652 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1653 switch (nodeBinary->getOp())
1654 {
1655 case EOpIndexDirect:
1656 {
1657 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1658
1659 TInfoSinkBase prefixSink;
1660 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1661 return TString(prefixSink.c_str());
1662 }
1663 case EOpIndexDirectStruct:
1664 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001665 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001666 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1667 const TField *field = s->fields()[index];
1668
1669 TInfoSinkBase prefixSink;
1670 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1671 << field->name();
1672 return TString(prefixSink.c_str());
1673 }
1674 default:
1675 UNREACHABLE();
1676 return TString("");
1677 }
1678}
1679
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001680bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1681{
1682 TInfoSinkBase &out = getInfoSink();
1683
1684 if (mInsideFunction)
1685 {
1686 outputLineDirective(out, node->getLine().first_line);
1687 out << "{\n";
1688 }
1689
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001690 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001691 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001692 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001693
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001694 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001695
1696 // Don't output ; after case labels, they're terminated by :
1697 // This is needed especially since outputting a ; after a case statement would turn empty
1698 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001699 // Also the output code is clearer if we don't output ; after statements where it is not
1700 // needed:
1701 // * if statements
1702 // * switch statements
1703 // * blocks
1704 // * function definitions
1705 // * loops (do-while loops output the semicolon in VisitLoop)
1706 // * declarations that don't generate output.
1707 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1708 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1709 statement->getAsSwitchNode() == nullptr &&
1710 statement->getAsFunctionDefinition() == nullptr &&
1711 (statement->getAsDeclarationNode() == nullptr ||
1712 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1713 statement->getAsInvariantDeclarationNode() == nullptr)
1714 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001715 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001716 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001717 }
1718
1719 if (mInsideFunction)
1720 {
1721 outputLineDirective(out, node->getLine().last_line);
1722 out << "}\n";
1723 }
1724
1725 return false;
1726}
1727
Olli Etuaho336b1472016-10-05 16:37:55 +01001728bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1729{
1730 TInfoSinkBase &out = getInfoSink();
1731
1732 ASSERT(mCurrentFunctionMetadata == nullptr);
1733
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001734 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001735 ASSERT(index != CallDAG::InvalidIndex);
1736 mCurrentFunctionMetadata = &mASTMetadataList[index];
1737
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001738 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001739
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001740 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001741
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001742 if (node->getFunction()->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001743 {
1744 out << "gl_main(";
1745 }
1746 else
1747 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001748 out << DecorateFunctionIfNeeded(node->getFunction()) << DisambiguateFunctionName(parameters)
1749 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001750 }
1751
1752 for (unsigned int i = 0; i < parameters->size(); i++)
1753 {
1754 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1755
1756 if (symbol)
1757 {
1758 ensureStructDefined(symbol->getType());
1759
1760 out << argumentString(symbol);
1761
1762 if (i < parameters->size() - 1)
1763 {
1764 out << ", ";
1765 }
1766 }
1767 else
1768 UNREACHABLE();
1769 }
1770
1771 out << ")\n";
1772
1773 mInsideFunction = true;
1774 // The function body node will output braces.
1775 node->getBody()->traverse(this);
1776 mInsideFunction = false;
1777
1778 mCurrentFunctionMetadata = nullptr;
1779
1780 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1781 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1782 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001783 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001784 mOutputLod0Function = true;
1785 node->traverse(this);
1786 mOutputLod0Function = false;
1787 }
1788
1789 return false;
1790}
1791
Olli Etuaho13389b62016-10-16 11:48:18 +01001792bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1793{
Olli Etuaho13389b62016-10-16 11:48:18 +01001794 if (visit == PreVisit)
1795 {
1796 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001797 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001798 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001799 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001800
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001801 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001802 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001803 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001804 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001805
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001806 if (!declarator->getAsSymbolNode() ||
1807 declarator->getAsSymbolNode()->variable().symbolType() !=
1808 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001809 {
1810 if (!mInsideFunction)
1811 {
1812 out << "static ";
1813 }
1814
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001815 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001816
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001817 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001818
1819 if (symbol)
1820 {
1821 symbol->traverse(this);
1822 out << ArrayString(symbol->getType());
1823 out << " = " + initializer(symbol->getType());
1824 }
1825 else
1826 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001827 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01001828 }
1829 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001830 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001831 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001832 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001833 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03001834 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001835
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001836 const TVariable &variable = symbol->variable();
1837
1838 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02001839 {
1840 // Vertex outputs which are declared but not written to should still be declared to
1841 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001842 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02001843 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001844 }
1845 }
1846 return false;
1847}
1848
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001849bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1850{
1851 // Do not do any translation
1852 return false;
1853}
1854
Olli Etuaho16c745a2017-01-16 17:02:27 +00001855bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1856{
1857 TInfoSinkBase &out = getInfoSink();
1858
1859 ASSERT(visit == PreVisit);
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001860 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001861 // Skip the prototype if it is not implemented (and thus not used)
1862 if (index == CallDAG::InvalidIndex)
1863 {
1864 return false;
1865 }
1866
1867 TIntermSequence *arguments = node->getSequence();
1868
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001869 TString name = DecorateFunctionIfNeeded(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001870 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1871 << (mOutputLod0Function ? "Lod0(" : "(");
1872
1873 for (unsigned int i = 0; i < arguments->size(); i++)
1874 {
1875 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1876 ASSERT(symbol != nullptr);
1877
1878 out << argumentString(symbol);
1879
1880 if (i < arguments->size() - 1)
1881 {
1882 out << ", ";
1883 }
1884 }
1885
1886 out << ");\n";
1887
1888 // Also prototype the Lod0 variant if needed
1889 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1890 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1891 {
1892 mOutputLod0Function = true;
1893 node->traverse(this);
1894 mOutputLod0Function = false;
1895 }
1896
1897 return false;
1898}
1899
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001900bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1901{
Jamie Madill32aab012015-01-27 14:12:26 -05001902 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001903
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001904 switch (node->getOp())
1905 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001906 case EOpCallBuiltInFunction:
1907 case EOpCallFunctionInAST:
1908 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001909 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001910 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001911
Corentin Wallez1239ee92015-03-19 14:38:02 -07001912 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001913 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001914 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001915 if (node->isArray())
1916 {
1917 UNIMPLEMENTED();
1918 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001919 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001920 ASSERT(index != CallDAG::InvalidIndex);
1921 lod0 &= mASTMetadataList[index].mNeedsLod0;
1922
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001923 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001924 out << DisambiguateFunctionName(node->getSequence());
1925 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001926 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001927 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001928 {
1929 // This path is used for internal functions that don't have their definitions in the
1930 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001931 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001932 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001933 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08001934 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001935 const TString &name = node->getFunction()->name();
Xinghua Cao711b7a12017-10-09 13:38:12 +08001936 TType type = (*arguments)[0]->getAsTyped()->getType();
1937 TString imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02001938 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08001939 type.getMemoryQualifier().readonly);
1940 out << imageFunctionName << "(";
1941 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001942 else
1943 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001944 const TString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001945 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001946 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1947 if (arguments->size() > 1)
1948 {
1949 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1950 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001951 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02001952 name, samplerType, coords, arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001953 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001954 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001955
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001956 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001957 {
Olli Etuaho96963162016-03-21 11:54:33 +02001958 TIntermTyped *typedArg = (*arg)->getAsTyped();
1959 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001960 {
1961 out << "texture_";
1962 (*arg)->traverse(this);
1963 out << ", sampler_";
1964 }
1965
1966 (*arg)->traverse(this);
1967
Olli Etuaho96963162016-03-21 11:54:33 +02001968 if (typedArg->getType().isStructureContainingSamplers())
1969 {
1970 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001971 TVector<const TVariable *> samplerSymbols;
Olli Etuaho96963162016-03-21 11:54:33 +02001972 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001973 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1974 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001975 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02001976 {
1977 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1978 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001979 out << ", texture_" << sampler->name();
1980 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001981 }
1982 else
1983 {
1984 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1985 // of D3D9, it's the sampler variable.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001986 out << ", " + sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001987 }
1988 }
1989 }
1990
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001991 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001992 {
1993 out << ", ";
1994 }
1995 }
1996
1997 out << ")";
1998
1999 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002000 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002001 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002002 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002003 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002004 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002005 outputTriplet(out, visit, "(", " == ", ")");
2006 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002007 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002008 outputTriplet(out, visit, "(", " != ", ")");
2009 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002010 case EOpLessThanComponentWise:
2011 outputTriplet(out, visit, "(", " < ", ")");
2012 break;
2013 case EOpGreaterThanComponentWise:
2014 outputTriplet(out, visit, "(", " > ", ")");
2015 break;
2016 case EOpLessThanEqualComponentWise:
2017 outputTriplet(out, visit, "(", " <= ", ")");
2018 break;
2019 case EOpGreaterThanEqualComponentWise:
2020 outputTriplet(out, visit, "(", " >= ", ")");
2021 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002022 case EOpMod:
2023 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002024 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002025 break;
2026 case EOpModf:
2027 outputTriplet(out, visit, "modf(", ", ", ")");
2028 break;
2029 case EOpPow:
2030 outputTriplet(out, visit, "pow(", ", ", ")");
2031 break;
2032 case EOpAtan:
2033 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2034 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002035 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002036 break;
2037 case EOpMin:
2038 outputTriplet(out, visit, "min(", ", ", ")");
2039 break;
2040 case EOpMax:
2041 outputTriplet(out, visit, "max(", ", ", ")");
2042 break;
2043 case EOpClamp:
2044 outputTriplet(out, visit, "clamp(", ", ", ")");
2045 break;
2046 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302047 {
2048 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2049 if (lastParamNode->getType().getBasicType() == EbtBool)
2050 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002051 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2052 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302053 // so use emulated version.
2054 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002055 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302056 }
2057 else
2058 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002059 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302060 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002061 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302062 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002063 case EOpStep:
2064 outputTriplet(out, visit, "step(", ", ", ")");
2065 break;
2066 case EOpSmoothStep:
2067 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2068 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002069 case EOpFrexp:
2070 case EOpLdexp:
2071 ASSERT(node->getUseEmulatedFunction());
2072 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2073 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002074 case EOpDistance:
2075 outputTriplet(out, visit, "distance(", ", ", ")");
2076 break;
2077 case EOpDot:
2078 outputTriplet(out, visit, "dot(", ", ", ")");
2079 break;
2080 case EOpCross:
2081 outputTriplet(out, visit, "cross(", ", ", ")");
2082 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002083 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002084 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002085 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002086 break;
2087 case EOpReflect:
2088 outputTriplet(out, visit, "reflect(", ", ", ")");
2089 break;
2090 case EOpRefract:
2091 outputTriplet(out, visit, "refract(", ", ", ")");
2092 break;
2093 case EOpOuterProduct:
2094 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002095 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002096 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002097 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002098 outputTriplet(out, visit, "(", " * ", ")");
2099 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002100 case EOpBitfieldExtract:
2101 case EOpBitfieldInsert:
2102 case EOpUaddCarry:
2103 case EOpUsubBorrow:
2104 case EOpUmulExtended:
2105 case EOpImulExtended:
2106 ASSERT(node->getUseEmulatedFunction());
2107 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2108 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002109 default:
2110 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002111 }
2112
2113 return true;
2114}
2115
Olli Etuaho57961272016-09-14 13:57:46 +03002116void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002117{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002118 out << "if (";
2119
2120 node->getCondition()->traverse(this);
2121
2122 out << ")\n";
2123
Jamie Madill8c46ab12015-12-07 16:39:19 -05002124 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002125
2126 bool discard = false;
2127
2128 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002129 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002130 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002131 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002132
Olli Etuahoa6f22092015-05-08 18:31:10 +03002133 // Detect true discard
2134 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2135 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002136 else
2137 {
2138 // TODO(oetuaho): Check if the semicolon inside is necessary.
2139 // It's there as a result of conservative refactoring of the output.
2140 out << "{;}\n";
2141 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002142
Jamie Madill8c46ab12015-12-07 16:39:19 -05002143 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002144
Olli Etuahoa6f22092015-05-08 18:31:10 +03002145 if (node->getFalseBlock())
2146 {
2147 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002148
Jamie Madill8c46ab12015-12-07 16:39:19 -05002149 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002150
Olli Etuaho32db19b2016-10-04 14:43:16 +01002151 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002152 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002153
Jamie Madill8c46ab12015-12-07 16:39:19 -05002154 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002155
Olli Etuahoa6f22092015-05-08 18:31:10 +03002156 // Detect false discard
2157 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2158 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002159
Olli Etuahoa6f22092015-05-08 18:31:10 +03002160 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002161 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002162 {
2163 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002164 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002165}
2166
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002167bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2168{
2169 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2170 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2171 UNREACHABLE();
2172 return false;
2173}
2174
Olli Etuaho57961272016-09-14 13:57:46 +03002175bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002176{
2177 TInfoSinkBase &out = getInfoSink();
2178
Olli Etuaho3d932d82016-04-12 11:10:30 +03002179 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002180
2181 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002182 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002183 {
2184 out << "FLATTEN ";
2185 }
2186
Olli Etuaho57961272016-09-14 13:57:46 +03002187 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188
2189 return false;
2190}
2191
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002192bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002193{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002194 TInfoSinkBase &out = getInfoSink();
2195
Olli Etuaho923ecef2017-10-11 12:01:38 +03002196 ASSERT(node->getStatementList());
2197 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002198 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002199 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002200 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002201 outputTriplet(out, visit, "switch (", ") ", "");
2202 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002203 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002204}
2205
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002206bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002207{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002208 TInfoSinkBase &out = getInfoSink();
2209
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002210 if (node->hasCondition())
2211 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002212 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002213 return true;
2214 }
2215 else
2216 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002217 out << "default:\n";
2218 return false;
2219 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002220}
2221
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002222void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2223{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002224 TInfoSinkBase &out = getInfoSink();
2225 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002226}
2227
2228bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2229{
Nicolas Capens655fe362014-04-11 13:12:34 -04002230 mNestedLoopDepth++;
2231
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002232 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002233 mInsideDiscontinuousLoop =
2234 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002235
Jamie Madill8c46ab12015-12-07 16:39:19 -05002236 TInfoSinkBase &out = getInfoSink();
2237
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002238 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002239 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002240 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002241 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002242 mInsideDiscontinuousLoop = wasDiscontinuous;
2243 mNestedLoopDepth--;
2244
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002245 return false;
2246 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002247 }
2248
Corentin Wallez1239ee92015-03-19 14:38:02 -07002249 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002250 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002251 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002252 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002253
Jamie Madill8c46ab12015-12-07 16:39:19 -05002254 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002255 }
2256 else
2257 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002258 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002259
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 if (node->getInit())
2261 {
2262 node->getInit()->traverse(this);
2263 }
2264
2265 out << "; ";
2266
alokp@chromium.org52813552010-11-16 18:36:09 +00002267 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002268 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002269 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002270 }
2271
2272 out << "; ";
2273
alokp@chromium.org52813552010-11-16 18:36:09 +00002274 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002275 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002276 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002277 }
2278
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002279 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002280
Jamie Madill8c46ab12015-12-07 16:39:19 -05002281 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002282 }
2283
2284 if (node->getBody())
2285 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002286 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002287 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002288 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002289 else
2290 {
2291 // TODO(oetuaho): Check if the semicolon inside is necessary.
2292 // It's there as a result of conservative refactoring of the output.
2293 out << "{;}\n";
2294 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002295
Jamie Madill8c46ab12015-12-07 16:39:19 -05002296 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002297
alokp@chromium.org52813552010-11-16 18:36:09 +00002298 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002299 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002300 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002301 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302
alokp@chromium.org52813552010-11-16 18:36:09 +00002303 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002304
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002305 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002306 }
2307
daniel@transgaming.com73536982012-03-21 20:45:49 +00002308 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002310 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002311 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002312
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002313 return false;
2314}
2315
2316bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2317{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002318 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002319 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002320 TInfoSinkBase &out = getInfoSink();
2321
2322 switch (node->getFlowOp())
2323 {
2324 case EOpKill:
2325 out << "discard";
2326 break;
2327 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002328 if (mNestedLoopDepth > 1)
2329 {
2330 mUsesNestedBreak = true;
2331 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002332
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002333 if (mExcessiveLoopIndex)
2334 {
2335 out << "{Break";
2336 mExcessiveLoopIndex->traverse(this);
2337 out << " = true; break;}\n";
2338 }
2339 else
2340 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002341 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002342 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002343 break;
2344 case EOpContinue:
2345 out << "continue";
2346 break;
2347 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002348 if (node->getExpression())
2349 {
2350 out << "return ";
2351 }
2352 else
2353 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002354 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002355 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002356 break;
2357 default:
2358 UNREACHABLE();
2359 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002360 }
2361
2362 return true;
2363}
2364
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002365// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002366// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2367// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002368bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002369{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002370 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002371
2372 // Parse loops of the form:
2373 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002374 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002375 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002376 int initial = 0;
2377 int limit = 0;
2378 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002379
2380 // Parse index name and intial value
2381 if (node->getInit())
2382 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002383 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002384
2385 if (init)
2386 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002387 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002388 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002389
2390 if (variable && variable->getQualifier() == EvqTemporary)
2391 {
2392 TIntermBinary *assign = variable->getAsBinaryNode();
2393
2394 if (assign->getOp() == EOpInitialize)
2395 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002396 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002397 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2398
2399 if (symbol && constant)
2400 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002401 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002402 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002403 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002404 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002405 }
2406 }
2407 }
2408 }
2409 }
2410 }
2411
2412 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002413 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002414 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002415 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002416
Olli Etuahob6af22b2017-12-15 14:05:44 +02002417 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002418 {
2419 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2420
2421 if (constant)
2422 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002423 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002424 {
2425 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002426 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002427 }
2428 }
2429 }
2430 }
2431
2432 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002433 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002434 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002435 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002436 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002437
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002438 if (binaryTerminal)
2439 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002440 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002441 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2442
2443 if (constant)
2444 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002445 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002446 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002447 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002448
2449 switch (op)
2450 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002451 case EOpAddAssign:
2452 increment = value;
2453 break;
2454 case EOpSubAssign:
2455 increment = -value;
2456 break;
2457 default:
2458 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002459 }
2460 }
2461 }
2462 }
2463 else if (unaryTerminal)
2464 {
2465 TOperator op = unaryTerminal->getOp();
2466
2467 switch (op)
2468 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002469 case EOpPostIncrement:
2470 increment = 1;
2471 break;
2472 case EOpPostDecrement:
2473 increment = -1;
2474 break;
2475 case EOpPreIncrement:
2476 increment = 1;
2477 break;
2478 case EOpPreDecrement:
2479 increment = -1;
2480 break;
2481 default:
2482 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002483 }
2484 }
2485 }
2486
Yunchao He4f285442017-04-21 12:15:49 +08002487 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002488 {
2489 if (comparator == EOpLessThanEqual)
2490 {
2491 comparator = EOpLessThan;
2492 limit += 1;
2493 }
2494
2495 if (comparator == EOpLessThan)
2496 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002497 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002499 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002500 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002501 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002502 }
2503
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002504 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002505 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002506
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002507 out << "{int ";
2508 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002509 out << ";\n"
2510 "bool Break";
2511 index->traverse(this);
2512 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002513
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002514 bool firstLoopFragment = true;
2515
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002516 while (iterations > 0)
2517 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002518 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002519
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002520 if (!firstLoopFragment)
2521 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002522 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002523 index->traverse(this);
2524 out << ") {\n";
2525 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002526
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002527 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002528 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002529 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002530 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002531
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002532 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002533 const char *unroll =
2534 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002535
Corentin Wallez1239ee92015-03-19 14:38:02 -07002536 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002537 index->traverse(this);
2538 out << " = ";
2539 out << initial;
2540
2541 out << "; ";
2542 index->traverse(this);
2543 out << " < ";
2544 out << clampedLimit;
2545
2546 out << "; ";
2547 index->traverse(this);
2548 out << " += ";
2549 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002550 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002551
Jamie Madill8c46ab12015-12-07 16:39:19 -05002552 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002553 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002554
2555 if (node->getBody())
2556 {
2557 node->getBody()->traverse(this);
2558 }
2559
Jamie Madill8c46ab12015-12-07 16:39:19 -05002560 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002561 out << ";}\n";
2562
2563 if (!firstLoopFragment)
2564 {
2565 out << "}\n";
2566 }
2567
2568 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002569
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002570 initial += MAX_LOOP_ITERATIONS * increment;
2571 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002572 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002573
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002574 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002575
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002576 mExcessiveLoopIndex = restoreIndex;
2577
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002578 return true;
2579 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002580 else
2581 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002582 }
2583
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002584 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002585}
2586
Jamie Madill8c46ab12015-12-07 16:39:19 -05002587void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2588 Visit visit,
2589 const char *preString,
2590 const char *inString,
2591 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002592{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002593 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002594 {
2595 out << preString;
2596 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002597 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002598 {
2599 out << inString;
2600 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002601 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002602 {
2603 out << postString;
2604 }
2605}
2606
Jamie Madill8c46ab12015-12-07 16:39:19 -05002607void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002608{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002609 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002610 {
Jamie Madill32aab012015-01-27 14:12:26 -05002611 out << "\n";
2612 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002613
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002614 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002615 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002616 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002617 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002618
Jamie Madill32aab012015-01-27 14:12:26 -05002619 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002620 }
2621}
2622
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002623TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2624{
2625 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002626 const TType &type = symbol->getType();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002627 const TVariable &variable = symbol->variable();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002628 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002629
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002630 if (variable.symbolType() ==
2631 SymbolType::Empty) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002632 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002633 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002634 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002635 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002636 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002637 nameStr = DecorateVariableIfNeeded(variable);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002638 }
2639
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002640 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002641 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002642 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2643 {
2644 // Samplers are passed as indices to the sampler array.
2645 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2646 return "const uint " + nameStr + ArrayString(type);
2647 }
2648 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2649 {
2650 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2651 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2652 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2653 ArrayString(type);
2654 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002655 }
2656
Olli Etuaho96963162016-03-21 11:54:33 +02002657 TStringStream argString;
2658 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2659 << ArrayString(type);
2660
2661 // If the structure parameter contains samplers, they need to be passed into the function as
2662 // separate parameters. HLSL doesn't natively support samplers in structs.
2663 if (type.isStructureContainingSamplers())
2664 {
2665 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002666 TVector<const TVariable *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002667 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002668 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002669 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002670 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002671 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2672 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002673 argString << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002674 }
2675 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2676 {
Olli Etuaho96963162016-03-21 11:54:33 +02002677 ASSERT(IsSampler(samplerType.getBasicType()));
2678 argString << ", " << QualifierString(qualifier) << " "
2679 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002680 << sampler->name() << ArrayString(samplerType) << ", "
Olli Etuaho28839f02017-08-15 11:38:16 +03002681 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002682 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002683 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002684 }
2685 else
2686 {
Olli Etuaho96963162016-03-21 11:54:33 +02002687 ASSERT(IsSampler(samplerType.getBasicType()));
2688 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002689 << " " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002690 }
2691 }
2692 }
2693
2694 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002695}
2696
2697TString OutputHLSL::initializer(const TType &type)
2698{
2699 TString string;
2700
Jamie Madill94bf7f22013-07-08 13:31:15 -04002701 size_t size = type.getObjectSize();
2702 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002703 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002704 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002705
Jamie Madill94bf7f22013-07-08 13:31:15 -04002706 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002707 {
2708 string += ", ";
2709 }
2710 }
2711
daniel@transgaming.comead23042010-04-29 03:35:36 +00002712 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002713}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002714
Olli Etuahobd3cd502017-11-03 15:48:52 +02002715void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002716{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002717 // Array constructors should have been already pruned from the code.
2718 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002719
2720 if (visit == PreVisit)
2721 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002722 TString constructorName;
2723 if (node->getBasicType() == EbtStruct)
2724 {
2725 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2726 }
2727 else
2728 {
2729 constructorName =
2730 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2731 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002732 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002733 }
2734 else if (visit == InVisit)
2735 {
2736 out << ", ";
2737 }
2738 else if (visit == PostVisit)
2739 {
2740 out << ")";
2741 }
2742}
2743
Jamie Madill8c46ab12015-12-07 16:39:19 -05002744const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2745 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002746 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002747{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002748 const TConstantUnion *constUnionIterated = constUnion;
2749
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002750 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002751 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002752 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002753 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002754
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002755 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002756
Jamie Madill98493dd2013-07-08 14:39:03 -04002757 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002758 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002759 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002760 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002761
Jamie Madill98493dd2013-07-08 14:39:03 -04002762 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002763 {
2764 out << ", ";
2765 }
2766 }
2767
2768 out << ")";
2769 }
2770 else
2771 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002772 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002773 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002774
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002775 if (writeType)
2776 {
Jamie Madill033dae62014-06-18 12:56:28 -04002777 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002778 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002779 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002780 if (writeType)
2781 {
2782 out << ")";
2783 }
2784 }
2785
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002786 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002787}
2788
Olli Etuahod68924e2017-01-02 17:34:40 +00002789void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002790{
Olli Etuahod68924e2017-01-02 17:34:40 +00002791 if (visit == PreVisit)
2792 {
2793 const char *opStr = GetOperatorString(op);
2794 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2795 out << "(";
2796 }
2797 else
2798 {
2799 outputTriplet(out, visit, nullptr, ", ", ")");
2800 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002801}
2802
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002803bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2804 TIntermSymbol *symbolNode,
2805 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002806{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002807 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
2808 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05002809
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002810 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002811 {
2812 // Type already printed
2813 out << "t" + str(mUniqueIndex) + " = ";
2814 expression->traverse(this);
2815 out << ", ";
2816 symbolNode->traverse(this);
2817 out << " = t" + str(mUniqueIndex);
2818
2819 mUniqueIndex++;
2820 return true;
2821 }
2822
2823 return false;
2824}
2825
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002826bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2827{
2828 // We support writing constant unions and constructors that only take constant unions as
2829 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002830 return !expression->getType().isArrayOfArrays() &&
2831 (expression->getAsConstantUnion() ||
2832 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002833}
2834
2835bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2836 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002837 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002838{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002839 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002840 {
2841 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002842 ASSERT(!symbolNode->getType().isArrayOfArrays());
2843 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002844 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002845 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002846 }
2847 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002848 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002849 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002850 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002851 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002852 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002853 }
2854 else
2855 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002856 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002857 ASSERT(constructor != nullptr);
2858 for (TIntermNode *&node : *constructor->getSequence())
2859 {
2860 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2861 ASSERT(nodeConst);
2862 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002863 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002864 if (node != constructor->getSequence()->back())
2865 {
2866 out << ", ";
2867 }
2868 }
2869 }
2870 out << "}";
2871 return true;
2872 }
2873 return false;
2874}
2875
Jamie Madill55e79e02015-02-09 15:35:00 -05002876TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2877{
2878 const TFieldList &fields = structure.fields();
2879
2880 for (const auto &eqFunction : mStructEqualityFunctions)
2881 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002882 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002883 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002885 }
2886 }
2887
2888 const TString &structNameString = StructNameString(structure);
2889
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002890 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002891 function->structure = &structure;
2892 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002893
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002894 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002895
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002896 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2897 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002898 << "{\n"
2899 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002900
2901 for (size_t i = 0; i < fields.size(); i++)
2902 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002903 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002904 const TType *fieldType = field->type();
2905
2906 const TString &fieldNameA = "a." + Decorate(field->name());
2907 const TString &fieldNameB = "b." + Decorate(field->name());
2908
2909 if (i > 0)
2910 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002911 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002912 }
2913
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002914 fnOut << "(";
2915 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2916 fnOut << fieldNameA;
2917 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2918 fnOut << fieldNameB;
2919 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2920 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002921 }
2922
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002923 fnOut << ";\n"
2924 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002925
2926 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002927
2928 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002929 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002930
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002931 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002932}
2933
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002934TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002935{
2936 for (const auto &eqFunction : mArrayEqualityFunctions)
2937 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002938 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002939 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002940 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002941 }
2942 }
2943
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002944 TType elementType(type);
2945 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002946
Olli Etuaho12690762015-03-31 12:55:28 +03002947 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002948 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002949
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002950 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002951
2952 TInfoSinkBase fnOut;
2953
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 const TString &typeName = TypeString(type);
2955 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2956 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002957 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002958 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002959 << type.getOutermostArraySize()
2960 << "; ++i)\n"
2961 " {\n"
2962 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002963
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002964 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002965 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002966 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002967 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002968 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002969
2970 fnOut << ") { return false; }\n"
2971 " }\n"
2972 " return true;\n"
2973 "}\n";
2974
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002975 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002976
2977 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002978 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002979
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002980 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002981}
2982
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002983TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002984{
2985 for (const auto &assignFunction : mArrayAssignmentFunctions)
2986 {
2987 if (assignFunction.type == type)
2988 {
2989 return assignFunction.functionName;
2990 }
2991 }
2992
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002993 TType elementType(type);
2994 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002995
2996 ArrayHelperFunction function;
2997 function.type = type;
2998
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002999 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003000
3001 TInfoSinkBase fnOut;
3002
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003003 const TString &typeName = TypeString(type);
3004 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3005 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003006 << "{\n"
3007 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003008 << type.getOutermostArraySize()
3009 << "; ++i)\n"
3010 " {\n"
3011 " ";
3012
3013 outputAssign(PreVisit, elementType, fnOut);
3014 fnOut << "a[i]";
3015 outputAssign(InVisit, elementType, fnOut);
3016 fnOut << "b[i]";
3017 outputAssign(PostVisit, elementType, fnOut);
3018
3019 fnOut << ";\n"
3020 " }\n"
3021 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003022
3023 function.functionDefinition = fnOut.c_str();
3024
3025 mArrayAssignmentFunctions.push_back(function);
3026
3027 return function.functionName;
3028}
3029
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003030TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003031{
3032 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3033 {
3034 if (constructIntoFunction.type == type)
3035 {
3036 return constructIntoFunction.functionName;
3037 }
3038 }
3039
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003040 TType elementType(type);
3041 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003042
3043 ArrayHelperFunction function;
3044 function.type = type;
3045
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003046 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003047
3048 TInfoSinkBase fnOut;
3049
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003050 const TString &typeName = TypeString(type);
3051 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3052 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003053 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003054 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003055 }
3056 fnOut << ")\n"
3057 "{\n";
3058
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003059 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003060 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003061 fnOut << " ";
3062 outputAssign(PreVisit, elementType, fnOut);
3063 fnOut << "a[" << i << "]";
3064 outputAssign(InVisit, elementType, fnOut);
3065 fnOut << "b" << i;
3066 outputAssign(PostVisit, elementType, fnOut);
3067 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003068 }
3069 fnOut << "}\n";
3070
3071 function.functionDefinition = fnOut.c_str();
3072
3073 mArrayConstructIntoFunctions.push_back(function);
3074
3075 return function.functionName;
3076}
3077
Jamie Madill2e295e22015-04-29 10:41:33 -04003078void OutputHLSL::ensureStructDefined(const TType &type)
3079{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003080 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003081 if (structure)
3082 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003083 ASSERT(type.getBasicType() == EbtStruct);
3084 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003085 }
3086}
3087
Jamie Madill45bcc782016-11-07 13:58:48 -05003088} // namespace sh