blob: 13a7016b68f01be5dcdb37d7a75e01506ebe61cc [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"
Xinghua Cao711b7a12017-10-09 13:38:12 +080019#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/InfoSink.h"
21#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020022#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/SearchSymbol.h"
24#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030025#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050027#include "compiler/translator/UniformHLSL.h"
28#include "compiler/translator/UtilsHLSL.h"
29#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050030#include "compiler/translator/util.h"
31
Jamie Madill45bcc782016-11-07 13:58:48 -050032namespace sh
33{
34
Olli Etuaho96f6adf2017-08-16 11:18:54 +030035namespace
36{
37
38TString ArrayHelperFunctionName(const char *prefix, const TType &type)
39{
40 TStringStream fnName;
41 fnName << prefix << "_";
42 for (unsigned int arraySize : type.getArraySizes())
43 {
44 fnName << arraySize << "_";
45 }
46 fnName << TypeString(type);
47 return fnName.str();
48}
49
Olli Etuaho40dbdd62017-10-13 13:34:19 +030050bool IsDeclarationWrittenOut(TIntermDeclaration *node)
51{
52 TIntermSequence *sequence = node->getSequence();
53 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
54 ASSERT(sequence->size() == 1);
55 ASSERT(variable);
56 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
57 variable->getQualifier() == EvqConst);
58}
59
Olli Etuaho96f6adf2017-08-16 11:18:54 +030060} // anonymous namespace
61
Olli Etuaho56a2f952016-12-08 12:16:27 +000062void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030063{
Olli Etuaho56a2f952016-12-08 12:16:27 +000064 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
65 // regardless.
66 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
67 mOutputType == SH_HLSL_4_1_OUTPUT)
68 {
69 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
70 }
71 else
72 {
73 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
74 }
75}
Olli Etuaho4785fec2015-05-18 16:09:37 +030076
Olli Etuaho56a2f952016-12-08 12:16:27 +000077void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020078{
79 ASSERT(constUnion != nullptr);
80 switch (constUnion->getType())
81 {
82 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000083 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020084 break;
85 case EbtInt:
86 out << constUnion->getIConst();
87 break;
88 case EbtUInt:
89 out << constUnion->getUConst();
90 break;
91 case EbtBool:
92 out << constUnion->getBConst();
93 break;
94 default:
95 UNREACHABLE();
96 }
97}
98
Olli Etuaho56a2f952016-12-08 12:16:27 +000099const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
100 const TConstantUnion *const constUnion,
101 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200102{
103 const TConstantUnion *constUnionIterated = constUnion;
104 for (size_t i = 0; i < size; i++, constUnionIterated++)
105 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000106 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200107
108 if (i != size - 1)
109 {
110 out << ", ";
111 }
112 }
113 return constUnionIterated;
114}
115
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800116OutputHLSL::OutputHLSL(sh::GLenum shaderType,
117 int shaderVersion,
118 const TExtensionBehavior &extensionBehavior,
119 const char *sourcePath,
120 ShShaderOutput outputType,
121 int numRenderTargets,
122 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300123 ShCompileOptions compileOptions,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300124 TSymbolTable *symbolTable,
125 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300126 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200127 mShaderType(shaderType),
128 mShaderVersion(shaderVersion),
129 mExtensionBehavior(extensionBehavior),
130 mSourcePath(sourcePath),
131 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700132 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000133 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300134 mCurrentFunctionMetadata(nullptr),
135 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000137 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000138
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 mUsesFragColor = false;
140 mUsesFragData = false;
141 mUsesDepthRange = false;
142 mUsesFragCoord = false;
143 mUsesPointCoord = false;
144 mUsesFrontFacing = false;
145 mUsesPointSize = false;
146 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300147 mHasMultiviewExtensionEnabled =
148 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300149 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500150 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500151 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800152 mUsesNumWorkGroups = false;
153 mUsesWorkGroupID = false;
154 mUsesLocalInvocationID = false;
155 mUsesGlobalInvocationID = false;
156 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500157 mUsesXor = false;
158 mUsesDiscardRewriting = false;
159 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530160 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000161
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000162 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000163
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500164 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000165 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500166 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000167
Yunchao Hed7297bf2017-04-19 15:27:10 +0800168 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000169
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500170 mStructureHLSL = new StructureHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800171 mUniformHLSL = new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300172 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800173 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400174
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200175 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000176 {
Arun Patole63419392015-03-13 11:51:07 +0530177 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500178 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
179 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530180 // In both cases total 3 uniform registers need to be reserved.
181 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000182 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000183
Geoff Lang00140f42016-02-03 18:47:33 +0000184 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800185 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186}
187
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000188OutputHLSL::~OutputHLSL()
189{
Jamie Madill8daaba12014-06-13 10:04:33 -0400190 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400191 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300192 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800193 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200194 for (auto &eqFunction : mStructEqualityFunctions)
195 {
196 SafeDelete(eqFunction);
197 }
198 for (auto &eqFunction : mArrayEqualityFunctions)
199 {
200 SafeDelete(eqFunction);
201 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000202}
203
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200204void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000205{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500206 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400207 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000208
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200209 BuiltInFunctionEmulator builtInFunctionEmulator;
210 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800211 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
212 {
213 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
214 mShaderVersion);
215 }
216
Olli Etuahodfa75e82017-01-23 09:43:06 -0800217 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500218
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700219 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000220 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700221 ASSERT(success == CallDAG::INITDAG_SUCCESS);
222 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700223
Jamie Madill37997142015-01-28 10:06:34 -0500224 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500225 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200226 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500227 mInfoSinkStack.pop();
228
Jamie Madill37997142015-01-28 10:06:34 -0500229 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500230 mInfoSinkStack.pop();
231
Jamie Madill32aab012015-01-27 14:12:26 -0500232 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500233 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500234 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000235
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200236 objSink << mHeader.c_str();
237 objSink << mBody.c_str();
238 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200239
Olli Etuahodfa75e82017-01-23 09:43:06 -0800240 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000241}
242
Jamie Madill570e04d2013-06-21 09:15:33 -0400243void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
244{
245 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
246 {
247 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
248
Jamie Madill32aab012015-01-27 14:12:26 -0500249 TInfoSinkBase structInfoSink;
250 mInfoSinkStack.push(&structInfoSink);
251
Jamie Madill570e04d2013-06-21 09:15:33 -0400252 // This will mark the necessary block elements as referenced
253 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500254
255 TString structName(structInfoSink.c_str());
256 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400257
258 mFlaggedStructOriginalNames[flaggedNode] = structName;
259
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500260 for (size_t pos = structName.find('.'); pos != std::string::npos;
261 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400262 {
263 structName.erase(pos, 1);
264 }
265
266 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
267 }
268}
269
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800270const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400271{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800272 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400273}
274
Jamie Madill9fe25e92014-07-18 10:33:08 -0400275const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
276{
277 return mUniformHLSL->getUniformRegisterMap();
278}
279
Olli Etuahoed049ab2017-06-30 17:38:33 +0300280TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400281{
282 TString init;
283
Olli Etuahoed049ab2017-06-30 17:38:33 +0300284 TString indentString;
285 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400286 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300287 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400288 }
289
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300292 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300293 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400294 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300295 TStringStream indexedString;
296 indexedString << name << "[" << arrayIndex << "]";
297 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300298 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300300 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300301 {
302 init += ",";
303 }
304 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400305 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300306 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400307 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300308 else if (type.getBasicType() == EbtStruct)
309 {
310 init += indentString + "{\n";
311 const TStructure &structure = *type.getStruct();
312 const TFieldList &fields = structure.fields();
313 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
314 {
315 const TField &field = *fields[fieldIndex];
316 const TString &fieldName = name + "." + Decorate(field.name());
317 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400318
Olli Etuahoed049ab2017-06-30 17:38:33 +0300319 init += structInitializerString(indent + 1, fieldType, fieldName);
320 if (fieldIndex < fields.size() - 1)
321 {
322 init += ",";
323 }
324 init += "\n";
325 }
326 init += indentString + "}";
327 }
328 else
329 {
330 init += indentString + name;
331 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400332
333 return init;
334}
335
Jamie Madill8c46ab12015-12-07 16:39:19 -0500336void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000338 TString varyings;
339 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400340 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000341
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500342 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
343 mFlaggedStructMappedNames.begin();
344 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400345 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500346 TIntermTyped *structNode = flaggedStructIt->first;
347 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400348 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400349 const TString &originalName = mFlaggedStructOriginalNames[structNode];
350
Olli Etuahoed049ab2017-06-30 17:38:33 +0300351 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
352 if (structNode->isArray())
353 {
354 flaggedStructs += ArrayString(structNode->getType());
355 }
356 flaggedStructs += " =\n";
357 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
358 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400359 }
360
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500361 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
362 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000363 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500364 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000365 const TString &name = varying->second->getSymbol();
366
367 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
369 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000370 }
371
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500372 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
373 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000374 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500375 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000376 const TString &name = attribute->second->getSymbol();
377
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500378 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
379 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000380 }
381
Jamie Madill8daaba12014-06-13 10:04:33 -0400382 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400383
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300384 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800385 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400386
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200387 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500388 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200389 out << "\n// Equality functions\n\n";
390 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500391 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200392 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200393 }
394 }
Olli Etuaho12690762015-03-31 12:55:28 +0300395 if (!mArrayAssignmentFunctions.empty())
396 {
397 out << "\n// Assignment functions\n\n";
398 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
399 {
400 out << assignmentFunction.functionDefinition << "\n";
401 }
402 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300403 if (!mArrayConstructIntoFunctions.empty())
404 {
405 out << "\n// Array constructor functions\n\n";
406 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
407 {
408 out << constructIntoFunction.functionDefinition << "\n";
409 }
410 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200411
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500412 if (mUsesDiscardRewriting)
413 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400414 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500415 }
416
Nicolas Capens655fe362014-04-11 13:12:34 -0400417 if (mUsesNestedBreak)
418 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400419 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400420 }
421
Arun Patole44efa0b2015-03-04 17:11:05 +0530422 if (mRequiresIEEEStrictCompiling)
423 {
424 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
425 }
426
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400427 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
428 "#define LOOP [loop]\n"
429 "#define FLATTEN [flatten]\n"
430 "#else\n"
431 "#define LOOP\n"
432 "#define FLATTEN\n"
433 "#endif\n";
434
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200435 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300437 const bool usingMRTExtension =
438 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000439
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000440 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500441 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400442 out << "\n";
443
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200444 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000445 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500446 for (ReferencedSymbols::const_iterator outputVariableIt =
447 mReferencedOutputVariables.begin();
448 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000449 {
Jamie Madill46131a32013-06-20 11:55:50 -0400450 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500451 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400452
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500453 out << "static " + TypeString(variableType) + " out_" + variableName +
454 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000455 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000456 }
Jamie Madill46131a32013-06-20 11:55:50 -0400457 else
458 {
459 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
460
461 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500462 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400463 for (unsigned int i = 0; i < numColorValues; i++)
464 {
465 out << " float4(0, 0, 0, 0)";
466 if (i + 1 != numColorValues)
467 {
468 out << ",";
469 }
470 out << "\n";
471 }
472
473 out << "};\n";
474 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000475
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400476 if (mUsesFragDepth)
477 {
478 out << "static float gl_Depth = 0.0;\n";
479 }
480
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000481 if (mUsesFragCoord)
482 {
483 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
484 }
485
486 if (mUsesPointCoord)
487 {
488 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
489 }
490
491 if (mUsesFrontFacing)
492 {
493 out << "static bool gl_FrontFacing = false;\n";
494 }
495
496 out << "\n";
497
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000498 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000499 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000500 out << "struct gl_DepthRangeParameters\n"
501 "{\n"
502 " float near;\n"
503 " float far;\n"
504 " float diff;\n"
505 "};\n"
506 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000507 }
508
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200509 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000510 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000511 out << "cbuffer DriverConstants : register(b1)\n"
512 "{\n";
513
514 if (mUsesDepthRange)
515 {
516 out << " float3 dx_DepthRange : packoffset(c0);\n";
517 }
518
519 if (mUsesFragCoord)
520 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000521 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000522 }
523
524 if (mUsesFragCoord || mUsesFrontFacing)
525 {
526 out << " float3 dx_DepthFront : packoffset(c2);\n";
527 }
528
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800529 if (mUsesFragCoord)
530 {
531 // dx_ViewScale is only used in the fragment shader to correct
532 // the value for glFragCoord if necessary
533 out << " float2 dx_ViewScale : packoffset(c3);\n";
534 }
535
Martin Radev72b4e1e2017-08-31 15:42:56 +0300536 if (mHasMultiviewExtensionEnabled)
537 {
538 // We have to add a value which we can use to keep track of which multi-view code
539 // path is to be selected in the GS.
540 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
541 }
542
Olli Etuaho618bebc2016-01-15 16:40:00 +0200543 if (mOutputType == SH_HLSL_4_1_OUTPUT)
544 {
545 mUniformHLSL->samplerMetadataUniforms(out, "c4");
546 }
547
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000548 out << "};\n";
549 }
550 else
551 {
552 if (mUsesDepthRange)
553 {
554 out << "uniform float3 dx_DepthRange : register(c0);";
555 }
556
557 if (mUsesFragCoord)
558 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000559 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000560 }
561
562 if (mUsesFragCoord || mUsesFrontFacing)
563 {
564 out << "uniform float3 dx_DepthFront : register(c2);\n";
565 }
566 }
567
568 out << "\n";
569
570 if (mUsesDepthRange)
571 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500572 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
573 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000574 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000575 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000576
Jamie Madillf91ce812014-06-13 10:04:34 -0400577 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000578 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400579 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000580 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400581 out << flaggedStructs;
582 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000583 }
584
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000585 if (usingMRTExtension && mNumRenderTargets > 1)
586 {
587 out << "#define GL_USES_MRT\n";
588 }
589
590 if (mUsesFragColor)
591 {
592 out << "#define GL_USES_FRAG_COLOR\n";
593 }
594
595 if (mUsesFragData)
596 {
597 out << "#define GL_USES_FRAG_DATA\n";
598 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 }
Xinghua Caob1239382016-12-13 15:07:05 +0800600 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000602 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500603 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000604 out << "\n"
605 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400606
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000607 if (mUsesPointSize)
608 {
609 out << "static float gl_PointSize = float(1);\n";
610 }
611
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000612 if (mUsesInstanceID)
613 {
614 out << "static int gl_InstanceID;";
615 }
616
Corentin Wallezb076add2016-01-11 16:45:46 -0500617 if (mUsesVertexID)
618 {
619 out << "static int gl_VertexID;";
620 }
621
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000622 out << "\n"
623 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500624 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000625 out << "\n";
626
627 if (mUsesDepthRange)
628 {
629 out << "struct gl_DepthRangeParameters\n"
630 "{\n"
631 " float near;\n"
632 " float far;\n"
633 " float diff;\n"
634 "};\n"
635 "\n";
636 }
637
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200638 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000639 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800640 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500641 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800642
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000643 if (mUsesDepthRange)
644 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800645 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000646 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800647
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800648 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
649 // shaders. However, we declare it for all shaders (including Feature Level 10+).
650 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
651 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800652 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800653 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800654 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800655
Martin Radev72b4e1e2017-08-31 15:42:56 +0300656 if (mHasMultiviewExtensionEnabled)
657 {
658 // We have to add a value which we can use to keep track of which multi-view code
659 // path is to be selected in the GS.
660 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
661 }
662
Olli Etuaho618bebc2016-01-15 16:40:00 +0200663 if (mOutputType == SH_HLSL_4_1_OUTPUT)
664 {
665 mUniformHLSL->samplerMetadataUniforms(out, "c4");
666 }
667
Austin Kinross4fd18b12014-12-22 12:32:05 -0800668 out << "};\n"
669 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000670 }
671 else
672 {
673 if (mUsesDepthRange)
674 {
675 out << "uniform float3 dx_DepthRange : register(c0);\n";
676 }
677
Cooper Partine6664f02015-01-09 16:22:24 -0800678 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
679 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000680 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000681 }
682
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000683 if (mUsesDepthRange)
684 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500685 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
686 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000687 "\n";
688 }
689
Jamie Madillf91ce812014-06-13 10:04:34 -0400690 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000691 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400692 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000693 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400694 out << flaggedStructs;
695 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000696 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400697 }
Xinghua Caob1239382016-12-13 15:07:05 +0800698 else // Compute shader
699 {
700 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800701
702 out << "cbuffer DriverConstants : register(b1)\n"
703 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800704 if (mUsesNumWorkGroups)
705 {
Xinghua Caob1239382016-12-13 15:07:05 +0800706 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800707 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800708 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
709 mUniformHLSL->samplerMetadataUniforms(out, "c1");
710 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800711
712 // Follow built-in variables would be initialized in
713 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
714 // are used in compute shader.
715 if (mUsesWorkGroupID)
716 {
717 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
718 }
719
720 if (mUsesLocalInvocationID)
721 {
722 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
723 }
724
725 if (mUsesGlobalInvocationID)
726 {
727 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
728 }
729
730 if (mUsesLocalInvocationIndex)
731 {
732 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
733 }
734 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000735
Geoff Lang1fe74c72016-08-25 13:23:01 -0400736 bool getDimensionsIgnoresBaseLevel =
737 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
738 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800739 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000741 if (mUsesFragCoord)
742 {
743 out << "#define GL_USES_FRAG_COORD\n";
744 }
745
746 if (mUsesPointCoord)
747 {
748 out << "#define GL_USES_POINT_COORD\n";
749 }
750
751 if (mUsesFrontFacing)
752 {
753 out << "#define GL_USES_FRONT_FACING\n";
754 }
755
756 if (mUsesPointSize)
757 {
758 out << "#define GL_USES_POINT_SIZE\n";
759 }
760
Martin Radev41ac68e2017-06-06 12:16:58 +0300761 if (mHasMultiviewExtensionEnabled)
762 {
763 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
764 }
765
766 if (mUsesViewID)
767 {
768 out << "#define GL_USES_VIEW_ID\n";
769 }
770
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400771 if (mUsesFragDepth)
772 {
773 out << "#define GL_USES_FRAG_DEPTH\n";
774 }
775
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000776 if (mUsesDepthRange)
777 {
778 out << "#define GL_USES_DEPTH_RANGE\n";
779 }
780
Xinghua Caob1239382016-12-13 15:07:05 +0800781 if (mUsesNumWorkGroups)
782 {
783 out << "#define GL_USES_NUM_WORK_GROUPS\n";
784 }
785
786 if (mUsesWorkGroupID)
787 {
788 out << "#define GL_USES_WORK_GROUP_ID\n";
789 }
790
791 if (mUsesLocalInvocationID)
792 {
793 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
794 }
795
796 if (mUsesGlobalInvocationID)
797 {
798 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
799 }
800
801 if (mUsesLocalInvocationIndex)
802 {
803 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
804 }
805
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000806 if (mUsesXor)
807 {
808 out << "bool xor(bool p, bool q)\n"
809 "{\n"
810 " return (p || q) && !(p && q);\n"
811 "}\n"
812 "\n";
813 }
814
Olli Etuahodfa75e82017-01-23 09:43:06 -0800815 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816}
817
818void OutputHLSL::visitSymbol(TIntermSymbol *node)
819{
Jamie Madill32aab012015-01-27 14:12:26 -0500820 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000821
Jamie Madill570e04d2013-06-21 09:15:33 -0400822 // Handle accessing std140 structs by value
823 if (mFlaggedStructMappedNames.count(node) > 0)
824 {
825 out << mFlaggedStructMappedNames[node];
826 return;
827 }
828
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829 TString name = node->getSymbol();
830
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000831 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000832 {
833 mUsesDepthRange = true;
834 out << name;
835 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836 else
837 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000838 TQualifier qualifier = node->getQualifier();
839
840 if (qualifier == EvqUniform)
841 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500842 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400843 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400844
845 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000846 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800847 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000848 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000849 else
850 {
851 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000852 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400853
Jamie Madill2e295e22015-04-29 10:41:33 -0400854 ensureStructDefined(nodeType);
855
Olli Etuahoff526f12017-06-30 12:26:54 +0300856 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000857 }
Jamie Madill19571812013-08-12 15:26:34 -0700858 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000859 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000860 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400861 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000862 }
Jamie Madill033dae62014-06-18 12:56:28 -0400863 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000864 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000865 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400866 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300867 if (name == "ViewID_OVR")
868 {
869 mUsesViewID = true;
870 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000871 }
Jamie Madill19571812013-08-12 15:26:34 -0700872 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400873 {
874 mReferencedOutputVariables[name] = node;
875 out << "out_" << name;
876 }
877 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000878 {
879 out << "gl_Color[0]";
880 mUsesFragColor = true;
881 }
882 else if (qualifier == EvqFragData)
883 {
884 out << "gl_Color";
885 mUsesFragData = true;
886 }
887 else if (qualifier == EvqFragCoord)
888 {
889 mUsesFragCoord = true;
890 out << name;
891 }
892 else if (qualifier == EvqPointCoord)
893 {
894 mUsesPointCoord = true;
895 out << name;
896 }
897 else if (qualifier == EvqFrontFacing)
898 {
899 mUsesFrontFacing = true;
900 out << name;
901 }
902 else if (qualifier == EvqPointSize)
903 {
904 mUsesPointSize = true;
905 out << name;
906 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000907 else if (qualifier == EvqInstanceID)
908 {
909 mUsesInstanceID = true;
910 out << name;
911 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500912 else if (qualifier == EvqVertexID)
913 {
914 mUsesVertexID = true;
915 out << name;
916 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300917 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400918 {
919 mUsesFragDepth = true;
920 out << "gl_Depth";
921 }
Xinghua Caob1239382016-12-13 15:07:05 +0800922 else if (qualifier == EvqNumWorkGroups)
923 {
924 mUsesNumWorkGroups = true;
925 out << name;
926 }
927 else if (qualifier == EvqWorkGroupID)
928 {
929 mUsesWorkGroupID = true;
930 out << name;
931 }
932 else if (qualifier == EvqLocalInvocationID)
933 {
934 mUsesLocalInvocationID = true;
935 out << name;
936 }
937 else if (qualifier == EvqGlobalInvocationID)
938 {
939 mUsesGlobalInvocationID = true;
940 out << name;
941 }
942 else if (qualifier == EvqLocalInvocationIndex)
943 {
944 mUsesLocalInvocationIndex = true;
945 out << name;
946 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000947 else
948 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300949 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000950 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000951 }
952}
953
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400954void OutputHLSL::visitRaw(TIntermRaw *node)
955{
Jamie Madill32aab012015-01-27 14:12:26 -0500956 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400957}
958
Olli Etuaho7fb49552015-03-18 17:27:44 +0200959void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
960{
961 if (type.isScalar() && !type.isArray())
962 {
963 if (op == EOpEqual)
964 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500965 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200966 }
967 else
968 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500969 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200970 }
971 }
972 else
973 {
974 if (visit == PreVisit && op == EOpNotEqual)
975 {
976 out << "!";
977 }
978
979 if (type.isArray())
980 {
981 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500982 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200983 }
984 else if (type.getBasicType() == EbtStruct)
985 {
986 const TStructure &structure = *type.getStruct();
987 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500988 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200989 }
990 else
991 {
992 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500993 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200994 }
995 }
996}
997
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300998void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
999{
1000 if (type.isArray())
1001 {
1002 const TString &functionName = addArrayAssignmentFunction(type);
1003 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1004 }
1005 else
1006 {
1007 outputTriplet(out, visit, "(", " = ", ")");
1008 }
1009}
1010
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001011bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001012{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001013 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001014 {
1015 TIntermNode *ancestor = getAncestorNode(n);
1016 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1017 if (ancestorBinary == nullptr)
1018 {
1019 return false;
1020 }
1021 switch (ancestorBinary->getOp())
1022 {
1023 case EOpIndexDirectStruct:
1024 {
1025 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1026 const TIntermConstantUnion *index =
1027 ancestorBinary->getRight()->getAsConstantUnion();
1028 const TField *field = structure->fields()[index->getIConst(0)];
1029 if (IsSampler(field->type()->getBasicType()))
1030 {
1031 return true;
1032 }
1033 break;
1034 }
1035 case EOpIndexDirect:
1036 break;
1037 default:
1038 // Returning a sampler from indirect indexing is not supported.
1039 return false;
1040 }
1041 }
1042 return false;
1043}
1044
Olli Etuahob6fa0432016-09-28 16:28:05 +01001045bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1046{
1047 TInfoSinkBase &out = getInfoSink();
1048 if (visit == PostVisit)
1049 {
1050 out << ".";
1051 node->writeOffsetsAsXYZW(&out);
1052 }
1053 return true;
1054}
1055
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001056bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1057{
Jamie Madill32aab012015-01-27 14:12:26 -05001058 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001059
Jamie Madill570e04d2013-06-21 09:15:33 -04001060 // Handle accessing std140 structs by value
1061 if (mFlaggedStructMappedNames.count(node) > 0)
1062 {
1063 out << mFlaggedStructMappedNames[node];
1064 return false;
1065 }
1066
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 switch (node->getOp())
1068 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001069 case EOpComma:
1070 outputTriplet(out, visit, "(", ", ", ")");
1071 break;
1072 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001073 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001074 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001075 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1076 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001077 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001078 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1079 out << functionName << "(";
1080 node->getLeft()->traverse(this);
1081 TIntermSequence *seq = rightAgg->getSequence();
1082 for (auto &arrayElement : *seq)
1083 {
1084 out << ", ";
1085 arrayElement->traverse(this);
1086 }
1087 out << ")";
1088 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001089 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001090 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1091 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001092 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001093 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001094 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001095 break;
1096 case EOpInitialize:
1097 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001098 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001099 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1100 ASSERT(symbolNode);
1101 TIntermTyped *expression = node->getRight();
1102
1103 // Global initializers must be constant at this point.
1104 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1105 canWriteAsHLSLLiteral(expression));
1106
1107 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1108 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1109 // new variable is created before the assignment is evaluated), so we need to
1110 // convert
1111 // this to "float t = x, x = t;".
1112 if (writeSameSymbolInitializer(out, symbolNode, expression))
1113 {
1114 // Skip initializing the rest of the expression
1115 return false;
1116 }
1117 else if (writeConstantInitialization(out, symbolNode, expression))
1118 {
1119 return false;
1120 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001121 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001122 else if (visit == InVisit)
1123 {
1124 out << " = ";
1125 }
1126 break;
1127 case EOpAddAssign:
1128 outputTriplet(out, visit, "(", " += ", ")");
1129 break;
1130 case EOpSubAssign:
1131 outputTriplet(out, visit, "(", " -= ", ")");
1132 break;
1133 case EOpMulAssign:
1134 outputTriplet(out, visit, "(", " *= ", ")");
1135 break;
1136 case EOpVectorTimesScalarAssign:
1137 outputTriplet(out, visit, "(", " *= ", ")");
1138 break;
1139 case EOpMatrixTimesScalarAssign:
1140 outputTriplet(out, visit, "(", " *= ", ")");
1141 break;
1142 case EOpVectorTimesMatrixAssign:
1143 if (visit == PreVisit)
1144 {
1145 out << "(";
1146 }
1147 else if (visit == InVisit)
1148 {
1149 out << " = mul(";
1150 node->getLeft()->traverse(this);
1151 out << ", transpose(";
1152 }
1153 else
1154 {
1155 out << ")))";
1156 }
1157 break;
1158 case EOpMatrixTimesMatrixAssign:
1159 if (visit == PreVisit)
1160 {
1161 out << "(";
1162 }
1163 else if (visit == InVisit)
1164 {
1165 out << " = transpose(mul(transpose(";
1166 node->getLeft()->traverse(this);
1167 out << "), transpose(";
1168 }
1169 else
1170 {
1171 out << "))))";
1172 }
1173 break;
1174 case EOpDivAssign:
1175 outputTriplet(out, visit, "(", " /= ", ")");
1176 break;
1177 case EOpIModAssign:
1178 outputTriplet(out, visit, "(", " %= ", ")");
1179 break;
1180 case EOpBitShiftLeftAssign:
1181 outputTriplet(out, visit, "(", " <<= ", ")");
1182 break;
1183 case EOpBitShiftRightAssign:
1184 outputTriplet(out, visit, "(", " >>= ", ")");
1185 break;
1186 case EOpBitwiseAndAssign:
1187 outputTriplet(out, visit, "(", " &= ", ")");
1188 break;
1189 case EOpBitwiseXorAssign:
1190 outputTriplet(out, visit, "(", " ^= ", ")");
1191 break;
1192 case EOpBitwiseOrAssign:
1193 outputTriplet(out, visit, "(", " |= ", ")");
1194 break;
1195 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001196 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001197 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001198 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001199 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001200 if (visit == PreVisit)
1201 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001202 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001203 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001204 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001205 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001206 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001207 return false;
1208 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001209 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001210 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001211 {
1212 // All parts of an expression that access a sampler in a struct need to use _ as
1213 // separator to access the sampler variable that has been moved out of the struct.
1214 outputTriplet(out, visit, "", "_", "");
1215 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001216 else
1217 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001218 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001219 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001220 }
1221 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001222 case EOpIndexIndirect:
1223 // We do not currently support indirect references to interface blocks
1224 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1225 outputTriplet(out, visit, "", "[", "]");
1226 break;
1227 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001228 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001229 const TStructure *structure = node->getLeft()->getType().getStruct();
1230 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1231 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001232
Olli Etuaho96963162016-03-21 11:54:33 +02001233 // In cases where indexing returns a sampler, we need to access the sampler variable
1234 // that has been moved out of the struct.
1235 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1236 if (visit == PreVisit && indexingReturnsSampler)
1237 {
1238 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1239 // This prefix is only output at the beginning of the indexing expression, which
1240 // may have multiple parts.
1241 out << "angle";
1242 }
1243 if (!indexingReturnsSampler)
1244 {
1245 // All parts of an expression that access a sampler in a struct need to use _ as
1246 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001247 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001248 }
1249 if (visit == InVisit)
1250 {
1251 if (indexingReturnsSampler)
1252 {
1253 out << "_" + field->name();
1254 }
1255 else
1256 {
1257 out << "." + DecorateField(field->name(), *structure);
1258 }
1259
1260 return false;
1261 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001262 }
1263 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001264 case EOpIndexDirectInterfaceBlock:
1265 if (visit == InVisit)
1266 {
1267 const TInterfaceBlock *interfaceBlock =
1268 node->getLeft()->getType().getInterfaceBlock();
1269 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1270 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1271 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001272
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001273 return false;
1274 }
1275 break;
1276 case EOpAdd:
1277 outputTriplet(out, visit, "(", " + ", ")");
1278 break;
1279 case EOpSub:
1280 outputTriplet(out, visit, "(", " - ", ")");
1281 break;
1282 case EOpMul:
1283 outputTriplet(out, visit, "(", " * ", ")");
1284 break;
1285 case EOpDiv:
1286 outputTriplet(out, visit, "(", " / ", ")");
1287 break;
1288 case EOpIMod:
1289 outputTriplet(out, visit, "(", " % ", ")");
1290 break;
1291 case EOpBitShiftLeft:
1292 outputTriplet(out, visit, "(", " << ", ")");
1293 break;
1294 case EOpBitShiftRight:
1295 outputTriplet(out, visit, "(", " >> ", ")");
1296 break;
1297 case EOpBitwiseAnd:
1298 outputTriplet(out, visit, "(", " & ", ")");
1299 break;
1300 case EOpBitwiseXor:
1301 outputTriplet(out, visit, "(", " ^ ", ")");
1302 break;
1303 case EOpBitwiseOr:
1304 outputTriplet(out, visit, "(", " | ", ")");
1305 break;
1306 case EOpEqual:
1307 case EOpNotEqual:
1308 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1309 break;
1310 case EOpLessThan:
1311 outputTriplet(out, visit, "(", " < ", ")");
1312 break;
1313 case EOpGreaterThan:
1314 outputTriplet(out, visit, "(", " > ", ")");
1315 break;
1316 case EOpLessThanEqual:
1317 outputTriplet(out, visit, "(", " <= ", ")");
1318 break;
1319 case EOpGreaterThanEqual:
1320 outputTriplet(out, visit, "(", " >= ", ")");
1321 break;
1322 case EOpVectorTimesScalar:
1323 outputTriplet(out, visit, "(", " * ", ")");
1324 break;
1325 case EOpMatrixTimesScalar:
1326 outputTriplet(out, visit, "(", " * ", ")");
1327 break;
1328 case EOpVectorTimesMatrix:
1329 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1330 break;
1331 case EOpMatrixTimesVector:
1332 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1333 break;
1334 case EOpMatrixTimesMatrix:
1335 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1336 break;
1337 case EOpLogicalOr:
1338 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1339 // been unfolded.
1340 ASSERT(!node->getRight()->hasSideEffects());
1341 outputTriplet(out, visit, "(", " || ", ")");
1342 return true;
1343 case EOpLogicalXor:
1344 mUsesXor = true;
1345 outputTriplet(out, visit, "xor(", ", ", ")");
1346 break;
1347 case EOpLogicalAnd:
1348 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1349 // been unfolded.
1350 ASSERT(!node->getRight()->hasSideEffects());
1351 outputTriplet(out, visit, "(", " && ", ")");
1352 return true;
1353 default:
1354 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355 }
1356
1357 return true;
1358}
1359
1360bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1361{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001362 TInfoSinkBase &out = getInfoSink();
1363
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001364 switch (node->getOp())
1365 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001366 case EOpNegative:
1367 outputTriplet(out, visit, "(-", "", ")");
1368 break;
1369 case EOpPositive:
1370 outputTriplet(out, visit, "(+", "", ")");
1371 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001372 case EOpLogicalNot:
1373 outputTriplet(out, visit, "(!", "", ")");
1374 break;
1375 case EOpBitwiseNot:
1376 outputTriplet(out, visit, "(~", "", ")");
1377 break;
1378 case EOpPostIncrement:
1379 outputTriplet(out, visit, "(", "", "++)");
1380 break;
1381 case EOpPostDecrement:
1382 outputTriplet(out, visit, "(", "", "--)");
1383 break;
1384 case EOpPreIncrement:
1385 outputTriplet(out, visit, "(++", "", ")");
1386 break;
1387 case EOpPreDecrement:
1388 outputTriplet(out, visit, "(--", "", ")");
1389 break;
1390 case EOpRadians:
1391 outputTriplet(out, visit, "radians(", "", ")");
1392 break;
1393 case EOpDegrees:
1394 outputTriplet(out, visit, "degrees(", "", ")");
1395 break;
1396 case EOpSin:
1397 outputTriplet(out, visit, "sin(", "", ")");
1398 break;
1399 case EOpCos:
1400 outputTriplet(out, visit, "cos(", "", ")");
1401 break;
1402 case EOpTan:
1403 outputTriplet(out, visit, "tan(", "", ")");
1404 break;
1405 case EOpAsin:
1406 outputTriplet(out, visit, "asin(", "", ")");
1407 break;
1408 case EOpAcos:
1409 outputTriplet(out, visit, "acos(", "", ")");
1410 break;
1411 case EOpAtan:
1412 outputTriplet(out, visit, "atan(", "", ")");
1413 break;
1414 case EOpSinh:
1415 outputTriplet(out, visit, "sinh(", "", ")");
1416 break;
1417 case EOpCosh:
1418 outputTriplet(out, visit, "cosh(", "", ")");
1419 break;
1420 case EOpTanh:
1421 outputTriplet(out, visit, "tanh(", "", ")");
1422 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001423 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001424 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001425 case EOpAtanh:
1426 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001427 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 break;
1429 case EOpExp:
1430 outputTriplet(out, visit, "exp(", "", ")");
1431 break;
1432 case EOpLog:
1433 outputTriplet(out, visit, "log(", "", ")");
1434 break;
1435 case EOpExp2:
1436 outputTriplet(out, visit, "exp2(", "", ")");
1437 break;
1438 case EOpLog2:
1439 outputTriplet(out, visit, "log2(", "", ")");
1440 break;
1441 case EOpSqrt:
1442 outputTriplet(out, visit, "sqrt(", "", ")");
1443 break;
1444 case EOpInverseSqrt:
1445 outputTriplet(out, visit, "rsqrt(", "", ")");
1446 break;
1447 case EOpAbs:
1448 outputTriplet(out, visit, "abs(", "", ")");
1449 break;
1450 case EOpSign:
1451 outputTriplet(out, visit, "sign(", "", ")");
1452 break;
1453 case EOpFloor:
1454 outputTriplet(out, visit, "floor(", "", ")");
1455 break;
1456 case EOpTrunc:
1457 outputTriplet(out, visit, "trunc(", "", ")");
1458 break;
1459 case EOpRound:
1460 outputTriplet(out, visit, "round(", "", ")");
1461 break;
1462 case EOpRoundEven:
1463 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001464 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001465 break;
1466 case EOpCeil:
1467 outputTriplet(out, visit, "ceil(", "", ")");
1468 break;
1469 case EOpFract:
1470 outputTriplet(out, visit, "frac(", "", ")");
1471 break;
1472 case EOpIsNan:
1473 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001474 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001475 else
1476 outputTriplet(out, visit, "isnan(", "", ")");
1477 mRequiresIEEEStrictCompiling = true;
1478 break;
1479 case EOpIsInf:
1480 outputTriplet(out, visit, "isinf(", "", ")");
1481 break;
1482 case EOpFloatBitsToInt:
1483 outputTriplet(out, visit, "asint(", "", ")");
1484 break;
1485 case EOpFloatBitsToUint:
1486 outputTriplet(out, visit, "asuint(", "", ")");
1487 break;
1488 case EOpIntBitsToFloat:
1489 outputTriplet(out, visit, "asfloat(", "", ")");
1490 break;
1491 case EOpUintBitsToFloat:
1492 outputTriplet(out, visit, "asfloat(", "", ")");
1493 break;
1494 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001495 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001497 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001499 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001500 case EOpPackUnorm4x8:
1501 case EOpPackSnorm4x8:
1502 case EOpUnpackUnorm4x8:
1503 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001504 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001505 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 break;
1507 case EOpLength:
1508 outputTriplet(out, visit, "length(", "", ")");
1509 break;
1510 case EOpNormalize:
1511 outputTriplet(out, visit, "normalize(", "", ")");
1512 break;
1513 case EOpDFdx:
1514 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1515 {
1516 outputTriplet(out, visit, "(", "", ", 0.0)");
1517 }
1518 else
1519 {
1520 outputTriplet(out, visit, "ddx(", "", ")");
1521 }
1522 break;
1523 case EOpDFdy:
1524 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1525 {
1526 outputTriplet(out, visit, "(", "", ", 0.0)");
1527 }
1528 else
1529 {
1530 outputTriplet(out, visit, "ddy(", "", ")");
1531 }
1532 break;
1533 case EOpFwidth:
1534 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1535 {
1536 outputTriplet(out, visit, "(", "", ", 0.0)");
1537 }
1538 else
1539 {
1540 outputTriplet(out, visit, "fwidth(", "", ")");
1541 }
1542 break;
1543 case EOpTranspose:
1544 outputTriplet(out, visit, "transpose(", "", ")");
1545 break;
1546 case EOpDeterminant:
1547 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1548 break;
1549 case EOpInverse:
1550 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001551 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001553
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 case EOpAny:
1555 outputTriplet(out, visit, "any(", "", ")");
1556 break;
1557 case EOpAll:
1558 outputTriplet(out, visit, "all(", "", ")");
1559 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001560 case EOpLogicalNotComponentWise:
1561 outputTriplet(out, visit, "(!", "", ")");
1562 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001563 case EOpBitfieldReverse:
1564 outputTriplet(out, visit, "reversebits(", "", ")");
1565 break;
1566 case EOpBitCount:
1567 outputTriplet(out, visit, "countbits(", "", ")");
1568 break;
1569 case EOpFindLSB:
1570 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1571 // in GLSLTest and results are consistent with GL.
1572 outputTriplet(out, visit, "firstbitlow(", "", ")");
1573 break;
1574 case EOpFindMSB:
1575 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1576 // tested in GLSLTest and results are consistent with GL.
1577 outputTriplet(out, visit, "firstbithigh(", "", ")");
1578 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001579 default:
1580 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001581 }
1582
1583 return true;
1584}
1585
Olli Etuaho96963162016-03-21 11:54:33 +02001586TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1587{
1588 if (node->getAsSymbolNode())
1589 {
1590 return node->getAsSymbolNode()->getSymbol();
1591 }
1592 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1593 switch (nodeBinary->getOp())
1594 {
1595 case EOpIndexDirect:
1596 {
1597 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1598
1599 TInfoSinkBase prefixSink;
1600 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1601 return TString(prefixSink.c_str());
1602 }
1603 case EOpIndexDirectStruct:
1604 {
1605 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1606 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1607 const TField *field = s->fields()[index];
1608
1609 TInfoSinkBase prefixSink;
1610 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1611 << field->name();
1612 return TString(prefixSink.c_str());
1613 }
1614 default:
1615 UNREACHABLE();
1616 return TString("");
1617 }
1618}
1619
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001620bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1621{
1622 TInfoSinkBase &out = getInfoSink();
1623
1624 if (mInsideFunction)
1625 {
1626 outputLineDirective(out, node->getLine().first_line);
1627 out << "{\n";
1628 }
1629
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001630 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001631 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001632 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001633
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001634 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001635
1636 // Don't output ; after case labels, they're terminated by :
1637 // This is needed especially since outputting a ; after a case statement would turn empty
1638 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001639 // Also the output code is clearer if we don't output ; after statements where it is not
1640 // needed:
1641 // * if statements
1642 // * switch statements
1643 // * blocks
1644 // * function definitions
1645 // * loops (do-while loops output the semicolon in VisitLoop)
1646 // * declarations that don't generate output.
1647 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1648 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1649 statement->getAsSwitchNode() == nullptr &&
1650 statement->getAsFunctionDefinition() == nullptr &&
1651 (statement->getAsDeclarationNode() == nullptr ||
1652 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1653 statement->getAsInvariantDeclarationNode() == nullptr)
1654 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001655 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001656 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001657 }
1658
1659 if (mInsideFunction)
1660 {
1661 outputLineDirective(out, node->getLine().last_line);
1662 out << "}\n";
1663 }
1664
1665 return false;
1666}
1667
Olli Etuaho336b1472016-10-05 16:37:55 +01001668bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1669{
1670 TInfoSinkBase &out = getInfoSink();
1671
1672 ASSERT(mCurrentFunctionMetadata == nullptr);
1673
1674 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1675 ASSERT(index != CallDAG::InvalidIndex);
1676 mCurrentFunctionMetadata = &mASTMetadataList[index];
1677
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001678 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001679
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001680 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001681
1682 if (node->getFunctionSymbolInfo()->isMain())
1683 {
1684 out << "gl_main(";
1685 }
1686 else
1687 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001688 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001689 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1690 }
1691
1692 for (unsigned int i = 0; i < parameters->size(); i++)
1693 {
1694 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1695
1696 if (symbol)
1697 {
1698 ensureStructDefined(symbol->getType());
1699
1700 out << argumentString(symbol);
1701
1702 if (i < parameters->size() - 1)
1703 {
1704 out << ", ";
1705 }
1706 }
1707 else
1708 UNREACHABLE();
1709 }
1710
1711 out << ")\n";
1712
1713 mInsideFunction = true;
1714 // The function body node will output braces.
1715 node->getBody()->traverse(this);
1716 mInsideFunction = false;
1717
1718 mCurrentFunctionMetadata = nullptr;
1719
1720 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1721 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1722 {
1723 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1724 mOutputLod0Function = true;
1725 node->traverse(this);
1726 mOutputLod0Function = false;
1727 }
1728
1729 return false;
1730}
1731
Olli Etuaho13389b62016-10-16 11:48:18 +01001732bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1733{
Olli Etuaho13389b62016-10-16 11:48:18 +01001734 if (visit == PreVisit)
1735 {
1736 TIntermSequence *sequence = node->getSequence();
1737 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1738 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001739 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001740
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001741 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001742 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001743 TInfoSinkBase &out = getInfoSink();
Olli Etuaho13389b62016-10-16 11:48:18 +01001744 ensureStructDefined(variable->getType());
1745
1746 if (!variable->getAsSymbolNode() ||
1747 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1748 {
1749 if (!mInsideFunction)
1750 {
1751 out << "static ";
1752 }
1753
1754 out << TypeString(variable->getType()) + " ";
1755
1756 TIntermSymbol *symbol = variable->getAsSymbolNode();
1757
1758 if (symbol)
1759 {
1760 symbol->traverse(this);
1761 out << ArrayString(symbol->getType());
1762 out << " = " + initializer(symbol->getType());
1763 }
1764 else
1765 {
1766 variable->traverse(this);
1767 }
1768 }
1769 else if (variable->getAsSymbolNode() &&
1770 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1771 {
1772 // Already added to constructor map
1773 }
1774 else
1775 UNREACHABLE();
1776 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001777 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001778 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001779 TIntermSymbol *symbol = variable->getAsSymbolNode();
1780 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001781
Olli Etuaho282847e2017-07-12 14:11:01 +03001782 // Vertex outputs which are declared but not written to should still be declared to
1783 // allow successful linking.
1784 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001785 }
1786 }
1787 return false;
1788}
1789
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001790bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1791{
1792 // Do not do any translation
1793 return false;
1794}
1795
Olli Etuaho16c745a2017-01-16 17:02:27 +00001796bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1797{
1798 TInfoSinkBase &out = getInfoSink();
1799
1800 ASSERT(visit == PreVisit);
1801 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1802 // Skip the prototype if it is not implemented (and thus not used)
1803 if (index == CallDAG::InvalidIndex)
1804 {
1805 return false;
1806 }
1807
1808 TIntermSequence *arguments = node->getSequence();
1809
Olli Etuahoff526f12017-06-30 12:26:54 +03001810 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001811 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1812 << (mOutputLod0Function ? "Lod0(" : "(");
1813
1814 for (unsigned int i = 0; i < arguments->size(); i++)
1815 {
1816 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1817 ASSERT(symbol != nullptr);
1818
1819 out << argumentString(symbol);
1820
1821 if (i < arguments->size() - 1)
1822 {
1823 out << ", ";
1824 }
1825 }
1826
1827 out << ");\n";
1828
1829 // Also prototype the Lod0 variant if needed
1830 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1831 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1832 {
1833 mOutputLod0Function = true;
1834 node->traverse(this);
1835 mOutputLod0Function = false;
1836 }
1837
1838 return false;
1839}
1840
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001841bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1842{
Jamie Madill32aab012015-01-27 14:12:26 -05001843 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001844
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001845 switch (node->getOp())
1846 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001847 case EOpCallBuiltInFunction:
1848 case EOpCallFunctionInAST:
1849 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001850 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001851 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001852
Corentin Wallez1239ee92015-03-19 14:38:02 -07001853 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001854 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001855 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001856 if (node->isArray())
1857 {
1858 UNIMPLEMENTED();
1859 }
Olli Etuahobd674552016-10-06 13:28:42 +01001860 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001861 ASSERT(index != CallDAG::InvalidIndex);
1862 lod0 &= mASTMetadataList[index].mNeedsLod0;
1863
Olli Etuahoff526f12017-06-30 12:26:54 +03001864 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001865 out << DisambiguateFunctionName(node->getSequence());
1866 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001867 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001868 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001869 {
1870 // This path is used for internal functions that don't have their definitions in the
1871 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001872 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001873 }
Xinghua Cao711b7a12017-10-09 13:38:12 +08001874 else if (node->getFunctionSymbolInfo()->isImageFunction())
1875 {
1876 TString name = node->getFunctionSymbolInfo()->getName();
1877 TType type = (*arguments)[0]->getAsTyped()->getType();
1878 TString imageFunctionName = mImageFunctionHLSL->useImageFunction(
1879 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
1880 type.getMemoryQualifier().readonly);
1881 out << imageFunctionName << "(";
1882 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001883 else
1884 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001885 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001886 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001887 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1888 if (arguments->size() > 1)
1889 {
1890 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1891 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001892 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1893 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1894 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001895 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001896
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001897 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001898 {
Olli Etuaho96963162016-03-21 11:54:33 +02001899 TIntermTyped *typedArg = (*arg)->getAsTyped();
1900 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001901 {
1902 out << "texture_";
1903 (*arg)->traverse(this);
1904 out << ", sampler_";
1905 }
1906
1907 (*arg)->traverse(this);
1908
Olli Etuaho96963162016-03-21 11:54:33 +02001909 if (typedArg->getType().isStructureContainingSamplers())
1910 {
1911 const TType &argType = typedArg->getType();
1912 TVector<TIntermSymbol *> samplerSymbols;
1913 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001914 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1915 nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02001916 for (const TIntermSymbol *sampler : samplerSymbols)
1917 {
1918 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1919 {
1920 out << ", texture_" << sampler->getSymbol();
1921 out << ", sampler_" << sampler->getSymbol();
1922 }
1923 else
1924 {
1925 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1926 // of D3D9, it's the sampler variable.
1927 out << ", " + sampler->getSymbol();
1928 }
1929 }
1930 }
1931
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001932 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001933 {
1934 out << ", ";
1935 }
1936 }
1937
1938 out << ")";
1939
1940 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001941 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001942 case EOpConstruct:
1943 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001944 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001945 if (node->getType().isArray())
1946 {
1947 UNIMPLEMENTED();
1948 }
1949 const TString &structName = StructNameString(*node->getType().getStruct());
1950 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1951 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001952 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001953 else
1954 {
1955 const char *name = "";
1956 if (node->getType().getNominalSize() == 1)
1957 {
1958 switch (node->getBasicType())
1959 {
1960 case EbtFloat:
1961 name = "vec1";
1962 break;
1963 case EbtInt:
1964 name = "ivec1";
1965 break;
1966 case EbtUInt:
1967 name = "uvec1";
1968 break;
1969 case EbtBool:
1970 name = "bvec1";
1971 break;
1972 default:
1973 UNREACHABLE();
1974 }
1975 }
1976 else
1977 {
1978 name = node->getType().getBuiltInTypeNameString();
1979 }
1980 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1981 }
1982 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001983 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001984 outputTriplet(out, visit, "(", " == ", ")");
1985 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001986 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001987 outputTriplet(out, visit, "(", " != ", ")");
1988 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001989 case EOpLessThanComponentWise:
1990 outputTriplet(out, visit, "(", " < ", ")");
1991 break;
1992 case EOpGreaterThanComponentWise:
1993 outputTriplet(out, visit, "(", " > ", ")");
1994 break;
1995 case EOpLessThanEqualComponentWise:
1996 outputTriplet(out, visit, "(", " <= ", ")");
1997 break;
1998 case EOpGreaterThanEqualComponentWise:
1999 outputTriplet(out, visit, "(", " >= ", ")");
2000 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002001 case EOpMod:
2002 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002003 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002004 break;
2005 case EOpModf:
2006 outputTriplet(out, visit, "modf(", ", ", ")");
2007 break;
2008 case EOpPow:
2009 outputTriplet(out, visit, "pow(", ", ", ")");
2010 break;
2011 case EOpAtan:
2012 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2013 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002014 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002015 break;
2016 case EOpMin:
2017 outputTriplet(out, visit, "min(", ", ", ")");
2018 break;
2019 case EOpMax:
2020 outputTriplet(out, visit, "max(", ", ", ")");
2021 break;
2022 case EOpClamp:
2023 outputTriplet(out, visit, "clamp(", ", ", ")");
2024 break;
2025 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302026 {
2027 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2028 if (lastParamNode->getType().getBasicType() == EbtBool)
2029 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002030 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2031 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302032 // so use emulated version.
2033 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002034 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302035 }
2036 else
2037 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002038 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302039 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002040 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302041 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002042 case EOpStep:
2043 outputTriplet(out, visit, "step(", ", ", ")");
2044 break;
2045 case EOpSmoothStep:
2046 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2047 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002048 case EOpFrexp:
2049 case EOpLdexp:
2050 ASSERT(node->getUseEmulatedFunction());
2051 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2052 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002053 case EOpDistance:
2054 outputTriplet(out, visit, "distance(", ", ", ")");
2055 break;
2056 case EOpDot:
2057 outputTriplet(out, visit, "dot(", ", ", ")");
2058 break;
2059 case EOpCross:
2060 outputTriplet(out, visit, "cross(", ", ", ")");
2061 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002062 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002063 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002064 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002065 break;
2066 case EOpReflect:
2067 outputTriplet(out, visit, "reflect(", ", ", ")");
2068 break;
2069 case EOpRefract:
2070 outputTriplet(out, visit, "refract(", ", ", ")");
2071 break;
2072 case EOpOuterProduct:
2073 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002074 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002075 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002076 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002077 outputTriplet(out, visit, "(", " * ", ")");
2078 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002079 case EOpBitfieldExtract:
2080 case EOpBitfieldInsert:
2081 case EOpUaddCarry:
2082 case EOpUsubBorrow:
2083 case EOpUmulExtended:
2084 case EOpImulExtended:
2085 ASSERT(node->getUseEmulatedFunction());
2086 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2087 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002088 default:
2089 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002090 }
2091
2092 return true;
2093}
2094
Olli Etuaho57961272016-09-14 13:57:46 +03002095void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002096{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002097 out << "if (";
2098
2099 node->getCondition()->traverse(this);
2100
2101 out << ")\n";
2102
Jamie Madill8c46ab12015-12-07 16:39:19 -05002103 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002104
2105 bool discard = false;
2106
2107 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002108 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002109 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002110 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002111
Olli Etuahoa6f22092015-05-08 18:31:10 +03002112 // Detect true discard
2113 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2114 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002115 else
2116 {
2117 // TODO(oetuaho): Check if the semicolon inside is necessary.
2118 // It's there as a result of conservative refactoring of the output.
2119 out << "{;}\n";
2120 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002121
Jamie Madill8c46ab12015-12-07 16:39:19 -05002122 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002123
Olli Etuahoa6f22092015-05-08 18:31:10 +03002124 if (node->getFalseBlock())
2125 {
2126 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002127
Jamie Madill8c46ab12015-12-07 16:39:19 -05002128 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002129
Olli Etuaho32db19b2016-10-04 14:43:16 +01002130 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002131 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002132
Jamie Madill8c46ab12015-12-07 16:39:19 -05002133 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002134
Olli Etuahoa6f22092015-05-08 18:31:10 +03002135 // Detect false discard
2136 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2137 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002138
Olli Etuahoa6f22092015-05-08 18:31:10 +03002139 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002140 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002141 {
2142 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002143 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002144}
2145
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002146bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2147{
2148 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2149 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2150 UNREACHABLE();
2151 return false;
2152}
2153
Olli Etuaho57961272016-09-14 13:57:46 +03002154bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002155{
2156 TInfoSinkBase &out = getInfoSink();
2157
Olli Etuaho3d932d82016-04-12 11:10:30 +03002158 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002159
2160 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002161 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002162 {
2163 out << "FLATTEN ";
2164 }
2165
Olli Etuaho57961272016-09-14 13:57:46 +03002166 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002167
2168 return false;
2169}
2170
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002171bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002172{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002173 TInfoSinkBase &out = getInfoSink();
2174
Olli Etuaho923ecef2017-10-11 12:01:38 +03002175 ASSERT(node->getStatementList());
2176 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002177 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002178 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002179 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002180 outputTriplet(out, visit, "switch (", ") ", "");
2181 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002182 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002183}
2184
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002185bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002186{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002187 TInfoSinkBase &out = getInfoSink();
2188
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002189 if (node->hasCondition())
2190 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002191 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002192 return true;
2193 }
2194 else
2195 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002196 out << "default:\n";
2197 return false;
2198 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002199}
2200
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002201void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2202{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002203 TInfoSinkBase &out = getInfoSink();
2204 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002205}
2206
2207bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2208{
Nicolas Capens655fe362014-04-11 13:12:34 -04002209 mNestedLoopDepth++;
2210
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002211 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002212 mInsideDiscontinuousLoop =
2213 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002214
Jamie Madill8c46ab12015-12-07 16:39:19 -05002215 TInfoSinkBase &out = getInfoSink();
2216
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002217 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002218 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002219 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002220 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002221 mInsideDiscontinuousLoop = wasDiscontinuous;
2222 mNestedLoopDepth--;
2223
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002224 return false;
2225 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002226 }
2227
Corentin Wallez1239ee92015-03-19 14:38:02 -07002228 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002229 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002230 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002231 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002232
Jamie Madill8c46ab12015-12-07 16:39:19 -05002233 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002234 }
2235 else
2236 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002237 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002238
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002239 if (node->getInit())
2240 {
2241 node->getInit()->traverse(this);
2242 }
2243
2244 out << "; ";
2245
alokp@chromium.org52813552010-11-16 18:36:09 +00002246 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002248 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002249 }
2250
2251 out << "; ";
2252
alokp@chromium.org52813552010-11-16 18:36:09 +00002253 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002255 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002256 }
2257
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002258 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002259
Jamie Madill8c46ab12015-12-07 16:39:19 -05002260 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002261 }
2262
2263 if (node->getBody())
2264 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002265 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002266 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002268 else
2269 {
2270 // TODO(oetuaho): Check if the semicolon inside is necessary.
2271 // It's there as a result of conservative refactoring of the output.
2272 out << "{;}\n";
2273 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002274
Jamie Madill8c46ab12015-12-07 16:39:19 -05002275 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002276
alokp@chromium.org52813552010-11-16 18:36:09 +00002277 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002278 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002279 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002280 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002281
alokp@chromium.org52813552010-11-16 18:36:09 +00002282 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002283
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002284 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002285 }
2286
daniel@transgaming.com73536982012-03-21 20:45:49 +00002287 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002288
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002289 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002290 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002291
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002292 return false;
2293}
2294
2295bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2296{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002297 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002299 TInfoSinkBase &out = getInfoSink();
2300
2301 switch (node->getFlowOp())
2302 {
2303 case EOpKill:
2304 out << "discard";
2305 break;
2306 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002307 if (mNestedLoopDepth > 1)
2308 {
2309 mUsesNestedBreak = true;
2310 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002311
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002312 if (mExcessiveLoopIndex)
2313 {
2314 out << "{Break";
2315 mExcessiveLoopIndex->traverse(this);
2316 out << " = true; break;}\n";
2317 }
2318 else
2319 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002320 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002321 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002322 break;
2323 case EOpContinue:
2324 out << "continue";
2325 break;
2326 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002327 if (node->getExpression())
2328 {
2329 out << "return ";
2330 }
2331 else
2332 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002333 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002334 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002335 break;
2336 default:
2337 UNREACHABLE();
2338 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002339 }
2340
2341 return true;
2342}
2343
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002344// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002345// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2346// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002347bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002348{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002349 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002350
2351 // Parse loops of the form:
2352 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002353 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002354 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002355 int initial = 0;
2356 int limit = 0;
2357 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002358
2359 // Parse index name and intial value
2360 if (node->getInit())
2361 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002362 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002363
2364 if (init)
2365 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002366 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002367 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002368
2369 if (variable && variable->getQualifier() == EvqTemporary)
2370 {
2371 TIntermBinary *assign = variable->getAsBinaryNode();
2372
2373 if (assign->getOp() == EOpInitialize)
2374 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002375 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002376 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2377
2378 if (symbol && constant)
2379 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002380 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002381 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002382 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002383 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002384 }
2385 }
2386 }
2387 }
2388 }
2389 }
2390
2391 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002392 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002393 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002394 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002395
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002396 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2397 {
2398 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2399
2400 if (constant)
2401 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002402 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002403 {
2404 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002405 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002406 }
2407 }
2408 }
2409 }
2410
2411 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002412 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002413 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002414 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002415 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002416
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002417 if (binaryTerminal)
2418 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002419 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002420 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2421
2422 if (constant)
2423 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002424 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002425 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002426 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002427
2428 switch (op)
2429 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002430 case EOpAddAssign:
2431 increment = value;
2432 break;
2433 case EOpSubAssign:
2434 increment = -value;
2435 break;
2436 default:
2437 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002438 }
2439 }
2440 }
2441 }
2442 else if (unaryTerminal)
2443 {
2444 TOperator op = unaryTerminal->getOp();
2445
2446 switch (op)
2447 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002448 case EOpPostIncrement:
2449 increment = 1;
2450 break;
2451 case EOpPostDecrement:
2452 increment = -1;
2453 break;
2454 case EOpPreIncrement:
2455 increment = 1;
2456 break;
2457 case EOpPreDecrement:
2458 increment = -1;
2459 break;
2460 default:
2461 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002462 }
2463 }
2464 }
2465
Yunchao He4f285442017-04-21 12:15:49 +08002466 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002467 {
2468 if (comparator == EOpLessThanEqual)
2469 {
2470 comparator = EOpLessThan;
2471 limit += 1;
2472 }
2473
2474 if (comparator == EOpLessThan)
2475 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002476 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002478 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002480 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002481 }
2482
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002483 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002484 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002485
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002486 out << "{int ";
2487 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002488 out << ";\n"
2489 "bool Break";
2490 index->traverse(this);
2491 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002492
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002493 bool firstLoopFragment = true;
2494
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002495 while (iterations > 0)
2496 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002497 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002499 if (!firstLoopFragment)
2500 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002501 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002502 index->traverse(this);
2503 out << ") {\n";
2504 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002505
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002506 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002507 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002508 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002509 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002510
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002511 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002512 const char *unroll =
2513 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002514
Corentin Wallez1239ee92015-03-19 14:38:02 -07002515 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002516 index->traverse(this);
2517 out << " = ";
2518 out << initial;
2519
2520 out << "; ";
2521 index->traverse(this);
2522 out << " < ";
2523 out << clampedLimit;
2524
2525 out << "; ";
2526 index->traverse(this);
2527 out << " += ";
2528 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002529 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002530
Jamie Madill8c46ab12015-12-07 16:39:19 -05002531 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002532 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533
2534 if (node->getBody())
2535 {
2536 node->getBody()->traverse(this);
2537 }
2538
Jamie Madill8c46ab12015-12-07 16:39:19 -05002539 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002540 out << ";}\n";
2541
2542 if (!firstLoopFragment)
2543 {
2544 out << "}\n";
2545 }
2546
2547 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002548
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002549 initial += MAX_LOOP_ITERATIONS * increment;
2550 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002551 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002552
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002553 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002554
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002555 mExcessiveLoopIndex = restoreIndex;
2556
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002557 return true;
2558 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002559 else
2560 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002561 }
2562
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002563 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002564}
2565
Jamie Madill8c46ab12015-12-07 16:39:19 -05002566void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2567 Visit visit,
2568 const char *preString,
2569 const char *inString,
2570 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002571{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002572 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002573 {
2574 out << preString;
2575 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002576 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002577 {
2578 out << inString;
2579 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002580 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002581 {
2582 out << postString;
2583 }
2584}
2585
Jamie Madill8c46ab12015-12-07 16:39:19 -05002586void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002587{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002588 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002589 {
Jamie Madill32aab012015-01-27 14:12:26 -05002590 out << "\n";
2591 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002592
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002593 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002594 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002595 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002596 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002597
Jamie Madill32aab012015-01-27 14:12:26 -05002598 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002599 }
2600}
2601
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002602TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2603{
2604 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002605 const TType &type = symbol->getType();
2606 const TName &name = symbol->getName();
2607 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002608
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002609 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002610 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002611 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002612 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002613 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002614 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002615 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002616 }
2617
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002618 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002619 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002620 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2621 {
2622 // Samplers are passed as indices to the sampler array.
2623 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2624 return "const uint " + nameStr + ArrayString(type);
2625 }
2626 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2627 {
2628 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2629 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2630 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2631 ArrayString(type);
2632 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002633 }
2634
Olli Etuaho96963162016-03-21 11:54:33 +02002635 TStringStream argString;
2636 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2637 << ArrayString(type);
2638
2639 // If the structure parameter contains samplers, they need to be passed into the function as
2640 // separate parameters. HLSL doesn't natively support samplers in structs.
2641 if (type.isStructureContainingSamplers())
2642 {
2643 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2644 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002645 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02002646 for (const TIntermSymbol *sampler : samplerSymbols)
2647 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002648 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002649 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2650 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002651 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002652 }
2653 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2654 {
Olli Etuaho96963162016-03-21 11:54:33 +02002655 ASSERT(IsSampler(samplerType.getBasicType()));
2656 argString << ", " << QualifierString(qualifier) << " "
2657 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002658 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2659 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002660 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002661 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002662 }
2663 else
2664 {
Olli Etuaho96963162016-03-21 11:54:33 +02002665 ASSERT(IsSampler(samplerType.getBasicType()));
2666 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002667 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002668 }
2669 }
2670 }
2671
2672 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002673}
2674
2675TString OutputHLSL::initializer(const TType &type)
2676{
2677 TString string;
2678
Jamie Madill94bf7f22013-07-08 13:31:15 -04002679 size_t size = type.getObjectSize();
2680 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002681 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002682 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002683
Jamie Madill94bf7f22013-07-08 13:31:15 -04002684 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002685 {
2686 string += ", ";
2687 }
2688 }
2689
daniel@transgaming.comead23042010-04-29 03:35:36 +00002690 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002691}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002692
Jamie Madill8c46ab12015-12-07 16:39:19 -05002693void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2694 Visit visit,
2695 const TType &type,
2696 const char *name,
2697 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002698{
Olli Etuahof40319e2015-03-10 14:33:00 +02002699 if (type.isArray())
2700 {
2701 UNIMPLEMENTED();
2702 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002703
2704 if (visit == PreVisit)
2705 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002706 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002707
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002708 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002709 }
2710 else if (visit == InVisit)
2711 {
2712 out << ", ";
2713 }
2714 else if (visit == PostVisit)
2715 {
2716 out << ")";
2717 }
2718}
2719
Jamie Madill8c46ab12015-12-07 16:39:19 -05002720const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2721 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002722 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002723{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002724 const TConstantUnion *constUnionIterated = constUnion;
2725
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002726 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002727 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002728 {
Jamie Madill033dae62014-06-18 12:56:28 -04002729 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002730
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002731 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002732
Jamie Madill98493dd2013-07-08 14:39:03 -04002733 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002734 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002735 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002736 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002737
Jamie Madill98493dd2013-07-08 14:39:03 -04002738 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002739 {
2740 out << ", ";
2741 }
2742 }
2743
2744 out << ")";
2745 }
2746 else
2747 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002748 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002749 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002750
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002751 if (writeType)
2752 {
Jamie Madill033dae62014-06-18 12:56:28 -04002753 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002754 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002755 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002756 if (writeType)
2757 {
2758 out << ")";
2759 }
2760 }
2761
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002762 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002763}
2764
Olli Etuahod68924e2017-01-02 17:34:40 +00002765void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002766{
Olli Etuahod68924e2017-01-02 17:34:40 +00002767 if (visit == PreVisit)
2768 {
2769 const char *opStr = GetOperatorString(op);
2770 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2771 out << "(";
2772 }
2773 else
2774 {
2775 outputTriplet(out, visit, nullptr, ", ", ")");
2776 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002777}
2778
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002779bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2780 TIntermSymbol *symbolNode,
2781 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002782{
2783 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2784 expression->traverse(&searchSymbol);
2785
2786 if (searchSymbol.foundMatch())
2787 {
2788 // Type already printed
2789 out << "t" + str(mUniqueIndex) + " = ";
2790 expression->traverse(this);
2791 out << ", ";
2792 symbolNode->traverse(this);
2793 out << " = t" + str(mUniqueIndex);
2794
2795 mUniqueIndex++;
2796 return true;
2797 }
2798
2799 return false;
2800}
2801
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002802bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2803{
2804 // We support writing constant unions and constructors that only take constant unions as
2805 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002806 return !expression->getType().isArrayOfArrays() &&
2807 (expression->getAsConstantUnion() ||
2808 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002809}
2810
2811bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2812 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002813 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002814{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002815 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002816 {
2817 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002818 ASSERT(!symbolNode->getType().isArrayOfArrays());
2819 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002820 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002821 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002822 }
2823 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002824 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002825 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002826 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002827 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002828 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002829 }
2830 else
2831 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002832 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002833 ASSERT(constructor != nullptr);
2834 for (TIntermNode *&node : *constructor->getSequence())
2835 {
2836 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2837 ASSERT(nodeConst);
2838 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002839 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002840 if (node != constructor->getSequence()->back())
2841 {
2842 out << ", ";
2843 }
2844 }
2845 }
2846 out << "}";
2847 return true;
2848 }
2849 return false;
2850}
2851
Jamie Madill55e79e02015-02-09 15:35:00 -05002852TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2853{
2854 const TFieldList &fields = structure.fields();
2855
2856 for (const auto &eqFunction : mStructEqualityFunctions)
2857 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002858 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002859 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002860 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002861 }
2862 }
2863
2864 const TString &structNameString = StructNameString(structure);
2865
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002866 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002867 function->structure = &structure;
2868 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002869
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002870 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002871
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002872 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2873 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002874 << "{\n"
2875 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002876
2877 for (size_t i = 0; i < fields.size(); i++)
2878 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002879 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002880 const TType *fieldType = field->type();
2881
2882 const TString &fieldNameA = "a." + Decorate(field->name());
2883 const TString &fieldNameB = "b." + Decorate(field->name());
2884
2885 if (i > 0)
2886 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002887 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002888 }
2889
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002890 fnOut << "(";
2891 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2892 fnOut << fieldNameA;
2893 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2894 fnOut << fieldNameB;
2895 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2896 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002897 }
2898
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002899 fnOut << ";\n"
2900 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002901
2902 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002903
2904 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002905 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002906
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002907 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002908}
2909
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002910TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002911{
2912 for (const auto &eqFunction : mArrayEqualityFunctions)
2913 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002914 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002915 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002916 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002917 }
2918 }
2919
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002920 TType elementType(type);
2921 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002922
Olli Etuaho12690762015-03-31 12:55:28 +03002923 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002924 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002925
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002926 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002927
2928 TInfoSinkBase fnOut;
2929
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002930 const TString &typeName = TypeString(type);
2931 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2932 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002933 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002934 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002935 << type.getOutermostArraySize()
2936 << "; ++i)\n"
2937 " {\n"
2938 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002939
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002940 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002941 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002942 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002943 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002944 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002945
2946 fnOut << ") { return false; }\n"
2947 " }\n"
2948 " return true;\n"
2949 "}\n";
2950
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002951 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002952
2953 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002954 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002955
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002956 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002957}
2958
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002959TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002960{
2961 for (const auto &assignFunction : mArrayAssignmentFunctions)
2962 {
2963 if (assignFunction.type == type)
2964 {
2965 return assignFunction.functionName;
2966 }
2967 }
2968
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002969 TType elementType(type);
2970 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002971
2972 ArrayHelperFunction function;
2973 function.type = type;
2974
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002975 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002976
2977 TInfoSinkBase fnOut;
2978
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002979 const TString &typeName = TypeString(type);
2980 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2981 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002982 << "{\n"
2983 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002984 << type.getOutermostArraySize()
2985 << "; ++i)\n"
2986 " {\n"
2987 " ";
2988
2989 outputAssign(PreVisit, elementType, fnOut);
2990 fnOut << "a[i]";
2991 outputAssign(InVisit, elementType, fnOut);
2992 fnOut << "b[i]";
2993 outputAssign(PostVisit, elementType, fnOut);
2994
2995 fnOut << ";\n"
2996 " }\n"
2997 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002998
2999 function.functionDefinition = fnOut.c_str();
3000
3001 mArrayAssignmentFunctions.push_back(function);
3002
3003 return function.functionName;
3004}
3005
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003006TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003007{
3008 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3009 {
3010 if (constructIntoFunction.type == type)
3011 {
3012 return constructIntoFunction.functionName;
3013 }
3014 }
3015
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003016 TType elementType(type);
3017 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003018
3019 ArrayHelperFunction function;
3020 function.type = type;
3021
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003022 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003023
3024 TInfoSinkBase fnOut;
3025
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003026 const TString &typeName = TypeString(type);
3027 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3028 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003029 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003030 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003031 }
3032 fnOut << ")\n"
3033 "{\n";
3034
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003035 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003036 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003037 fnOut << " ";
3038 outputAssign(PreVisit, elementType, fnOut);
3039 fnOut << "a[" << i << "]";
3040 outputAssign(InVisit, elementType, fnOut);
3041 fnOut << "b" << i;
3042 outputAssign(PostVisit, elementType, fnOut);
3043 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003044 }
3045 fnOut << "}\n";
3046
3047 function.functionDefinition = fnOut.c_str();
3048
3049 mArrayConstructIntoFunctions.push_back(function);
3050
3051 return function.functionName;
3052}
3053
Jamie Madill2e295e22015-04-29 10:41:33 -04003054void OutputHLSL::ensureStructDefined(const TType &type)
3055{
3056 TStructure *structure = type.getStruct();
3057
3058 if (structure)
3059 {
3060 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3061 }
3062}
3063
Jamie Madill45bcc782016-11-07 13:58:48 -05003064} // namespace sh