blob: 70bd12f3e5bc5f0dd98b49daf5f6bb9249820bde [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"
Xinghua Cao711b7a12017-10-09 13:38:12 +080018#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/InfoSink.h"
20#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020021#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/SearchSymbol.h"
23#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;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800194 mUniformHLSL = new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300195 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800196 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400197
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200198 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000199 {
Arun Patole63419392015-03-13 11:51:07 +0530200 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500201 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
202 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530203 // In both cases total 3 uniform registers need to be reserved.
204 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000205 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000206
Geoff Lang00140f42016-02-03 18:47:33 +0000207 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800208 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209}
210
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000211OutputHLSL::~OutputHLSL()
212{
Jamie Madill8daaba12014-06-13 10:04:33 -0400213 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400214 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300215 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800216 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200217 for (auto &eqFunction : mStructEqualityFunctions)
218 {
219 SafeDelete(eqFunction);
220 }
221 for (auto &eqFunction : mArrayEqualityFunctions)
222 {
223 SafeDelete(eqFunction);
224 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000225}
226
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200227void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000228{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200229 BuiltInFunctionEmulator builtInFunctionEmulator;
230 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800231 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
232 {
233 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
234 mShaderVersion);
235 }
236
Olli Etuahodfa75e82017-01-23 09:43:06 -0800237 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500238
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700239 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000240 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700241 ASSERT(success == CallDAG::INITDAG_SUCCESS);
242 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700243
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200244 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
245 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
246 // the shader code. When we add shader storage blocks we might also consider an alternative
247 // solution, since the struct mapping won't work very well for shader storage blocks.
248
Jamie Madill37997142015-01-28 10:06:34 -0500249 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500250 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200251 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500252 mInfoSinkStack.pop();
253
Jamie Madill37997142015-01-28 10:06:34 -0500254 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500255 mInfoSinkStack.pop();
256
Jamie Madill32aab012015-01-27 14:12:26 -0500257 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200258 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500259 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000260
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200261 objSink << mHeader.c_str();
262 objSink << mBody.c_str();
263 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200264
Olli Etuahodfa75e82017-01-23 09:43:06 -0800265 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000266}
267
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800268const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400269{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800270 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400271}
272
Jamie Madill9fe25e92014-07-18 10:33:08 -0400273const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
274{
275 return mUniformHLSL->getUniformRegisterMap();
276}
277
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200278TString OutputHLSL::structInitializerString(int indent,
279 const TType &type,
280 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400281{
282 TString init;
283
Olli Etuahoed049ab2017-06-30 17:38:33 +0300284 TString indentString;
285 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400286 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300287 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400288 }
289
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300292 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300293 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400294 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300295 TStringStream indexedString;
296 indexedString << name << "[" << arrayIndex << "]";
297 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300298 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300300 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300301 {
302 init += ",";
303 }
304 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400305 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300306 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400307 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300308 else if (type.getBasicType() == EbtStruct)
309 {
310 init += indentString + "{\n";
311 const TStructure &structure = *type.getStruct();
312 const TFieldList &fields = structure.fields();
313 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
314 {
315 const TField &field = *fields[fieldIndex];
316 const TString &fieldName = name + "." + Decorate(field.name());
317 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400318
Olli Etuahoed049ab2017-06-30 17:38:33 +0300319 init += structInitializerString(indent + 1, fieldType, fieldName);
320 if (fieldIndex < fields.size() - 1)
321 {
322 init += ",";
323 }
324 init += "\n";
325 }
326 init += indentString + "}";
327 }
328 else
329 {
330 init += indentString + name;
331 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400332
333 return init;
334}
335
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200336TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
337{
338 TString mappedStructs;
339
340 for (auto &mappedStruct : std140Structs)
341 {
342 TInterfaceBlock *interfaceBlock =
343 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
344 const TString &interfaceBlockName = interfaceBlock->name();
345 const TName &instanceName = mappedStruct.blockDeclarator->getName();
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200346 if (mReferencedUniformBlocks.count(interfaceBlockName) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200347 {
348 continue;
349 }
350
351 unsigned int instanceCount = 1u;
352 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
353 if (isInstanceArray)
354 {
355 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
356 }
357
358 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
359 ++instanceArrayIndex)
360 {
361 TString originalName;
362 TString mappedName("map");
363
364 if (instanceName.getString() != "")
365 {
366 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
367 if (isInstanceArray)
368 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200369 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
370 instanceName.getString(), instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200371 originalName += instanceString;
372 mappedName += instanceString;
373 originalName += ".";
374 mappedName += "_";
375 }
376
377 TString fieldName = Decorate(mappedStruct.field->name());
378 originalName += fieldName;
379 mappedName += fieldName;
380
381 TType *structType = mappedStruct.field->type();
382 mappedStructs +=
383 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
384
385 if (structType->isArray())
386 {
387 mappedStructs += ArrayString(*mappedStruct.field->type());
388 }
389
390 mappedStructs += " =\n";
391 mappedStructs += structInitializerString(0, *structType, originalName);
392 mappedStructs += ";\n";
393 }
394 }
395 return mappedStructs;
396}
397
398void OutputHLSL::header(TInfoSinkBase &out,
399 const std::vector<MappedStruct> &std140Structs,
400 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000402 TString varyings;
403 TString attributes;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200404 TString mappedStructs = generateStructMapping(std140Structs);
Jamie Madill570e04d2013-06-21 09:15:33 -0400405
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500406 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
407 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000408 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500409 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000410 const TString &name = varying->second->getSymbol();
411
412 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500413 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
414 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000415 }
416
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500417 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
418 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000419 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500420 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000421 const TString &name = attribute->second->getSymbol();
422
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500423 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
424 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000425 }
426
Jamie Madill8daaba12014-06-13 10:04:33 -0400427 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400428
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300429 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800430 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400431
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200432 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500433 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200434 out << "\n// Equality functions\n\n";
435 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500436 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200437 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200438 }
439 }
Olli Etuaho12690762015-03-31 12:55:28 +0300440 if (!mArrayAssignmentFunctions.empty())
441 {
442 out << "\n// Assignment functions\n\n";
443 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
444 {
445 out << assignmentFunction.functionDefinition << "\n";
446 }
447 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300448 if (!mArrayConstructIntoFunctions.empty())
449 {
450 out << "\n// Array constructor functions\n\n";
451 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
452 {
453 out << constructIntoFunction.functionDefinition << "\n";
454 }
455 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200456
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500457 if (mUsesDiscardRewriting)
458 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400459 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500460 }
461
Nicolas Capens655fe362014-04-11 13:12:34 -0400462 if (mUsesNestedBreak)
463 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400464 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400465 }
466
Arun Patole44efa0b2015-03-04 17:11:05 +0530467 if (mRequiresIEEEStrictCompiling)
468 {
469 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
470 }
471
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400472 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
473 "#define LOOP [loop]\n"
474 "#define FLATTEN [flatten]\n"
475 "#else\n"
476 "#define LOOP\n"
477 "#define FLATTEN\n"
478 "#endif\n";
479
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200480 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300482 const bool usingMRTExtension =
483 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000484
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000485 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500486 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400487 out << "\n";
488
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200489 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000490 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500491 for (ReferencedSymbols::const_iterator outputVariableIt =
492 mReferencedOutputVariables.begin();
493 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000494 {
Jamie Madill46131a32013-06-20 11:55:50 -0400495 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500496 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400497
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500498 out << "static " + TypeString(variableType) + " out_" + variableName +
499 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000500 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000501 }
Jamie Madill46131a32013-06-20 11:55:50 -0400502 else
503 {
504 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
505
506 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500507 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400508 for (unsigned int i = 0; i < numColorValues; i++)
509 {
510 out << " float4(0, 0, 0, 0)";
511 if (i + 1 != numColorValues)
512 {
513 out << ",";
514 }
515 out << "\n";
516 }
517
518 out << "};\n";
519 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000520
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400521 if (mUsesFragDepth)
522 {
523 out << "static float gl_Depth = 0.0;\n";
524 }
525
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000526 if (mUsesFragCoord)
527 {
528 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
529 }
530
531 if (mUsesPointCoord)
532 {
533 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
534 }
535
536 if (mUsesFrontFacing)
537 {
538 out << "static bool gl_FrontFacing = false;\n";
539 }
540
541 out << "\n";
542
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000543 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000544 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000545 out << "struct gl_DepthRangeParameters\n"
546 "{\n"
547 " float near;\n"
548 " float far;\n"
549 " float diff;\n"
550 "};\n"
551 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000552 }
553
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200554 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000555 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000556 out << "cbuffer DriverConstants : register(b1)\n"
557 "{\n";
558
559 if (mUsesDepthRange)
560 {
561 out << " float3 dx_DepthRange : packoffset(c0);\n";
562 }
563
564 if (mUsesFragCoord)
565 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000566 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000567 }
568
569 if (mUsesFragCoord || mUsesFrontFacing)
570 {
571 out << " float3 dx_DepthFront : packoffset(c2);\n";
572 }
573
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800574 if (mUsesFragCoord)
575 {
576 // dx_ViewScale is only used in the fragment shader to correct
577 // the value for glFragCoord if necessary
578 out << " float2 dx_ViewScale : packoffset(c3);\n";
579 }
580
Martin Radev72b4e1e2017-08-31 15:42:56 +0300581 if (mHasMultiviewExtensionEnabled)
582 {
583 // We have to add a value which we can use to keep track of which multi-view code
584 // path is to be selected in the GS.
585 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
586 }
587
Olli Etuaho618bebc2016-01-15 16:40:00 +0200588 if (mOutputType == SH_HLSL_4_1_OUTPUT)
589 {
590 mUniformHLSL->samplerMetadataUniforms(out, "c4");
591 }
592
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000593 out << "};\n";
594 }
595 else
596 {
597 if (mUsesDepthRange)
598 {
599 out << "uniform float3 dx_DepthRange : register(c0);";
600 }
601
602 if (mUsesFragCoord)
603 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000604 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000605 }
606
607 if (mUsesFragCoord || mUsesFrontFacing)
608 {
609 out << "uniform float3 dx_DepthFront : register(c2);\n";
610 }
611 }
612
613 out << "\n";
614
615 if (mUsesDepthRange)
616 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500617 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
618 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000619 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000620 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000621
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200622 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000623 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200624 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000625 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200626 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400627 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000628 }
629
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000630 if (usingMRTExtension && mNumRenderTargets > 1)
631 {
632 out << "#define GL_USES_MRT\n";
633 }
634
635 if (mUsesFragColor)
636 {
637 out << "#define GL_USES_FRAG_COLOR\n";
638 }
639
640 if (mUsesFragData)
641 {
642 out << "#define GL_USES_FRAG_DATA\n";
643 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644 }
Xinghua Caob1239382016-12-13 15:07:05 +0800645 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000647 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500648 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000649 out << "\n"
650 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400651
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000652 if (mUsesPointSize)
653 {
654 out << "static float gl_PointSize = float(1);\n";
655 }
656
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000657 if (mUsesInstanceID)
658 {
659 out << "static int gl_InstanceID;";
660 }
661
Corentin Wallezb076add2016-01-11 16:45:46 -0500662 if (mUsesVertexID)
663 {
664 out << "static int gl_VertexID;";
665 }
666
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000667 out << "\n"
668 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500669 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000670 out << "\n";
671
672 if (mUsesDepthRange)
673 {
674 out << "struct gl_DepthRangeParameters\n"
675 "{\n"
676 " float near;\n"
677 " float far;\n"
678 " float diff;\n"
679 "};\n"
680 "\n";
681 }
682
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200683 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000684 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800685 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500686 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800687
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000688 if (mUsesDepthRange)
689 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800690 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000691 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800692
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800693 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
694 // shaders. However, we declare it for all shaders (including Feature Level 10+).
695 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
696 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800697 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800698 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800699 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800700
Martin Radev72b4e1e2017-08-31 15:42:56 +0300701 if (mHasMultiviewExtensionEnabled)
702 {
703 // We have to add a value which we can use to keep track of which multi-view code
704 // path is to be selected in the GS.
705 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
706 }
707
Olli Etuaho618bebc2016-01-15 16:40:00 +0200708 if (mOutputType == SH_HLSL_4_1_OUTPUT)
709 {
710 mUniformHLSL->samplerMetadataUniforms(out, "c4");
711 }
712
Austin Kinross4fd18b12014-12-22 12:32:05 -0800713 out << "};\n"
714 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000715 }
716 else
717 {
718 if (mUsesDepthRange)
719 {
720 out << "uniform float3 dx_DepthRange : register(c0);\n";
721 }
722
Cooper Partine6664f02015-01-09 16:22:24 -0800723 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
724 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000725 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000726 }
727
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000728 if (mUsesDepthRange)
729 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500730 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
731 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000732 "\n";
733 }
734
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200735 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000736 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200737 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000738 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200739 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400740 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000741 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400742 }
Xinghua Caob1239382016-12-13 15:07:05 +0800743 else // Compute shader
744 {
745 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800746
747 out << "cbuffer DriverConstants : register(b1)\n"
748 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800749 if (mUsesNumWorkGroups)
750 {
Xinghua Caob1239382016-12-13 15:07:05 +0800751 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800752 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800753 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
754 mUniformHLSL->samplerMetadataUniforms(out, "c1");
755 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800756
757 // Follow built-in variables would be initialized in
758 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
759 // are used in compute shader.
760 if (mUsesWorkGroupID)
761 {
762 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
763 }
764
765 if (mUsesLocalInvocationID)
766 {
767 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
768 }
769
770 if (mUsesGlobalInvocationID)
771 {
772 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
773 }
774
775 if (mUsesLocalInvocationIndex)
776 {
777 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
778 }
779 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000780
Geoff Lang1fe74c72016-08-25 13:23:01 -0400781 bool getDimensionsIgnoresBaseLevel =
782 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
783 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800784 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000786 if (mUsesFragCoord)
787 {
788 out << "#define GL_USES_FRAG_COORD\n";
789 }
790
791 if (mUsesPointCoord)
792 {
793 out << "#define GL_USES_POINT_COORD\n";
794 }
795
796 if (mUsesFrontFacing)
797 {
798 out << "#define GL_USES_FRONT_FACING\n";
799 }
800
801 if (mUsesPointSize)
802 {
803 out << "#define GL_USES_POINT_SIZE\n";
804 }
805
Martin Radev41ac68e2017-06-06 12:16:58 +0300806 if (mHasMultiviewExtensionEnabled)
807 {
808 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
809 }
810
811 if (mUsesViewID)
812 {
813 out << "#define GL_USES_VIEW_ID\n";
814 }
815
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400816 if (mUsesFragDepth)
817 {
818 out << "#define GL_USES_FRAG_DEPTH\n";
819 }
820
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000821 if (mUsesDepthRange)
822 {
823 out << "#define GL_USES_DEPTH_RANGE\n";
824 }
825
Xinghua Caob1239382016-12-13 15:07:05 +0800826 if (mUsesNumWorkGroups)
827 {
828 out << "#define GL_USES_NUM_WORK_GROUPS\n";
829 }
830
831 if (mUsesWorkGroupID)
832 {
833 out << "#define GL_USES_WORK_GROUP_ID\n";
834 }
835
836 if (mUsesLocalInvocationID)
837 {
838 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
839 }
840
841 if (mUsesGlobalInvocationID)
842 {
843 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
844 }
845
846 if (mUsesLocalInvocationIndex)
847 {
848 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
849 }
850
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000851 if (mUsesXor)
852 {
853 out << "bool xor(bool p, bool q)\n"
854 "{\n"
855 " return (p || q) && !(p && q);\n"
856 "}\n"
857 "\n";
858 }
859
Olli Etuahodfa75e82017-01-23 09:43:06 -0800860 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000861}
862
863void OutputHLSL::visitSymbol(TIntermSymbol *node)
864{
Jamie Madill32aab012015-01-27 14:12:26 -0500865 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000866
Jamie Madill570e04d2013-06-21 09:15:33 -0400867 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200868 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400869 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200870 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400871 }
872
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000873 TString name = node->getSymbol();
874
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000875 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000876 {
877 mUsesDepthRange = true;
878 out << name;
879 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880 else
881 {
Olli Etuahobd3cd502017-11-03 15:48:52 +0200882 const TType &nodeType = node->getType();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000883 TQualifier qualifier = node->getQualifier();
884
Olli Etuahobd3cd502017-11-03 15:48:52 +0200885 ensureStructDefined(nodeType);
886
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000887 if (qualifier == EvqUniform)
888 {
Jamie Madill2e295e22015-04-29 10:41:33 -0400889 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400890
891 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000892 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800893 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000894 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000895 else
896 {
897 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000898 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400899
Olli Etuahoff526f12017-06-30 12:26:54 +0300900 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000901 }
Jamie Madill19571812013-08-12 15:26:34 -0700902 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000903 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000904 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400905 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000906 }
Jamie Madill033dae62014-06-18 12:56:28 -0400907 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000908 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000909 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400910 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300911 if (name == "ViewID_OVR")
912 {
913 mUsesViewID = true;
914 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000915 }
Jamie Madill19571812013-08-12 15:26:34 -0700916 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400917 {
918 mReferencedOutputVariables[name] = node;
919 out << "out_" << name;
920 }
921 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000922 {
923 out << "gl_Color[0]";
924 mUsesFragColor = true;
925 }
926 else if (qualifier == EvqFragData)
927 {
928 out << "gl_Color";
929 mUsesFragData = true;
930 }
931 else if (qualifier == EvqFragCoord)
932 {
933 mUsesFragCoord = true;
934 out << name;
935 }
936 else if (qualifier == EvqPointCoord)
937 {
938 mUsesPointCoord = true;
939 out << name;
940 }
941 else if (qualifier == EvqFrontFacing)
942 {
943 mUsesFrontFacing = true;
944 out << name;
945 }
946 else if (qualifier == EvqPointSize)
947 {
948 mUsesPointSize = true;
949 out << name;
950 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000951 else if (qualifier == EvqInstanceID)
952 {
953 mUsesInstanceID = true;
954 out << name;
955 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500956 else if (qualifier == EvqVertexID)
957 {
958 mUsesVertexID = true;
959 out << name;
960 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300961 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400962 {
963 mUsesFragDepth = true;
964 out << "gl_Depth";
965 }
Xinghua Caob1239382016-12-13 15:07:05 +0800966 else if (qualifier == EvqNumWorkGroups)
967 {
968 mUsesNumWorkGroups = true;
969 out << name;
970 }
971 else if (qualifier == EvqWorkGroupID)
972 {
973 mUsesWorkGroupID = true;
974 out << name;
975 }
976 else if (qualifier == EvqLocalInvocationID)
977 {
978 mUsesLocalInvocationID = true;
979 out << name;
980 }
981 else if (qualifier == EvqGlobalInvocationID)
982 {
983 mUsesGlobalInvocationID = true;
984 out << name;
985 }
986 else if (qualifier == EvqLocalInvocationIndex)
987 {
988 mUsesLocalInvocationIndex = true;
989 out << name;
990 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000991 else
992 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300993 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000994 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000995 }
996}
997
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400998void OutputHLSL::visitRaw(TIntermRaw *node)
999{
Jamie Madill32aab012015-01-27 14:12:26 -05001000 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001001}
1002
Olli Etuaho7fb49552015-03-18 17:27:44 +02001003void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1004{
1005 if (type.isScalar() && !type.isArray())
1006 {
1007 if (op == EOpEqual)
1008 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001009 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001010 }
1011 else
1012 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001013 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001014 }
1015 }
1016 else
1017 {
1018 if (visit == PreVisit && op == EOpNotEqual)
1019 {
1020 out << "!";
1021 }
1022
1023 if (type.isArray())
1024 {
1025 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001026 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001027 }
1028 else if (type.getBasicType() == EbtStruct)
1029 {
1030 const TStructure &structure = *type.getStruct();
1031 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001032 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001033 }
1034 else
1035 {
1036 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001037 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001038 }
1039 }
1040}
1041
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001042void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1043{
1044 if (type.isArray())
1045 {
1046 const TString &functionName = addArrayAssignmentFunction(type);
1047 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1048 }
1049 else
1050 {
1051 outputTriplet(out, visit, "(", " = ", ")");
1052 }
1053}
1054
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001055bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001056{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001057 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001058 {
1059 TIntermNode *ancestor = getAncestorNode(n);
1060 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1061 if (ancestorBinary == nullptr)
1062 {
1063 return false;
1064 }
1065 switch (ancestorBinary->getOp())
1066 {
1067 case EOpIndexDirectStruct:
1068 {
1069 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1070 const TIntermConstantUnion *index =
1071 ancestorBinary->getRight()->getAsConstantUnion();
1072 const TField *field = structure->fields()[index->getIConst(0)];
1073 if (IsSampler(field->type()->getBasicType()))
1074 {
1075 return true;
1076 }
1077 break;
1078 }
1079 case EOpIndexDirect:
1080 break;
1081 default:
1082 // Returning a sampler from indirect indexing is not supported.
1083 return false;
1084 }
1085 }
1086 return false;
1087}
1088
Olli Etuahob6fa0432016-09-28 16:28:05 +01001089bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1090{
1091 TInfoSinkBase &out = getInfoSink();
1092 if (visit == PostVisit)
1093 {
1094 out << ".";
1095 node->writeOffsetsAsXYZW(&out);
1096 }
1097 return true;
1098}
1099
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001100bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1101{
Jamie Madill32aab012015-01-27 14:12:26 -05001102 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001103
1104 switch (node->getOp())
1105 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001106 case EOpComma:
1107 outputTriplet(out, visit, "(", ", ", ")");
1108 break;
1109 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001110 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001111 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001112 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1113 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001114 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001115 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1116 out << functionName << "(";
1117 node->getLeft()->traverse(this);
1118 TIntermSequence *seq = rightAgg->getSequence();
1119 for (auto &arrayElement : *seq)
1120 {
1121 out << ", ";
1122 arrayElement->traverse(this);
1123 }
1124 out << ")";
1125 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001126 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001127 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1128 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001129 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001130 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001131 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001132 break;
1133 case EOpInitialize:
1134 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001135 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001136 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1137 ASSERT(symbolNode);
1138 TIntermTyped *expression = node->getRight();
1139
1140 // Global initializers must be constant at this point.
1141 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1142 canWriteAsHLSLLiteral(expression));
1143
1144 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1145 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1146 // new variable is created before the assignment is evaluated), so we need to
1147 // convert
1148 // this to "float t = x, x = t;".
1149 if (writeSameSymbolInitializer(out, symbolNode, expression))
1150 {
1151 // Skip initializing the rest of the expression
1152 return false;
1153 }
1154 else if (writeConstantInitialization(out, symbolNode, expression))
1155 {
1156 return false;
1157 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001158 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001159 else if (visit == InVisit)
1160 {
1161 out << " = ";
1162 }
1163 break;
1164 case EOpAddAssign:
1165 outputTriplet(out, visit, "(", " += ", ")");
1166 break;
1167 case EOpSubAssign:
1168 outputTriplet(out, visit, "(", " -= ", ")");
1169 break;
1170 case EOpMulAssign:
1171 outputTriplet(out, visit, "(", " *= ", ")");
1172 break;
1173 case EOpVectorTimesScalarAssign:
1174 outputTriplet(out, visit, "(", " *= ", ")");
1175 break;
1176 case EOpMatrixTimesScalarAssign:
1177 outputTriplet(out, visit, "(", " *= ", ")");
1178 break;
1179 case EOpVectorTimesMatrixAssign:
1180 if (visit == PreVisit)
1181 {
1182 out << "(";
1183 }
1184 else if (visit == InVisit)
1185 {
1186 out << " = mul(";
1187 node->getLeft()->traverse(this);
1188 out << ", transpose(";
1189 }
1190 else
1191 {
1192 out << ")))";
1193 }
1194 break;
1195 case EOpMatrixTimesMatrixAssign:
1196 if (visit == PreVisit)
1197 {
1198 out << "(";
1199 }
1200 else if (visit == InVisit)
1201 {
1202 out << " = transpose(mul(transpose(";
1203 node->getLeft()->traverse(this);
1204 out << "), transpose(";
1205 }
1206 else
1207 {
1208 out << "))))";
1209 }
1210 break;
1211 case EOpDivAssign:
1212 outputTriplet(out, visit, "(", " /= ", ")");
1213 break;
1214 case EOpIModAssign:
1215 outputTriplet(out, visit, "(", " %= ", ")");
1216 break;
1217 case EOpBitShiftLeftAssign:
1218 outputTriplet(out, visit, "(", " <<= ", ")");
1219 break;
1220 case EOpBitShiftRightAssign:
1221 outputTriplet(out, visit, "(", " >>= ", ")");
1222 break;
1223 case EOpBitwiseAndAssign:
1224 outputTriplet(out, visit, "(", " &= ", ")");
1225 break;
1226 case EOpBitwiseXorAssign:
1227 outputTriplet(out, visit, "(", " ^= ", ")");
1228 break;
1229 case EOpBitwiseOrAssign:
1230 outputTriplet(out, visit, "(", " |= ", ")");
1231 break;
1232 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001233 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001234 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001235 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001236 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001237 if (visit == PreVisit)
1238 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001239 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuaho12a18ad2017-12-01 16:59:47 +02001240 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
1241 mReferencedUniformBlocks[interfaceBlock->name()] = instanceArraySymbol;
Jamie Madill98493dd2013-07-08 14:39:03 -04001242 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho12a18ad2017-12-01 16:59:47 +02001243 out << mUniformHLSL->UniformBlockInstanceString(
1244 instanceArraySymbol->getSymbol(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001245 return false;
1246 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001247 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001248 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001249 {
1250 // All parts of an expression that access a sampler in a struct need to use _ as
1251 // separator to access the sampler variable that has been moved out of the struct.
1252 outputTriplet(out, visit, "", "_", "");
1253 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001254 else
1255 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001256 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001257 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001258 }
1259 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001260 case EOpIndexIndirect:
1261 // We do not currently support indirect references to interface blocks
1262 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1263 outputTriplet(out, visit, "", "[", "]");
1264 break;
1265 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001266 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001267 const TStructure *structure = node->getLeft()->getType().getStruct();
1268 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1269 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001270
Olli Etuaho96963162016-03-21 11:54:33 +02001271 // In cases where indexing returns a sampler, we need to access the sampler variable
1272 // that has been moved out of the struct.
1273 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1274 if (visit == PreVisit && indexingReturnsSampler)
1275 {
1276 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1277 // This prefix is only output at the beginning of the indexing expression, which
1278 // may have multiple parts.
1279 out << "angle";
1280 }
1281 if (!indexingReturnsSampler)
1282 {
1283 // All parts of an expression that access a sampler in a struct need to use _ as
1284 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001285 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001286 }
1287 if (visit == InVisit)
1288 {
1289 if (indexingReturnsSampler)
1290 {
1291 out << "_" + field->name();
1292 }
1293 else
1294 {
1295 out << "." + DecorateField(field->name(), *structure);
1296 }
1297
1298 return false;
1299 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001300 }
1301 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001302 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001303 {
1304 bool structInStd140Block =
1305 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1306 if (visit == PreVisit && structInStd140Block)
1307 {
1308 out << "map";
1309 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001310 if (visit == InVisit)
1311 {
1312 const TInterfaceBlock *interfaceBlock =
1313 node->getLeft()->getType().getInterfaceBlock();
1314 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1315 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001316 if (structInStd140Block)
1317 {
1318 out << "_";
1319 }
1320 else
1321 {
1322 out << ".";
1323 }
1324 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001325
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001326 return false;
1327 }
1328 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001329 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001330 case EOpAdd:
1331 outputTriplet(out, visit, "(", " + ", ")");
1332 break;
1333 case EOpSub:
1334 outputTriplet(out, visit, "(", " - ", ")");
1335 break;
1336 case EOpMul:
1337 outputTriplet(out, visit, "(", " * ", ")");
1338 break;
1339 case EOpDiv:
1340 outputTriplet(out, visit, "(", " / ", ")");
1341 break;
1342 case EOpIMod:
1343 outputTriplet(out, visit, "(", " % ", ")");
1344 break;
1345 case EOpBitShiftLeft:
1346 outputTriplet(out, visit, "(", " << ", ")");
1347 break;
1348 case EOpBitShiftRight:
1349 outputTriplet(out, visit, "(", " >> ", ")");
1350 break;
1351 case EOpBitwiseAnd:
1352 outputTriplet(out, visit, "(", " & ", ")");
1353 break;
1354 case EOpBitwiseXor:
1355 outputTriplet(out, visit, "(", " ^ ", ")");
1356 break;
1357 case EOpBitwiseOr:
1358 outputTriplet(out, visit, "(", " | ", ")");
1359 break;
1360 case EOpEqual:
1361 case EOpNotEqual:
1362 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1363 break;
1364 case EOpLessThan:
1365 outputTriplet(out, visit, "(", " < ", ")");
1366 break;
1367 case EOpGreaterThan:
1368 outputTriplet(out, visit, "(", " > ", ")");
1369 break;
1370 case EOpLessThanEqual:
1371 outputTriplet(out, visit, "(", " <= ", ")");
1372 break;
1373 case EOpGreaterThanEqual:
1374 outputTriplet(out, visit, "(", " >= ", ")");
1375 break;
1376 case EOpVectorTimesScalar:
1377 outputTriplet(out, visit, "(", " * ", ")");
1378 break;
1379 case EOpMatrixTimesScalar:
1380 outputTriplet(out, visit, "(", " * ", ")");
1381 break;
1382 case EOpVectorTimesMatrix:
1383 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1384 break;
1385 case EOpMatrixTimesVector:
1386 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1387 break;
1388 case EOpMatrixTimesMatrix:
1389 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1390 break;
1391 case EOpLogicalOr:
1392 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1393 // been unfolded.
1394 ASSERT(!node->getRight()->hasSideEffects());
1395 outputTriplet(out, visit, "(", " || ", ")");
1396 return true;
1397 case EOpLogicalXor:
1398 mUsesXor = true;
1399 outputTriplet(out, visit, "xor(", ", ", ")");
1400 break;
1401 case EOpLogicalAnd:
1402 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1403 // been unfolded.
1404 ASSERT(!node->getRight()->hasSideEffects());
1405 outputTriplet(out, visit, "(", " && ", ")");
1406 return true;
1407 default:
1408 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001409 }
1410
1411 return true;
1412}
1413
1414bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1415{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001416 TInfoSinkBase &out = getInfoSink();
1417
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001418 switch (node->getOp())
1419 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001420 case EOpNegative:
1421 outputTriplet(out, visit, "(-", "", ")");
1422 break;
1423 case EOpPositive:
1424 outputTriplet(out, visit, "(+", "", ")");
1425 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001426 case EOpLogicalNot:
1427 outputTriplet(out, visit, "(!", "", ")");
1428 break;
1429 case EOpBitwiseNot:
1430 outputTriplet(out, visit, "(~", "", ")");
1431 break;
1432 case EOpPostIncrement:
1433 outputTriplet(out, visit, "(", "", "++)");
1434 break;
1435 case EOpPostDecrement:
1436 outputTriplet(out, visit, "(", "", "--)");
1437 break;
1438 case EOpPreIncrement:
1439 outputTriplet(out, visit, "(++", "", ")");
1440 break;
1441 case EOpPreDecrement:
1442 outputTriplet(out, visit, "(--", "", ")");
1443 break;
1444 case EOpRadians:
1445 outputTriplet(out, visit, "radians(", "", ")");
1446 break;
1447 case EOpDegrees:
1448 outputTriplet(out, visit, "degrees(", "", ")");
1449 break;
1450 case EOpSin:
1451 outputTriplet(out, visit, "sin(", "", ")");
1452 break;
1453 case EOpCos:
1454 outputTriplet(out, visit, "cos(", "", ")");
1455 break;
1456 case EOpTan:
1457 outputTriplet(out, visit, "tan(", "", ")");
1458 break;
1459 case EOpAsin:
1460 outputTriplet(out, visit, "asin(", "", ")");
1461 break;
1462 case EOpAcos:
1463 outputTriplet(out, visit, "acos(", "", ")");
1464 break;
1465 case EOpAtan:
1466 outputTriplet(out, visit, "atan(", "", ")");
1467 break;
1468 case EOpSinh:
1469 outputTriplet(out, visit, "sinh(", "", ")");
1470 break;
1471 case EOpCosh:
1472 outputTriplet(out, visit, "cosh(", "", ")");
1473 break;
1474 case EOpTanh:
1475 outputTriplet(out, visit, "tanh(", "", ")");
1476 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001477 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001478 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 case EOpAtanh:
1480 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001481 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 break;
1483 case EOpExp:
1484 outputTriplet(out, visit, "exp(", "", ")");
1485 break;
1486 case EOpLog:
1487 outputTriplet(out, visit, "log(", "", ")");
1488 break;
1489 case EOpExp2:
1490 outputTriplet(out, visit, "exp2(", "", ")");
1491 break;
1492 case EOpLog2:
1493 outputTriplet(out, visit, "log2(", "", ")");
1494 break;
1495 case EOpSqrt:
1496 outputTriplet(out, visit, "sqrt(", "", ")");
1497 break;
1498 case EOpInverseSqrt:
1499 outputTriplet(out, visit, "rsqrt(", "", ")");
1500 break;
1501 case EOpAbs:
1502 outputTriplet(out, visit, "abs(", "", ")");
1503 break;
1504 case EOpSign:
1505 outputTriplet(out, visit, "sign(", "", ")");
1506 break;
1507 case EOpFloor:
1508 outputTriplet(out, visit, "floor(", "", ")");
1509 break;
1510 case EOpTrunc:
1511 outputTriplet(out, visit, "trunc(", "", ")");
1512 break;
1513 case EOpRound:
1514 outputTriplet(out, visit, "round(", "", ")");
1515 break;
1516 case EOpRoundEven:
1517 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001518 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 break;
1520 case EOpCeil:
1521 outputTriplet(out, visit, "ceil(", "", ")");
1522 break;
1523 case EOpFract:
1524 outputTriplet(out, visit, "frac(", "", ")");
1525 break;
1526 case EOpIsNan:
1527 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001528 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001529 else
1530 outputTriplet(out, visit, "isnan(", "", ")");
1531 mRequiresIEEEStrictCompiling = true;
1532 break;
1533 case EOpIsInf:
1534 outputTriplet(out, visit, "isinf(", "", ")");
1535 break;
1536 case EOpFloatBitsToInt:
1537 outputTriplet(out, visit, "asint(", "", ")");
1538 break;
1539 case EOpFloatBitsToUint:
1540 outputTriplet(out, visit, "asuint(", "", ")");
1541 break;
1542 case EOpIntBitsToFloat:
1543 outputTriplet(out, visit, "asfloat(", "", ")");
1544 break;
1545 case EOpUintBitsToFloat:
1546 outputTriplet(out, visit, "asfloat(", "", ")");
1547 break;
1548 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001550 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001551 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001553 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001554 case EOpPackUnorm4x8:
1555 case EOpPackSnorm4x8:
1556 case EOpUnpackUnorm4x8:
1557 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001558 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001559 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001560 break;
1561 case EOpLength:
1562 outputTriplet(out, visit, "length(", "", ")");
1563 break;
1564 case EOpNormalize:
1565 outputTriplet(out, visit, "normalize(", "", ")");
1566 break;
1567 case EOpDFdx:
1568 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1569 {
1570 outputTriplet(out, visit, "(", "", ", 0.0)");
1571 }
1572 else
1573 {
1574 outputTriplet(out, visit, "ddx(", "", ")");
1575 }
1576 break;
1577 case EOpDFdy:
1578 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1579 {
1580 outputTriplet(out, visit, "(", "", ", 0.0)");
1581 }
1582 else
1583 {
1584 outputTriplet(out, visit, "ddy(", "", ")");
1585 }
1586 break;
1587 case EOpFwidth:
1588 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1589 {
1590 outputTriplet(out, visit, "(", "", ", 0.0)");
1591 }
1592 else
1593 {
1594 outputTriplet(out, visit, "fwidth(", "", ")");
1595 }
1596 break;
1597 case EOpTranspose:
1598 outputTriplet(out, visit, "transpose(", "", ")");
1599 break;
1600 case EOpDeterminant:
1601 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1602 break;
1603 case EOpInverse:
1604 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001605 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001606 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001607
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001608 case EOpAny:
1609 outputTriplet(out, visit, "any(", "", ")");
1610 break;
1611 case EOpAll:
1612 outputTriplet(out, visit, "all(", "", ")");
1613 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001614 case EOpLogicalNotComponentWise:
1615 outputTriplet(out, visit, "(!", "", ")");
1616 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001617 case EOpBitfieldReverse:
1618 outputTriplet(out, visit, "reversebits(", "", ")");
1619 break;
1620 case EOpBitCount:
1621 outputTriplet(out, visit, "countbits(", "", ")");
1622 break;
1623 case EOpFindLSB:
1624 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1625 // in GLSLTest and results are consistent with GL.
1626 outputTriplet(out, visit, "firstbitlow(", "", ")");
1627 break;
1628 case EOpFindMSB:
1629 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1630 // tested in GLSLTest and results are consistent with GL.
1631 outputTriplet(out, visit, "firstbithigh(", "", ")");
1632 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001633 default:
1634 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 }
1636
1637 return true;
1638}
1639
Olli Etuaho96963162016-03-21 11:54:33 +02001640TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1641{
1642 if (node->getAsSymbolNode())
1643 {
1644 return node->getAsSymbolNode()->getSymbol();
1645 }
1646 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1647 switch (nodeBinary->getOp())
1648 {
1649 case EOpIndexDirect:
1650 {
1651 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1652
1653 TInfoSinkBase prefixSink;
1654 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1655 return TString(prefixSink.c_str());
1656 }
1657 case EOpIndexDirectStruct:
1658 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001659 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001660 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1661 const TField *field = s->fields()[index];
1662
1663 TInfoSinkBase prefixSink;
1664 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1665 << field->name();
1666 return TString(prefixSink.c_str());
1667 }
1668 default:
1669 UNREACHABLE();
1670 return TString("");
1671 }
1672}
1673
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001674bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1675{
1676 TInfoSinkBase &out = getInfoSink();
1677
1678 if (mInsideFunction)
1679 {
1680 outputLineDirective(out, node->getLine().first_line);
1681 out << "{\n";
1682 }
1683
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001684 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001685 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001686 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001687
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001688 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001689
1690 // Don't output ; after case labels, they're terminated by :
1691 // This is needed especially since outputting a ; after a case statement would turn empty
1692 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001693 // Also the output code is clearer if we don't output ; after statements where it is not
1694 // needed:
1695 // * if statements
1696 // * switch statements
1697 // * blocks
1698 // * function definitions
1699 // * loops (do-while loops output the semicolon in VisitLoop)
1700 // * declarations that don't generate output.
1701 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1702 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1703 statement->getAsSwitchNode() == nullptr &&
1704 statement->getAsFunctionDefinition() == nullptr &&
1705 (statement->getAsDeclarationNode() == nullptr ||
1706 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1707 statement->getAsInvariantDeclarationNode() == nullptr)
1708 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001709 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001710 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001711 }
1712
1713 if (mInsideFunction)
1714 {
1715 outputLineDirective(out, node->getLine().last_line);
1716 out << "}\n";
1717 }
1718
1719 return false;
1720}
1721
Olli Etuaho336b1472016-10-05 16:37:55 +01001722bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1723{
1724 TInfoSinkBase &out = getInfoSink();
1725
1726 ASSERT(mCurrentFunctionMetadata == nullptr);
1727
1728 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1729 ASSERT(index != CallDAG::InvalidIndex);
1730 mCurrentFunctionMetadata = &mASTMetadataList[index];
1731
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001732 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001733
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001734 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001735
1736 if (node->getFunctionSymbolInfo()->isMain())
1737 {
1738 out << "gl_main(";
1739 }
1740 else
1741 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001742 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001743 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1744 }
1745
1746 for (unsigned int i = 0; i < parameters->size(); i++)
1747 {
1748 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1749
1750 if (symbol)
1751 {
1752 ensureStructDefined(symbol->getType());
1753
1754 out << argumentString(symbol);
1755
1756 if (i < parameters->size() - 1)
1757 {
1758 out << ", ";
1759 }
1760 }
1761 else
1762 UNREACHABLE();
1763 }
1764
1765 out << ")\n";
1766
1767 mInsideFunction = true;
1768 // The function body node will output braces.
1769 node->getBody()->traverse(this);
1770 mInsideFunction = false;
1771
1772 mCurrentFunctionMetadata = nullptr;
1773
1774 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1775 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1776 {
1777 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1778 mOutputLod0Function = true;
1779 node->traverse(this);
1780 mOutputLod0Function = false;
1781 }
1782
1783 return false;
1784}
1785
Olli Etuaho13389b62016-10-16 11:48:18 +01001786bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1787{
Olli Etuaho13389b62016-10-16 11:48:18 +01001788 if (visit == PreVisit)
1789 {
1790 TIntermSequence *sequence = node->getSequence();
1791 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1792 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001793 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001794
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001795 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001796 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001797 TInfoSinkBase &out = getInfoSink();
Olli Etuaho13389b62016-10-16 11:48:18 +01001798 ensureStructDefined(variable->getType());
1799
1800 if (!variable->getAsSymbolNode() ||
1801 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1802 {
1803 if (!mInsideFunction)
1804 {
1805 out << "static ";
1806 }
1807
1808 out << TypeString(variable->getType()) + " ";
1809
1810 TIntermSymbol *symbol = variable->getAsSymbolNode();
1811
1812 if (symbol)
1813 {
1814 symbol->traverse(this);
1815 out << ArrayString(symbol->getType());
1816 out << " = " + initializer(symbol->getType());
1817 }
1818 else
1819 {
1820 variable->traverse(this);
1821 }
1822 }
1823 else if (variable->getAsSymbolNode() &&
1824 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1825 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001826 ASSERT(variable->getBasicType() == EbtStruct);
1827 // ensureStructDefined has already been called.
Olli Etuaho13389b62016-10-16 11:48:18 +01001828 }
1829 else
1830 UNREACHABLE();
1831 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001832 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001833 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001834 TIntermSymbol *symbol = variable->getAsSymbolNode();
1835 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001836
Olli Etuaho282847e2017-07-12 14:11:01 +03001837 // Vertex outputs which are declared but not written to should still be declared to
1838 // allow successful linking.
1839 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001840 }
1841 }
1842 return false;
1843}
1844
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001845bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1846{
1847 // Do not do any translation
1848 return false;
1849}
1850
Olli Etuaho16c745a2017-01-16 17:02:27 +00001851bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1852{
1853 TInfoSinkBase &out = getInfoSink();
1854
1855 ASSERT(visit == PreVisit);
1856 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1857 // Skip the prototype if it is not implemented (and thus not used)
1858 if (index == CallDAG::InvalidIndex)
1859 {
1860 return false;
1861 }
1862
1863 TIntermSequence *arguments = node->getSequence();
1864
Olli Etuahoff526f12017-06-30 12:26:54 +03001865 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001866 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1867 << (mOutputLod0Function ? "Lod0(" : "(");
1868
1869 for (unsigned int i = 0; i < arguments->size(); i++)
1870 {
1871 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1872 ASSERT(symbol != nullptr);
1873
1874 out << argumentString(symbol);
1875
1876 if (i < arguments->size() - 1)
1877 {
1878 out << ", ";
1879 }
1880 }
1881
1882 out << ");\n";
1883
1884 // Also prototype the Lod0 variant if needed
1885 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1886 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1887 {
1888 mOutputLod0Function = true;
1889 node->traverse(this);
1890 mOutputLod0Function = false;
1891 }
1892
1893 return false;
1894}
1895
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001896bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1897{
Jamie Madill32aab012015-01-27 14:12:26 -05001898 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001899
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001900 switch (node->getOp())
1901 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001902 case EOpCallBuiltInFunction:
1903 case EOpCallFunctionInAST:
1904 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001905 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001906 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001907
Corentin Wallez1239ee92015-03-19 14:38:02 -07001908 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001909 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001910 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001911 if (node->isArray())
1912 {
1913 UNIMPLEMENTED();
1914 }
Olli Etuahobd674552016-10-06 13:28:42 +01001915 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001916 ASSERT(index != CallDAG::InvalidIndex);
1917 lod0 &= mASTMetadataList[index].mNeedsLod0;
1918
Olli Etuahoff526f12017-06-30 12:26:54 +03001919 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001920 out << DisambiguateFunctionName(node->getSequence());
1921 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001922 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001923 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001924 {
1925 // This path is used for internal functions that don't have their definitions in the
1926 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001927 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001928 }
Xinghua Cao711b7a12017-10-09 13:38:12 +08001929 else if (node->getFunctionSymbolInfo()->isImageFunction())
1930 {
1931 TString name = node->getFunctionSymbolInfo()->getName();
1932 TType type = (*arguments)[0]->getAsTyped()->getType();
1933 TString imageFunctionName = mImageFunctionHLSL->useImageFunction(
1934 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
1935 type.getMemoryQualifier().readonly);
1936 out << imageFunctionName << "(";
1937 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001938 else
1939 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001940 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001941 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001942 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1943 if (arguments->size() > 1)
1944 {
1945 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1946 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001947 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1948 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1949 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001950 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001951
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001952 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001953 {
Olli Etuaho96963162016-03-21 11:54:33 +02001954 TIntermTyped *typedArg = (*arg)->getAsTyped();
1955 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001956 {
1957 out << "texture_";
1958 (*arg)->traverse(this);
1959 out << ", sampler_";
1960 }
1961
1962 (*arg)->traverse(this);
1963
Olli Etuaho96963162016-03-21 11:54:33 +02001964 if (typedArg->getType().isStructureContainingSamplers())
1965 {
1966 const TType &argType = typedArg->getType();
1967 TVector<TIntermSymbol *> samplerSymbols;
1968 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001969 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1970 nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02001971 for (const TIntermSymbol *sampler : samplerSymbols)
1972 {
1973 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1974 {
1975 out << ", texture_" << sampler->getSymbol();
1976 out << ", sampler_" << sampler->getSymbol();
1977 }
1978 else
1979 {
1980 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1981 // of D3D9, it's the sampler variable.
1982 out << ", " + sampler->getSymbol();
1983 }
1984 }
1985 }
1986
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001987 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001988 {
1989 out << ", ";
1990 }
1991 }
1992
1993 out << ")";
1994
1995 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001996 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001997 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02001998 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03001999 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002000 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002001 outputTriplet(out, visit, "(", " == ", ")");
2002 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002003 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002004 outputTriplet(out, visit, "(", " != ", ")");
2005 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002006 case EOpLessThanComponentWise:
2007 outputTriplet(out, visit, "(", " < ", ")");
2008 break;
2009 case EOpGreaterThanComponentWise:
2010 outputTriplet(out, visit, "(", " > ", ")");
2011 break;
2012 case EOpLessThanEqualComponentWise:
2013 outputTriplet(out, visit, "(", " <= ", ")");
2014 break;
2015 case EOpGreaterThanEqualComponentWise:
2016 outputTriplet(out, visit, "(", " >= ", ")");
2017 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002018 case EOpMod:
2019 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002020 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002021 break;
2022 case EOpModf:
2023 outputTriplet(out, visit, "modf(", ", ", ")");
2024 break;
2025 case EOpPow:
2026 outputTriplet(out, visit, "pow(", ", ", ")");
2027 break;
2028 case EOpAtan:
2029 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2030 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002031 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002032 break;
2033 case EOpMin:
2034 outputTriplet(out, visit, "min(", ", ", ")");
2035 break;
2036 case EOpMax:
2037 outputTriplet(out, visit, "max(", ", ", ")");
2038 break;
2039 case EOpClamp:
2040 outputTriplet(out, visit, "clamp(", ", ", ")");
2041 break;
2042 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302043 {
2044 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2045 if (lastParamNode->getType().getBasicType() == EbtBool)
2046 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002047 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2048 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302049 // so use emulated version.
2050 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002051 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302052 }
2053 else
2054 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002055 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302056 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002057 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302058 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002059 case EOpStep:
2060 outputTriplet(out, visit, "step(", ", ", ")");
2061 break;
2062 case EOpSmoothStep:
2063 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2064 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002065 case EOpFrexp:
2066 case EOpLdexp:
2067 ASSERT(node->getUseEmulatedFunction());
2068 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2069 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002070 case EOpDistance:
2071 outputTriplet(out, visit, "distance(", ", ", ")");
2072 break;
2073 case EOpDot:
2074 outputTriplet(out, visit, "dot(", ", ", ")");
2075 break;
2076 case EOpCross:
2077 outputTriplet(out, visit, "cross(", ", ", ")");
2078 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002079 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002080 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002081 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002082 break;
2083 case EOpReflect:
2084 outputTriplet(out, visit, "reflect(", ", ", ")");
2085 break;
2086 case EOpRefract:
2087 outputTriplet(out, visit, "refract(", ", ", ")");
2088 break;
2089 case EOpOuterProduct:
2090 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002091 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002092 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002093 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002094 outputTriplet(out, visit, "(", " * ", ")");
2095 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002096 case EOpBitfieldExtract:
2097 case EOpBitfieldInsert:
2098 case EOpUaddCarry:
2099 case EOpUsubBorrow:
2100 case EOpUmulExtended:
2101 case EOpImulExtended:
2102 ASSERT(node->getUseEmulatedFunction());
2103 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2104 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002105 default:
2106 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002107 }
2108
2109 return true;
2110}
2111
Olli Etuaho57961272016-09-14 13:57:46 +03002112void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002113{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002114 out << "if (";
2115
2116 node->getCondition()->traverse(this);
2117
2118 out << ")\n";
2119
Jamie Madill8c46ab12015-12-07 16:39:19 -05002120 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002121
2122 bool discard = false;
2123
2124 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002125 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002126 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002127 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002128
Olli Etuahoa6f22092015-05-08 18:31:10 +03002129 // Detect true discard
2130 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2131 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002132 else
2133 {
2134 // TODO(oetuaho): Check if the semicolon inside is necessary.
2135 // It's there as a result of conservative refactoring of the output.
2136 out << "{;}\n";
2137 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002138
Jamie Madill8c46ab12015-12-07 16:39:19 -05002139 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002140
Olli Etuahoa6f22092015-05-08 18:31:10 +03002141 if (node->getFalseBlock())
2142 {
2143 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002144
Jamie Madill8c46ab12015-12-07 16:39:19 -05002145 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002146
Olli Etuaho32db19b2016-10-04 14:43:16 +01002147 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002148 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002149
Jamie Madill8c46ab12015-12-07 16:39:19 -05002150 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002151
Olli Etuahoa6f22092015-05-08 18:31:10 +03002152 // Detect false discard
2153 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2154 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002155
Olli Etuahoa6f22092015-05-08 18:31:10 +03002156 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002157 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002158 {
2159 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002160 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002161}
2162
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002163bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2164{
2165 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2166 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2167 UNREACHABLE();
2168 return false;
2169}
2170
Olli Etuaho57961272016-09-14 13:57:46 +03002171bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002172{
2173 TInfoSinkBase &out = getInfoSink();
2174
Olli Etuaho3d932d82016-04-12 11:10:30 +03002175 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002176
2177 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002178 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002179 {
2180 out << "FLATTEN ";
2181 }
2182
Olli Etuaho57961272016-09-14 13:57:46 +03002183 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002184
2185 return false;
2186}
2187
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002188bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002189{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002190 TInfoSinkBase &out = getInfoSink();
2191
Olli Etuaho923ecef2017-10-11 12:01:38 +03002192 ASSERT(node->getStatementList());
2193 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002194 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002195 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002196 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002197 outputTriplet(out, visit, "switch (", ") ", "");
2198 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002199 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002200}
2201
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002202bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002203{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002204 TInfoSinkBase &out = getInfoSink();
2205
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002206 if (node->hasCondition())
2207 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002208 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002209 return true;
2210 }
2211 else
2212 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002213 out << "default:\n";
2214 return false;
2215 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002216}
2217
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2219{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002220 TInfoSinkBase &out = getInfoSink();
2221 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002222}
2223
2224bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2225{
Nicolas Capens655fe362014-04-11 13:12:34 -04002226 mNestedLoopDepth++;
2227
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002228 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002229 mInsideDiscontinuousLoop =
2230 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002231
Jamie Madill8c46ab12015-12-07 16:39:19 -05002232 TInfoSinkBase &out = getInfoSink();
2233
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002234 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002235 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002236 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002237 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002238 mInsideDiscontinuousLoop = wasDiscontinuous;
2239 mNestedLoopDepth--;
2240
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002241 return false;
2242 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002243 }
2244
Corentin Wallez1239ee92015-03-19 14:38:02 -07002245 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002246 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002248 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002249
Jamie Madill8c46ab12015-12-07 16:39:19 -05002250 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002251 }
2252 else
2253 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002254 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002255
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002256 if (node->getInit())
2257 {
2258 node->getInit()->traverse(this);
2259 }
2260
2261 out << "; ";
2262
alokp@chromium.org52813552010-11-16 18:36:09 +00002263 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002264 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002265 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002266 }
2267
2268 out << "; ";
2269
alokp@chromium.org52813552010-11-16 18:36:09 +00002270 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002271 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002272 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002273 }
2274
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002275 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002276
Jamie Madill8c46ab12015-12-07 16:39:19 -05002277 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002278 }
2279
2280 if (node->getBody())
2281 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002282 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002283 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002284 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002285 else
2286 {
2287 // TODO(oetuaho): Check if the semicolon inside is necessary.
2288 // It's there as a result of conservative refactoring of the output.
2289 out << "{;}\n";
2290 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002291
Jamie Madill8c46ab12015-12-07 16:39:19 -05002292 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002293
alokp@chromium.org52813552010-11-16 18:36:09 +00002294 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002295 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002296 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002297 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298
alokp@chromium.org52813552010-11-16 18:36:09 +00002299 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002300
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002301 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302 }
2303
daniel@transgaming.com73536982012-03-21 20:45:49 +00002304 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002305
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002306 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002307 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002308
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309 return false;
2310}
2311
2312bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2313{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002314 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002315 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002316 TInfoSinkBase &out = getInfoSink();
2317
2318 switch (node->getFlowOp())
2319 {
2320 case EOpKill:
2321 out << "discard";
2322 break;
2323 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002324 if (mNestedLoopDepth > 1)
2325 {
2326 mUsesNestedBreak = true;
2327 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002328
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002329 if (mExcessiveLoopIndex)
2330 {
2331 out << "{Break";
2332 mExcessiveLoopIndex->traverse(this);
2333 out << " = true; break;}\n";
2334 }
2335 else
2336 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002337 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002338 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002339 break;
2340 case EOpContinue:
2341 out << "continue";
2342 break;
2343 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002344 if (node->getExpression())
2345 {
2346 out << "return ";
2347 }
2348 else
2349 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002350 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002351 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002352 break;
2353 default:
2354 UNREACHABLE();
2355 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002356 }
2357
2358 return true;
2359}
2360
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002361// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002362// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2363// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002364bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002365{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002366 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002367
2368 // Parse loops of the form:
2369 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002370 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002371 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002372 int initial = 0;
2373 int limit = 0;
2374 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002375
2376 // Parse index name and intial value
2377 if (node->getInit())
2378 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002379 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002380
2381 if (init)
2382 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002383 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002384 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002385
2386 if (variable && variable->getQualifier() == EvqTemporary)
2387 {
2388 TIntermBinary *assign = variable->getAsBinaryNode();
2389
2390 if (assign->getOp() == EOpInitialize)
2391 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002392 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002393 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2394
2395 if (symbol && constant)
2396 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002397 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002398 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002399 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002400 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002401 }
2402 }
2403 }
2404 }
2405 }
2406 }
2407
2408 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002409 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002410 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002411 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002412
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002413 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2414 {
2415 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2416
2417 if (constant)
2418 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002419 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002420 {
2421 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002422 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002423 }
2424 }
2425 }
2426 }
2427
2428 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002429 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002430 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002431 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002432 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002433
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002434 if (binaryTerminal)
2435 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002436 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002437 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2438
2439 if (constant)
2440 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002441 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002442 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002443 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002444
2445 switch (op)
2446 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002447 case EOpAddAssign:
2448 increment = value;
2449 break;
2450 case EOpSubAssign:
2451 increment = -value;
2452 break;
2453 default:
2454 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002455 }
2456 }
2457 }
2458 }
2459 else if (unaryTerminal)
2460 {
2461 TOperator op = unaryTerminal->getOp();
2462
2463 switch (op)
2464 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002465 case EOpPostIncrement:
2466 increment = 1;
2467 break;
2468 case EOpPostDecrement:
2469 increment = -1;
2470 break;
2471 case EOpPreIncrement:
2472 increment = 1;
2473 break;
2474 case EOpPreDecrement:
2475 increment = -1;
2476 break;
2477 default:
2478 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479 }
2480 }
2481 }
2482
Yunchao He4f285442017-04-21 12:15:49 +08002483 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002484 {
2485 if (comparator == EOpLessThanEqual)
2486 {
2487 comparator = EOpLessThan;
2488 limit += 1;
2489 }
2490
2491 if (comparator == EOpLessThan)
2492 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002493 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002494
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002495 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002496 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002497 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498 }
2499
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002500 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002501 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002502
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002503 out << "{int ";
2504 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002505 out << ";\n"
2506 "bool Break";
2507 index->traverse(this);
2508 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002509
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002510 bool firstLoopFragment = true;
2511
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002512 while (iterations > 0)
2513 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002514 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002515
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002516 if (!firstLoopFragment)
2517 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002518 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002519 index->traverse(this);
2520 out << ") {\n";
2521 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002522
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002523 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002524 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002525 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002526 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002527
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002528 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002529 const char *unroll =
2530 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002531
Corentin Wallez1239ee92015-03-19 14:38:02 -07002532 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533 index->traverse(this);
2534 out << " = ";
2535 out << initial;
2536
2537 out << "; ";
2538 index->traverse(this);
2539 out << " < ";
2540 out << clampedLimit;
2541
2542 out << "; ";
2543 index->traverse(this);
2544 out << " += ";
2545 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002546 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002547
Jamie Madill8c46ab12015-12-07 16:39:19 -05002548 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002549 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002550
2551 if (node->getBody())
2552 {
2553 node->getBody()->traverse(this);
2554 }
2555
Jamie Madill8c46ab12015-12-07 16:39:19 -05002556 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002557 out << ";}\n";
2558
2559 if (!firstLoopFragment)
2560 {
2561 out << "}\n";
2562 }
2563
2564 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002565
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002566 initial += MAX_LOOP_ITERATIONS * increment;
2567 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002568 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002569
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002570 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002571
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002572 mExcessiveLoopIndex = restoreIndex;
2573
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002574 return true;
2575 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002576 else
2577 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002578 }
2579
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002580 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002581}
2582
Jamie Madill8c46ab12015-12-07 16:39:19 -05002583void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2584 Visit visit,
2585 const char *preString,
2586 const char *inString,
2587 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002588{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002589 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002590 {
2591 out << preString;
2592 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002593 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002594 {
2595 out << inString;
2596 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002597 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002598 {
2599 out << postString;
2600 }
2601}
2602
Jamie Madill8c46ab12015-12-07 16:39:19 -05002603void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002604{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002605 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002606 {
Jamie Madill32aab012015-01-27 14:12:26 -05002607 out << "\n";
2608 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002609
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002610 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002611 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002612 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002613 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002614
Jamie Madill32aab012015-01-27 14:12:26 -05002615 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002616 }
2617}
2618
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002619TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2620{
2621 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002622 const TType &type = symbol->getType();
2623 const TName &name = symbol->getName();
2624 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002625
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002626 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002627 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002628 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002629 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002630 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002631 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002632 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002633 }
2634
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002635 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002636 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002637 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2638 {
2639 // Samplers are passed as indices to the sampler array.
2640 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2641 return "const uint " + nameStr + ArrayString(type);
2642 }
2643 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2644 {
2645 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2646 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2647 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2648 ArrayString(type);
2649 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002650 }
2651
Olli Etuaho96963162016-03-21 11:54:33 +02002652 TStringStream argString;
2653 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2654 << ArrayString(type);
2655
2656 // If the structure parameter contains samplers, they need to be passed into the function as
2657 // separate parameters. HLSL doesn't natively support samplers in structs.
2658 if (type.isStructureContainingSamplers())
2659 {
2660 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2661 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002662 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02002663 for (const TIntermSymbol *sampler : samplerSymbols)
2664 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002665 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002666 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2667 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002668 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002669 }
2670 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2671 {
Olli Etuaho96963162016-03-21 11:54:33 +02002672 ASSERT(IsSampler(samplerType.getBasicType()));
2673 argString << ", " << QualifierString(qualifier) << " "
2674 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002675 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2676 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002677 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002678 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002679 }
2680 else
2681 {
Olli Etuaho96963162016-03-21 11:54:33 +02002682 ASSERT(IsSampler(samplerType.getBasicType()));
2683 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002684 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002685 }
2686 }
2687 }
2688
2689 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002690}
2691
2692TString OutputHLSL::initializer(const TType &type)
2693{
2694 TString string;
2695
Jamie Madill94bf7f22013-07-08 13:31:15 -04002696 size_t size = type.getObjectSize();
2697 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002698 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002699 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002700
Jamie Madill94bf7f22013-07-08 13:31:15 -04002701 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002702 {
2703 string += ", ";
2704 }
2705 }
2706
daniel@transgaming.comead23042010-04-29 03:35:36 +00002707 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002708}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002709
Olli Etuahobd3cd502017-11-03 15:48:52 +02002710void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002711{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002712 // Array constructors should have been already pruned from the code.
2713 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002714
2715 if (visit == PreVisit)
2716 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002717 TString constructorName;
2718 if (node->getBasicType() == EbtStruct)
2719 {
2720 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2721 }
2722 else
2723 {
2724 constructorName =
2725 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2726 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002727 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002728 }
2729 else if (visit == InVisit)
2730 {
2731 out << ", ";
2732 }
2733 else if (visit == PostVisit)
2734 {
2735 out << ")";
2736 }
2737}
2738
Jamie Madill8c46ab12015-12-07 16:39:19 -05002739const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2740 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002741 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002742{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002743 const TConstantUnion *constUnionIterated = constUnion;
2744
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002745 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002746 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002747 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002748 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002749
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002750 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002751
Jamie Madill98493dd2013-07-08 14:39:03 -04002752 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002753 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002754 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002755 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002756
Jamie Madill98493dd2013-07-08 14:39:03 -04002757 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002758 {
2759 out << ", ";
2760 }
2761 }
2762
2763 out << ")";
2764 }
2765 else
2766 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002767 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002768 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002769
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002770 if (writeType)
2771 {
Jamie Madill033dae62014-06-18 12:56:28 -04002772 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002773 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002774 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002775 if (writeType)
2776 {
2777 out << ")";
2778 }
2779 }
2780
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002781 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002782}
2783
Olli Etuahod68924e2017-01-02 17:34:40 +00002784void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002785{
Olli Etuahod68924e2017-01-02 17:34:40 +00002786 if (visit == PreVisit)
2787 {
2788 const char *opStr = GetOperatorString(op);
2789 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2790 out << "(";
2791 }
2792 else
2793 {
2794 outputTriplet(out, visit, nullptr, ", ", ")");
2795 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002796}
2797
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002798bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2799 TIntermSymbol *symbolNode,
2800 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002801{
2802 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2803 expression->traverse(&searchSymbol);
2804
2805 if (searchSymbol.foundMatch())
2806 {
2807 // Type already printed
2808 out << "t" + str(mUniqueIndex) + " = ";
2809 expression->traverse(this);
2810 out << ", ";
2811 symbolNode->traverse(this);
2812 out << " = t" + str(mUniqueIndex);
2813
2814 mUniqueIndex++;
2815 return true;
2816 }
2817
2818 return false;
2819}
2820
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002821bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2822{
2823 // We support writing constant unions and constructors that only take constant unions as
2824 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002825 return !expression->getType().isArrayOfArrays() &&
2826 (expression->getAsConstantUnion() ||
2827 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002828}
2829
2830bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2831 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002832 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002833{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002834 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002835 {
2836 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002837 ASSERT(!symbolNode->getType().isArrayOfArrays());
2838 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002839 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002840 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002841 }
2842 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002843 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002844 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002845 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002846 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002847 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002848 }
2849 else
2850 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002851 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002852 ASSERT(constructor != nullptr);
2853 for (TIntermNode *&node : *constructor->getSequence())
2854 {
2855 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2856 ASSERT(nodeConst);
2857 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002858 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002859 if (node != constructor->getSequence()->back())
2860 {
2861 out << ", ";
2862 }
2863 }
2864 }
2865 out << "}";
2866 return true;
2867 }
2868 return false;
2869}
2870
Jamie Madill55e79e02015-02-09 15:35:00 -05002871TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2872{
2873 const TFieldList &fields = structure.fields();
2874
2875 for (const auto &eqFunction : mStructEqualityFunctions)
2876 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002877 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002878 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002879 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002880 }
2881 }
2882
2883 const TString &structNameString = StructNameString(structure);
2884
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002885 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002886 function->structure = &structure;
2887 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002888
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002889 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002890
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002891 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2892 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002893 << "{\n"
2894 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002895
2896 for (size_t i = 0; i < fields.size(); i++)
2897 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002898 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002899 const TType *fieldType = field->type();
2900
2901 const TString &fieldNameA = "a." + Decorate(field->name());
2902 const TString &fieldNameB = "b." + Decorate(field->name());
2903
2904 if (i > 0)
2905 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002906 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002907 }
2908
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002909 fnOut << "(";
2910 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2911 fnOut << fieldNameA;
2912 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2913 fnOut << fieldNameB;
2914 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2915 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002916 }
2917
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002918 fnOut << ";\n"
2919 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002920
2921 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002922
2923 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002924 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002925
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002926 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002927}
2928
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002929TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002930{
2931 for (const auto &eqFunction : mArrayEqualityFunctions)
2932 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002933 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002934 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002935 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002936 }
2937 }
2938
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002939 TType elementType(type);
2940 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002941
Olli Etuaho12690762015-03-31 12:55:28 +03002942 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002943 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002944
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002945 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002946
2947 TInfoSinkBase fnOut;
2948
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002949 const TString &typeName = TypeString(type);
2950 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2951 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002952 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002953 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 << type.getOutermostArraySize()
2955 << "; ++i)\n"
2956 " {\n"
2957 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002958
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002959 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002960 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002961 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002962 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002963 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002964
2965 fnOut << ") { return false; }\n"
2966 " }\n"
2967 " return true;\n"
2968 "}\n";
2969
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002970 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002971
2972 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002973 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002974
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002975 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002976}
2977
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002978TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002979{
2980 for (const auto &assignFunction : mArrayAssignmentFunctions)
2981 {
2982 if (assignFunction.type == type)
2983 {
2984 return assignFunction.functionName;
2985 }
2986 }
2987
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002988 TType elementType(type);
2989 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002990
2991 ArrayHelperFunction function;
2992 function.type = type;
2993
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002994 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002995
2996 TInfoSinkBase fnOut;
2997
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002998 const TString &typeName = TypeString(type);
2999 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3000 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003001 << "{\n"
3002 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003003 << type.getOutermostArraySize()
3004 << "; ++i)\n"
3005 " {\n"
3006 " ";
3007
3008 outputAssign(PreVisit, elementType, fnOut);
3009 fnOut << "a[i]";
3010 outputAssign(InVisit, elementType, fnOut);
3011 fnOut << "b[i]";
3012 outputAssign(PostVisit, elementType, fnOut);
3013
3014 fnOut << ";\n"
3015 " }\n"
3016 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003017
3018 function.functionDefinition = fnOut.c_str();
3019
3020 mArrayAssignmentFunctions.push_back(function);
3021
3022 return function.functionName;
3023}
3024
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003025TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003026{
3027 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3028 {
3029 if (constructIntoFunction.type == type)
3030 {
3031 return constructIntoFunction.functionName;
3032 }
3033 }
3034
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003035 TType elementType(type);
3036 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003037
3038 ArrayHelperFunction function;
3039 function.type = type;
3040
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003041 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003042
3043 TInfoSinkBase fnOut;
3044
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003045 const TString &typeName = TypeString(type);
3046 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3047 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003048 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003049 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003050 }
3051 fnOut << ")\n"
3052 "{\n";
3053
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003054 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003055 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003056 fnOut << " ";
3057 outputAssign(PreVisit, elementType, fnOut);
3058 fnOut << "a[" << i << "]";
3059 outputAssign(InVisit, elementType, fnOut);
3060 fnOut << "b" << i;
3061 outputAssign(PostVisit, elementType, fnOut);
3062 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003063 }
3064 fnOut << "}\n";
3065
3066 function.functionDefinition = fnOut.c_str();
3067
3068 mArrayConstructIntoFunctions.push_back(function);
3069
3070 return function.functionName;
3071}
3072
Jamie Madill2e295e22015-04-29 10:41:33 -04003073void OutputHLSL::ensureStructDefined(const TType &type)
3074{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003075 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003076 if (structure)
3077 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003078 ASSERT(type.getBasicType() == EbtStruct);
3079 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003080 }
3081}
3082
Jamie Madill45bcc782016-11-07 13:58:48 -05003083} // namespace sh