blob: 39f856dd816ac7b8d5cc310bb895b3e4d5269453 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00009#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000010#include <cfloat>
11#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000012
Jamie Madill9e0478f2015-01-13 11:13:54 -050013#include "common/angleutils.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030014#include "common/debug.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/utilities.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020016#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050017#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/FlagStd140Structs.h"
19#include "compiler/translator/InfoSink.h"
20#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020021#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/SearchSymbol.h"
23#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030024#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/UniformHLSL.h"
27#include "compiler/translator/UtilsHLSL.h"
28#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho56a2f952016-12-08 12:16:27 +000034void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030035{
Olli Etuaho56a2f952016-12-08 12:16:27 +000036 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
37 // regardless.
38 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
39 mOutputType == SH_HLSL_4_1_OUTPUT)
40 {
41 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
42 }
43 else
44 {
45 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
46 }
47}
Olli Etuaho4785fec2015-05-18 16:09:37 +030048
Olli Etuaho56a2f952016-12-08 12:16:27 +000049void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020050{
51 ASSERT(constUnion != nullptr);
52 switch (constUnion->getType())
53 {
54 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000055 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020056 break;
57 case EbtInt:
58 out << constUnion->getIConst();
59 break;
60 case EbtUInt:
61 out << constUnion->getUConst();
62 break;
63 case EbtBool:
64 out << constUnion->getBConst();
65 break;
66 default:
67 UNREACHABLE();
68 }
69}
70
Olli Etuaho56a2f952016-12-08 12:16:27 +000071const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
72 const TConstantUnion *const constUnion,
73 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020074{
75 const TConstantUnion *constUnionIterated = constUnion;
76 for (size_t i = 0; i < size; i++, constUnionIterated++)
77 {
Olli Etuaho56a2f952016-12-08 12:16:27 +000078 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +020079
80 if (i != size - 1)
81 {
82 out << ", ";
83 }
84 }
85 return constUnionIterated;
86}
87
Qiankun Miao7ebb97f2016-09-08 18:01:50 +080088OutputHLSL::OutputHLSL(sh::GLenum shaderType,
89 int shaderVersion,
90 const TExtensionBehavior &extensionBehavior,
91 const char *sourcePath,
92 ShShaderOutput outputType,
93 int numRenderTargets,
94 const std::vector<Uniform> &uniforms,
95 ShCompileOptions compileOptions)
Jamie Madill54ad4f82014-09-03 09:40:46 -040096 : TIntermTraverser(true, true, true),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +020097 mShaderType(shaderType),
98 mShaderVersion(shaderVersion),
99 mExtensionBehavior(extensionBehavior),
100 mSourcePath(sourcePath),
101 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700102 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000103 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700104 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000105{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000106 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000107
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500108 mUsesFragColor = false;
109 mUsesFragData = false;
110 mUsesDepthRange = false;
111 mUsesFragCoord = false;
112 mUsesPointCoord = false;
113 mUsesFrontFacing = false;
114 mUsesPointSize = false;
115 mUsesInstanceID = false;
Martin Radev41ac68e2017-06-06 12:16:58 +0300116 mHasMultiviewExtensionEnabled = IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview") ||
117 IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview2");
118 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500119 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500120 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800121 mUsesNumWorkGroups = false;
122 mUsesWorkGroupID = false;
123 mUsesLocalInvocationID = false;
124 mUsesGlobalInvocationID = false;
125 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500126 mUsesXor = false;
127 mUsesDiscardRewriting = false;
128 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530129 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000130
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000131 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000132
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500133 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000134 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000136
Yunchao Hed7297bf2017-04-19 15:27:10 +0800137 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000138
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500139 mStructureHLSL = new StructureHLSL;
140 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300141 mTextureFunctionHLSL = new TextureFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400142
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200143 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000144 {
Arun Patole63419392015-03-13 11:51:07 +0530145 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500146 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
147 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530148 // In both cases total 3 uniform registers need to be reserved.
149 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000150 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000151
Geoff Lang00140f42016-02-03 18:47:33 +0000152 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800153 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154}
155
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000156OutputHLSL::~OutputHLSL()
157{
Jamie Madill8daaba12014-06-13 10:04:33 -0400158 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400159 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300160 SafeDelete(mTextureFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200161 for (auto &eqFunction : mStructEqualityFunctions)
162 {
163 SafeDelete(eqFunction);
164 }
165 for (auto &eqFunction : mArrayEqualityFunctions)
166 {
167 SafeDelete(eqFunction);
168 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000169}
170
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200171void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000172{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500173 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400174 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000175
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200176 BuiltInFunctionEmulator builtInFunctionEmulator;
177 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800178 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
179 {
180 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
181 mShaderVersion);
182 }
183
Olli Etuahodfa75e82017-01-23 09:43:06 -0800184 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500185
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700186 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000187 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700188 ASSERT(success == CallDAG::INITDAG_SUCCESS);
189 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700190
Jamie Madill37997142015-01-28 10:06:34 -0500191 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500192 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200193 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500194 mInfoSinkStack.pop();
195
Jamie Madill37997142015-01-28 10:06:34 -0500196 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500197 mInfoSinkStack.pop();
198
Jamie Madill32aab012015-01-27 14:12:26 -0500199 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500200 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500201 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000202
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200203 objSink << mHeader.c_str();
204 objSink << mBody.c_str();
205 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200206
Olli Etuahodfa75e82017-01-23 09:43:06 -0800207 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000208}
209
Jamie Madill570e04d2013-06-21 09:15:33 -0400210void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
211{
212 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
213 {
214 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
215
Jamie Madill32aab012015-01-27 14:12:26 -0500216 TInfoSinkBase structInfoSink;
217 mInfoSinkStack.push(&structInfoSink);
218
Jamie Madill570e04d2013-06-21 09:15:33 -0400219 // This will mark the necessary block elements as referenced
220 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500221
222 TString structName(structInfoSink.c_str());
223 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400224
225 mFlaggedStructOriginalNames[flaggedNode] = structName;
226
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500227 for (size_t pos = structName.find('.'); pos != std::string::npos;
228 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400229 {
230 structName.erase(pos, 1);
231 }
232
233 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
234 }
235}
236
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800237const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400238{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800239 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400240}
241
Jamie Madill9fe25e92014-07-18 10:33:08 -0400242const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
243{
244 return mUniformHLSL->getUniformRegisterMap();
245}
246
Olli Etuahoed049ab2017-06-30 17:38:33 +0300247TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400248{
249 TString init;
250
Olli Etuahoed049ab2017-06-30 17:38:33 +0300251 TString indentString;
252 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400253 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300254 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400255 }
256
Olli Etuahoed049ab2017-06-30 17:38:33 +0300257 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400258 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300259 init += indentString + "{\n";
260 for (unsigned int arrayIndex = 0u; arrayIndex < type.getArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400261 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300262 TStringStream indexedString;
263 indexedString << name << "[" << arrayIndex << "]";
264 TType elementType = type;
265 elementType.clearArrayness();
266 init += structInitializerString(indent + 1, elementType, indexedString.str());
267 if (arrayIndex < type.getArraySize() - 1)
268 {
269 init += ",";
270 }
271 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400272 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300273 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400274 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300275 else if (type.getBasicType() == EbtStruct)
276 {
277 init += indentString + "{\n";
278 const TStructure &structure = *type.getStruct();
279 const TFieldList &fields = structure.fields();
280 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
281 {
282 const TField &field = *fields[fieldIndex];
283 const TString &fieldName = name + "." + Decorate(field.name());
284 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400285
Olli Etuahoed049ab2017-06-30 17:38:33 +0300286 init += structInitializerString(indent + 1, fieldType, fieldName);
287 if (fieldIndex < fields.size() - 1)
288 {
289 init += ",";
290 }
291 init += "\n";
292 }
293 init += indentString + "}";
294 }
295 else
296 {
297 init += indentString + name;
298 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400299
300 return init;
301}
302
Jamie Madill8c46ab12015-12-07 16:39:19 -0500303void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000305 TString varyings;
306 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400307 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000308
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500309 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
310 mFlaggedStructMappedNames.begin();
311 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400312 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500313 TIntermTyped *structNode = flaggedStructIt->first;
314 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400315 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400316 const TString &originalName = mFlaggedStructOriginalNames[structNode];
317
Olli Etuahoed049ab2017-06-30 17:38:33 +0300318 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
319 if (structNode->isArray())
320 {
321 flaggedStructs += ArrayString(structNode->getType());
322 }
323 flaggedStructs += " =\n";
324 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
325 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400326 }
327
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500328 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
329 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000330 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500331 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000332 const TString &name = varying->second->getSymbol();
333
334 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500335 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
336 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000337 }
338
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500339 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
340 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000341 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500342 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000343 const TString &name = attribute->second->getSymbol();
344
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500345 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
346 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000347 }
348
Jamie Madill8daaba12014-06-13 10:04:33 -0400349 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400350
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200351 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800352 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400353
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200354 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500355 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200356 out << "\n// Equality functions\n\n";
357 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500358 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200359 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200360 }
361 }
Olli Etuaho12690762015-03-31 12:55:28 +0300362 if (!mArrayAssignmentFunctions.empty())
363 {
364 out << "\n// Assignment functions\n\n";
365 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
366 {
367 out << assignmentFunction.functionDefinition << "\n";
368 }
369 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300370 if (!mArrayConstructIntoFunctions.empty())
371 {
372 out << "\n// Array constructor functions\n\n";
373 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
374 {
375 out << constructIntoFunction.functionDefinition << "\n";
376 }
377 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200378
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500379 if (mUsesDiscardRewriting)
380 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400381 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500382 }
383
Nicolas Capens655fe362014-04-11 13:12:34 -0400384 if (mUsesNestedBreak)
385 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400386 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400387 }
388
Arun Patole44efa0b2015-03-04 17:11:05 +0530389 if (mRequiresIEEEStrictCompiling)
390 {
391 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
392 }
393
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400394 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
395 "#define LOOP [loop]\n"
396 "#define FLATTEN [flatten]\n"
397 "#else\n"
398 "#define LOOP\n"
399 "#define FLATTEN\n"
400 "#endif\n";
401
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200402 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200404 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500405 const bool usingMRTExtension = (iter != mExtensionBehavior.end() &&
406 (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000407
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000408 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500409 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400410 out << "\n";
411
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200412 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000413 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500414 for (ReferencedSymbols::const_iterator outputVariableIt =
415 mReferencedOutputVariables.begin();
416 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000417 {
Jamie Madill46131a32013-06-20 11:55:50 -0400418 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500419 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400420
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500421 out << "static " + TypeString(variableType) + " out_" + variableName +
422 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000423 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000424 }
Jamie Madill46131a32013-06-20 11:55:50 -0400425 else
426 {
427 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
428
429 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500430 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400431 for (unsigned int i = 0; i < numColorValues; i++)
432 {
433 out << " float4(0, 0, 0, 0)";
434 if (i + 1 != numColorValues)
435 {
436 out << ",";
437 }
438 out << "\n";
439 }
440
441 out << "};\n";
442 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000443
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400444 if (mUsesFragDepth)
445 {
446 out << "static float gl_Depth = 0.0;\n";
447 }
448
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000449 if (mUsesFragCoord)
450 {
451 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
452 }
453
454 if (mUsesPointCoord)
455 {
456 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
457 }
458
459 if (mUsesFrontFacing)
460 {
461 out << "static bool gl_FrontFacing = false;\n";
462 }
463
464 out << "\n";
465
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000466 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000467 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000468 out << "struct gl_DepthRangeParameters\n"
469 "{\n"
470 " float near;\n"
471 " float far;\n"
472 " float diff;\n"
473 "};\n"
474 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000475 }
476
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200477 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000478 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000479 out << "cbuffer DriverConstants : register(b1)\n"
480 "{\n";
481
482 if (mUsesDepthRange)
483 {
484 out << " float3 dx_DepthRange : packoffset(c0);\n";
485 }
486
487 if (mUsesFragCoord)
488 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000489 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000490 }
491
492 if (mUsesFragCoord || mUsesFrontFacing)
493 {
494 out << " float3 dx_DepthFront : packoffset(c2);\n";
495 }
496
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800497 if (mUsesFragCoord)
498 {
499 // dx_ViewScale is only used in the fragment shader to correct
500 // the value for glFragCoord if necessary
501 out << " float2 dx_ViewScale : packoffset(c3);\n";
502 }
503
Olli Etuaho618bebc2016-01-15 16:40:00 +0200504 if (mOutputType == SH_HLSL_4_1_OUTPUT)
505 {
506 mUniformHLSL->samplerMetadataUniforms(out, "c4");
507 }
508
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000509 out << "};\n";
510 }
511 else
512 {
513 if (mUsesDepthRange)
514 {
515 out << "uniform float3 dx_DepthRange : register(c0);";
516 }
517
518 if (mUsesFragCoord)
519 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000520 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000521 }
522
523 if (mUsesFragCoord || mUsesFrontFacing)
524 {
525 out << "uniform float3 dx_DepthFront : register(c2);\n";
526 }
527 }
528
529 out << "\n";
530
531 if (mUsesDepthRange)
532 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500533 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
534 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000535 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000536 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000537
Jamie Madillf91ce812014-06-13 10:04:34 -0400538 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000539 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400540 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000541 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400542 out << flaggedStructs;
543 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000544 }
545
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000546 if (usingMRTExtension && mNumRenderTargets > 1)
547 {
548 out << "#define GL_USES_MRT\n";
549 }
550
551 if (mUsesFragColor)
552 {
553 out << "#define GL_USES_FRAG_COLOR\n";
554 }
555
556 if (mUsesFragData)
557 {
558 out << "#define GL_USES_FRAG_DATA\n";
559 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000560 }
Xinghua Caob1239382016-12-13 15:07:05 +0800561 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000563 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500564 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000565 out << "\n"
566 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400567
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000568 if (mUsesPointSize)
569 {
570 out << "static float gl_PointSize = float(1);\n";
571 }
572
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000573 if (mUsesInstanceID)
574 {
575 out << "static int gl_InstanceID;";
576 }
577
Corentin Wallezb076add2016-01-11 16:45:46 -0500578 if (mUsesVertexID)
579 {
580 out << "static int gl_VertexID;";
581 }
582
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000583 out << "\n"
584 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500585 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000586 out << "\n";
587
588 if (mUsesDepthRange)
589 {
590 out << "struct gl_DepthRangeParameters\n"
591 "{\n"
592 " float near;\n"
593 " float far;\n"
594 " float diff;\n"
595 "};\n"
596 "\n";
597 }
598
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200599 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000600 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800601 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500602 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800603
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000604 if (mUsesDepthRange)
605 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800606 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000607 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800608
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800609 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
610 // shaders. However, we declare it for all shaders (including Feature Level 10+).
611 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
612 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800613 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800614 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800615 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800616
Olli Etuaho618bebc2016-01-15 16:40:00 +0200617 if (mOutputType == SH_HLSL_4_1_OUTPUT)
618 {
619 mUniformHLSL->samplerMetadataUniforms(out, "c4");
620 }
621
Austin Kinross4fd18b12014-12-22 12:32:05 -0800622 out << "};\n"
623 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000624 }
625 else
626 {
627 if (mUsesDepthRange)
628 {
629 out << "uniform float3 dx_DepthRange : register(c0);\n";
630 }
631
Cooper Partine6664f02015-01-09 16:22:24 -0800632 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
633 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000634 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000635 }
636
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000637 if (mUsesDepthRange)
638 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500639 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
640 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000641 "\n";
642 }
643
Jamie Madillf91ce812014-06-13 10:04:34 -0400644 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000645 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400646 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000647 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400648 out << flaggedStructs;
649 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000650 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400651 }
Xinghua Caob1239382016-12-13 15:07:05 +0800652 else // Compute shader
653 {
654 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800655
656 out << "cbuffer DriverConstants : register(b1)\n"
657 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800658 if (mUsesNumWorkGroups)
659 {
Xinghua Caob1239382016-12-13 15:07:05 +0800660 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800661 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800662 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
663 mUniformHLSL->samplerMetadataUniforms(out, "c1");
664 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800665
666 // Follow built-in variables would be initialized in
667 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
668 // are used in compute shader.
669 if (mUsesWorkGroupID)
670 {
671 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
672 }
673
674 if (mUsesLocalInvocationID)
675 {
676 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
677 }
678
679 if (mUsesGlobalInvocationID)
680 {
681 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
682 }
683
684 if (mUsesLocalInvocationIndex)
685 {
686 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
687 }
688 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000689
Geoff Lang1fe74c72016-08-25 13:23:01 -0400690 bool getDimensionsIgnoresBaseLevel =
691 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
692 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000694 if (mUsesFragCoord)
695 {
696 out << "#define GL_USES_FRAG_COORD\n";
697 }
698
699 if (mUsesPointCoord)
700 {
701 out << "#define GL_USES_POINT_COORD\n";
702 }
703
704 if (mUsesFrontFacing)
705 {
706 out << "#define GL_USES_FRONT_FACING\n";
707 }
708
709 if (mUsesPointSize)
710 {
711 out << "#define GL_USES_POINT_SIZE\n";
712 }
713
Martin Radev41ac68e2017-06-06 12:16:58 +0300714 if (mHasMultiviewExtensionEnabled)
715 {
716 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
717 }
718
719 if (mUsesViewID)
720 {
721 out << "#define GL_USES_VIEW_ID\n";
722 }
723
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400724 if (mUsesFragDepth)
725 {
726 out << "#define GL_USES_FRAG_DEPTH\n";
727 }
728
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000729 if (mUsesDepthRange)
730 {
731 out << "#define GL_USES_DEPTH_RANGE\n";
732 }
733
Xinghua Caob1239382016-12-13 15:07:05 +0800734 if (mUsesNumWorkGroups)
735 {
736 out << "#define GL_USES_NUM_WORK_GROUPS\n";
737 }
738
739 if (mUsesWorkGroupID)
740 {
741 out << "#define GL_USES_WORK_GROUP_ID\n";
742 }
743
744 if (mUsesLocalInvocationID)
745 {
746 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
747 }
748
749 if (mUsesGlobalInvocationID)
750 {
751 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
752 }
753
754 if (mUsesLocalInvocationIndex)
755 {
756 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
757 }
758
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000759 if (mUsesXor)
760 {
761 out << "bool xor(bool p, bool q)\n"
762 "{\n"
763 " return (p || q) && !(p && q);\n"
764 "}\n"
765 "\n";
766 }
767
Olli Etuahodfa75e82017-01-23 09:43:06 -0800768 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769}
770
771void OutputHLSL::visitSymbol(TIntermSymbol *node)
772{
Jamie Madill32aab012015-01-27 14:12:26 -0500773 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000774
Jamie Madill570e04d2013-06-21 09:15:33 -0400775 // Handle accessing std140 structs by value
776 if (mFlaggedStructMappedNames.count(node) > 0)
777 {
778 out << mFlaggedStructMappedNames[node];
779 return;
780 }
781
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782 TString name = node->getSymbol();
783
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000784 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000785 {
786 mUsesDepthRange = true;
787 out << name;
788 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000789 else
790 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000791 TQualifier qualifier = node->getQualifier();
792
793 if (qualifier == EvqUniform)
794 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500795 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400796 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400797
798 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000799 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800800 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000801 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000802 else
803 {
804 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000805 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400806
Jamie Madill2e295e22015-04-29 10:41:33 -0400807 ensureStructDefined(nodeType);
808
Olli Etuahoff526f12017-06-30 12:26:54 +0300809 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000810 }
Jamie Madill19571812013-08-12 15:26:34 -0700811 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000812 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000813 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400814 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000815 }
Jamie Madill033dae62014-06-18 12:56:28 -0400816 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000817 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000818 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400819 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300820 if (name == "ViewID_OVR")
821 {
822 mUsesViewID = true;
823 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000824 }
Jamie Madill19571812013-08-12 15:26:34 -0700825 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400826 {
827 mReferencedOutputVariables[name] = node;
828 out << "out_" << name;
829 }
830 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000831 {
832 out << "gl_Color[0]";
833 mUsesFragColor = true;
834 }
835 else if (qualifier == EvqFragData)
836 {
837 out << "gl_Color";
838 mUsesFragData = true;
839 }
840 else if (qualifier == EvqFragCoord)
841 {
842 mUsesFragCoord = true;
843 out << name;
844 }
845 else if (qualifier == EvqPointCoord)
846 {
847 mUsesPointCoord = true;
848 out << name;
849 }
850 else if (qualifier == EvqFrontFacing)
851 {
852 mUsesFrontFacing = true;
853 out << name;
854 }
855 else if (qualifier == EvqPointSize)
856 {
857 mUsesPointSize = true;
858 out << name;
859 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000860 else if (qualifier == EvqInstanceID)
861 {
862 mUsesInstanceID = true;
863 out << name;
864 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500865 else if (qualifier == EvqVertexID)
866 {
867 mUsesVertexID = true;
868 out << name;
869 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300870 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400871 {
872 mUsesFragDepth = true;
873 out << "gl_Depth";
874 }
Xinghua Caob1239382016-12-13 15:07:05 +0800875 else if (qualifier == EvqNumWorkGroups)
876 {
877 mUsesNumWorkGroups = true;
878 out << name;
879 }
880 else if (qualifier == EvqWorkGroupID)
881 {
882 mUsesWorkGroupID = true;
883 out << name;
884 }
885 else if (qualifier == EvqLocalInvocationID)
886 {
887 mUsesLocalInvocationID = true;
888 out << name;
889 }
890 else if (qualifier == EvqGlobalInvocationID)
891 {
892 mUsesGlobalInvocationID = true;
893 out << name;
894 }
895 else if (qualifier == EvqLocalInvocationIndex)
896 {
897 mUsesLocalInvocationIndex = true;
898 out << name;
899 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000900 else
901 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300902 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000903 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000904 }
905}
906
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400907void OutputHLSL::visitRaw(TIntermRaw *node)
908{
Jamie Madill32aab012015-01-27 14:12:26 -0500909 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400910}
911
Olli Etuaho7fb49552015-03-18 17:27:44 +0200912void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
913{
914 if (type.isScalar() && !type.isArray())
915 {
916 if (op == EOpEqual)
917 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500918 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200919 }
920 else
921 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500922 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200923 }
924 }
925 else
926 {
927 if (visit == PreVisit && op == EOpNotEqual)
928 {
929 out << "!";
930 }
931
932 if (type.isArray())
933 {
934 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500935 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200936 }
937 else if (type.getBasicType() == EbtStruct)
938 {
939 const TStructure &structure = *type.getStruct();
940 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500941 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200942 }
943 else
944 {
945 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500946 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200947 }
948 }
949}
950
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000951bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200952{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000953 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200954 {
955 TIntermNode *ancestor = getAncestorNode(n);
956 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
957 if (ancestorBinary == nullptr)
958 {
959 return false;
960 }
961 switch (ancestorBinary->getOp())
962 {
963 case EOpIndexDirectStruct:
964 {
965 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
966 const TIntermConstantUnion *index =
967 ancestorBinary->getRight()->getAsConstantUnion();
968 const TField *field = structure->fields()[index->getIConst(0)];
969 if (IsSampler(field->type()->getBasicType()))
970 {
971 return true;
972 }
973 break;
974 }
975 case EOpIndexDirect:
976 break;
977 default:
978 // Returning a sampler from indirect indexing is not supported.
979 return false;
980 }
981 }
982 return false;
983}
984
Olli Etuahob6fa0432016-09-28 16:28:05 +0100985bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
986{
987 TInfoSinkBase &out = getInfoSink();
988 if (visit == PostVisit)
989 {
990 out << ".";
991 node->writeOffsetsAsXYZW(&out);
992 }
993 return true;
994}
995
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000996bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
997{
Jamie Madill32aab012015-01-27 14:12:26 -0500998 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999
Jamie Madill570e04d2013-06-21 09:15:33 -04001000 // Handle accessing std140 structs by value
1001 if (mFlaggedStructMappedNames.count(node) > 0)
1002 {
1003 out << mFlaggedStructMappedNames[node];
1004 return false;
1005 }
1006
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 switch (node->getOp())
1008 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001009 case EOpComma:
1010 outputTriplet(out, visit, "(", ", ", ")");
1011 break;
1012 case EOpAssign:
1013 if (node->getLeft()->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001014 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001015 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1016 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001017 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001018 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1019 out << functionName << "(";
1020 node->getLeft()->traverse(this);
1021 TIntermSequence *seq = rightAgg->getSequence();
1022 for (auto &arrayElement : *seq)
1023 {
1024 out << ", ";
1025 arrayElement->traverse(this);
1026 }
1027 out << ")";
1028 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001029 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001030 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1031 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001032 ASSERT(rightAgg == nullptr);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001033
1034 const TString &functionName = addArrayAssignmentFunction(node->getType());
1035 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho9638c352015-04-01 14:34:52 +03001036 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001037 else
Jamie Madill37997142015-01-28 10:06:34 -05001038 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001039 outputTriplet(out, visit, "(", " = ", ")");
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001040 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001041 break;
1042 case EOpInitialize:
1043 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001044 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001045 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1046 ASSERT(symbolNode);
1047 TIntermTyped *expression = node->getRight();
1048
1049 // Global initializers must be constant at this point.
1050 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1051 canWriteAsHLSLLiteral(expression));
1052
1053 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1054 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1055 // new variable is created before the assignment is evaluated), so we need to
1056 // convert
1057 // this to "float t = x, x = t;".
1058 if (writeSameSymbolInitializer(out, symbolNode, expression))
1059 {
1060 // Skip initializing the rest of the expression
1061 return false;
1062 }
1063 else if (writeConstantInitialization(out, symbolNode, expression))
1064 {
1065 return false;
1066 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001067 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001068 else if (visit == InVisit)
1069 {
1070 out << " = ";
1071 }
1072 break;
1073 case EOpAddAssign:
1074 outputTriplet(out, visit, "(", " += ", ")");
1075 break;
1076 case EOpSubAssign:
1077 outputTriplet(out, visit, "(", " -= ", ")");
1078 break;
1079 case EOpMulAssign:
1080 outputTriplet(out, visit, "(", " *= ", ")");
1081 break;
1082 case EOpVectorTimesScalarAssign:
1083 outputTriplet(out, visit, "(", " *= ", ")");
1084 break;
1085 case EOpMatrixTimesScalarAssign:
1086 outputTriplet(out, visit, "(", " *= ", ")");
1087 break;
1088 case EOpVectorTimesMatrixAssign:
1089 if (visit == PreVisit)
1090 {
1091 out << "(";
1092 }
1093 else if (visit == InVisit)
1094 {
1095 out << " = mul(";
1096 node->getLeft()->traverse(this);
1097 out << ", transpose(";
1098 }
1099 else
1100 {
1101 out << ")))";
1102 }
1103 break;
1104 case EOpMatrixTimesMatrixAssign:
1105 if (visit == PreVisit)
1106 {
1107 out << "(";
1108 }
1109 else if (visit == InVisit)
1110 {
1111 out << " = transpose(mul(transpose(";
1112 node->getLeft()->traverse(this);
1113 out << "), transpose(";
1114 }
1115 else
1116 {
1117 out << "))))";
1118 }
1119 break;
1120 case EOpDivAssign:
1121 outputTriplet(out, visit, "(", " /= ", ")");
1122 break;
1123 case EOpIModAssign:
1124 outputTriplet(out, visit, "(", " %= ", ")");
1125 break;
1126 case EOpBitShiftLeftAssign:
1127 outputTriplet(out, visit, "(", " <<= ", ")");
1128 break;
1129 case EOpBitShiftRightAssign:
1130 outputTriplet(out, visit, "(", " >>= ", ")");
1131 break;
1132 case EOpBitwiseAndAssign:
1133 outputTriplet(out, visit, "(", " &= ", ")");
1134 break;
1135 case EOpBitwiseXorAssign:
1136 outputTriplet(out, visit, "(", " ^= ", ")");
1137 break;
1138 case EOpBitwiseOrAssign:
1139 outputTriplet(out, visit, "(", " |= ", ")");
1140 break;
1141 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001142 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001143 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001144 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001145 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001146 if (visit == PreVisit)
1147 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001148 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001149 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001150 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001151 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001152 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001153 return false;
1154 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001155 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001156 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001157 {
1158 // All parts of an expression that access a sampler in a struct need to use _ as
1159 // separator to access the sampler variable that has been moved out of the struct.
1160 outputTriplet(out, visit, "", "_", "");
1161 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001162 else
1163 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001164 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001165 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001166 }
1167 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001168 case EOpIndexIndirect:
1169 // We do not currently support indirect references to interface blocks
1170 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1171 outputTriplet(out, visit, "", "[", "]");
1172 break;
1173 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001174 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001175 const TStructure *structure = node->getLeft()->getType().getStruct();
1176 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1177 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001178
Olli Etuaho96963162016-03-21 11:54:33 +02001179 // In cases where indexing returns a sampler, we need to access the sampler variable
1180 // that has been moved out of the struct.
1181 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1182 if (visit == PreVisit && indexingReturnsSampler)
1183 {
1184 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1185 // This prefix is only output at the beginning of the indexing expression, which
1186 // may have multiple parts.
1187 out << "angle";
1188 }
1189 if (!indexingReturnsSampler)
1190 {
1191 // All parts of an expression that access a sampler in a struct need to use _ as
1192 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001193 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001194 }
1195 if (visit == InVisit)
1196 {
1197 if (indexingReturnsSampler)
1198 {
1199 out << "_" + field->name();
1200 }
1201 else
1202 {
1203 out << "." + DecorateField(field->name(), *structure);
1204 }
1205
1206 return false;
1207 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001208 }
1209 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001210 case EOpIndexDirectInterfaceBlock:
1211 if (visit == InVisit)
1212 {
1213 const TInterfaceBlock *interfaceBlock =
1214 node->getLeft()->getType().getInterfaceBlock();
1215 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1216 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1217 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001218
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001219 return false;
1220 }
1221 break;
1222 case EOpAdd:
1223 outputTriplet(out, visit, "(", " + ", ")");
1224 break;
1225 case EOpSub:
1226 outputTriplet(out, visit, "(", " - ", ")");
1227 break;
1228 case EOpMul:
1229 outputTriplet(out, visit, "(", " * ", ")");
1230 break;
1231 case EOpDiv:
1232 outputTriplet(out, visit, "(", " / ", ")");
1233 break;
1234 case EOpIMod:
1235 outputTriplet(out, visit, "(", " % ", ")");
1236 break;
1237 case EOpBitShiftLeft:
1238 outputTriplet(out, visit, "(", " << ", ")");
1239 break;
1240 case EOpBitShiftRight:
1241 outputTriplet(out, visit, "(", " >> ", ")");
1242 break;
1243 case EOpBitwiseAnd:
1244 outputTriplet(out, visit, "(", " & ", ")");
1245 break;
1246 case EOpBitwiseXor:
1247 outputTriplet(out, visit, "(", " ^ ", ")");
1248 break;
1249 case EOpBitwiseOr:
1250 outputTriplet(out, visit, "(", " | ", ")");
1251 break;
1252 case EOpEqual:
1253 case EOpNotEqual:
1254 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1255 break;
1256 case EOpLessThan:
1257 outputTriplet(out, visit, "(", " < ", ")");
1258 break;
1259 case EOpGreaterThan:
1260 outputTriplet(out, visit, "(", " > ", ")");
1261 break;
1262 case EOpLessThanEqual:
1263 outputTriplet(out, visit, "(", " <= ", ")");
1264 break;
1265 case EOpGreaterThanEqual:
1266 outputTriplet(out, visit, "(", " >= ", ")");
1267 break;
1268 case EOpVectorTimesScalar:
1269 outputTriplet(out, visit, "(", " * ", ")");
1270 break;
1271 case EOpMatrixTimesScalar:
1272 outputTriplet(out, visit, "(", " * ", ")");
1273 break;
1274 case EOpVectorTimesMatrix:
1275 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1276 break;
1277 case EOpMatrixTimesVector:
1278 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1279 break;
1280 case EOpMatrixTimesMatrix:
1281 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1282 break;
1283 case EOpLogicalOr:
1284 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1285 // been unfolded.
1286 ASSERT(!node->getRight()->hasSideEffects());
1287 outputTriplet(out, visit, "(", " || ", ")");
1288 return true;
1289 case EOpLogicalXor:
1290 mUsesXor = true;
1291 outputTriplet(out, visit, "xor(", ", ", ")");
1292 break;
1293 case EOpLogicalAnd:
1294 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1295 // been unfolded.
1296 ASSERT(!node->getRight()->hasSideEffects());
1297 outputTriplet(out, visit, "(", " && ", ")");
1298 return true;
1299 default:
1300 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001301 }
1302
1303 return true;
1304}
1305
1306bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1307{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001308 TInfoSinkBase &out = getInfoSink();
1309
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001310 switch (node->getOp())
1311 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001312 case EOpNegative:
1313 outputTriplet(out, visit, "(-", "", ")");
1314 break;
1315 case EOpPositive:
1316 outputTriplet(out, visit, "(+", "", ")");
1317 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001318 case EOpLogicalNot:
1319 outputTriplet(out, visit, "(!", "", ")");
1320 break;
1321 case EOpBitwiseNot:
1322 outputTriplet(out, visit, "(~", "", ")");
1323 break;
1324 case EOpPostIncrement:
1325 outputTriplet(out, visit, "(", "", "++)");
1326 break;
1327 case EOpPostDecrement:
1328 outputTriplet(out, visit, "(", "", "--)");
1329 break;
1330 case EOpPreIncrement:
1331 outputTriplet(out, visit, "(++", "", ")");
1332 break;
1333 case EOpPreDecrement:
1334 outputTriplet(out, visit, "(--", "", ")");
1335 break;
1336 case EOpRadians:
1337 outputTriplet(out, visit, "radians(", "", ")");
1338 break;
1339 case EOpDegrees:
1340 outputTriplet(out, visit, "degrees(", "", ")");
1341 break;
1342 case EOpSin:
1343 outputTriplet(out, visit, "sin(", "", ")");
1344 break;
1345 case EOpCos:
1346 outputTriplet(out, visit, "cos(", "", ")");
1347 break;
1348 case EOpTan:
1349 outputTriplet(out, visit, "tan(", "", ")");
1350 break;
1351 case EOpAsin:
1352 outputTriplet(out, visit, "asin(", "", ")");
1353 break;
1354 case EOpAcos:
1355 outputTriplet(out, visit, "acos(", "", ")");
1356 break;
1357 case EOpAtan:
1358 outputTriplet(out, visit, "atan(", "", ")");
1359 break;
1360 case EOpSinh:
1361 outputTriplet(out, visit, "sinh(", "", ")");
1362 break;
1363 case EOpCosh:
1364 outputTriplet(out, visit, "cosh(", "", ")");
1365 break;
1366 case EOpTanh:
1367 outputTriplet(out, visit, "tanh(", "", ")");
1368 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001369 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001370 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001371 case EOpAtanh:
1372 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001373 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001374 break;
1375 case EOpExp:
1376 outputTriplet(out, visit, "exp(", "", ")");
1377 break;
1378 case EOpLog:
1379 outputTriplet(out, visit, "log(", "", ")");
1380 break;
1381 case EOpExp2:
1382 outputTriplet(out, visit, "exp2(", "", ")");
1383 break;
1384 case EOpLog2:
1385 outputTriplet(out, visit, "log2(", "", ")");
1386 break;
1387 case EOpSqrt:
1388 outputTriplet(out, visit, "sqrt(", "", ")");
1389 break;
1390 case EOpInverseSqrt:
1391 outputTriplet(out, visit, "rsqrt(", "", ")");
1392 break;
1393 case EOpAbs:
1394 outputTriplet(out, visit, "abs(", "", ")");
1395 break;
1396 case EOpSign:
1397 outputTriplet(out, visit, "sign(", "", ")");
1398 break;
1399 case EOpFloor:
1400 outputTriplet(out, visit, "floor(", "", ")");
1401 break;
1402 case EOpTrunc:
1403 outputTriplet(out, visit, "trunc(", "", ")");
1404 break;
1405 case EOpRound:
1406 outputTriplet(out, visit, "round(", "", ")");
1407 break;
1408 case EOpRoundEven:
1409 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001410 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001411 break;
1412 case EOpCeil:
1413 outputTriplet(out, visit, "ceil(", "", ")");
1414 break;
1415 case EOpFract:
1416 outputTriplet(out, visit, "frac(", "", ")");
1417 break;
1418 case EOpIsNan:
1419 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001420 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001421 else
1422 outputTriplet(out, visit, "isnan(", "", ")");
1423 mRequiresIEEEStrictCompiling = true;
1424 break;
1425 case EOpIsInf:
1426 outputTriplet(out, visit, "isinf(", "", ")");
1427 break;
1428 case EOpFloatBitsToInt:
1429 outputTriplet(out, visit, "asint(", "", ")");
1430 break;
1431 case EOpFloatBitsToUint:
1432 outputTriplet(out, visit, "asuint(", "", ")");
1433 break;
1434 case EOpIntBitsToFloat:
1435 outputTriplet(out, visit, "asfloat(", "", ")");
1436 break;
1437 case EOpUintBitsToFloat:
1438 outputTriplet(out, visit, "asfloat(", "", ")");
1439 break;
1440 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001441 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001442 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001443 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001444 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001445 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001446 case EOpPackUnorm4x8:
1447 case EOpPackSnorm4x8:
1448 case EOpUnpackUnorm4x8:
1449 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001450 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001451 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001452 break;
1453 case EOpLength:
1454 outputTriplet(out, visit, "length(", "", ")");
1455 break;
1456 case EOpNormalize:
1457 outputTriplet(out, visit, "normalize(", "", ")");
1458 break;
1459 case EOpDFdx:
1460 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1461 {
1462 outputTriplet(out, visit, "(", "", ", 0.0)");
1463 }
1464 else
1465 {
1466 outputTriplet(out, visit, "ddx(", "", ")");
1467 }
1468 break;
1469 case EOpDFdy:
1470 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1471 {
1472 outputTriplet(out, visit, "(", "", ", 0.0)");
1473 }
1474 else
1475 {
1476 outputTriplet(out, visit, "ddy(", "", ")");
1477 }
1478 break;
1479 case EOpFwidth:
1480 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1481 {
1482 outputTriplet(out, visit, "(", "", ", 0.0)");
1483 }
1484 else
1485 {
1486 outputTriplet(out, visit, "fwidth(", "", ")");
1487 }
1488 break;
1489 case EOpTranspose:
1490 outputTriplet(out, visit, "transpose(", "", ")");
1491 break;
1492 case EOpDeterminant:
1493 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1494 break;
1495 case EOpInverse:
1496 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001497 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001499
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001500 case EOpAny:
1501 outputTriplet(out, visit, "any(", "", ")");
1502 break;
1503 case EOpAll:
1504 outputTriplet(out, visit, "all(", "", ")");
1505 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001506 case EOpLogicalNotComponentWise:
1507 outputTriplet(out, visit, "(!", "", ")");
1508 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001509 case EOpBitfieldReverse:
1510 outputTriplet(out, visit, "reversebits(", "", ")");
1511 break;
1512 case EOpBitCount:
1513 outputTriplet(out, visit, "countbits(", "", ")");
1514 break;
1515 case EOpFindLSB:
1516 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1517 // in GLSLTest and results are consistent with GL.
1518 outputTriplet(out, visit, "firstbitlow(", "", ")");
1519 break;
1520 case EOpFindMSB:
1521 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1522 // tested in GLSLTest and results are consistent with GL.
1523 outputTriplet(out, visit, "firstbithigh(", "", ")");
1524 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001525 default:
1526 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001527 }
1528
1529 return true;
1530}
1531
Olli Etuaho96963162016-03-21 11:54:33 +02001532TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1533{
1534 if (node->getAsSymbolNode())
1535 {
1536 return node->getAsSymbolNode()->getSymbol();
1537 }
1538 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1539 switch (nodeBinary->getOp())
1540 {
1541 case EOpIndexDirect:
1542 {
1543 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1544
1545 TInfoSinkBase prefixSink;
1546 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1547 return TString(prefixSink.c_str());
1548 }
1549 case EOpIndexDirectStruct:
1550 {
1551 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1552 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1553 const TField *field = s->fields()[index];
1554
1555 TInfoSinkBase prefixSink;
1556 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1557 << field->name();
1558 return TString(prefixSink.c_str());
1559 }
1560 default:
1561 UNREACHABLE();
1562 return TString("");
1563 }
1564}
1565
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001566bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1567{
1568 TInfoSinkBase &out = getInfoSink();
1569
1570 if (mInsideFunction)
1571 {
1572 outputLineDirective(out, node->getLine().first_line);
1573 out << "{\n";
1574 }
1575
1576 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1577 sit != node->getSequence()->end(); sit++)
1578 {
1579 outputLineDirective(out, (*sit)->getLine().first_line);
1580
1581 (*sit)->traverse(this);
1582
1583 // Don't output ; after case labels, they're terminated by :
1584 // This is needed especially since outputting a ; after a case statement would turn empty
1585 // case statements into non-empty case statements, disallowing fall-through from them.
1586 // Also no need to output ; after if statements or sequences. This is done just for
1587 // code clarity.
1588 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1589 (*sit)->getAsBlock() == nullptr)
1590 out << ";\n";
1591 }
1592
1593 if (mInsideFunction)
1594 {
1595 outputLineDirective(out, node->getLine().last_line);
1596 out << "}\n";
1597 }
1598
1599 return false;
1600}
1601
Olli Etuaho336b1472016-10-05 16:37:55 +01001602bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1603{
1604 TInfoSinkBase &out = getInfoSink();
1605
1606 ASSERT(mCurrentFunctionMetadata == nullptr);
1607
1608 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1609 ASSERT(index != CallDAG::InvalidIndex);
1610 mCurrentFunctionMetadata = &mASTMetadataList[index];
1611
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001612 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001613
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001614 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001615
1616 if (node->getFunctionSymbolInfo()->isMain())
1617 {
1618 out << "gl_main(";
1619 }
1620 else
1621 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001622 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001623 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1624 }
1625
1626 for (unsigned int i = 0; i < parameters->size(); i++)
1627 {
1628 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1629
1630 if (symbol)
1631 {
1632 ensureStructDefined(symbol->getType());
1633
1634 out << argumentString(symbol);
1635
1636 if (i < parameters->size() - 1)
1637 {
1638 out << ", ";
1639 }
1640 }
1641 else
1642 UNREACHABLE();
1643 }
1644
1645 out << ")\n";
1646
1647 mInsideFunction = true;
1648 // The function body node will output braces.
1649 node->getBody()->traverse(this);
1650 mInsideFunction = false;
1651
1652 mCurrentFunctionMetadata = nullptr;
1653
1654 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1655 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1656 {
1657 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1658 mOutputLod0Function = true;
1659 node->traverse(this);
1660 mOutputLod0Function = false;
1661 }
1662
1663 return false;
1664}
1665
Olli Etuaho13389b62016-10-16 11:48:18 +01001666bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1667{
1668 TInfoSinkBase &out = getInfoSink();
1669 if (visit == PreVisit)
1670 {
1671 TIntermSequence *sequence = node->getSequence();
1672 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1673 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001674 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001675
Olli Etuaho282847e2017-07-12 14:11:01 +03001676 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001677 variable->getQualifier() == EvqConst))
1678 {
1679 ensureStructDefined(variable->getType());
1680
1681 if (!variable->getAsSymbolNode() ||
1682 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1683 {
1684 if (!mInsideFunction)
1685 {
1686 out << "static ";
1687 }
1688
1689 out << TypeString(variable->getType()) + " ";
1690
1691 TIntermSymbol *symbol = variable->getAsSymbolNode();
1692
1693 if (symbol)
1694 {
1695 symbol->traverse(this);
1696 out << ArrayString(symbol->getType());
1697 out << " = " + initializer(symbol->getType());
1698 }
1699 else
1700 {
1701 variable->traverse(this);
1702 }
1703 }
1704 else if (variable->getAsSymbolNode() &&
1705 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1706 {
1707 // Already added to constructor map
1708 }
1709 else
1710 UNREACHABLE();
1711 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001712 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001713 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001714 TIntermSymbol *symbol = variable->getAsSymbolNode();
1715 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001716
Olli Etuaho282847e2017-07-12 14:11:01 +03001717 // Vertex outputs which are declared but not written to should still be declared to
1718 // allow successful linking.
1719 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001720 }
1721 }
1722 return false;
1723}
1724
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001725bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1726{
1727 // Do not do any translation
1728 return false;
1729}
1730
Olli Etuaho16c745a2017-01-16 17:02:27 +00001731bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1732{
1733 TInfoSinkBase &out = getInfoSink();
1734
1735 ASSERT(visit == PreVisit);
1736 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1737 // Skip the prototype if it is not implemented (and thus not used)
1738 if (index == CallDAG::InvalidIndex)
1739 {
1740 return false;
1741 }
1742
1743 TIntermSequence *arguments = node->getSequence();
1744
Olli Etuahoff526f12017-06-30 12:26:54 +03001745 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001746 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1747 << (mOutputLod0Function ? "Lod0(" : "(");
1748
1749 for (unsigned int i = 0; i < arguments->size(); i++)
1750 {
1751 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1752 ASSERT(symbol != nullptr);
1753
1754 out << argumentString(symbol);
1755
1756 if (i < arguments->size() - 1)
1757 {
1758 out << ", ";
1759 }
1760 }
1761
1762 out << ");\n";
1763
1764 // Also prototype the Lod0 variant if needed
1765 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1766 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1767 {
1768 mOutputLod0Function = true;
1769 node->traverse(this);
1770 mOutputLod0Function = false;
1771 }
1772
1773 return false;
1774}
1775
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001776bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1777{
Jamie Madill32aab012015-01-27 14:12:26 -05001778 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001779
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001780 switch (node->getOp())
1781 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001782 case EOpCallBuiltInFunction:
1783 case EOpCallFunctionInAST:
1784 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001786 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001787
Corentin Wallez1239ee92015-03-19 14:38:02 -07001788 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001789 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001791 if (node->isArray())
1792 {
1793 UNIMPLEMENTED();
1794 }
Olli Etuahobd674552016-10-06 13:28:42 +01001795 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001796 ASSERT(index != CallDAG::InvalidIndex);
1797 lod0 &= mASTMetadataList[index].mNeedsLod0;
1798
Olli Etuahoff526f12017-06-30 12:26:54 +03001799 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001800 out << DisambiguateFunctionName(node->getSequence());
1801 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001802 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001803 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001804 {
1805 // This path is used for internal functions that don't have their definitions in the
1806 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001807 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001808 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001809 else
1810 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001811 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001812 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001813 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1814 if (arguments->size() > 1)
1815 {
1816 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1817 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001818 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1819 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1820 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001821 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001822
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001823 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001824 {
Olli Etuaho96963162016-03-21 11:54:33 +02001825 TIntermTyped *typedArg = (*arg)->getAsTyped();
1826 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001827 {
1828 out << "texture_";
1829 (*arg)->traverse(this);
1830 out << ", sampler_";
1831 }
1832
1833 (*arg)->traverse(this);
1834
Olli Etuaho96963162016-03-21 11:54:33 +02001835 if (typedArg->getType().isStructureContainingSamplers())
1836 {
1837 const TType &argType = typedArg->getType();
1838 TVector<TIntermSymbol *> samplerSymbols;
1839 TString structName = samplerNamePrefixFromStruct(typedArg);
1840 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho96963162016-03-21 11:54:33 +02001841 &samplerSymbols, nullptr);
1842 for (const TIntermSymbol *sampler : samplerSymbols)
1843 {
1844 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1845 {
1846 out << ", texture_" << sampler->getSymbol();
1847 out << ", sampler_" << sampler->getSymbol();
1848 }
1849 else
1850 {
1851 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1852 // of D3D9, it's the sampler variable.
1853 out << ", " + sampler->getSymbol();
1854 }
1855 }
1856 }
1857
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001858 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001859 {
1860 out << ", ";
1861 }
1862 }
1863
1864 out << ")";
1865
1866 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001867 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001868 case EOpConstruct:
1869 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001870 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001871 if (node->getType().isArray())
1872 {
1873 UNIMPLEMENTED();
1874 }
1875 const TString &structName = StructNameString(*node->getType().getStruct());
1876 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1877 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001878 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001879 else
1880 {
1881 const char *name = "";
1882 if (node->getType().getNominalSize() == 1)
1883 {
1884 switch (node->getBasicType())
1885 {
1886 case EbtFloat:
1887 name = "vec1";
1888 break;
1889 case EbtInt:
1890 name = "ivec1";
1891 break;
1892 case EbtUInt:
1893 name = "uvec1";
1894 break;
1895 case EbtBool:
1896 name = "bvec1";
1897 break;
1898 default:
1899 UNREACHABLE();
1900 }
1901 }
1902 else
1903 {
1904 name = node->getType().getBuiltInTypeNameString();
1905 }
1906 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1907 }
1908 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001909 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001910 outputTriplet(out, visit, "(", " == ", ")");
1911 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001912 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001913 outputTriplet(out, visit, "(", " != ", ")");
1914 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001915 case EOpLessThanComponentWise:
1916 outputTriplet(out, visit, "(", " < ", ")");
1917 break;
1918 case EOpGreaterThanComponentWise:
1919 outputTriplet(out, visit, "(", " > ", ")");
1920 break;
1921 case EOpLessThanEqualComponentWise:
1922 outputTriplet(out, visit, "(", " <= ", ")");
1923 break;
1924 case EOpGreaterThanEqualComponentWise:
1925 outputTriplet(out, visit, "(", " >= ", ")");
1926 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001927 case EOpMod:
1928 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001929 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001930 break;
1931 case EOpModf:
1932 outputTriplet(out, visit, "modf(", ", ", ")");
1933 break;
1934 case EOpPow:
1935 outputTriplet(out, visit, "pow(", ", ", ")");
1936 break;
1937 case EOpAtan:
1938 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1939 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001940 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001941 break;
1942 case EOpMin:
1943 outputTriplet(out, visit, "min(", ", ", ")");
1944 break;
1945 case EOpMax:
1946 outputTriplet(out, visit, "max(", ", ", ")");
1947 break;
1948 case EOpClamp:
1949 outputTriplet(out, visit, "clamp(", ", ", ")");
1950 break;
1951 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301952 {
1953 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1954 if (lastParamNode->getType().getBasicType() == EbtBool)
1955 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001956 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1957 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301958 // so use emulated version.
1959 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001960 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301961 }
1962 else
1963 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001964 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301965 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001966 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301967 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001968 case EOpStep:
1969 outputTriplet(out, visit, "step(", ", ", ")");
1970 break;
1971 case EOpSmoothStep:
1972 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1973 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001974 case EOpFrexp:
1975 case EOpLdexp:
1976 ASSERT(node->getUseEmulatedFunction());
1977 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1978 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001979 case EOpDistance:
1980 outputTriplet(out, visit, "distance(", ", ", ")");
1981 break;
1982 case EOpDot:
1983 outputTriplet(out, visit, "dot(", ", ", ")");
1984 break;
1985 case EOpCross:
1986 outputTriplet(out, visit, "cross(", ", ", ")");
1987 break;
Jamie Madille72595b2017-06-06 15:12:26 -04001988 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01001989 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001990 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001991 break;
1992 case EOpReflect:
1993 outputTriplet(out, visit, "reflect(", ", ", ")");
1994 break;
1995 case EOpRefract:
1996 outputTriplet(out, visit, "refract(", ", ", ")");
1997 break;
1998 case EOpOuterProduct:
1999 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002000 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002001 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002002 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002003 outputTriplet(out, visit, "(", " * ", ")");
2004 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002005 case EOpBitfieldExtract:
2006 case EOpBitfieldInsert:
2007 case EOpUaddCarry:
2008 case EOpUsubBorrow:
2009 case EOpUmulExtended:
2010 case EOpImulExtended:
2011 ASSERT(node->getUseEmulatedFunction());
2012 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2013 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002014 default:
2015 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002016 }
2017
2018 return true;
2019}
2020
Olli Etuaho57961272016-09-14 13:57:46 +03002021void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002022{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002023 out << "if (";
2024
2025 node->getCondition()->traverse(this);
2026
2027 out << ")\n";
2028
Jamie Madill8c46ab12015-12-07 16:39:19 -05002029 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002030
2031 bool discard = false;
2032
2033 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002034 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002035 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002036 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002037
Olli Etuahoa6f22092015-05-08 18:31:10 +03002038 // Detect true discard
2039 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2040 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002041 else
2042 {
2043 // TODO(oetuaho): Check if the semicolon inside is necessary.
2044 // It's there as a result of conservative refactoring of the output.
2045 out << "{;}\n";
2046 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002047
Jamie Madill8c46ab12015-12-07 16:39:19 -05002048 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002049
Olli Etuahoa6f22092015-05-08 18:31:10 +03002050 if (node->getFalseBlock())
2051 {
2052 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002053
Jamie Madill8c46ab12015-12-07 16:39:19 -05002054 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002055
Olli Etuaho32db19b2016-10-04 14:43:16 +01002056 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002057 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002058
Jamie Madill8c46ab12015-12-07 16:39:19 -05002059 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002060
Olli Etuahoa6f22092015-05-08 18:31:10 +03002061 // Detect false discard
2062 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2063 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002064
Olli Etuahoa6f22092015-05-08 18:31:10 +03002065 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002066 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002067 {
2068 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002069 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002070}
2071
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002072bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2073{
2074 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2075 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2076 UNREACHABLE();
2077 return false;
2078}
2079
Olli Etuaho57961272016-09-14 13:57:46 +03002080bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002081{
2082 TInfoSinkBase &out = getInfoSink();
2083
Olli Etuaho3d932d82016-04-12 11:10:30 +03002084 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002085
2086 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002087 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002088 {
2089 out << "FLATTEN ";
2090 }
2091
Olli Etuaho57961272016-09-14 13:57:46 +03002092 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002093
2094 return false;
2095}
2096
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002097bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002098{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002099 TInfoSinkBase &out = getInfoSink();
2100
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002101 if (node->getStatementList())
2102 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002103 node->setStatementList(
2104 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002105 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002106 // The curly braces get written when visiting the statementList aggregate
2107 }
2108 else
2109 {
2110 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002111 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002112 }
2113 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002114}
2115
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002116bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002117{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002118 TInfoSinkBase &out = getInfoSink();
2119
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002120 if (node->hasCondition())
2121 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002122 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002123 return true;
2124 }
2125 else
2126 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002127 out << "default:\n";
2128 return false;
2129 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002130}
2131
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002132void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2133{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002134 TInfoSinkBase &out = getInfoSink();
2135 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002136}
2137
2138bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2139{
Nicolas Capens655fe362014-04-11 13:12:34 -04002140 mNestedLoopDepth++;
2141
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002142 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002143 mInsideDiscontinuousLoop =
2144 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002145
Jamie Madill8c46ab12015-12-07 16:39:19 -05002146 TInfoSinkBase &out = getInfoSink();
2147
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002148 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002149 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002150 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002151 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002152 mInsideDiscontinuousLoop = wasDiscontinuous;
2153 mNestedLoopDepth--;
2154
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002155 return false;
2156 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002157 }
2158
Corentin Wallez1239ee92015-03-19 14:38:02 -07002159 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002160 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002161 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002162 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002163
Jamie Madill8c46ab12015-12-07 16:39:19 -05002164 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002165 }
2166 else
2167 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002168 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002169
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170 if (node->getInit())
2171 {
2172 node->getInit()->traverse(this);
2173 }
2174
2175 out << "; ";
2176
alokp@chromium.org52813552010-11-16 18:36:09 +00002177 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002179 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002180 }
2181
2182 out << "; ";
2183
alokp@chromium.org52813552010-11-16 18:36:09 +00002184 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002185 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002186 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002187 }
2188
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002189 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002190
Jamie Madill8c46ab12015-12-07 16:39:19 -05002191 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002192 }
2193
2194 if (node->getBody())
2195 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002196 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002197 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002199 else
2200 {
2201 // TODO(oetuaho): Check if the semicolon inside is necessary.
2202 // It's there as a result of conservative refactoring of the output.
2203 out << "{;}\n";
2204 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002205
Jamie Madill8c46ab12015-12-07 16:39:19 -05002206 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207
alokp@chromium.org52813552010-11-16 18:36:09 +00002208 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002209 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002210 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002211 out << "while(\n";
2212
alokp@chromium.org52813552010-11-16 18:36:09 +00002213 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002214
daniel@transgaming.com73536982012-03-21 20:45:49 +00002215 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 }
2217
daniel@transgaming.com73536982012-03-21 20:45:49 +00002218 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002220 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002221 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002222
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002223 return false;
2224}
2225
2226bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2227{
Jamie Madill32aab012015-01-27 14:12:26 -05002228 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229
2230 switch (node->getFlowOp())
2231 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002232 case EOpKill:
2233 outputTriplet(out, visit, "discard;\n", "", "");
2234 break;
2235 case EOpBreak:
2236 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002237 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002238 if (mNestedLoopDepth > 1)
2239 {
2240 mUsesNestedBreak = true;
2241 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002242
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002243 if (mExcessiveLoopIndex)
2244 {
2245 out << "{Break";
2246 mExcessiveLoopIndex->traverse(this);
2247 out << " = true; break;}\n";
2248 }
2249 else
2250 {
2251 out << "break;\n";
2252 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002253 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002254 break;
2255 case EOpContinue:
2256 outputTriplet(out, visit, "continue;\n", "", "");
2257 break;
2258 case EOpReturn:
2259 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002260 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002261 if (node->getExpression())
2262 {
2263 out << "return ";
2264 }
2265 else
2266 {
2267 out << "return;\n";
2268 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002269 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002270 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002271 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002272 if (node->getExpression())
2273 {
2274 out << ";\n";
2275 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002276 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002277 break;
2278 default:
2279 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002280 }
2281
2282 return true;
2283}
2284
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002285// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002286// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2287// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002288bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002289{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002290 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002291
2292 // Parse loops of the form:
2293 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002294 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002295 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002296 int initial = 0;
2297 int limit = 0;
2298 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002299
2300 // Parse index name and intial value
2301 if (node->getInit())
2302 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002303 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002304
2305 if (init)
2306 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002307 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002308 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002309
2310 if (variable && variable->getQualifier() == EvqTemporary)
2311 {
2312 TIntermBinary *assign = variable->getAsBinaryNode();
2313
2314 if (assign->getOp() == EOpInitialize)
2315 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002316 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002317 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2318
2319 if (symbol && constant)
2320 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002321 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002322 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002323 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002324 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002325 }
2326 }
2327 }
2328 }
2329 }
2330 }
2331
2332 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002333 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002334 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002335 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002336
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002337 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2338 {
2339 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2340
2341 if (constant)
2342 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002343 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002344 {
2345 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002346 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002347 }
2348 }
2349 }
2350 }
2351
2352 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002353 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002354 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002355 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002356 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002357
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002358 if (binaryTerminal)
2359 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002360 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002361 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2362
2363 if (constant)
2364 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002365 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002366 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002367 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002368
2369 switch (op)
2370 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002371 case EOpAddAssign:
2372 increment = value;
2373 break;
2374 case EOpSubAssign:
2375 increment = -value;
2376 break;
2377 default:
2378 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002379 }
2380 }
2381 }
2382 }
2383 else if (unaryTerminal)
2384 {
2385 TOperator op = unaryTerminal->getOp();
2386
2387 switch (op)
2388 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002389 case EOpPostIncrement:
2390 increment = 1;
2391 break;
2392 case EOpPostDecrement:
2393 increment = -1;
2394 break;
2395 case EOpPreIncrement:
2396 increment = 1;
2397 break;
2398 case EOpPreDecrement:
2399 increment = -1;
2400 break;
2401 default:
2402 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002403 }
2404 }
2405 }
2406
Yunchao He4f285442017-04-21 12:15:49 +08002407 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002408 {
2409 if (comparator == EOpLessThanEqual)
2410 {
2411 comparator = EOpLessThan;
2412 limit += 1;
2413 }
2414
2415 if (comparator == EOpLessThan)
2416 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002417 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002418
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002419 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002420 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002421 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002422 }
2423
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002424 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002425 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002426
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002427 out << "{int ";
2428 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002429 out << ";\n"
2430 "bool Break";
2431 index->traverse(this);
2432 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002433
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002434 bool firstLoopFragment = true;
2435
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002436 while (iterations > 0)
2437 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002438 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002439
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002440 if (!firstLoopFragment)
2441 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002442 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002443 index->traverse(this);
2444 out << ") {\n";
2445 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002446
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002447 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002448 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002449 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002450 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002451
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002452 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002453 const char *unroll =
2454 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002455
Corentin Wallez1239ee92015-03-19 14:38:02 -07002456 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002457 index->traverse(this);
2458 out << " = ";
2459 out << initial;
2460
2461 out << "; ";
2462 index->traverse(this);
2463 out << " < ";
2464 out << clampedLimit;
2465
2466 out << "; ";
2467 index->traverse(this);
2468 out << " += ";
2469 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002470 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002471
Jamie Madill8c46ab12015-12-07 16:39:19 -05002472 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002473 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002474
2475 if (node->getBody())
2476 {
2477 node->getBody()->traverse(this);
2478 }
2479
Jamie Madill8c46ab12015-12-07 16:39:19 -05002480 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002481 out << ";}\n";
2482
2483 if (!firstLoopFragment)
2484 {
2485 out << "}\n";
2486 }
2487
2488 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002489
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002490 initial += MAX_LOOP_ITERATIONS * increment;
2491 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002492 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002493
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002494 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002495
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002496 mExcessiveLoopIndex = restoreIndex;
2497
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498 return true;
2499 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002500 else
2501 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002502 }
2503
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002504 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002505}
2506
Jamie Madill8c46ab12015-12-07 16:39:19 -05002507void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2508 Visit visit,
2509 const char *preString,
2510 const char *inString,
2511 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002512{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002513 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002514 {
2515 out << preString;
2516 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002517 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002518 {
2519 out << inString;
2520 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002521 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002522 {
2523 out << postString;
2524 }
2525}
2526
Jamie Madill8c46ab12015-12-07 16:39:19 -05002527void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002528{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002529 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002530 {
Jamie Madill32aab012015-01-27 14:12:26 -05002531 out << "\n";
2532 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002533
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002534 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002535 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002536 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002537 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002538
Jamie Madill32aab012015-01-27 14:12:26 -05002539 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002540 }
2541}
2542
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002543TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2544{
2545 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002546 const TType &type = symbol->getType();
2547 const TName &name = symbol->getName();
2548 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002549
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002550 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002551 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002552 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002553 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002554 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002555 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002556 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002557 }
2558
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002559 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002560 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002561 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2562 {
2563 // Samplers are passed as indices to the sampler array.
2564 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2565 return "const uint " + nameStr + ArrayString(type);
2566 }
2567 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2568 {
2569 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2570 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2571 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2572 ArrayString(type);
2573 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002574 }
2575
Olli Etuaho96963162016-03-21 11:54:33 +02002576 TStringStream argString;
2577 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2578 << ArrayString(type);
2579
2580 // If the structure parameter contains samplers, they need to be passed into the function as
2581 // separate parameters. HLSL doesn't natively support samplers in structs.
2582 if (type.isStructureContainingSamplers())
2583 {
2584 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2585 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho599555b2017-08-15 11:12:42 +03002586 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002587 for (const TIntermSymbol *sampler : samplerSymbols)
2588 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002589 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002590 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2591 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002592 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002593 }
2594 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2595 {
Olli Etuaho96963162016-03-21 11:54:33 +02002596 ASSERT(IsSampler(samplerType.getBasicType()));
2597 argString << ", " << QualifierString(qualifier) << " "
2598 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002599 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2600 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002601 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002602 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002603 }
2604 else
2605 {
Olli Etuaho96963162016-03-21 11:54:33 +02002606 ASSERT(IsSampler(samplerType.getBasicType()));
2607 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002608 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002609 }
2610 }
2611 }
2612
2613 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002614}
2615
2616TString OutputHLSL::initializer(const TType &type)
2617{
2618 TString string;
2619
Jamie Madill94bf7f22013-07-08 13:31:15 -04002620 size_t size = type.getObjectSize();
2621 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002622 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002623 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002624
Jamie Madill94bf7f22013-07-08 13:31:15 -04002625 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002626 {
2627 string += ", ";
2628 }
2629 }
2630
daniel@transgaming.comead23042010-04-29 03:35:36 +00002631 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002632}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002633
Jamie Madill8c46ab12015-12-07 16:39:19 -05002634void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2635 Visit visit,
2636 const TType &type,
2637 const char *name,
2638 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002639{
Olli Etuahof40319e2015-03-10 14:33:00 +02002640 if (type.isArray())
2641 {
2642 UNIMPLEMENTED();
2643 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002644
2645 if (visit == PreVisit)
2646 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002647 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002648
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002649 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002650 }
2651 else if (visit == InVisit)
2652 {
2653 out << ", ";
2654 }
2655 else if (visit == PostVisit)
2656 {
2657 out << ")";
2658 }
2659}
2660
Jamie Madill8c46ab12015-12-07 16:39:19 -05002661const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2662 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002663 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002664{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002665 const TConstantUnion *constUnionIterated = constUnion;
2666
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002667 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002668 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002669 {
Jamie Madill033dae62014-06-18 12:56:28 -04002670 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002671
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002672 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002673
Jamie Madill98493dd2013-07-08 14:39:03 -04002674 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002675 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002676 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002677 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002678
Jamie Madill98493dd2013-07-08 14:39:03 -04002679 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002680 {
2681 out << ", ";
2682 }
2683 }
2684
2685 out << ")";
2686 }
2687 else
2688 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002689 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002690 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002691
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002692 if (writeType)
2693 {
Jamie Madill033dae62014-06-18 12:56:28 -04002694 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002695 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002696 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002697 if (writeType)
2698 {
2699 out << ")";
2700 }
2701 }
2702
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002703 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002704}
2705
Olli Etuahod68924e2017-01-02 17:34:40 +00002706void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002707{
Olli Etuahod68924e2017-01-02 17:34:40 +00002708 if (visit == PreVisit)
2709 {
2710 const char *opStr = GetOperatorString(op);
2711 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2712 out << "(";
2713 }
2714 else
2715 {
2716 outputTriplet(out, visit, nullptr, ", ", ")");
2717 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002718}
2719
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002720bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2721 TIntermSymbol *symbolNode,
2722 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002723{
2724 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2725 expression->traverse(&searchSymbol);
2726
2727 if (searchSymbol.foundMatch())
2728 {
2729 // Type already printed
2730 out << "t" + str(mUniqueIndex) + " = ";
2731 expression->traverse(this);
2732 out << ", ";
2733 symbolNode->traverse(this);
2734 out << " = t" + str(mUniqueIndex);
2735
2736 mUniqueIndex++;
2737 return true;
2738 }
2739
2740 return false;
2741}
2742
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002743bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2744{
2745 // We support writing constant unions and constructors that only take constant unions as
2746 // parameters as HLSL literals.
Olli Etuahod4f4c112016-04-15 15:11:24 +03002747 return expression->getAsConstantUnion() ||
2748 expression->isConstructorWithOnlyConstantUnionParameters();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002749}
2750
2751bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2752 TIntermSymbol *symbolNode,
2753 TIntermTyped *expression)
2754{
2755 if (canWriteAsHLSLLiteral(expression))
2756 {
2757 symbolNode->traverse(this);
2758 if (expression->getType().isArray())
2759 {
2760 out << "[" << expression->getType().getArraySize() << "]";
2761 }
2762 out << " = {";
2763 if (expression->getAsConstantUnion())
2764 {
2765 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2766 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002767 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002768 }
2769 else
2770 {
2771 TIntermAggregate *constructor = expression->getAsAggregate();
2772 ASSERT(constructor != nullptr);
2773 for (TIntermNode *&node : *constructor->getSequence())
2774 {
2775 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2776 ASSERT(nodeConst);
2777 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002778 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002779 if (node != constructor->getSequence()->back())
2780 {
2781 out << ", ";
2782 }
2783 }
2784 }
2785 out << "}";
2786 return true;
2787 }
2788 return false;
2789}
2790
Jamie Madill55e79e02015-02-09 15:35:00 -05002791TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2792{
2793 const TFieldList &fields = structure.fields();
2794
2795 for (const auto &eqFunction : mStructEqualityFunctions)
2796 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002797 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002798 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002799 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002800 }
2801 }
2802
2803 const TString &structNameString = StructNameString(structure);
2804
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002805 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002806 function->structure = &structure;
2807 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002808
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002809 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002810
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002811 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2812 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002813 << "{\n"
2814 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002815
2816 for (size_t i = 0; i < fields.size(); i++)
2817 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002818 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002819 const TType *fieldType = field->type();
2820
2821 const TString &fieldNameA = "a." + Decorate(field->name());
2822 const TString &fieldNameB = "b." + Decorate(field->name());
2823
2824 if (i > 0)
2825 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002826 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002827 }
2828
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002829 fnOut << "(";
2830 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2831 fnOut << fieldNameA;
2832 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2833 fnOut << fieldNameB;
2834 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2835 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002836 }
2837
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002838 fnOut << ";\n"
2839 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002840
2841 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002842
2843 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002844 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002845
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002846 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002847}
2848
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002849TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002850{
2851 for (const auto &eqFunction : mArrayEqualityFunctions)
2852 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002853 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002854 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002855 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002856 }
2857 }
2858
2859 const TString &typeName = TypeString(type);
2860
Olli Etuaho12690762015-03-31 12:55:28 +03002861 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002862 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002863
2864 TInfoSinkBase fnNameOut;
2865 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002866 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002867
2868 TType nonArrayType = type;
2869 nonArrayType.clearArrayness();
2870
2871 TInfoSinkBase fnOut;
2872
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002873 fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize()
2874 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002875 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002876 " for (int i = 0; i < "
2877 << type.getArraySize() << "; ++i)\n"
2878 " {\n"
2879 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002880
2881 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2882 fnOut << "a[i]";
2883 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2884 fnOut << "b[i]";
2885 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2886
2887 fnOut << ") { return false; }\n"
2888 " }\n"
2889 " return true;\n"
2890 "}\n";
2891
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002892 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002893
2894 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002895 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002896
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002897 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002898}
2899
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002900TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002901{
2902 for (const auto &assignFunction : mArrayAssignmentFunctions)
2903 {
2904 if (assignFunction.type == type)
2905 {
2906 return assignFunction.functionName;
2907 }
2908 }
2909
2910 const TString &typeName = TypeString(type);
2911
2912 ArrayHelperFunction function;
2913 function.type = type;
2914
2915 TInfoSinkBase fnNameOut;
2916 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
2917 function.functionName = fnNameOut.c_str();
2918
2919 TInfoSinkBase fnOut;
2920
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002921 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2922 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
2923 << "{\n"
2924 " for (int i = 0; i < "
2925 << type.getArraySize() << "; ++i)\n"
2926 " {\n"
2927 " a[i] = b[i];\n"
2928 " }\n"
2929 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002930
2931 function.functionDefinition = fnOut.c_str();
2932
2933 mArrayAssignmentFunctions.push_back(function);
2934
2935 return function.functionName;
2936}
2937
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002938TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002939{
2940 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2941 {
2942 if (constructIntoFunction.type == type)
2943 {
2944 return constructIntoFunction.functionName;
2945 }
2946 }
2947
2948 const TString &typeName = TypeString(type);
2949
2950 ArrayHelperFunction function;
2951 function.type = type;
2952
2953 TInfoSinkBase fnNameOut;
2954 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2955 function.functionName = fnNameOut.c_str();
2956
2957 TInfoSinkBase fnOut;
2958
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002959 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2960 << "]";
Olli Etuaho856c4972016-08-08 11:38:39 +03002961 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002962 {
2963 fnOut << ", " << typeName << " b" << i;
2964 }
2965 fnOut << ")\n"
2966 "{\n";
2967
Olli Etuaho856c4972016-08-08 11:38:39 +03002968 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002969 {
2970 fnOut << " a[" << i << "] = b" << i << ";\n";
2971 }
2972 fnOut << "}\n";
2973
2974 function.functionDefinition = fnOut.c_str();
2975
2976 mArrayConstructIntoFunctions.push_back(function);
2977
2978 return function.functionName;
2979}
2980
Jamie Madill2e295e22015-04-29 10:41:33 -04002981void OutputHLSL::ensureStructDefined(const TType &type)
2982{
2983 TStructure *structure = type.getStruct();
2984
2985 if (structure)
2986 {
2987 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
2988 }
2989}
2990
Jamie Madill45bcc782016-11-07 13:58:48 -05002991} // namespace sh