blob: b00ab7828cb2b3e7dd12a49082cfd54e9ec3e3d6 [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"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/FlagStd140Structs.h"
19#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 << "_";
41 for (unsigned int arraySize : type.getArraySizes())
42 {
43 fnName << arraySize << "_";
44 }
45 fnName << TypeString(type);
46 return fnName.str();
47}
48
Olli Etuaho40dbdd62017-10-13 13:34:19 +030049bool IsDeclarationWrittenOut(TIntermDeclaration *node)
50{
51 TIntermSequence *sequence = node->getSequence();
52 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
53 ASSERT(sequence->size() == 1);
54 ASSERT(variable);
55 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
56 variable->getQualifier() == EvqConst);
57}
58
Olli Etuaho96f6adf2017-08-16 11:18:54 +030059} // anonymous namespace
60
Olli Etuaho56a2f952016-12-08 12:16:27 +000061void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030062{
Olli Etuaho56a2f952016-12-08 12:16:27 +000063 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
64 // regardless.
65 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
66 mOutputType == SH_HLSL_4_1_OUTPUT)
67 {
68 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
69 }
70 else
71 {
72 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
73 }
74}
Olli Etuaho4785fec2015-05-18 16:09:37 +030075
Olli Etuaho56a2f952016-12-08 12:16:27 +000076void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020077{
78 ASSERT(constUnion != nullptr);
79 switch (constUnion->getType())
80 {
81 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000082 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020083 break;
84 case EbtInt:
85 out << constUnion->getIConst();
86 break;
87 case EbtUInt:
88 out << constUnion->getUConst();
89 break;
90 case EbtBool:
91 out << constUnion->getBConst();
92 break;
93 default:
94 UNREACHABLE();
95 }
96}
97
Olli Etuaho56a2f952016-12-08 12:16:27 +000098const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
99 const TConstantUnion *const constUnion,
100 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200101{
102 const TConstantUnion *constUnionIterated = constUnion;
103 for (size_t i = 0; i < size; i++, constUnionIterated++)
104 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000105 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200106
107 if (i != size - 1)
108 {
109 out << ", ";
110 }
111 }
112 return constUnionIterated;
113}
114
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800115OutputHLSL::OutputHLSL(sh::GLenum shaderType,
116 int shaderVersion,
117 const TExtensionBehavior &extensionBehavior,
118 const char *sourcePath,
119 ShShaderOutput outputType,
120 int numRenderTargets,
121 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300122 ShCompileOptions compileOptions,
123 TSymbolTable *symbolTable)
124 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200125 mShaderType(shaderType),
126 mShaderVersion(shaderVersion),
127 mExtensionBehavior(extensionBehavior),
128 mSourcePath(sourcePath),
129 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700130 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000131 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700132 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000134 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000135
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500136 mUsesFragColor = false;
137 mUsesFragData = false;
138 mUsesDepthRange = false;
139 mUsesFragCoord = false;
140 mUsesPointCoord = false;
141 mUsesFrontFacing = false;
142 mUsesPointSize = false;
143 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300144 mHasMultiviewExtensionEnabled =
145 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300146 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500147 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500148 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800149 mUsesNumWorkGroups = false;
150 mUsesWorkGroupID = false;
151 mUsesLocalInvocationID = false;
152 mUsesGlobalInvocationID = false;
153 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500154 mUsesXor = false;
155 mUsesDiscardRewriting = false;
156 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530157 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000158
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000159 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000160
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500161 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000162 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000164
Yunchao Hed7297bf2017-04-19 15:27:10 +0800165 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000166
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500167 mStructureHLSL = new StructureHLSL;
168 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300169 mTextureFunctionHLSL = new TextureFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400170
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200171 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000172 {
Arun Patole63419392015-03-13 11:51:07 +0530173 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
175 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530176 // In both cases total 3 uniform registers need to be reserved.
177 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000178 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000179
Geoff Lang00140f42016-02-03 18:47:33 +0000180 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800181 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182}
183
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000184OutputHLSL::~OutputHLSL()
185{
Jamie Madill8daaba12014-06-13 10:04:33 -0400186 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400187 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300188 SafeDelete(mTextureFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200189 for (auto &eqFunction : mStructEqualityFunctions)
190 {
191 SafeDelete(eqFunction);
192 }
193 for (auto &eqFunction : mArrayEqualityFunctions)
194 {
195 SafeDelete(eqFunction);
196 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000197}
198
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200199void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000200{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500201 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400202 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000203
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200204 BuiltInFunctionEmulator builtInFunctionEmulator;
205 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800206 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
207 {
208 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
209 mShaderVersion);
210 }
211
Olli Etuahodfa75e82017-01-23 09:43:06 -0800212 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500213
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700214 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000215 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700216 ASSERT(success == CallDAG::INITDAG_SUCCESS);
217 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700218
Jamie Madill37997142015-01-28 10:06:34 -0500219 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500220 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200221 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500222 mInfoSinkStack.pop();
223
Jamie Madill37997142015-01-28 10:06:34 -0500224 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500225 mInfoSinkStack.pop();
226
Jamie Madill32aab012015-01-27 14:12:26 -0500227 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500228 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500229 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000230
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200231 objSink << mHeader.c_str();
232 objSink << mBody.c_str();
233 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200234
Olli Etuahodfa75e82017-01-23 09:43:06 -0800235 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000236}
237
Jamie Madill570e04d2013-06-21 09:15:33 -0400238void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
239{
240 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
241 {
242 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
243
Jamie Madill32aab012015-01-27 14:12:26 -0500244 TInfoSinkBase structInfoSink;
245 mInfoSinkStack.push(&structInfoSink);
246
Jamie Madill570e04d2013-06-21 09:15:33 -0400247 // This will mark the necessary block elements as referenced
248 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500249
250 TString structName(structInfoSink.c_str());
251 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400252
253 mFlaggedStructOriginalNames[flaggedNode] = structName;
254
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255 for (size_t pos = structName.find('.'); pos != std::string::npos;
256 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400257 {
258 structName.erase(pos, 1);
259 }
260
261 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
262 }
263}
264
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800265const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400266{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800267 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400268}
269
Jamie Madill9fe25e92014-07-18 10:33:08 -0400270const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
271{
272 return mUniformHLSL->getUniformRegisterMap();
273}
274
Olli Etuahoed049ab2017-06-30 17:38:33 +0300275TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400276{
277 TString init;
278
Olli Etuahoed049ab2017-06-30 17:38:33 +0300279 TString indentString;
280 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400281 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300282 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400283 }
284
Olli Etuahoed049ab2017-06-30 17:38:33 +0300285 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400286 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300287 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300288 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400289 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 TStringStream indexedString;
291 indexedString << name << "[" << arrayIndex << "]";
292 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300293 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300294 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300295 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300296 {
297 init += ",";
298 }
299 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400300 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300301 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400302 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300303 else if (type.getBasicType() == EbtStruct)
304 {
305 init += indentString + "{\n";
306 const TStructure &structure = *type.getStruct();
307 const TFieldList &fields = structure.fields();
308 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
309 {
310 const TField &field = *fields[fieldIndex];
311 const TString &fieldName = name + "." + Decorate(field.name());
312 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400313
Olli Etuahoed049ab2017-06-30 17:38:33 +0300314 init += structInitializerString(indent + 1, fieldType, fieldName);
315 if (fieldIndex < fields.size() - 1)
316 {
317 init += ",";
318 }
319 init += "\n";
320 }
321 init += indentString + "}";
322 }
323 else
324 {
325 init += indentString + name;
326 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400327
328 return init;
329}
330
Jamie Madill8c46ab12015-12-07 16:39:19 -0500331void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000333 TString varyings;
334 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400335 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000336
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500337 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
338 mFlaggedStructMappedNames.begin();
339 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400340 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500341 TIntermTyped *structNode = flaggedStructIt->first;
342 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400343 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400344 const TString &originalName = mFlaggedStructOriginalNames[structNode];
345
Olli Etuahoed049ab2017-06-30 17:38:33 +0300346 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
347 if (structNode->isArray())
348 {
349 flaggedStructs += ArrayString(structNode->getType());
350 }
351 flaggedStructs += " =\n";
352 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
353 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400354 }
355
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500356 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
357 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000358 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500359 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000360 const TString &name = varying->second->getSymbol();
361
362 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500363 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
364 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000365 }
366
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500367 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
368 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000369 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500370 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000371 const TString &name = attribute->second->getSymbol();
372
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500373 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
374 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000375 }
376
Jamie Madill8daaba12014-06-13 10:04:33 -0400377 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400378
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300379 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800380 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400381
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200382 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500383 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200384 out << "\n// Equality functions\n\n";
385 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500386 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200387 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200388 }
389 }
Olli Etuaho12690762015-03-31 12:55:28 +0300390 if (!mArrayAssignmentFunctions.empty())
391 {
392 out << "\n// Assignment functions\n\n";
393 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
394 {
395 out << assignmentFunction.functionDefinition << "\n";
396 }
397 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300398 if (!mArrayConstructIntoFunctions.empty())
399 {
400 out << "\n// Array constructor functions\n\n";
401 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
402 {
403 out << constructIntoFunction.functionDefinition << "\n";
404 }
405 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200406
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500407 if (mUsesDiscardRewriting)
408 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400409 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500410 }
411
Nicolas Capens655fe362014-04-11 13:12:34 -0400412 if (mUsesNestedBreak)
413 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400414 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400415 }
416
Arun Patole44efa0b2015-03-04 17:11:05 +0530417 if (mRequiresIEEEStrictCompiling)
418 {
419 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
420 }
421
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400422 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
423 "#define LOOP [loop]\n"
424 "#define FLATTEN [flatten]\n"
425 "#else\n"
426 "#define LOOP\n"
427 "#define FLATTEN\n"
428 "#endif\n";
429
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200430 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300432 const bool usingMRTExtension =
433 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000434
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000435 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500436 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400437 out << "\n";
438
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200439 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000440 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500441 for (ReferencedSymbols::const_iterator outputVariableIt =
442 mReferencedOutputVariables.begin();
443 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000444 {
Jamie Madill46131a32013-06-20 11:55:50 -0400445 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500446 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400447
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500448 out << "static " + TypeString(variableType) + " out_" + variableName +
449 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000450 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000451 }
Jamie Madill46131a32013-06-20 11:55:50 -0400452 else
453 {
454 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
455
456 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500457 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400458 for (unsigned int i = 0; i < numColorValues; i++)
459 {
460 out << " float4(0, 0, 0, 0)";
461 if (i + 1 != numColorValues)
462 {
463 out << ",";
464 }
465 out << "\n";
466 }
467
468 out << "};\n";
469 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000470
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400471 if (mUsesFragDepth)
472 {
473 out << "static float gl_Depth = 0.0;\n";
474 }
475
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000476 if (mUsesFragCoord)
477 {
478 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
479 }
480
481 if (mUsesPointCoord)
482 {
483 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
484 }
485
486 if (mUsesFrontFacing)
487 {
488 out << "static bool gl_FrontFacing = false;\n";
489 }
490
491 out << "\n";
492
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000493 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000494 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000495 out << "struct gl_DepthRangeParameters\n"
496 "{\n"
497 " float near;\n"
498 " float far;\n"
499 " float diff;\n"
500 "};\n"
501 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000502 }
503
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200504 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000505 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000506 out << "cbuffer DriverConstants : register(b1)\n"
507 "{\n";
508
509 if (mUsesDepthRange)
510 {
511 out << " float3 dx_DepthRange : packoffset(c0);\n";
512 }
513
514 if (mUsesFragCoord)
515 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000516 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000517 }
518
519 if (mUsesFragCoord || mUsesFrontFacing)
520 {
521 out << " float3 dx_DepthFront : packoffset(c2);\n";
522 }
523
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800524 if (mUsesFragCoord)
525 {
526 // dx_ViewScale is only used in the fragment shader to correct
527 // the value for glFragCoord if necessary
528 out << " float2 dx_ViewScale : packoffset(c3);\n";
529 }
530
Martin Radev72b4e1e2017-08-31 15:42:56 +0300531 if (mHasMultiviewExtensionEnabled)
532 {
533 // We have to add a value which we can use to keep track of which multi-view code
534 // path is to be selected in the GS.
535 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
536 }
537
Olli Etuaho618bebc2016-01-15 16:40:00 +0200538 if (mOutputType == SH_HLSL_4_1_OUTPUT)
539 {
540 mUniformHLSL->samplerMetadataUniforms(out, "c4");
541 }
542
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000543 out << "};\n";
544 }
545 else
546 {
547 if (mUsesDepthRange)
548 {
549 out << "uniform float3 dx_DepthRange : register(c0);";
550 }
551
552 if (mUsesFragCoord)
553 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000554 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000555 }
556
557 if (mUsesFragCoord || mUsesFrontFacing)
558 {
559 out << "uniform float3 dx_DepthFront : register(c2);\n";
560 }
561 }
562
563 out << "\n";
564
565 if (mUsesDepthRange)
566 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500567 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
568 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000569 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000570 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000571
Jamie Madillf91ce812014-06-13 10:04:34 -0400572 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000573 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400574 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000575 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400576 out << flaggedStructs;
577 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000578 }
579
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000580 if (usingMRTExtension && mNumRenderTargets > 1)
581 {
582 out << "#define GL_USES_MRT\n";
583 }
584
585 if (mUsesFragColor)
586 {
587 out << "#define GL_USES_FRAG_COLOR\n";
588 }
589
590 if (mUsesFragData)
591 {
592 out << "#define GL_USES_FRAG_DATA\n";
593 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594 }
Xinghua Caob1239382016-12-13 15:07:05 +0800595 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000597 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500598 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000599 out << "\n"
600 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400601
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000602 if (mUsesPointSize)
603 {
604 out << "static float gl_PointSize = float(1);\n";
605 }
606
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000607 if (mUsesInstanceID)
608 {
609 out << "static int gl_InstanceID;";
610 }
611
Corentin Wallezb076add2016-01-11 16:45:46 -0500612 if (mUsesVertexID)
613 {
614 out << "static int gl_VertexID;";
615 }
616
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000617 out << "\n"
618 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500619 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000620 out << "\n";
621
622 if (mUsesDepthRange)
623 {
624 out << "struct gl_DepthRangeParameters\n"
625 "{\n"
626 " float near;\n"
627 " float far;\n"
628 " float diff;\n"
629 "};\n"
630 "\n";
631 }
632
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200633 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000634 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800635 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500636 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800637
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000638 if (mUsesDepthRange)
639 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800640 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000641 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800642
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800643 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
644 // shaders. However, we declare it for all shaders (including Feature Level 10+).
645 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
646 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800647 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800648 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800649 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800650
Martin Radev72b4e1e2017-08-31 15:42:56 +0300651 if (mHasMultiviewExtensionEnabled)
652 {
653 // We have to add a value which we can use to keep track of which multi-view code
654 // path is to be selected in the GS.
655 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
656 }
657
Olli Etuaho618bebc2016-01-15 16:40:00 +0200658 if (mOutputType == SH_HLSL_4_1_OUTPUT)
659 {
660 mUniformHLSL->samplerMetadataUniforms(out, "c4");
661 }
662
Austin Kinross4fd18b12014-12-22 12:32:05 -0800663 out << "};\n"
664 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000665 }
666 else
667 {
668 if (mUsesDepthRange)
669 {
670 out << "uniform float3 dx_DepthRange : register(c0);\n";
671 }
672
Cooper Partine6664f02015-01-09 16:22:24 -0800673 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
674 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000675 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000676 }
677
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000678 if (mUsesDepthRange)
679 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500680 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
681 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000682 "\n";
683 }
684
Jamie Madillf91ce812014-06-13 10:04:34 -0400685 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000686 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400687 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000688 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400689 out << flaggedStructs;
690 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000691 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400692 }
Xinghua Caob1239382016-12-13 15:07:05 +0800693 else // Compute shader
694 {
695 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800696
697 out << "cbuffer DriverConstants : register(b1)\n"
698 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800699 if (mUsesNumWorkGroups)
700 {
Xinghua Caob1239382016-12-13 15:07:05 +0800701 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800702 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800703 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
704 mUniformHLSL->samplerMetadataUniforms(out, "c1");
705 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800706
707 // Follow built-in variables would be initialized in
708 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
709 // are used in compute shader.
710 if (mUsesWorkGroupID)
711 {
712 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
713 }
714
715 if (mUsesLocalInvocationID)
716 {
717 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
718 }
719
720 if (mUsesGlobalInvocationID)
721 {
722 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
723 }
724
725 if (mUsesLocalInvocationIndex)
726 {
727 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
728 }
729 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000730
Geoff Lang1fe74c72016-08-25 13:23:01 -0400731 bool getDimensionsIgnoresBaseLevel =
732 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
733 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000734
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000735 if (mUsesFragCoord)
736 {
737 out << "#define GL_USES_FRAG_COORD\n";
738 }
739
740 if (mUsesPointCoord)
741 {
742 out << "#define GL_USES_POINT_COORD\n";
743 }
744
745 if (mUsesFrontFacing)
746 {
747 out << "#define GL_USES_FRONT_FACING\n";
748 }
749
750 if (mUsesPointSize)
751 {
752 out << "#define GL_USES_POINT_SIZE\n";
753 }
754
Martin Radev41ac68e2017-06-06 12:16:58 +0300755 if (mHasMultiviewExtensionEnabled)
756 {
757 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
758 }
759
760 if (mUsesViewID)
761 {
762 out << "#define GL_USES_VIEW_ID\n";
763 }
764
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400765 if (mUsesFragDepth)
766 {
767 out << "#define GL_USES_FRAG_DEPTH\n";
768 }
769
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000770 if (mUsesDepthRange)
771 {
772 out << "#define GL_USES_DEPTH_RANGE\n";
773 }
774
Xinghua Caob1239382016-12-13 15:07:05 +0800775 if (mUsesNumWorkGroups)
776 {
777 out << "#define GL_USES_NUM_WORK_GROUPS\n";
778 }
779
780 if (mUsesWorkGroupID)
781 {
782 out << "#define GL_USES_WORK_GROUP_ID\n";
783 }
784
785 if (mUsesLocalInvocationID)
786 {
787 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
788 }
789
790 if (mUsesGlobalInvocationID)
791 {
792 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
793 }
794
795 if (mUsesLocalInvocationIndex)
796 {
797 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
798 }
799
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000800 if (mUsesXor)
801 {
802 out << "bool xor(bool p, bool q)\n"
803 "{\n"
804 " return (p || q) && !(p && q);\n"
805 "}\n"
806 "\n";
807 }
808
Olli Etuahodfa75e82017-01-23 09:43:06 -0800809 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000810}
811
812void OutputHLSL::visitSymbol(TIntermSymbol *node)
813{
Jamie Madill32aab012015-01-27 14:12:26 -0500814 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000815
Jamie Madill570e04d2013-06-21 09:15:33 -0400816 // Handle accessing std140 structs by value
817 if (mFlaggedStructMappedNames.count(node) > 0)
818 {
819 out << mFlaggedStructMappedNames[node];
820 return;
821 }
822
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823 TString name = node->getSymbol();
824
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000825 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000826 {
827 mUsesDepthRange = true;
828 out << name;
829 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000830 else
831 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000832 TQualifier qualifier = node->getQualifier();
833
834 if (qualifier == EvqUniform)
835 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500836 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400837 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400838
839 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000840 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800841 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000842 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000843 else
844 {
845 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000846 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400847
Jamie Madill2e295e22015-04-29 10:41:33 -0400848 ensureStructDefined(nodeType);
849
Olli Etuahoff526f12017-06-30 12:26:54 +0300850 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000851 }
Jamie Madill19571812013-08-12 15:26:34 -0700852 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000853 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000854 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400855 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000856 }
Jamie Madill033dae62014-06-18 12:56:28 -0400857 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000858 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000859 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400860 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300861 if (name == "ViewID_OVR")
862 {
863 mUsesViewID = true;
864 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000865 }
Jamie Madill19571812013-08-12 15:26:34 -0700866 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400867 {
868 mReferencedOutputVariables[name] = node;
869 out << "out_" << name;
870 }
871 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000872 {
873 out << "gl_Color[0]";
874 mUsesFragColor = true;
875 }
876 else if (qualifier == EvqFragData)
877 {
878 out << "gl_Color";
879 mUsesFragData = true;
880 }
881 else if (qualifier == EvqFragCoord)
882 {
883 mUsesFragCoord = true;
884 out << name;
885 }
886 else if (qualifier == EvqPointCoord)
887 {
888 mUsesPointCoord = true;
889 out << name;
890 }
891 else if (qualifier == EvqFrontFacing)
892 {
893 mUsesFrontFacing = true;
894 out << name;
895 }
896 else if (qualifier == EvqPointSize)
897 {
898 mUsesPointSize = true;
899 out << name;
900 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000901 else if (qualifier == EvqInstanceID)
902 {
903 mUsesInstanceID = true;
904 out << name;
905 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500906 else if (qualifier == EvqVertexID)
907 {
908 mUsesVertexID = true;
909 out << name;
910 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300911 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400912 {
913 mUsesFragDepth = true;
914 out << "gl_Depth";
915 }
Xinghua Caob1239382016-12-13 15:07:05 +0800916 else if (qualifier == EvqNumWorkGroups)
917 {
918 mUsesNumWorkGroups = true;
919 out << name;
920 }
921 else if (qualifier == EvqWorkGroupID)
922 {
923 mUsesWorkGroupID = true;
924 out << name;
925 }
926 else if (qualifier == EvqLocalInvocationID)
927 {
928 mUsesLocalInvocationID = true;
929 out << name;
930 }
931 else if (qualifier == EvqGlobalInvocationID)
932 {
933 mUsesGlobalInvocationID = true;
934 out << name;
935 }
936 else if (qualifier == EvqLocalInvocationIndex)
937 {
938 mUsesLocalInvocationIndex = true;
939 out << name;
940 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000941 else
942 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300943 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000944 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 }
946}
947
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400948void OutputHLSL::visitRaw(TIntermRaw *node)
949{
Jamie Madill32aab012015-01-27 14:12:26 -0500950 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400951}
952
Olli Etuaho7fb49552015-03-18 17:27:44 +0200953void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
954{
955 if (type.isScalar() && !type.isArray())
956 {
957 if (op == EOpEqual)
958 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500959 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200960 }
961 else
962 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500963 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200964 }
965 }
966 else
967 {
968 if (visit == PreVisit && op == EOpNotEqual)
969 {
970 out << "!";
971 }
972
973 if (type.isArray())
974 {
975 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500976 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200977 }
978 else if (type.getBasicType() == EbtStruct)
979 {
980 const TStructure &structure = *type.getStruct();
981 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500982 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200983 }
984 else
985 {
986 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500987 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200988 }
989 }
990}
991
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300992void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
993{
994 if (type.isArray())
995 {
996 const TString &functionName = addArrayAssignmentFunction(type);
997 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
998 }
999 else
1000 {
1001 outputTriplet(out, visit, "(", " = ", ")");
1002 }
1003}
1004
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001005bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001006{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001007 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001008 {
1009 TIntermNode *ancestor = getAncestorNode(n);
1010 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1011 if (ancestorBinary == nullptr)
1012 {
1013 return false;
1014 }
1015 switch (ancestorBinary->getOp())
1016 {
1017 case EOpIndexDirectStruct:
1018 {
1019 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1020 const TIntermConstantUnion *index =
1021 ancestorBinary->getRight()->getAsConstantUnion();
1022 const TField *field = structure->fields()[index->getIConst(0)];
1023 if (IsSampler(field->type()->getBasicType()))
1024 {
1025 return true;
1026 }
1027 break;
1028 }
1029 case EOpIndexDirect:
1030 break;
1031 default:
1032 // Returning a sampler from indirect indexing is not supported.
1033 return false;
1034 }
1035 }
1036 return false;
1037}
1038
Olli Etuahob6fa0432016-09-28 16:28:05 +01001039bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1040{
1041 TInfoSinkBase &out = getInfoSink();
1042 if (visit == PostVisit)
1043 {
1044 out << ".";
1045 node->writeOffsetsAsXYZW(&out);
1046 }
1047 return true;
1048}
1049
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1051{
Jamie Madill32aab012015-01-27 14:12:26 -05001052 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001053
Jamie Madill570e04d2013-06-21 09:15:33 -04001054 // Handle accessing std140 structs by value
1055 if (mFlaggedStructMappedNames.count(node) > 0)
1056 {
1057 out << mFlaggedStructMappedNames[node];
1058 return false;
1059 }
1060
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061 switch (node->getOp())
1062 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001063 case EOpComma:
1064 outputTriplet(out, visit, "(", ", ", ")");
1065 break;
1066 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001067 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001068 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001069 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1070 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001071 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001072 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1073 out << functionName << "(";
1074 node->getLeft()->traverse(this);
1075 TIntermSequence *seq = rightAgg->getSequence();
1076 for (auto &arrayElement : *seq)
1077 {
1078 out << ", ";
1079 arrayElement->traverse(this);
1080 }
1081 out << ")";
1082 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001083 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001084 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1085 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001086 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001087 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001088 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001089 break;
1090 case EOpInitialize:
1091 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001092 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001093 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1094 ASSERT(symbolNode);
1095 TIntermTyped *expression = node->getRight();
1096
1097 // Global initializers must be constant at this point.
1098 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1099 canWriteAsHLSLLiteral(expression));
1100
1101 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1102 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1103 // new variable is created before the assignment is evaluated), so we need to
1104 // convert
1105 // this to "float t = x, x = t;".
1106 if (writeSameSymbolInitializer(out, symbolNode, expression))
1107 {
1108 // Skip initializing the rest of the expression
1109 return false;
1110 }
1111 else if (writeConstantInitialization(out, symbolNode, expression))
1112 {
1113 return false;
1114 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001115 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001116 else if (visit == InVisit)
1117 {
1118 out << " = ";
1119 }
1120 break;
1121 case EOpAddAssign:
1122 outputTriplet(out, visit, "(", " += ", ")");
1123 break;
1124 case EOpSubAssign:
1125 outputTriplet(out, visit, "(", " -= ", ")");
1126 break;
1127 case EOpMulAssign:
1128 outputTriplet(out, visit, "(", " *= ", ")");
1129 break;
1130 case EOpVectorTimesScalarAssign:
1131 outputTriplet(out, visit, "(", " *= ", ")");
1132 break;
1133 case EOpMatrixTimesScalarAssign:
1134 outputTriplet(out, visit, "(", " *= ", ")");
1135 break;
1136 case EOpVectorTimesMatrixAssign:
1137 if (visit == PreVisit)
1138 {
1139 out << "(";
1140 }
1141 else if (visit == InVisit)
1142 {
1143 out << " = mul(";
1144 node->getLeft()->traverse(this);
1145 out << ", transpose(";
1146 }
1147 else
1148 {
1149 out << ")))";
1150 }
1151 break;
1152 case EOpMatrixTimesMatrixAssign:
1153 if (visit == PreVisit)
1154 {
1155 out << "(";
1156 }
1157 else if (visit == InVisit)
1158 {
1159 out << " = transpose(mul(transpose(";
1160 node->getLeft()->traverse(this);
1161 out << "), transpose(";
1162 }
1163 else
1164 {
1165 out << "))))";
1166 }
1167 break;
1168 case EOpDivAssign:
1169 outputTriplet(out, visit, "(", " /= ", ")");
1170 break;
1171 case EOpIModAssign:
1172 outputTriplet(out, visit, "(", " %= ", ")");
1173 break;
1174 case EOpBitShiftLeftAssign:
1175 outputTriplet(out, visit, "(", " <<= ", ")");
1176 break;
1177 case EOpBitShiftRightAssign:
1178 outputTriplet(out, visit, "(", " >>= ", ")");
1179 break;
1180 case EOpBitwiseAndAssign:
1181 outputTriplet(out, visit, "(", " &= ", ")");
1182 break;
1183 case EOpBitwiseXorAssign:
1184 outputTriplet(out, visit, "(", " ^= ", ")");
1185 break;
1186 case EOpBitwiseOrAssign:
1187 outputTriplet(out, visit, "(", " |= ", ")");
1188 break;
1189 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001190 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001191 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001192 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001193 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001194 if (visit == PreVisit)
1195 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001196 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001197 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001198 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001199 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001200 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001201 return false;
1202 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001203 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001204 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001205 {
1206 // All parts of an expression that access a sampler in a struct need to use _ as
1207 // separator to access the sampler variable that has been moved out of the struct.
1208 outputTriplet(out, visit, "", "_", "");
1209 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001210 else
1211 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001212 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001213 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001214 }
1215 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001216 case EOpIndexIndirect:
1217 // We do not currently support indirect references to interface blocks
1218 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1219 outputTriplet(out, visit, "", "[", "]");
1220 break;
1221 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001222 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001223 const TStructure *structure = node->getLeft()->getType().getStruct();
1224 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1225 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001226
Olli Etuaho96963162016-03-21 11:54:33 +02001227 // In cases where indexing returns a sampler, we need to access the sampler variable
1228 // that has been moved out of the struct.
1229 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1230 if (visit == PreVisit && indexingReturnsSampler)
1231 {
1232 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1233 // This prefix is only output at the beginning of the indexing expression, which
1234 // may have multiple parts.
1235 out << "angle";
1236 }
1237 if (!indexingReturnsSampler)
1238 {
1239 // All parts of an expression that access a sampler in a struct need to use _ as
1240 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001241 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001242 }
1243 if (visit == InVisit)
1244 {
1245 if (indexingReturnsSampler)
1246 {
1247 out << "_" + field->name();
1248 }
1249 else
1250 {
1251 out << "." + DecorateField(field->name(), *structure);
1252 }
1253
1254 return false;
1255 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001256 }
1257 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001258 case EOpIndexDirectInterfaceBlock:
1259 if (visit == InVisit)
1260 {
1261 const TInterfaceBlock *interfaceBlock =
1262 node->getLeft()->getType().getInterfaceBlock();
1263 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1264 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1265 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001266
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001267 return false;
1268 }
1269 break;
1270 case EOpAdd:
1271 outputTriplet(out, visit, "(", " + ", ")");
1272 break;
1273 case EOpSub:
1274 outputTriplet(out, visit, "(", " - ", ")");
1275 break;
1276 case EOpMul:
1277 outputTriplet(out, visit, "(", " * ", ")");
1278 break;
1279 case EOpDiv:
1280 outputTriplet(out, visit, "(", " / ", ")");
1281 break;
1282 case EOpIMod:
1283 outputTriplet(out, visit, "(", " % ", ")");
1284 break;
1285 case EOpBitShiftLeft:
1286 outputTriplet(out, visit, "(", " << ", ")");
1287 break;
1288 case EOpBitShiftRight:
1289 outputTriplet(out, visit, "(", " >> ", ")");
1290 break;
1291 case EOpBitwiseAnd:
1292 outputTriplet(out, visit, "(", " & ", ")");
1293 break;
1294 case EOpBitwiseXor:
1295 outputTriplet(out, visit, "(", " ^ ", ")");
1296 break;
1297 case EOpBitwiseOr:
1298 outputTriplet(out, visit, "(", " | ", ")");
1299 break;
1300 case EOpEqual:
1301 case EOpNotEqual:
1302 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1303 break;
1304 case EOpLessThan:
1305 outputTriplet(out, visit, "(", " < ", ")");
1306 break;
1307 case EOpGreaterThan:
1308 outputTriplet(out, visit, "(", " > ", ")");
1309 break;
1310 case EOpLessThanEqual:
1311 outputTriplet(out, visit, "(", " <= ", ")");
1312 break;
1313 case EOpGreaterThanEqual:
1314 outputTriplet(out, visit, "(", " >= ", ")");
1315 break;
1316 case EOpVectorTimesScalar:
1317 outputTriplet(out, visit, "(", " * ", ")");
1318 break;
1319 case EOpMatrixTimesScalar:
1320 outputTriplet(out, visit, "(", " * ", ")");
1321 break;
1322 case EOpVectorTimesMatrix:
1323 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1324 break;
1325 case EOpMatrixTimesVector:
1326 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1327 break;
1328 case EOpMatrixTimesMatrix:
1329 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1330 break;
1331 case EOpLogicalOr:
1332 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1333 // been unfolded.
1334 ASSERT(!node->getRight()->hasSideEffects());
1335 outputTriplet(out, visit, "(", " || ", ")");
1336 return true;
1337 case EOpLogicalXor:
1338 mUsesXor = true;
1339 outputTriplet(out, visit, "xor(", ", ", ")");
1340 break;
1341 case EOpLogicalAnd:
1342 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1343 // been unfolded.
1344 ASSERT(!node->getRight()->hasSideEffects());
1345 outputTriplet(out, visit, "(", " && ", ")");
1346 return true;
1347 default:
1348 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349 }
1350
1351 return true;
1352}
1353
1354bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1355{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001356 TInfoSinkBase &out = getInfoSink();
1357
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001358 switch (node->getOp())
1359 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001360 case EOpNegative:
1361 outputTriplet(out, visit, "(-", "", ")");
1362 break;
1363 case EOpPositive:
1364 outputTriplet(out, visit, "(+", "", ")");
1365 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001366 case EOpLogicalNot:
1367 outputTriplet(out, visit, "(!", "", ")");
1368 break;
1369 case EOpBitwiseNot:
1370 outputTriplet(out, visit, "(~", "", ")");
1371 break;
1372 case EOpPostIncrement:
1373 outputTriplet(out, visit, "(", "", "++)");
1374 break;
1375 case EOpPostDecrement:
1376 outputTriplet(out, visit, "(", "", "--)");
1377 break;
1378 case EOpPreIncrement:
1379 outputTriplet(out, visit, "(++", "", ")");
1380 break;
1381 case EOpPreDecrement:
1382 outputTriplet(out, visit, "(--", "", ")");
1383 break;
1384 case EOpRadians:
1385 outputTriplet(out, visit, "radians(", "", ")");
1386 break;
1387 case EOpDegrees:
1388 outputTriplet(out, visit, "degrees(", "", ")");
1389 break;
1390 case EOpSin:
1391 outputTriplet(out, visit, "sin(", "", ")");
1392 break;
1393 case EOpCos:
1394 outputTriplet(out, visit, "cos(", "", ")");
1395 break;
1396 case EOpTan:
1397 outputTriplet(out, visit, "tan(", "", ")");
1398 break;
1399 case EOpAsin:
1400 outputTriplet(out, visit, "asin(", "", ")");
1401 break;
1402 case EOpAcos:
1403 outputTriplet(out, visit, "acos(", "", ")");
1404 break;
1405 case EOpAtan:
1406 outputTriplet(out, visit, "atan(", "", ")");
1407 break;
1408 case EOpSinh:
1409 outputTriplet(out, visit, "sinh(", "", ")");
1410 break;
1411 case EOpCosh:
1412 outputTriplet(out, visit, "cosh(", "", ")");
1413 break;
1414 case EOpTanh:
1415 outputTriplet(out, visit, "tanh(", "", ")");
1416 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001417 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001418 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001419 case EOpAtanh:
1420 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001421 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001422 break;
1423 case EOpExp:
1424 outputTriplet(out, visit, "exp(", "", ")");
1425 break;
1426 case EOpLog:
1427 outputTriplet(out, visit, "log(", "", ")");
1428 break;
1429 case EOpExp2:
1430 outputTriplet(out, visit, "exp2(", "", ")");
1431 break;
1432 case EOpLog2:
1433 outputTriplet(out, visit, "log2(", "", ")");
1434 break;
1435 case EOpSqrt:
1436 outputTriplet(out, visit, "sqrt(", "", ")");
1437 break;
1438 case EOpInverseSqrt:
1439 outputTriplet(out, visit, "rsqrt(", "", ")");
1440 break;
1441 case EOpAbs:
1442 outputTriplet(out, visit, "abs(", "", ")");
1443 break;
1444 case EOpSign:
1445 outputTriplet(out, visit, "sign(", "", ")");
1446 break;
1447 case EOpFloor:
1448 outputTriplet(out, visit, "floor(", "", ")");
1449 break;
1450 case EOpTrunc:
1451 outputTriplet(out, visit, "trunc(", "", ")");
1452 break;
1453 case EOpRound:
1454 outputTriplet(out, visit, "round(", "", ")");
1455 break;
1456 case EOpRoundEven:
1457 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001458 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001459 break;
1460 case EOpCeil:
1461 outputTriplet(out, visit, "ceil(", "", ")");
1462 break;
1463 case EOpFract:
1464 outputTriplet(out, visit, "frac(", "", ")");
1465 break;
1466 case EOpIsNan:
1467 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001468 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 else
1470 outputTriplet(out, visit, "isnan(", "", ")");
1471 mRequiresIEEEStrictCompiling = true;
1472 break;
1473 case EOpIsInf:
1474 outputTriplet(out, visit, "isinf(", "", ")");
1475 break;
1476 case EOpFloatBitsToInt:
1477 outputTriplet(out, visit, "asint(", "", ")");
1478 break;
1479 case EOpFloatBitsToUint:
1480 outputTriplet(out, visit, "asuint(", "", ")");
1481 break;
1482 case EOpIntBitsToFloat:
1483 outputTriplet(out, visit, "asfloat(", "", ")");
1484 break;
1485 case EOpUintBitsToFloat:
1486 outputTriplet(out, visit, "asfloat(", "", ")");
1487 break;
1488 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001489 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001490 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001491 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001493 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001494 case EOpPackUnorm4x8:
1495 case EOpPackSnorm4x8:
1496 case EOpUnpackUnorm4x8:
1497 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001499 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001500 break;
1501 case EOpLength:
1502 outputTriplet(out, visit, "length(", "", ")");
1503 break;
1504 case EOpNormalize:
1505 outputTriplet(out, visit, "normalize(", "", ")");
1506 break;
1507 case EOpDFdx:
1508 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1509 {
1510 outputTriplet(out, visit, "(", "", ", 0.0)");
1511 }
1512 else
1513 {
1514 outputTriplet(out, visit, "ddx(", "", ")");
1515 }
1516 break;
1517 case EOpDFdy:
1518 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1519 {
1520 outputTriplet(out, visit, "(", "", ", 0.0)");
1521 }
1522 else
1523 {
1524 outputTriplet(out, visit, "ddy(", "", ")");
1525 }
1526 break;
1527 case EOpFwidth:
1528 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1529 {
1530 outputTriplet(out, visit, "(", "", ", 0.0)");
1531 }
1532 else
1533 {
1534 outputTriplet(out, visit, "fwidth(", "", ")");
1535 }
1536 break;
1537 case EOpTranspose:
1538 outputTriplet(out, visit, "transpose(", "", ")");
1539 break;
1540 case EOpDeterminant:
1541 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1542 break;
1543 case EOpInverse:
1544 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001545 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001547
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 case EOpAny:
1549 outputTriplet(out, visit, "any(", "", ")");
1550 break;
1551 case EOpAll:
1552 outputTriplet(out, visit, "all(", "", ")");
1553 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001554 case EOpLogicalNotComponentWise:
1555 outputTriplet(out, visit, "(!", "", ")");
1556 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001557 case EOpBitfieldReverse:
1558 outputTriplet(out, visit, "reversebits(", "", ")");
1559 break;
1560 case EOpBitCount:
1561 outputTriplet(out, visit, "countbits(", "", ")");
1562 break;
1563 case EOpFindLSB:
1564 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1565 // in GLSLTest and results are consistent with GL.
1566 outputTriplet(out, visit, "firstbitlow(", "", ")");
1567 break;
1568 case EOpFindMSB:
1569 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1570 // tested in GLSLTest and results are consistent with GL.
1571 outputTriplet(out, visit, "firstbithigh(", "", ")");
1572 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001573 default:
1574 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001575 }
1576
1577 return true;
1578}
1579
Olli Etuaho96963162016-03-21 11:54:33 +02001580TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1581{
1582 if (node->getAsSymbolNode())
1583 {
1584 return node->getAsSymbolNode()->getSymbol();
1585 }
1586 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1587 switch (nodeBinary->getOp())
1588 {
1589 case EOpIndexDirect:
1590 {
1591 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1592
1593 TInfoSinkBase prefixSink;
1594 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1595 return TString(prefixSink.c_str());
1596 }
1597 case EOpIndexDirectStruct:
1598 {
1599 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1600 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1601 const TField *field = s->fields()[index];
1602
1603 TInfoSinkBase prefixSink;
1604 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1605 << field->name();
1606 return TString(prefixSink.c_str());
1607 }
1608 default:
1609 UNREACHABLE();
1610 return TString("");
1611 }
1612}
1613
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001614bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1615{
1616 TInfoSinkBase &out = getInfoSink();
1617
1618 if (mInsideFunction)
1619 {
1620 outputLineDirective(out, node->getLine().first_line);
1621 out << "{\n";
1622 }
1623
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001624 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001625 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001626 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001627
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001628 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001629
1630 // Don't output ; after case labels, they're terminated by :
1631 // This is needed especially since outputting a ; after a case statement would turn empty
1632 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001633 // Also the output code is clearer if we don't output ; after statements where it is not
1634 // needed:
1635 // * if statements
1636 // * switch statements
1637 // * blocks
1638 // * function definitions
1639 // * loops (do-while loops output the semicolon in VisitLoop)
1640 // * declarations that don't generate output.
1641 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1642 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1643 statement->getAsSwitchNode() == nullptr &&
1644 statement->getAsFunctionDefinition() == nullptr &&
1645 (statement->getAsDeclarationNode() == nullptr ||
1646 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1647 statement->getAsInvariantDeclarationNode() == nullptr)
1648 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001649 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001650 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001651 }
1652
1653 if (mInsideFunction)
1654 {
1655 outputLineDirective(out, node->getLine().last_line);
1656 out << "}\n";
1657 }
1658
1659 return false;
1660}
1661
Olli Etuaho336b1472016-10-05 16:37:55 +01001662bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1663{
1664 TInfoSinkBase &out = getInfoSink();
1665
1666 ASSERT(mCurrentFunctionMetadata == nullptr);
1667
1668 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1669 ASSERT(index != CallDAG::InvalidIndex);
1670 mCurrentFunctionMetadata = &mASTMetadataList[index];
1671
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001672 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001673
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001674 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001675
1676 if (node->getFunctionSymbolInfo()->isMain())
1677 {
1678 out << "gl_main(";
1679 }
1680 else
1681 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001682 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001683 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1684 }
1685
1686 for (unsigned int i = 0; i < parameters->size(); i++)
1687 {
1688 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1689
1690 if (symbol)
1691 {
1692 ensureStructDefined(symbol->getType());
1693
1694 out << argumentString(symbol);
1695
1696 if (i < parameters->size() - 1)
1697 {
1698 out << ", ";
1699 }
1700 }
1701 else
1702 UNREACHABLE();
1703 }
1704
1705 out << ")\n";
1706
1707 mInsideFunction = true;
1708 // The function body node will output braces.
1709 node->getBody()->traverse(this);
1710 mInsideFunction = false;
1711
1712 mCurrentFunctionMetadata = nullptr;
1713
1714 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1715 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1716 {
1717 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1718 mOutputLod0Function = true;
1719 node->traverse(this);
1720 mOutputLod0Function = false;
1721 }
1722
1723 return false;
1724}
1725
Olli Etuaho13389b62016-10-16 11:48:18 +01001726bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1727{
Olli Etuaho13389b62016-10-16 11:48:18 +01001728 if (visit == PreVisit)
1729 {
1730 TIntermSequence *sequence = node->getSequence();
1731 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1732 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001733 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001734
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001735 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001736 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001737 TInfoSinkBase &out = getInfoSink();
Olli Etuaho13389b62016-10-16 11:48:18 +01001738 ensureStructDefined(variable->getType());
1739
1740 if (!variable->getAsSymbolNode() ||
1741 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1742 {
1743 if (!mInsideFunction)
1744 {
1745 out << "static ";
1746 }
1747
1748 out << TypeString(variable->getType()) + " ";
1749
1750 TIntermSymbol *symbol = variable->getAsSymbolNode();
1751
1752 if (symbol)
1753 {
1754 symbol->traverse(this);
1755 out << ArrayString(symbol->getType());
1756 out << " = " + initializer(symbol->getType());
1757 }
1758 else
1759 {
1760 variable->traverse(this);
1761 }
1762 }
1763 else if (variable->getAsSymbolNode() &&
1764 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1765 {
1766 // Already added to constructor map
1767 }
1768 else
1769 UNREACHABLE();
1770 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001771 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001772 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001773 TIntermSymbol *symbol = variable->getAsSymbolNode();
1774 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001775
Olli Etuaho282847e2017-07-12 14:11:01 +03001776 // Vertex outputs which are declared but not written to should still be declared to
1777 // allow successful linking.
1778 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001779 }
1780 }
1781 return false;
1782}
1783
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001784bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1785{
1786 // Do not do any translation
1787 return false;
1788}
1789
Olli Etuaho16c745a2017-01-16 17:02:27 +00001790bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1791{
1792 TInfoSinkBase &out = getInfoSink();
1793
1794 ASSERT(visit == PreVisit);
1795 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1796 // Skip the prototype if it is not implemented (and thus not used)
1797 if (index == CallDAG::InvalidIndex)
1798 {
1799 return false;
1800 }
1801
1802 TIntermSequence *arguments = node->getSequence();
1803
Olli Etuahoff526f12017-06-30 12:26:54 +03001804 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001805 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1806 << (mOutputLod0Function ? "Lod0(" : "(");
1807
1808 for (unsigned int i = 0; i < arguments->size(); i++)
1809 {
1810 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1811 ASSERT(symbol != nullptr);
1812
1813 out << argumentString(symbol);
1814
1815 if (i < arguments->size() - 1)
1816 {
1817 out << ", ";
1818 }
1819 }
1820
1821 out << ");\n";
1822
1823 // Also prototype the Lod0 variant if needed
1824 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1825 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1826 {
1827 mOutputLod0Function = true;
1828 node->traverse(this);
1829 mOutputLod0Function = false;
1830 }
1831
1832 return false;
1833}
1834
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001835bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1836{
Jamie Madill32aab012015-01-27 14:12:26 -05001837 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001838
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001839 switch (node->getOp())
1840 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001841 case EOpCallBuiltInFunction:
1842 case EOpCallFunctionInAST:
1843 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001844 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001845 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001846
Corentin Wallez1239ee92015-03-19 14:38:02 -07001847 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001848 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001849 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001850 if (node->isArray())
1851 {
1852 UNIMPLEMENTED();
1853 }
Olli Etuahobd674552016-10-06 13:28:42 +01001854 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001855 ASSERT(index != CallDAG::InvalidIndex);
1856 lod0 &= mASTMetadataList[index].mNeedsLod0;
1857
Olli Etuahoff526f12017-06-30 12:26:54 +03001858 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001859 out << DisambiguateFunctionName(node->getSequence());
1860 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001861 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001862 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001863 {
1864 // This path is used for internal functions that don't have their definitions in the
1865 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001866 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001867 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001868 else
1869 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001870 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001871 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001872 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1873 if (arguments->size() > 1)
1874 {
1875 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1876 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001877 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1878 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1879 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001880 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001881
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001882 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001883 {
Olli Etuaho96963162016-03-21 11:54:33 +02001884 TIntermTyped *typedArg = (*arg)->getAsTyped();
1885 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001886 {
1887 out << "texture_";
1888 (*arg)->traverse(this);
1889 out << ", sampler_";
1890 }
1891
1892 (*arg)->traverse(this);
1893
Olli Etuaho96963162016-03-21 11:54:33 +02001894 if (typedArg->getType().isStructureContainingSamplers())
1895 {
1896 const TType &argType = typedArg->getType();
1897 TVector<TIntermSymbol *> samplerSymbols;
1898 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001899 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1900 nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02001901 for (const TIntermSymbol *sampler : samplerSymbols)
1902 {
1903 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1904 {
1905 out << ", texture_" << sampler->getSymbol();
1906 out << ", sampler_" << sampler->getSymbol();
1907 }
1908 else
1909 {
1910 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1911 // of D3D9, it's the sampler variable.
1912 out << ", " + sampler->getSymbol();
1913 }
1914 }
1915 }
1916
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001917 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001918 {
1919 out << ", ";
1920 }
1921 }
1922
1923 out << ")";
1924
1925 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001926 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001927 case EOpConstruct:
1928 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001929 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001930 if (node->getType().isArray())
1931 {
1932 UNIMPLEMENTED();
1933 }
1934 const TString &structName = StructNameString(*node->getType().getStruct());
1935 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1936 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001937 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001938 else
1939 {
1940 const char *name = "";
1941 if (node->getType().getNominalSize() == 1)
1942 {
1943 switch (node->getBasicType())
1944 {
1945 case EbtFloat:
1946 name = "vec1";
1947 break;
1948 case EbtInt:
1949 name = "ivec1";
1950 break;
1951 case EbtUInt:
1952 name = "uvec1";
1953 break;
1954 case EbtBool:
1955 name = "bvec1";
1956 break;
1957 default:
1958 UNREACHABLE();
1959 }
1960 }
1961 else
1962 {
1963 name = node->getType().getBuiltInTypeNameString();
1964 }
1965 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1966 }
1967 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001968 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001969 outputTriplet(out, visit, "(", " == ", ")");
1970 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001971 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001972 outputTriplet(out, visit, "(", " != ", ")");
1973 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001974 case EOpLessThanComponentWise:
1975 outputTriplet(out, visit, "(", " < ", ")");
1976 break;
1977 case EOpGreaterThanComponentWise:
1978 outputTriplet(out, visit, "(", " > ", ")");
1979 break;
1980 case EOpLessThanEqualComponentWise:
1981 outputTriplet(out, visit, "(", " <= ", ")");
1982 break;
1983 case EOpGreaterThanEqualComponentWise:
1984 outputTriplet(out, visit, "(", " >= ", ")");
1985 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001986 case EOpMod:
1987 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001988 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001989 break;
1990 case EOpModf:
1991 outputTriplet(out, visit, "modf(", ", ", ")");
1992 break;
1993 case EOpPow:
1994 outputTriplet(out, visit, "pow(", ", ", ")");
1995 break;
1996 case EOpAtan:
1997 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1998 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001999 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002000 break;
2001 case EOpMin:
2002 outputTriplet(out, visit, "min(", ", ", ")");
2003 break;
2004 case EOpMax:
2005 outputTriplet(out, visit, "max(", ", ", ")");
2006 break;
2007 case EOpClamp:
2008 outputTriplet(out, visit, "clamp(", ", ", ")");
2009 break;
2010 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302011 {
2012 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2013 if (lastParamNode->getType().getBasicType() == EbtBool)
2014 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002015 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2016 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302017 // so use emulated version.
2018 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002019 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302020 }
2021 else
2022 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002023 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302024 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002025 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302026 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002027 case EOpStep:
2028 outputTriplet(out, visit, "step(", ", ", ")");
2029 break;
2030 case EOpSmoothStep:
2031 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2032 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002033 case EOpFrexp:
2034 case EOpLdexp:
2035 ASSERT(node->getUseEmulatedFunction());
2036 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2037 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002038 case EOpDistance:
2039 outputTriplet(out, visit, "distance(", ", ", ")");
2040 break;
2041 case EOpDot:
2042 outputTriplet(out, visit, "dot(", ", ", ")");
2043 break;
2044 case EOpCross:
2045 outputTriplet(out, visit, "cross(", ", ", ")");
2046 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002047 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002048 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002049 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002050 break;
2051 case EOpReflect:
2052 outputTriplet(out, visit, "reflect(", ", ", ")");
2053 break;
2054 case EOpRefract:
2055 outputTriplet(out, visit, "refract(", ", ", ")");
2056 break;
2057 case EOpOuterProduct:
2058 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002059 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002060 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002061 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002062 outputTriplet(out, visit, "(", " * ", ")");
2063 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002064 case EOpBitfieldExtract:
2065 case EOpBitfieldInsert:
2066 case EOpUaddCarry:
2067 case EOpUsubBorrow:
2068 case EOpUmulExtended:
2069 case EOpImulExtended:
2070 ASSERT(node->getUseEmulatedFunction());
2071 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2072 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002073 default:
2074 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002075 }
2076
2077 return true;
2078}
2079
Olli Etuaho57961272016-09-14 13:57:46 +03002080void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002082 out << "if (";
2083
2084 node->getCondition()->traverse(this);
2085
2086 out << ")\n";
2087
Jamie Madill8c46ab12015-12-07 16:39:19 -05002088 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002089
2090 bool discard = false;
2091
2092 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002093 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002094 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002095 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002096
Olli Etuahoa6f22092015-05-08 18:31:10 +03002097 // Detect true discard
2098 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2099 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002100 else
2101 {
2102 // TODO(oetuaho): Check if the semicolon inside is necessary.
2103 // It's there as a result of conservative refactoring of the output.
2104 out << "{;}\n";
2105 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002106
Jamie Madill8c46ab12015-12-07 16:39:19 -05002107 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002108
Olli Etuahoa6f22092015-05-08 18:31:10 +03002109 if (node->getFalseBlock())
2110 {
2111 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002112
Jamie Madill8c46ab12015-12-07 16:39:19 -05002113 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002114
Olli Etuaho32db19b2016-10-04 14:43:16 +01002115 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002116 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002117
Jamie Madill8c46ab12015-12-07 16:39:19 -05002118 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002119
Olli Etuahoa6f22092015-05-08 18:31:10 +03002120 // Detect false discard
2121 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2122 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002123
Olli Etuahoa6f22092015-05-08 18:31:10 +03002124 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002125 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002126 {
2127 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002128 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002129}
2130
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002131bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2132{
2133 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2134 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2135 UNREACHABLE();
2136 return false;
2137}
2138
Olli Etuaho57961272016-09-14 13:57:46 +03002139bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002140{
2141 TInfoSinkBase &out = getInfoSink();
2142
Olli Etuaho3d932d82016-04-12 11:10:30 +03002143 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002144
2145 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002146 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002147 {
2148 out << "FLATTEN ";
2149 }
2150
Olli Etuaho57961272016-09-14 13:57:46 +03002151 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152
2153 return false;
2154}
2155
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002156bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002157{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002158 TInfoSinkBase &out = getInfoSink();
2159
Olli Etuaho923ecef2017-10-11 12:01:38 +03002160 ASSERT(node->getStatementList());
2161 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002162 {
Olli Etuaho923ecef2017-10-11 12:01:38 +03002163 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList()));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002164 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002165 outputTriplet(out, visit, "switch (", ") ", "");
2166 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002167 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002168}
2169
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002170bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002171{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002172 TInfoSinkBase &out = getInfoSink();
2173
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002174 if (node->hasCondition())
2175 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002176 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002177 return true;
2178 }
2179 else
2180 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002181 out << "default:\n";
2182 return false;
2183 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002184}
2185
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002186void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2187{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002188 TInfoSinkBase &out = getInfoSink();
2189 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002190}
2191
2192bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2193{
Nicolas Capens655fe362014-04-11 13:12:34 -04002194 mNestedLoopDepth++;
2195
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002196 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002197 mInsideDiscontinuousLoop =
2198 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002199
Jamie Madill8c46ab12015-12-07 16:39:19 -05002200 TInfoSinkBase &out = getInfoSink();
2201
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002202 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002203 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002204 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002205 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002206 mInsideDiscontinuousLoop = wasDiscontinuous;
2207 mNestedLoopDepth--;
2208
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002209 return false;
2210 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002211 }
2212
Corentin Wallez1239ee92015-03-19 14:38:02 -07002213 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002214 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002215 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002216 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002217
Jamie Madill8c46ab12015-12-07 16:39:19 -05002218 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
2220 else
2221 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002222 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002223
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002224 if (node->getInit())
2225 {
2226 node->getInit()->traverse(this);
2227 }
2228
2229 out << "; ";
2230
alokp@chromium.org52813552010-11-16 18:36:09 +00002231 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002232 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002233 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002234 }
2235
2236 out << "; ";
2237
alokp@chromium.org52813552010-11-16 18:36:09 +00002238 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002239 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002240 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241 }
2242
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002243 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002244
Jamie Madill8c46ab12015-12-07 16:39:19 -05002245 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002246 }
2247
2248 if (node->getBody())
2249 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002250 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002251 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002252 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002253 else
2254 {
2255 // TODO(oetuaho): Check if the semicolon inside is necessary.
2256 // It's there as a result of conservative refactoring of the output.
2257 out << "{;}\n";
2258 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002259
Jamie Madill8c46ab12015-12-07 16:39:19 -05002260 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002261
alokp@chromium.org52813552010-11-16 18:36:09 +00002262 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002263 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002264 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002265 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002266
alokp@chromium.org52813552010-11-16 18:36:09 +00002267 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002268
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002269 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002270 }
2271
daniel@transgaming.com73536982012-03-21 20:45:49 +00002272 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002273
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002274 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002275 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002276
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002277 return false;
2278}
2279
2280bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2281{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002282 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002283 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002284 TInfoSinkBase &out = getInfoSink();
2285
2286 switch (node->getFlowOp())
2287 {
2288 case EOpKill:
2289 out << "discard";
2290 break;
2291 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002292 if (mNestedLoopDepth > 1)
2293 {
2294 mUsesNestedBreak = true;
2295 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002296
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002297 if (mExcessiveLoopIndex)
2298 {
2299 out << "{Break";
2300 mExcessiveLoopIndex->traverse(this);
2301 out << " = true; break;}\n";
2302 }
2303 else
2304 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002305 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002306 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002307 break;
2308 case EOpContinue:
2309 out << "continue";
2310 break;
2311 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002312 if (node->getExpression())
2313 {
2314 out << "return ";
2315 }
2316 else
2317 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002318 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002319 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002320 break;
2321 default:
2322 UNREACHABLE();
2323 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002324 }
2325
2326 return true;
2327}
2328
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002329// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002330// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2331// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002332bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002333{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002334 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002335
2336 // Parse loops of the form:
2337 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002338 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002339 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002340 int initial = 0;
2341 int limit = 0;
2342 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002343
2344 // Parse index name and intial value
2345 if (node->getInit())
2346 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002347 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002348
2349 if (init)
2350 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002351 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002352 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002353
2354 if (variable && variable->getQualifier() == EvqTemporary)
2355 {
2356 TIntermBinary *assign = variable->getAsBinaryNode();
2357
2358 if (assign->getOp() == EOpInitialize)
2359 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002360 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002361 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2362
2363 if (symbol && constant)
2364 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002365 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002366 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002367 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002368 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002369 }
2370 }
2371 }
2372 }
2373 }
2374 }
2375
2376 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002377 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002378 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002379 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002380
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002381 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2382 {
2383 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2384
2385 if (constant)
2386 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002387 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002388 {
2389 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002390 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002391 }
2392 }
2393 }
2394 }
2395
2396 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002397 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002398 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002399 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002400 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002401
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002402 if (binaryTerminal)
2403 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002404 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002405 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2406
2407 if (constant)
2408 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002409 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002410 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002411 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002412
2413 switch (op)
2414 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002415 case EOpAddAssign:
2416 increment = value;
2417 break;
2418 case EOpSubAssign:
2419 increment = -value;
2420 break;
2421 default:
2422 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002423 }
2424 }
2425 }
2426 }
2427 else if (unaryTerminal)
2428 {
2429 TOperator op = unaryTerminal->getOp();
2430
2431 switch (op)
2432 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002433 case EOpPostIncrement:
2434 increment = 1;
2435 break;
2436 case EOpPostDecrement:
2437 increment = -1;
2438 break;
2439 case EOpPreIncrement:
2440 increment = 1;
2441 break;
2442 case EOpPreDecrement:
2443 increment = -1;
2444 break;
2445 default:
2446 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002447 }
2448 }
2449 }
2450
Yunchao He4f285442017-04-21 12:15:49 +08002451 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002452 {
2453 if (comparator == EOpLessThanEqual)
2454 {
2455 comparator = EOpLessThan;
2456 limit += 1;
2457 }
2458
2459 if (comparator == EOpLessThan)
2460 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002461 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002462
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002463 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002464 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002465 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002466 }
2467
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002468 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002469 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002470
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002471 out << "{int ";
2472 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002473 out << ";\n"
2474 "bool Break";
2475 index->traverse(this);
2476 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002477
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002478 bool firstLoopFragment = true;
2479
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002480 while (iterations > 0)
2481 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002482 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002483
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002484 if (!firstLoopFragment)
2485 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002486 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002487 index->traverse(this);
2488 out << ") {\n";
2489 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002490
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002491 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002492 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002493 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002494 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002495
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002496 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002497 const char *unroll =
2498 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002499
Corentin Wallez1239ee92015-03-19 14:38:02 -07002500 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002501 index->traverse(this);
2502 out << " = ";
2503 out << initial;
2504
2505 out << "; ";
2506 index->traverse(this);
2507 out << " < ";
2508 out << clampedLimit;
2509
2510 out << "; ";
2511 index->traverse(this);
2512 out << " += ";
2513 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002514 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002515
Jamie Madill8c46ab12015-12-07 16:39:19 -05002516 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002517 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002518
2519 if (node->getBody())
2520 {
2521 node->getBody()->traverse(this);
2522 }
2523
Jamie Madill8c46ab12015-12-07 16:39:19 -05002524 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002525 out << ";}\n";
2526
2527 if (!firstLoopFragment)
2528 {
2529 out << "}\n";
2530 }
2531
2532 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002534 initial += MAX_LOOP_ITERATIONS * increment;
2535 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002536 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002537
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002538 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002539
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002540 mExcessiveLoopIndex = restoreIndex;
2541
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002542 return true;
2543 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002544 else
2545 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002546 }
2547
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002548 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002549}
2550
Jamie Madill8c46ab12015-12-07 16:39:19 -05002551void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2552 Visit visit,
2553 const char *preString,
2554 const char *inString,
2555 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002556{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002557 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002558 {
2559 out << preString;
2560 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002561 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002562 {
2563 out << inString;
2564 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002565 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002566 {
2567 out << postString;
2568 }
2569}
2570
Jamie Madill8c46ab12015-12-07 16:39:19 -05002571void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002572{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002573 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002574 {
Jamie Madill32aab012015-01-27 14:12:26 -05002575 out << "\n";
2576 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002577
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002578 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002579 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002580 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002581 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002582
Jamie Madill32aab012015-01-27 14:12:26 -05002583 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002584 }
2585}
2586
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002587TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2588{
2589 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002590 const TType &type = symbol->getType();
2591 const TName &name = symbol->getName();
2592 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002593
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002594 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002595 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002596 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002597 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002598 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002599 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002600 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002601 }
2602
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002603 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002604 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002605 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2606 {
2607 // Samplers are passed as indices to the sampler array.
2608 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2609 return "const uint " + nameStr + ArrayString(type);
2610 }
2611 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2612 {
2613 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2614 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2615 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2616 ArrayString(type);
2617 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002618 }
2619
Olli Etuaho96963162016-03-21 11:54:33 +02002620 TStringStream argString;
2621 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2622 << ArrayString(type);
2623
2624 // If the structure parameter contains samplers, they need to be passed into the function as
2625 // separate parameters. HLSL doesn't natively support samplers in structs.
2626 if (type.isStructureContainingSamplers())
2627 {
2628 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2629 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002630 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02002631 for (const TIntermSymbol *sampler : samplerSymbols)
2632 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002633 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002634 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2635 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002636 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002637 }
2638 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2639 {
Olli Etuaho96963162016-03-21 11:54:33 +02002640 ASSERT(IsSampler(samplerType.getBasicType()));
2641 argString << ", " << QualifierString(qualifier) << " "
2642 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002643 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2644 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002645 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002646 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002647 }
2648 else
2649 {
Olli Etuaho96963162016-03-21 11:54:33 +02002650 ASSERT(IsSampler(samplerType.getBasicType()));
2651 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002652 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002653 }
2654 }
2655 }
2656
2657 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002658}
2659
2660TString OutputHLSL::initializer(const TType &type)
2661{
2662 TString string;
2663
Jamie Madill94bf7f22013-07-08 13:31:15 -04002664 size_t size = type.getObjectSize();
2665 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002666 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002667 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002668
Jamie Madill94bf7f22013-07-08 13:31:15 -04002669 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002670 {
2671 string += ", ";
2672 }
2673 }
2674
daniel@transgaming.comead23042010-04-29 03:35:36 +00002675 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002676}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002677
Jamie Madill8c46ab12015-12-07 16:39:19 -05002678void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2679 Visit visit,
2680 const TType &type,
2681 const char *name,
2682 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002683{
Olli Etuahof40319e2015-03-10 14:33:00 +02002684 if (type.isArray())
2685 {
2686 UNIMPLEMENTED();
2687 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002688
2689 if (visit == PreVisit)
2690 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002691 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002692
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002693 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002694 }
2695 else if (visit == InVisit)
2696 {
2697 out << ", ";
2698 }
2699 else if (visit == PostVisit)
2700 {
2701 out << ")";
2702 }
2703}
2704
Jamie Madill8c46ab12015-12-07 16:39:19 -05002705const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2706 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002707 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002708{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002709 const TConstantUnion *constUnionIterated = constUnion;
2710
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002711 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002712 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002713 {
Jamie Madill033dae62014-06-18 12:56:28 -04002714 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002715
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002716 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002717
Jamie Madill98493dd2013-07-08 14:39:03 -04002718 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002719 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002720 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002721 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002722
Jamie Madill98493dd2013-07-08 14:39:03 -04002723 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002724 {
2725 out << ", ";
2726 }
2727 }
2728
2729 out << ")";
2730 }
2731 else
2732 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002733 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002734 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002735
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002736 if (writeType)
2737 {
Jamie Madill033dae62014-06-18 12:56:28 -04002738 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002739 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002740 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002741 if (writeType)
2742 {
2743 out << ")";
2744 }
2745 }
2746
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002747 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002748}
2749
Olli Etuahod68924e2017-01-02 17:34:40 +00002750void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002751{
Olli Etuahod68924e2017-01-02 17:34:40 +00002752 if (visit == PreVisit)
2753 {
2754 const char *opStr = GetOperatorString(op);
2755 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2756 out << "(";
2757 }
2758 else
2759 {
2760 outputTriplet(out, visit, nullptr, ", ", ")");
2761 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002762}
2763
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002764bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2765 TIntermSymbol *symbolNode,
2766 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002767{
2768 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2769 expression->traverse(&searchSymbol);
2770
2771 if (searchSymbol.foundMatch())
2772 {
2773 // Type already printed
2774 out << "t" + str(mUniqueIndex) + " = ";
2775 expression->traverse(this);
2776 out << ", ";
2777 symbolNode->traverse(this);
2778 out << " = t" + str(mUniqueIndex);
2779
2780 mUniqueIndex++;
2781 return true;
2782 }
2783
2784 return false;
2785}
2786
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002787bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2788{
2789 // We support writing constant unions and constructors that only take constant unions as
2790 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002791 return !expression->getType().isArrayOfArrays() &&
2792 (expression->getAsConstantUnion() ||
2793 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002794}
2795
2796bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2797 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002798 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002799{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002800 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002801 {
2802 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002803 ASSERT(!symbolNode->getType().isArrayOfArrays());
2804 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002805 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002806 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002807 }
2808 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002809 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002810 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002811 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002812 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002813 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002814 }
2815 else
2816 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002817 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002818 ASSERT(constructor != nullptr);
2819 for (TIntermNode *&node : *constructor->getSequence())
2820 {
2821 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2822 ASSERT(nodeConst);
2823 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002824 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002825 if (node != constructor->getSequence()->back())
2826 {
2827 out << ", ";
2828 }
2829 }
2830 }
2831 out << "}";
2832 return true;
2833 }
2834 return false;
2835}
2836
Jamie Madill55e79e02015-02-09 15:35:00 -05002837TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2838{
2839 const TFieldList &fields = structure.fields();
2840
2841 for (const auto &eqFunction : mStructEqualityFunctions)
2842 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002843 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002844 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002845 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002846 }
2847 }
2848
2849 const TString &structNameString = StructNameString(structure);
2850
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002851 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002852 function->structure = &structure;
2853 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002854
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002855 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002856
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002857 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2858 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002859 << "{\n"
2860 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002861
2862 for (size_t i = 0; i < fields.size(); i++)
2863 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002864 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002865 const TType *fieldType = field->type();
2866
2867 const TString &fieldNameA = "a." + Decorate(field->name());
2868 const TString &fieldNameB = "b." + Decorate(field->name());
2869
2870 if (i > 0)
2871 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002872 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002873 }
2874
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002875 fnOut << "(";
2876 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2877 fnOut << fieldNameA;
2878 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2879 fnOut << fieldNameB;
2880 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2881 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002882 }
2883
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002884 fnOut << ";\n"
2885 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002886
2887 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002888
2889 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002890 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002891
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002892 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002893}
2894
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002895TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002896{
2897 for (const auto &eqFunction : mArrayEqualityFunctions)
2898 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002899 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002900 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002901 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002902 }
2903 }
2904
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002905 TType elementType(type);
2906 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002907
Olli Etuaho12690762015-03-31 12:55:28 +03002908 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002909 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002910
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002911 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002912
2913 TInfoSinkBase fnOut;
2914
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002915 const TString &typeName = TypeString(type);
2916 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2917 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002918 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002919 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002920 << type.getOutermostArraySize()
2921 << "; ++i)\n"
2922 " {\n"
2923 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002924
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002925 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002926 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002927 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002928 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002929 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002930
2931 fnOut << ") { return false; }\n"
2932 " }\n"
2933 " return true;\n"
2934 "}\n";
2935
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002936 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002937
2938 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002939 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002940
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002941 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002942}
2943
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002944TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002945{
2946 for (const auto &assignFunction : mArrayAssignmentFunctions)
2947 {
2948 if (assignFunction.type == type)
2949 {
2950 return assignFunction.functionName;
2951 }
2952 }
2953
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 TType elementType(type);
2955 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002956
2957 ArrayHelperFunction function;
2958 function.type = type;
2959
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002960 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002961
2962 TInfoSinkBase fnOut;
2963
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002964 const TString &typeName = TypeString(type);
2965 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2966 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002967 << "{\n"
2968 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002969 << type.getOutermostArraySize()
2970 << "; ++i)\n"
2971 " {\n"
2972 " ";
2973
2974 outputAssign(PreVisit, elementType, fnOut);
2975 fnOut << "a[i]";
2976 outputAssign(InVisit, elementType, fnOut);
2977 fnOut << "b[i]";
2978 outputAssign(PostVisit, elementType, fnOut);
2979
2980 fnOut << ";\n"
2981 " }\n"
2982 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002983
2984 function.functionDefinition = fnOut.c_str();
2985
2986 mArrayAssignmentFunctions.push_back(function);
2987
2988 return function.functionName;
2989}
2990
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002991TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002992{
2993 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2994 {
2995 if (constructIntoFunction.type == type)
2996 {
2997 return constructIntoFunction.functionName;
2998 }
2999 }
3000
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003001 TType elementType(type);
3002 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003003
3004 ArrayHelperFunction function;
3005 function.type = type;
3006
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003007 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003008
3009 TInfoSinkBase fnOut;
3010
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003011 const TString &typeName = TypeString(type);
3012 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3013 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003014 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003015 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003016 }
3017 fnOut << ")\n"
3018 "{\n";
3019
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003020 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003021 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003022 fnOut << " ";
3023 outputAssign(PreVisit, elementType, fnOut);
3024 fnOut << "a[" << i << "]";
3025 outputAssign(InVisit, elementType, fnOut);
3026 fnOut << "b" << i;
3027 outputAssign(PostVisit, elementType, fnOut);
3028 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003029 }
3030 fnOut << "}\n";
3031
3032 function.functionDefinition = fnOut.c_str();
3033
3034 mArrayConstructIntoFunctions.push_back(function);
3035
3036 return function.functionName;
3037}
3038
Jamie Madill2e295e22015-04-29 10:41:33 -04003039void OutputHLSL::ensureStructDefined(const TType &type)
3040{
3041 TStructure *structure = type.getStruct();
3042
3043 if (structure)
3044 {
3045 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3046 }
3047}
3048
Jamie Madill45bcc782016-11-07 13:58:48 -05003049} // namespace sh