blob: 4397a06d8d98fa1039b953da848d48801456c668 [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;
Corentin Wallezb076add2016-01-11 16:45:46 -0500116 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500117 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800118 mUsesNumWorkGroups = false;
119 mUsesWorkGroupID = false;
120 mUsesLocalInvocationID = false;
121 mUsesGlobalInvocationID = false;
122 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500123 mUsesXor = false;
124 mUsesDiscardRewriting = false;
125 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530126 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000127
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000128 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000129
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500130 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000131 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500132 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000133
Yunchao Hed7297bf2017-04-19 15:27:10 +0800134 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000135
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500136 mStructureHLSL = new StructureHLSL;
137 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300138 mTextureFunctionHLSL = new TextureFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400139
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200140 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000141 {
Arun Patole63419392015-03-13 11:51:07 +0530142 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500143 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
144 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530145 // In both cases total 3 uniform registers need to be reserved.
146 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000147 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000148
Geoff Lang00140f42016-02-03 18:47:33 +0000149 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800150 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151}
152
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000153OutputHLSL::~OutputHLSL()
154{
Jamie Madill8daaba12014-06-13 10:04:33 -0400155 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400156 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300157 SafeDelete(mTextureFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200158 for (auto &eqFunction : mStructEqualityFunctions)
159 {
160 SafeDelete(eqFunction);
161 }
162 for (auto &eqFunction : mArrayEqualityFunctions)
163 {
164 SafeDelete(eqFunction);
165 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000166}
167
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200168void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000169{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500170 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400171 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000172
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200173 BuiltInFunctionEmulator builtInFunctionEmulator;
174 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800175 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
176 {
177 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
178 mShaderVersion);
179 }
180
Olli Etuahodfa75e82017-01-23 09:43:06 -0800181 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500182
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700183 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000184 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700185 ASSERT(success == CallDAG::INITDAG_SUCCESS);
186 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700187
Jamie Madill37997142015-01-28 10:06:34 -0500188 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500189 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200190 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500191 mInfoSinkStack.pop();
192
Jamie Madill37997142015-01-28 10:06:34 -0500193 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500194 mInfoSinkStack.pop();
195
Jamie Madill32aab012015-01-27 14:12:26 -0500196 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500197 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500198 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000199
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200200 objSink << mHeader.c_str();
201 objSink << mBody.c_str();
202 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200203
Olli Etuahodfa75e82017-01-23 09:43:06 -0800204 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000205}
206
Jamie Madill570e04d2013-06-21 09:15:33 -0400207void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
208{
209 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
210 {
211 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
212
Jamie Madill32aab012015-01-27 14:12:26 -0500213 TInfoSinkBase structInfoSink;
214 mInfoSinkStack.push(&structInfoSink);
215
Jamie Madill570e04d2013-06-21 09:15:33 -0400216 // This will mark the necessary block elements as referenced
217 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500218
219 TString structName(structInfoSink.c_str());
220 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400221
222 mFlaggedStructOriginalNames[flaggedNode] = structName;
223
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500224 for (size_t pos = structName.find('.'); pos != std::string::npos;
225 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400226 {
227 structName.erase(pos, 1);
228 }
229
230 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
231 }
232}
233
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800234const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400235{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800236 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400237}
238
Jamie Madill9fe25e92014-07-18 10:33:08 -0400239const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
240{
241 return mUniformHLSL->getUniformRegisterMap();
242}
243
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000244int OutputHLSL::vectorSize(const TType &type) const
245{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500246 int elementSize = type.isMatrix() ? type.getCols() : 1;
Olli Etuaho856c4972016-08-08 11:38:39 +0300247 unsigned int arraySize = type.isArray() ? type.getArraySize() : 1u;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000248
249 return elementSize * arraySize;
250}
251
Olli Etuahoed049ab2017-06-30 17:38:33 +0300252TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400253{
254 TString init;
255
Olli Etuahoed049ab2017-06-30 17:38:33 +0300256 TString indentString;
257 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400258 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300259 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400260 }
261
Olli Etuahoed049ab2017-06-30 17:38:33 +0300262 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400263 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300264 init += indentString + "{\n";
265 for (unsigned int arrayIndex = 0u; arrayIndex < type.getArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400266 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300267 TStringStream indexedString;
268 indexedString << name << "[" << arrayIndex << "]";
269 TType elementType = type;
270 elementType.clearArrayness();
271 init += structInitializerString(indent + 1, elementType, indexedString.str());
272 if (arrayIndex < type.getArraySize() - 1)
273 {
274 init += ",";
275 }
276 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400277 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300278 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400279 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300280 else if (type.getBasicType() == EbtStruct)
281 {
282 init += indentString + "{\n";
283 const TStructure &structure = *type.getStruct();
284 const TFieldList &fields = structure.fields();
285 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
286 {
287 const TField &field = *fields[fieldIndex];
288 const TString &fieldName = name + "." + Decorate(field.name());
289 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400290
Olli Etuahoed049ab2017-06-30 17:38:33 +0300291 init += structInitializerString(indent + 1, fieldType, fieldName);
292 if (fieldIndex < fields.size() - 1)
293 {
294 init += ",";
295 }
296 init += "\n";
297 }
298 init += indentString + "}";
299 }
300 else
301 {
302 init += indentString + name;
303 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400304
305 return init;
306}
307
Jamie Madill8c46ab12015-12-07 16:39:19 -0500308void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000310 TString varyings;
311 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400312 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000313
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500314 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
315 mFlaggedStructMappedNames.begin();
316 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400317 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500318 TIntermTyped *structNode = flaggedStructIt->first;
319 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400320 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400321 const TString &originalName = mFlaggedStructOriginalNames[structNode];
322
Olli Etuahoed049ab2017-06-30 17:38:33 +0300323 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
324 if (structNode->isArray())
325 {
326 flaggedStructs += ArrayString(structNode->getType());
327 }
328 flaggedStructs += " =\n";
329 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
330 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400331 }
332
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500333 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
334 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000335 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500336 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000337 const TString &name = varying->second->getSymbol();
338
339 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500340 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
341 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000342 }
343
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500344 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
345 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000346 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500347 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000348 const TString &name = attribute->second->getSymbol();
349
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500350 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
351 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000352 }
353
Jamie Madill8daaba12014-06-13 10:04:33 -0400354 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400355
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200356 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800357 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400358
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200359 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500360 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200361 out << "\n// Equality functions\n\n";
362 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500363 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200364 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200365 }
366 }
Olli Etuaho12690762015-03-31 12:55:28 +0300367 if (!mArrayAssignmentFunctions.empty())
368 {
369 out << "\n// Assignment functions\n\n";
370 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
371 {
372 out << assignmentFunction.functionDefinition << "\n";
373 }
374 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300375 if (!mArrayConstructIntoFunctions.empty())
376 {
377 out << "\n// Array constructor functions\n\n";
378 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
379 {
380 out << constructIntoFunction.functionDefinition << "\n";
381 }
382 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200383
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500384 if (mUsesDiscardRewriting)
385 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400386 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500387 }
388
Nicolas Capens655fe362014-04-11 13:12:34 -0400389 if (mUsesNestedBreak)
390 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400391 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400392 }
393
Arun Patole44efa0b2015-03-04 17:11:05 +0530394 if (mRequiresIEEEStrictCompiling)
395 {
396 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
397 }
398
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400399 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
400 "#define LOOP [loop]\n"
401 "#define FLATTEN [flatten]\n"
402 "#else\n"
403 "#define LOOP\n"
404 "#define FLATTEN\n"
405 "#endif\n";
406
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200407 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000408 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200409 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500410 const bool usingMRTExtension = (iter != mExtensionBehavior.end() &&
411 (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000412
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000413 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500414 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400415 out << "\n";
416
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200417 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000418 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500419 for (ReferencedSymbols::const_iterator outputVariableIt =
420 mReferencedOutputVariables.begin();
421 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000422 {
Jamie Madill46131a32013-06-20 11:55:50 -0400423 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500424 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400425
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500426 out << "static " + TypeString(variableType) + " out_" + variableName +
427 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000428 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000429 }
Jamie Madill46131a32013-06-20 11:55:50 -0400430 else
431 {
432 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
433
434 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400436 for (unsigned int i = 0; i < numColorValues; i++)
437 {
438 out << " float4(0, 0, 0, 0)";
439 if (i + 1 != numColorValues)
440 {
441 out << ",";
442 }
443 out << "\n";
444 }
445
446 out << "};\n";
447 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000448
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400449 if (mUsesFragDepth)
450 {
451 out << "static float gl_Depth = 0.0;\n";
452 }
453
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000454 if (mUsesFragCoord)
455 {
456 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
457 }
458
459 if (mUsesPointCoord)
460 {
461 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
462 }
463
464 if (mUsesFrontFacing)
465 {
466 out << "static bool gl_FrontFacing = false;\n";
467 }
468
469 out << "\n";
470
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000471 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000472 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000473 out << "struct gl_DepthRangeParameters\n"
474 "{\n"
475 " float near;\n"
476 " float far;\n"
477 " float diff;\n"
478 "};\n"
479 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000480 }
481
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200482 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000483 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000484 out << "cbuffer DriverConstants : register(b1)\n"
485 "{\n";
486
487 if (mUsesDepthRange)
488 {
489 out << " float3 dx_DepthRange : packoffset(c0);\n";
490 }
491
492 if (mUsesFragCoord)
493 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000494 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000495 }
496
497 if (mUsesFragCoord || mUsesFrontFacing)
498 {
499 out << " float3 dx_DepthFront : packoffset(c2);\n";
500 }
501
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800502 if (mUsesFragCoord)
503 {
504 // dx_ViewScale is only used in the fragment shader to correct
505 // the value for glFragCoord if necessary
506 out << " float2 dx_ViewScale : packoffset(c3);\n";
507 }
508
Olli Etuaho618bebc2016-01-15 16:40:00 +0200509 if (mOutputType == SH_HLSL_4_1_OUTPUT)
510 {
511 mUniformHLSL->samplerMetadataUniforms(out, "c4");
512 }
513
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000514 out << "};\n";
515 }
516 else
517 {
518 if (mUsesDepthRange)
519 {
520 out << "uniform float3 dx_DepthRange : register(c0);";
521 }
522
523 if (mUsesFragCoord)
524 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000525 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000526 }
527
528 if (mUsesFragCoord || mUsesFrontFacing)
529 {
530 out << "uniform float3 dx_DepthFront : register(c2);\n";
531 }
532 }
533
534 out << "\n";
535
536 if (mUsesDepthRange)
537 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500538 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
539 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000540 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000541 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000542
Jamie Madillf91ce812014-06-13 10:04:34 -0400543 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000544 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400545 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000546 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400547 out << flaggedStructs;
548 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000549 }
550
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000551 if (usingMRTExtension && mNumRenderTargets > 1)
552 {
553 out << "#define GL_USES_MRT\n";
554 }
555
556 if (mUsesFragColor)
557 {
558 out << "#define GL_USES_FRAG_COLOR\n";
559 }
560
561 if (mUsesFragData)
562 {
563 out << "#define GL_USES_FRAG_DATA\n";
564 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565 }
Xinghua Caob1239382016-12-13 15:07:05 +0800566 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000567 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000568 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500569 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000570 out << "\n"
571 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400572
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000573 if (mUsesPointSize)
574 {
575 out << "static float gl_PointSize = float(1);\n";
576 }
577
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000578 if (mUsesInstanceID)
579 {
580 out << "static int gl_InstanceID;";
581 }
582
Corentin Wallezb076add2016-01-11 16:45:46 -0500583 if (mUsesVertexID)
584 {
585 out << "static int gl_VertexID;";
586 }
587
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 out << "\n"
589 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500590 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000591 out << "\n";
592
593 if (mUsesDepthRange)
594 {
595 out << "struct gl_DepthRangeParameters\n"
596 "{\n"
597 " float near;\n"
598 " float far;\n"
599 " float diff;\n"
600 "};\n"
601 "\n";
602 }
603
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200604 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000605 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800606 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500607 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800608
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000609 if (mUsesDepthRange)
610 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800611 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000612 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800613
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800614 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
615 // shaders. However, we declare it for all shaders (including Feature Level 10+).
616 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
617 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800618 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800619 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800620 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800621
Olli Etuaho618bebc2016-01-15 16:40:00 +0200622 if (mOutputType == SH_HLSL_4_1_OUTPUT)
623 {
624 mUniformHLSL->samplerMetadataUniforms(out, "c4");
625 }
626
Austin Kinross4fd18b12014-12-22 12:32:05 -0800627 out << "};\n"
628 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000629 }
630 else
631 {
632 if (mUsesDepthRange)
633 {
634 out << "uniform float3 dx_DepthRange : register(c0);\n";
635 }
636
Cooper Partine6664f02015-01-09 16:22:24 -0800637 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
638 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000639 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000640 }
641
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000642 if (mUsesDepthRange)
643 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500644 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
645 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000646 "\n";
647 }
648
Jamie Madillf91ce812014-06-13 10:04:34 -0400649 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000650 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400651 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000652 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400653 out << flaggedStructs;
654 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000655 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400656 }
Xinghua Caob1239382016-12-13 15:07:05 +0800657 else // Compute shader
658 {
659 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800660
661 out << "cbuffer DriverConstants : register(b1)\n"
662 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800663 if (mUsesNumWorkGroups)
664 {
Xinghua Caob1239382016-12-13 15:07:05 +0800665 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800666 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800667 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
668 mUniformHLSL->samplerMetadataUniforms(out, "c1");
669 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800670
671 // Follow built-in variables would be initialized in
672 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
673 // are used in compute shader.
674 if (mUsesWorkGroupID)
675 {
676 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
677 }
678
679 if (mUsesLocalInvocationID)
680 {
681 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
682 }
683
684 if (mUsesGlobalInvocationID)
685 {
686 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
687 }
688
689 if (mUsesLocalInvocationIndex)
690 {
691 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
692 }
693 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000694
Geoff Lang1fe74c72016-08-25 13:23:01 -0400695 bool getDimensionsIgnoresBaseLevel =
696 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
697 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000699 if (mUsesFragCoord)
700 {
701 out << "#define GL_USES_FRAG_COORD\n";
702 }
703
704 if (mUsesPointCoord)
705 {
706 out << "#define GL_USES_POINT_COORD\n";
707 }
708
709 if (mUsesFrontFacing)
710 {
711 out << "#define GL_USES_FRONT_FACING\n";
712 }
713
714 if (mUsesPointSize)
715 {
716 out << "#define GL_USES_POINT_SIZE\n";
717 }
718
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400719 if (mUsesFragDepth)
720 {
721 out << "#define GL_USES_FRAG_DEPTH\n";
722 }
723
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000724 if (mUsesDepthRange)
725 {
726 out << "#define GL_USES_DEPTH_RANGE\n";
727 }
728
Xinghua Caob1239382016-12-13 15:07:05 +0800729 if (mUsesNumWorkGroups)
730 {
731 out << "#define GL_USES_NUM_WORK_GROUPS\n";
732 }
733
734 if (mUsesWorkGroupID)
735 {
736 out << "#define GL_USES_WORK_GROUP_ID\n";
737 }
738
739 if (mUsesLocalInvocationID)
740 {
741 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
742 }
743
744 if (mUsesGlobalInvocationID)
745 {
746 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
747 }
748
749 if (mUsesLocalInvocationIndex)
750 {
751 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
752 }
753
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000754 if (mUsesXor)
755 {
756 out << "bool xor(bool p, bool q)\n"
757 "{\n"
758 " return (p || q) && !(p && q);\n"
759 "}\n"
760 "\n";
761 }
762
Olli Etuahodfa75e82017-01-23 09:43:06 -0800763 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764}
765
766void OutputHLSL::visitSymbol(TIntermSymbol *node)
767{
Jamie Madill32aab012015-01-27 14:12:26 -0500768 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769
Jamie Madill570e04d2013-06-21 09:15:33 -0400770 // Handle accessing std140 structs by value
771 if (mFlaggedStructMappedNames.count(node) > 0)
772 {
773 out << mFlaggedStructMappedNames[node];
774 return;
775 }
776
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000777 TString name = node->getSymbol();
778
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000779 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000780 {
781 mUsesDepthRange = true;
782 out << name;
783 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784 else
785 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000786 TQualifier qualifier = node->getQualifier();
787
788 if (qualifier == EvqUniform)
789 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400791 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400792
793 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000794 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800795 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000796 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000797 else
798 {
799 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000800 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400801
Jamie Madill2e295e22015-04-29 10:41:33 -0400802 ensureStructDefined(nodeType);
803
Olli Etuahoff526f12017-06-30 12:26:54 +0300804 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000805 }
Jamie Madill19571812013-08-12 15:26:34 -0700806 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000807 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000808 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400809 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000810 }
Jamie Madill033dae62014-06-18 12:56:28 -0400811 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000812 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000813 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400814 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000815 }
Jamie Madill19571812013-08-12 15:26:34 -0700816 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400817 {
818 mReferencedOutputVariables[name] = node;
819 out << "out_" << name;
820 }
821 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000822 {
823 out << "gl_Color[0]";
824 mUsesFragColor = true;
825 }
826 else if (qualifier == EvqFragData)
827 {
828 out << "gl_Color";
829 mUsesFragData = true;
830 }
831 else if (qualifier == EvqFragCoord)
832 {
833 mUsesFragCoord = true;
834 out << name;
835 }
836 else if (qualifier == EvqPointCoord)
837 {
838 mUsesPointCoord = true;
839 out << name;
840 }
841 else if (qualifier == EvqFrontFacing)
842 {
843 mUsesFrontFacing = true;
844 out << name;
845 }
846 else if (qualifier == EvqPointSize)
847 {
848 mUsesPointSize = true;
849 out << name;
850 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000851 else if (qualifier == EvqInstanceID)
852 {
853 mUsesInstanceID = true;
854 out << name;
855 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500856 else if (qualifier == EvqVertexID)
857 {
858 mUsesVertexID = true;
859 out << name;
860 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300861 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400862 {
863 mUsesFragDepth = true;
864 out << "gl_Depth";
865 }
Xinghua Caob1239382016-12-13 15:07:05 +0800866 else if (qualifier == EvqNumWorkGroups)
867 {
868 mUsesNumWorkGroups = true;
869 out << name;
870 }
871 else if (qualifier == EvqWorkGroupID)
872 {
873 mUsesWorkGroupID = true;
874 out << name;
875 }
876 else if (qualifier == EvqLocalInvocationID)
877 {
878 mUsesLocalInvocationID = true;
879 out << name;
880 }
881 else if (qualifier == EvqGlobalInvocationID)
882 {
883 mUsesGlobalInvocationID = true;
884 out << name;
885 }
886 else if (qualifier == EvqLocalInvocationIndex)
887 {
888 mUsesLocalInvocationIndex = true;
889 out << name;
890 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000891 else
892 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300893 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000894 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000895 }
896}
897
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400898void OutputHLSL::visitRaw(TIntermRaw *node)
899{
Jamie Madill32aab012015-01-27 14:12:26 -0500900 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400901}
902
Olli Etuaho7fb49552015-03-18 17:27:44 +0200903void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
904{
905 if (type.isScalar() && !type.isArray())
906 {
907 if (op == EOpEqual)
908 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500909 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200910 }
911 else
912 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500913 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200914 }
915 }
916 else
917 {
918 if (visit == PreVisit && op == EOpNotEqual)
919 {
920 out << "!";
921 }
922
923 if (type.isArray())
924 {
925 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500926 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200927 }
928 else if (type.getBasicType() == EbtStruct)
929 {
930 const TStructure &structure = *type.getStruct();
931 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500932 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200933 }
934 else
935 {
936 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500937 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200938 }
939 }
940}
941
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000942bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200943{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000944 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200945 {
946 TIntermNode *ancestor = getAncestorNode(n);
947 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
948 if (ancestorBinary == nullptr)
949 {
950 return false;
951 }
952 switch (ancestorBinary->getOp())
953 {
954 case EOpIndexDirectStruct:
955 {
956 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
957 const TIntermConstantUnion *index =
958 ancestorBinary->getRight()->getAsConstantUnion();
959 const TField *field = structure->fields()[index->getIConst(0)];
960 if (IsSampler(field->type()->getBasicType()))
961 {
962 return true;
963 }
964 break;
965 }
966 case EOpIndexDirect:
967 break;
968 default:
969 // Returning a sampler from indirect indexing is not supported.
970 return false;
971 }
972 }
973 return false;
974}
975
Olli Etuahob6fa0432016-09-28 16:28:05 +0100976bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
977{
978 TInfoSinkBase &out = getInfoSink();
979 if (visit == PostVisit)
980 {
981 out << ".";
982 node->writeOffsetsAsXYZW(&out);
983 }
984 return true;
985}
986
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000987bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
988{
Jamie Madill32aab012015-01-27 14:12:26 -0500989 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000990
Jamie Madill570e04d2013-06-21 09:15:33 -0400991 // Handle accessing std140 structs by value
992 if (mFlaggedStructMappedNames.count(node) > 0)
993 {
994 out << mFlaggedStructMappedNames[node];
995 return false;
996 }
997
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000998 switch (node->getOp())
999 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001000 case EOpComma:
1001 outputTriplet(out, visit, "(", ", ", ")");
1002 break;
1003 case EOpAssign:
1004 if (node->getLeft()->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001005 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001006 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1007 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001008 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001009 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1010 out << functionName << "(";
1011 node->getLeft()->traverse(this);
1012 TIntermSequence *seq = rightAgg->getSequence();
1013 for (auto &arrayElement : *seq)
1014 {
1015 out << ", ";
1016 arrayElement->traverse(this);
1017 }
1018 out << ")";
1019 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001020 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001021 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1022 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001023 ASSERT(rightAgg == nullptr);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001024
1025 const TString &functionName = addArrayAssignmentFunction(node->getType());
1026 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho9638c352015-04-01 14:34:52 +03001027 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001028 else
Jamie Madill37997142015-01-28 10:06:34 -05001029 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001030 outputTriplet(out, visit, "(", " = ", ")");
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001031 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001032 break;
1033 case EOpInitialize:
1034 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001035 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001036 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1037 ASSERT(symbolNode);
1038 TIntermTyped *expression = node->getRight();
1039
1040 // Global initializers must be constant at this point.
1041 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1042 canWriteAsHLSLLiteral(expression));
1043
1044 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1045 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1046 // new variable is created before the assignment is evaluated), so we need to
1047 // convert
1048 // this to "float t = x, x = t;".
1049 if (writeSameSymbolInitializer(out, symbolNode, expression))
1050 {
1051 // Skip initializing the rest of the expression
1052 return false;
1053 }
1054 else if (writeConstantInitialization(out, symbolNode, expression))
1055 {
1056 return false;
1057 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001058 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001059 else if (visit == InVisit)
1060 {
1061 out << " = ";
1062 }
1063 break;
1064 case EOpAddAssign:
1065 outputTriplet(out, visit, "(", " += ", ")");
1066 break;
1067 case EOpSubAssign:
1068 outputTriplet(out, visit, "(", " -= ", ")");
1069 break;
1070 case EOpMulAssign:
1071 outputTriplet(out, visit, "(", " *= ", ")");
1072 break;
1073 case EOpVectorTimesScalarAssign:
1074 outputTriplet(out, visit, "(", " *= ", ")");
1075 break;
1076 case EOpMatrixTimesScalarAssign:
1077 outputTriplet(out, visit, "(", " *= ", ")");
1078 break;
1079 case EOpVectorTimesMatrixAssign:
1080 if (visit == PreVisit)
1081 {
1082 out << "(";
1083 }
1084 else if (visit == InVisit)
1085 {
1086 out << " = mul(";
1087 node->getLeft()->traverse(this);
1088 out << ", transpose(";
1089 }
1090 else
1091 {
1092 out << ")))";
1093 }
1094 break;
1095 case EOpMatrixTimesMatrixAssign:
1096 if (visit == PreVisit)
1097 {
1098 out << "(";
1099 }
1100 else if (visit == InVisit)
1101 {
1102 out << " = transpose(mul(transpose(";
1103 node->getLeft()->traverse(this);
1104 out << "), transpose(";
1105 }
1106 else
1107 {
1108 out << "))))";
1109 }
1110 break;
1111 case EOpDivAssign:
1112 outputTriplet(out, visit, "(", " /= ", ")");
1113 break;
1114 case EOpIModAssign:
1115 outputTriplet(out, visit, "(", " %= ", ")");
1116 break;
1117 case EOpBitShiftLeftAssign:
1118 outputTriplet(out, visit, "(", " <<= ", ")");
1119 break;
1120 case EOpBitShiftRightAssign:
1121 outputTriplet(out, visit, "(", " >>= ", ")");
1122 break;
1123 case EOpBitwiseAndAssign:
1124 outputTriplet(out, visit, "(", " &= ", ")");
1125 break;
1126 case EOpBitwiseXorAssign:
1127 outputTriplet(out, visit, "(", " ^= ", ")");
1128 break;
1129 case EOpBitwiseOrAssign:
1130 outputTriplet(out, visit, "(", " |= ", ")");
1131 break;
1132 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001133 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001134 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001135 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001136 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001137 if (visit == PreVisit)
1138 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001139 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001140 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001141 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001142 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001143 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001144 return false;
1145 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001146 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001147 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001148 {
1149 // All parts of an expression that access a sampler in a struct need to use _ as
1150 // separator to access the sampler variable that has been moved out of the struct.
1151 outputTriplet(out, visit, "", "_", "");
1152 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001153 else
1154 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001155 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001156 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001157 }
1158 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001159 case EOpIndexIndirect:
1160 // We do not currently support indirect references to interface blocks
1161 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1162 outputTriplet(out, visit, "", "[", "]");
1163 break;
1164 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001165 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001166 const TStructure *structure = node->getLeft()->getType().getStruct();
1167 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1168 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001169
Olli Etuaho96963162016-03-21 11:54:33 +02001170 // In cases where indexing returns a sampler, we need to access the sampler variable
1171 // that has been moved out of the struct.
1172 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1173 if (visit == PreVisit && indexingReturnsSampler)
1174 {
1175 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1176 // This prefix is only output at the beginning of the indexing expression, which
1177 // may have multiple parts.
1178 out << "angle";
1179 }
1180 if (!indexingReturnsSampler)
1181 {
1182 // All parts of an expression that access a sampler in a struct need to use _ as
1183 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001184 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001185 }
1186 if (visit == InVisit)
1187 {
1188 if (indexingReturnsSampler)
1189 {
1190 out << "_" + field->name();
1191 }
1192 else
1193 {
1194 out << "." + DecorateField(field->name(), *structure);
1195 }
1196
1197 return false;
1198 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001199 }
1200 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001201 case EOpIndexDirectInterfaceBlock:
1202 if (visit == InVisit)
1203 {
1204 const TInterfaceBlock *interfaceBlock =
1205 node->getLeft()->getType().getInterfaceBlock();
1206 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1207 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1208 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001209
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001210 return false;
1211 }
1212 break;
1213 case EOpAdd:
1214 outputTriplet(out, visit, "(", " + ", ")");
1215 break;
1216 case EOpSub:
1217 outputTriplet(out, visit, "(", " - ", ")");
1218 break;
1219 case EOpMul:
1220 outputTriplet(out, visit, "(", " * ", ")");
1221 break;
1222 case EOpDiv:
1223 outputTriplet(out, visit, "(", " / ", ")");
1224 break;
1225 case EOpIMod:
1226 outputTriplet(out, visit, "(", " % ", ")");
1227 break;
1228 case EOpBitShiftLeft:
1229 outputTriplet(out, visit, "(", " << ", ")");
1230 break;
1231 case EOpBitShiftRight:
1232 outputTriplet(out, visit, "(", " >> ", ")");
1233 break;
1234 case EOpBitwiseAnd:
1235 outputTriplet(out, visit, "(", " & ", ")");
1236 break;
1237 case EOpBitwiseXor:
1238 outputTriplet(out, visit, "(", " ^ ", ")");
1239 break;
1240 case EOpBitwiseOr:
1241 outputTriplet(out, visit, "(", " | ", ")");
1242 break;
1243 case EOpEqual:
1244 case EOpNotEqual:
1245 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1246 break;
1247 case EOpLessThan:
1248 outputTriplet(out, visit, "(", " < ", ")");
1249 break;
1250 case EOpGreaterThan:
1251 outputTriplet(out, visit, "(", " > ", ")");
1252 break;
1253 case EOpLessThanEqual:
1254 outputTriplet(out, visit, "(", " <= ", ")");
1255 break;
1256 case EOpGreaterThanEqual:
1257 outputTriplet(out, visit, "(", " >= ", ")");
1258 break;
1259 case EOpVectorTimesScalar:
1260 outputTriplet(out, visit, "(", " * ", ")");
1261 break;
1262 case EOpMatrixTimesScalar:
1263 outputTriplet(out, visit, "(", " * ", ")");
1264 break;
1265 case EOpVectorTimesMatrix:
1266 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1267 break;
1268 case EOpMatrixTimesVector:
1269 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1270 break;
1271 case EOpMatrixTimesMatrix:
1272 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1273 break;
1274 case EOpLogicalOr:
1275 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1276 // been unfolded.
1277 ASSERT(!node->getRight()->hasSideEffects());
1278 outputTriplet(out, visit, "(", " || ", ")");
1279 return true;
1280 case EOpLogicalXor:
1281 mUsesXor = true;
1282 outputTriplet(out, visit, "xor(", ", ", ")");
1283 break;
1284 case EOpLogicalAnd:
1285 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1286 // been unfolded.
1287 ASSERT(!node->getRight()->hasSideEffects());
1288 outputTriplet(out, visit, "(", " && ", ")");
1289 return true;
1290 default:
1291 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001292 }
1293
1294 return true;
1295}
1296
1297bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1298{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001299 TInfoSinkBase &out = getInfoSink();
1300
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001301 switch (node->getOp())
1302 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001303 case EOpNegative:
1304 outputTriplet(out, visit, "(-", "", ")");
1305 break;
1306 case EOpPositive:
1307 outputTriplet(out, visit, "(+", "", ")");
1308 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001309 case EOpLogicalNot:
1310 outputTriplet(out, visit, "(!", "", ")");
1311 break;
1312 case EOpBitwiseNot:
1313 outputTriplet(out, visit, "(~", "", ")");
1314 break;
1315 case EOpPostIncrement:
1316 outputTriplet(out, visit, "(", "", "++)");
1317 break;
1318 case EOpPostDecrement:
1319 outputTriplet(out, visit, "(", "", "--)");
1320 break;
1321 case EOpPreIncrement:
1322 outputTriplet(out, visit, "(++", "", ")");
1323 break;
1324 case EOpPreDecrement:
1325 outputTriplet(out, visit, "(--", "", ")");
1326 break;
1327 case EOpRadians:
1328 outputTriplet(out, visit, "radians(", "", ")");
1329 break;
1330 case EOpDegrees:
1331 outputTriplet(out, visit, "degrees(", "", ")");
1332 break;
1333 case EOpSin:
1334 outputTriplet(out, visit, "sin(", "", ")");
1335 break;
1336 case EOpCos:
1337 outputTriplet(out, visit, "cos(", "", ")");
1338 break;
1339 case EOpTan:
1340 outputTriplet(out, visit, "tan(", "", ")");
1341 break;
1342 case EOpAsin:
1343 outputTriplet(out, visit, "asin(", "", ")");
1344 break;
1345 case EOpAcos:
1346 outputTriplet(out, visit, "acos(", "", ")");
1347 break;
1348 case EOpAtan:
1349 outputTriplet(out, visit, "atan(", "", ")");
1350 break;
1351 case EOpSinh:
1352 outputTriplet(out, visit, "sinh(", "", ")");
1353 break;
1354 case EOpCosh:
1355 outputTriplet(out, visit, "cosh(", "", ")");
1356 break;
1357 case EOpTanh:
1358 outputTriplet(out, visit, "tanh(", "", ")");
1359 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001360 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001361 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001362 case EOpAtanh:
1363 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001364 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001365 break;
1366 case EOpExp:
1367 outputTriplet(out, visit, "exp(", "", ")");
1368 break;
1369 case EOpLog:
1370 outputTriplet(out, visit, "log(", "", ")");
1371 break;
1372 case EOpExp2:
1373 outputTriplet(out, visit, "exp2(", "", ")");
1374 break;
1375 case EOpLog2:
1376 outputTriplet(out, visit, "log2(", "", ")");
1377 break;
1378 case EOpSqrt:
1379 outputTriplet(out, visit, "sqrt(", "", ")");
1380 break;
1381 case EOpInverseSqrt:
1382 outputTriplet(out, visit, "rsqrt(", "", ")");
1383 break;
1384 case EOpAbs:
1385 outputTriplet(out, visit, "abs(", "", ")");
1386 break;
1387 case EOpSign:
1388 outputTriplet(out, visit, "sign(", "", ")");
1389 break;
1390 case EOpFloor:
1391 outputTriplet(out, visit, "floor(", "", ")");
1392 break;
1393 case EOpTrunc:
1394 outputTriplet(out, visit, "trunc(", "", ")");
1395 break;
1396 case EOpRound:
1397 outputTriplet(out, visit, "round(", "", ")");
1398 break;
1399 case EOpRoundEven:
1400 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001401 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001402 break;
1403 case EOpCeil:
1404 outputTriplet(out, visit, "ceil(", "", ")");
1405 break;
1406 case EOpFract:
1407 outputTriplet(out, visit, "frac(", "", ")");
1408 break;
1409 case EOpIsNan:
1410 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001411 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001412 else
1413 outputTriplet(out, visit, "isnan(", "", ")");
1414 mRequiresIEEEStrictCompiling = true;
1415 break;
1416 case EOpIsInf:
1417 outputTriplet(out, visit, "isinf(", "", ")");
1418 break;
1419 case EOpFloatBitsToInt:
1420 outputTriplet(out, visit, "asint(", "", ")");
1421 break;
1422 case EOpFloatBitsToUint:
1423 outputTriplet(out, visit, "asuint(", "", ")");
1424 break;
1425 case EOpIntBitsToFloat:
1426 outputTriplet(out, visit, "asfloat(", "", ")");
1427 break;
1428 case EOpUintBitsToFloat:
1429 outputTriplet(out, visit, "asfloat(", "", ")");
1430 break;
1431 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001432 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001433 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001434 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001436 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001437 case EOpPackUnorm4x8:
1438 case EOpPackSnorm4x8:
1439 case EOpUnpackUnorm4x8:
1440 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001441 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001442 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001443 break;
1444 case EOpLength:
1445 outputTriplet(out, visit, "length(", "", ")");
1446 break;
1447 case EOpNormalize:
1448 outputTriplet(out, visit, "normalize(", "", ")");
1449 break;
1450 case EOpDFdx:
1451 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1452 {
1453 outputTriplet(out, visit, "(", "", ", 0.0)");
1454 }
1455 else
1456 {
1457 outputTriplet(out, visit, "ddx(", "", ")");
1458 }
1459 break;
1460 case EOpDFdy:
1461 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1462 {
1463 outputTriplet(out, visit, "(", "", ", 0.0)");
1464 }
1465 else
1466 {
1467 outputTriplet(out, visit, "ddy(", "", ")");
1468 }
1469 break;
1470 case EOpFwidth:
1471 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1472 {
1473 outputTriplet(out, visit, "(", "", ", 0.0)");
1474 }
1475 else
1476 {
1477 outputTriplet(out, visit, "fwidth(", "", ")");
1478 }
1479 break;
1480 case EOpTranspose:
1481 outputTriplet(out, visit, "transpose(", "", ")");
1482 break;
1483 case EOpDeterminant:
1484 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1485 break;
1486 case EOpInverse:
1487 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001488 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001489 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001490
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001491 case EOpAny:
1492 outputTriplet(out, visit, "any(", "", ")");
1493 break;
1494 case EOpAll:
1495 outputTriplet(out, visit, "all(", "", ")");
1496 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001497 case EOpLogicalNotComponentWise:
1498 outputTriplet(out, visit, "(!", "", ")");
1499 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001500 case EOpBitfieldReverse:
1501 outputTriplet(out, visit, "reversebits(", "", ")");
1502 break;
1503 case EOpBitCount:
1504 outputTriplet(out, visit, "countbits(", "", ")");
1505 break;
1506 case EOpFindLSB:
1507 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1508 // in GLSLTest and results are consistent with GL.
1509 outputTriplet(out, visit, "firstbitlow(", "", ")");
1510 break;
1511 case EOpFindMSB:
1512 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1513 // tested in GLSLTest and results are consistent with GL.
1514 outputTriplet(out, visit, "firstbithigh(", "", ")");
1515 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001516 default:
1517 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001518 }
1519
1520 return true;
1521}
1522
Olli Etuaho96963162016-03-21 11:54:33 +02001523TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1524{
1525 if (node->getAsSymbolNode())
1526 {
1527 return node->getAsSymbolNode()->getSymbol();
1528 }
1529 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1530 switch (nodeBinary->getOp())
1531 {
1532 case EOpIndexDirect:
1533 {
1534 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1535
1536 TInfoSinkBase prefixSink;
1537 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1538 return TString(prefixSink.c_str());
1539 }
1540 case EOpIndexDirectStruct:
1541 {
1542 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1543 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1544 const TField *field = s->fields()[index];
1545
1546 TInfoSinkBase prefixSink;
1547 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1548 << field->name();
1549 return TString(prefixSink.c_str());
1550 }
1551 default:
1552 UNREACHABLE();
1553 return TString("");
1554 }
1555}
1556
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001557bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1558{
1559 TInfoSinkBase &out = getInfoSink();
1560
1561 if (mInsideFunction)
1562 {
1563 outputLineDirective(out, node->getLine().first_line);
1564 out << "{\n";
1565 }
1566
1567 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1568 sit != node->getSequence()->end(); sit++)
1569 {
1570 outputLineDirective(out, (*sit)->getLine().first_line);
1571
1572 (*sit)->traverse(this);
1573
1574 // Don't output ; after case labels, they're terminated by :
1575 // This is needed especially since outputting a ; after a case statement would turn empty
1576 // case statements into non-empty case statements, disallowing fall-through from them.
1577 // Also no need to output ; after if statements or sequences. This is done just for
1578 // code clarity.
1579 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1580 (*sit)->getAsBlock() == nullptr)
1581 out << ";\n";
1582 }
1583
1584 if (mInsideFunction)
1585 {
1586 outputLineDirective(out, node->getLine().last_line);
1587 out << "}\n";
1588 }
1589
1590 return false;
1591}
1592
Olli Etuaho336b1472016-10-05 16:37:55 +01001593bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1594{
1595 TInfoSinkBase &out = getInfoSink();
1596
1597 ASSERT(mCurrentFunctionMetadata == nullptr);
1598
1599 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1600 ASSERT(index != CallDAG::InvalidIndex);
1601 mCurrentFunctionMetadata = &mASTMetadataList[index];
1602
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001603 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001604
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001605 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001606
1607 if (node->getFunctionSymbolInfo()->isMain())
1608 {
1609 out << "gl_main(";
1610 }
1611 else
1612 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001613 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001614 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1615 }
1616
1617 for (unsigned int i = 0; i < parameters->size(); i++)
1618 {
1619 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1620
1621 if (symbol)
1622 {
1623 ensureStructDefined(symbol->getType());
1624
1625 out << argumentString(symbol);
1626
1627 if (i < parameters->size() - 1)
1628 {
1629 out << ", ";
1630 }
1631 }
1632 else
1633 UNREACHABLE();
1634 }
1635
1636 out << ")\n";
1637
1638 mInsideFunction = true;
1639 // The function body node will output braces.
1640 node->getBody()->traverse(this);
1641 mInsideFunction = false;
1642
1643 mCurrentFunctionMetadata = nullptr;
1644
1645 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1646 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1647 {
1648 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1649 mOutputLod0Function = true;
1650 node->traverse(this);
1651 mOutputLod0Function = false;
1652 }
1653
1654 return false;
1655}
1656
Olli Etuaho13389b62016-10-16 11:48:18 +01001657bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1658{
1659 TInfoSinkBase &out = getInfoSink();
1660 if (visit == PreVisit)
1661 {
1662 TIntermSequence *sequence = node->getSequence();
1663 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1664 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001665 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001666
Olli Etuaho282847e2017-07-12 14:11:01 +03001667 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001668 variable->getQualifier() == EvqConst))
1669 {
1670 ensureStructDefined(variable->getType());
1671
1672 if (!variable->getAsSymbolNode() ||
1673 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1674 {
1675 if (!mInsideFunction)
1676 {
1677 out << "static ";
1678 }
1679
1680 out << TypeString(variable->getType()) + " ";
1681
1682 TIntermSymbol *symbol = variable->getAsSymbolNode();
1683
1684 if (symbol)
1685 {
1686 symbol->traverse(this);
1687 out << ArrayString(symbol->getType());
1688 out << " = " + initializer(symbol->getType());
1689 }
1690 else
1691 {
1692 variable->traverse(this);
1693 }
1694 }
1695 else if (variable->getAsSymbolNode() &&
1696 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1697 {
1698 // Already added to constructor map
1699 }
1700 else
1701 UNREACHABLE();
1702 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001703 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001704 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001705 TIntermSymbol *symbol = variable->getAsSymbolNode();
1706 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001707
Olli Etuaho282847e2017-07-12 14:11:01 +03001708 // Vertex outputs which are declared but not written to should still be declared to
1709 // allow successful linking.
1710 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001711 }
1712 }
1713 return false;
1714}
1715
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001716bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1717{
1718 // Do not do any translation
1719 return false;
1720}
1721
Olli Etuaho16c745a2017-01-16 17:02:27 +00001722bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1723{
1724 TInfoSinkBase &out = getInfoSink();
1725
1726 ASSERT(visit == PreVisit);
1727 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1728 // Skip the prototype if it is not implemented (and thus not used)
1729 if (index == CallDAG::InvalidIndex)
1730 {
1731 return false;
1732 }
1733
1734 TIntermSequence *arguments = node->getSequence();
1735
Olli Etuahoff526f12017-06-30 12:26:54 +03001736 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001737 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1738 << (mOutputLod0Function ? "Lod0(" : "(");
1739
1740 for (unsigned int i = 0; i < arguments->size(); i++)
1741 {
1742 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1743 ASSERT(symbol != nullptr);
1744
1745 out << argumentString(symbol);
1746
1747 if (i < arguments->size() - 1)
1748 {
1749 out << ", ";
1750 }
1751 }
1752
1753 out << ");\n";
1754
1755 // Also prototype the Lod0 variant if needed
1756 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1757 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1758 {
1759 mOutputLod0Function = true;
1760 node->traverse(this);
1761 mOutputLod0Function = false;
1762 }
1763
1764 return false;
1765}
1766
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1768{
Jamie Madill32aab012015-01-27 14:12:26 -05001769 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001770
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001771 switch (node->getOp())
1772 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001773 case EOpCallBuiltInFunction:
1774 case EOpCallFunctionInAST:
1775 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001776 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001777 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001778
Corentin Wallez1239ee92015-03-19 14:38:02 -07001779 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001780 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001781 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001782 if (node->isArray())
1783 {
1784 UNIMPLEMENTED();
1785 }
Olli Etuahobd674552016-10-06 13:28:42 +01001786 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001787 ASSERT(index != CallDAG::InvalidIndex);
1788 lod0 &= mASTMetadataList[index].mNeedsLod0;
1789
Olli Etuahoff526f12017-06-30 12:26:54 +03001790 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001791 out << DisambiguateFunctionName(node->getSequence());
1792 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001793 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001794 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001795 {
1796 // This path is used for internal functions that don't have their definitions in the
1797 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001798 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001799 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001800 else
1801 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001802 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001803 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001804 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1805 if (arguments->size() > 1)
1806 {
1807 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1808 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001809 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1810 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1811 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001812 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001813
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001814 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001815 {
Olli Etuaho96963162016-03-21 11:54:33 +02001816 TIntermTyped *typedArg = (*arg)->getAsTyped();
1817 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001818 {
1819 out << "texture_";
1820 (*arg)->traverse(this);
1821 out << ", sampler_";
1822 }
1823
1824 (*arg)->traverse(this);
1825
Olli Etuaho96963162016-03-21 11:54:33 +02001826 if (typedArg->getType().isStructureContainingSamplers())
1827 {
1828 const TType &argType = typedArg->getType();
1829 TVector<TIntermSymbol *> samplerSymbols;
1830 TString structName = samplerNamePrefixFromStruct(typedArg);
1831 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho96963162016-03-21 11:54:33 +02001832 &samplerSymbols, nullptr);
1833 for (const TIntermSymbol *sampler : samplerSymbols)
1834 {
1835 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1836 {
1837 out << ", texture_" << sampler->getSymbol();
1838 out << ", sampler_" << sampler->getSymbol();
1839 }
1840 else
1841 {
1842 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1843 // of D3D9, it's the sampler variable.
1844 out << ", " + sampler->getSymbol();
1845 }
1846 }
1847 }
1848
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001849 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001850 {
1851 out << ", ";
1852 }
1853 }
1854
1855 out << ")";
1856
1857 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001858 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001859 case EOpConstruct:
1860 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001861 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001862 if (node->getType().isArray())
1863 {
1864 UNIMPLEMENTED();
1865 }
1866 const TString &structName = StructNameString(*node->getType().getStruct());
1867 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1868 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001869 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001870 else
1871 {
1872 const char *name = "";
1873 if (node->getType().getNominalSize() == 1)
1874 {
1875 switch (node->getBasicType())
1876 {
1877 case EbtFloat:
1878 name = "vec1";
1879 break;
1880 case EbtInt:
1881 name = "ivec1";
1882 break;
1883 case EbtUInt:
1884 name = "uvec1";
1885 break;
1886 case EbtBool:
1887 name = "bvec1";
1888 break;
1889 default:
1890 UNREACHABLE();
1891 }
1892 }
1893 else
1894 {
1895 name = node->getType().getBuiltInTypeNameString();
1896 }
1897 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1898 }
1899 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001900 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001901 outputTriplet(out, visit, "(", " == ", ")");
1902 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001903 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001904 outputTriplet(out, visit, "(", " != ", ")");
1905 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001906 case EOpLessThanComponentWise:
1907 outputTriplet(out, visit, "(", " < ", ")");
1908 break;
1909 case EOpGreaterThanComponentWise:
1910 outputTriplet(out, visit, "(", " > ", ")");
1911 break;
1912 case EOpLessThanEqualComponentWise:
1913 outputTriplet(out, visit, "(", " <= ", ")");
1914 break;
1915 case EOpGreaterThanEqualComponentWise:
1916 outputTriplet(out, visit, "(", " >= ", ")");
1917 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001918 case EOpMod:
1919 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001920 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001921 break;
1922 case EOpModf:
1923 outputTriplet(out, visit, "modf(", ", ", ")");
1924 break;
1925 case EOpPow:
1926 outputTriplet(out, visit, "pow(", ", ", ")");
1927 break;
1928 case EOpAtan:
1929 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1930 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001931 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001932 break;
1933 case EOpMin:
1934 outputTriplet(out, visit, "min(", ", ", ")");
1935 break;
1936 case EOpMax:
1937 outputTriplet(out, visit, "max(", ", ", ")");
1938 break;
1939 case EOpClamp:
1940 outputTriplet(out, visit, "clamp(", ", ", ")");
1941 break;
1942 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301943 {
1944 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1945 if (lastParamNode->getType().getBasicType() == EbtBool)
1946 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001947 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1948 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301949 // so use emulated version.
1950 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001951 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301952 }
1953 else
1954 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001955 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301956 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001957 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301958 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001959 case EOpStep:
1960 outputTriplet(out, visit, "step(", ", ", ")");
1961 break;
1962 case EOpSmoothStep:
1963 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1964 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001965 case EOpFrexp:
1966 case EOpLdexp:
1967 ASSERT(node->getUseEmulatedFunction());
1968 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1969 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001970 case EOpDistance:
1971 outputTriplet(out, visit, "distance(", ", ", ")");
1972 break;
1973 case EOpDot:
1974 outputTriplet(out, visit, "dot(", ", ", ")");
1975 break;
1976 case EOpCross:
1977 outputTriplet(out, visit, "cross(", ", ", ")");
1978 break;
Jamie Madille72595b2017-06-06 15:12:26 -04001979 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01001980 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001981 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001982 break;
1983 case EOpReflect:
1984 outputTriplet(out, visit, "reflect(", ", ", ")");
1985 break;
1986 case EOpRefract:
1987 outputTriplet(out, visit, "refract(", ", ", ")");
1988 break;
1989 case EOpOuterProduct:
1990 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001991 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001992 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001993 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01001994 outputTriplet(out, visit, "(", " * ", ")");
1995 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001996 case EOpBitfieldExtract:
1997 case EOpBitfieldInsert:
1998 case EOpUaddCarry:
1999 case EOpUsubBorrow:
2000 case EOpUmulExtended:
2001 case EOpImulExtended:
2002 ASSERT(node->getUseEmulatedFunction());
2003 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2004 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002005 default:
2006 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002007 }
2008
2009 return true;
2010}
2011
Olli Etuaho57961272016-09-14 13:57:46 +03002012void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002013{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002014 out << "if (";
2015
2016 node->getCondition()->traverse(this);
2017
2018 out << ")\n";
2019
Jamie Madill8c46ab12015-12-07 16:39:19 -05002020 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002021
2022 bool discard = false;
2023
2024 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002025 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002026 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002027 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002028
Olli Etuahoa6f22092015-05-08 18:31:10 +03002029 // Detect true discard
2030 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2031 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002032 else
2033 {
2034 // TODO(oetuaho): Check if the semicolon inside is necessary.
2035 // It's there as a result of conservative refactoring of the output.
2036 out << "{;}\n";
2037 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002038
Jamie Madill8c46ab12015-12-07 16:39:19 -05002039 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002040
Olli Etuahoa6f22092015-05-08 18:31:10 +03002041 if (node->getFalseBlock())
2042 {
2043 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002044
Jamie Madill8c46ab12015-12-07 16:39:19 -05002045 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046
Olli Etuaho32db19b2016-10-04 14:43:16 +01002047 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002048 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002049
Jamie Madill8c46ab12015-12-07 16:39:19 -05002050 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002051
Olli Etuahoa6f22092015-05-08 18:31:10 +03002052 // Detect false discard
2053 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2054 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002055
Olli Etuahoa6f22092015-05-08 18:31:10 +03002056 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002057 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002058 {
2059 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002060 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002061}
2062
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002063bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2064{
2065 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2066 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2067 UNREACHABLE();
2068 return false;
2069}
2070
Olli Etuaho57961272016-09-14 13:57:46 +03002071bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002072{
2073 TInfoSinkBase &out = getInfoSink();
2074
Olli Etuaho3d932d82016-04-12 11:10:30 +03002075 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002076
2077 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002078 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002079 {
2080 out << "FLATTEN ";
2081 }
2082
Olli Etuaho57961272016-09-14 13:57:46 +03002083 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002084
2085 return false;
2086}
2087
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002088bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002089{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002090 TInfoSinkBase &out = getInfoSink();
2091
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002092 if (node->getStatementList())
2093 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002094 node->setStatementList(
2095 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002096 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002097 // The curly braces get written when visiting the statementList aggregate
2098 }
2099 else
2100 {
2101 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002102 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002103 }
2104 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002105}
2106
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002107bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002108{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002109 TInfoSinkBase &out = getInfoSink();
2110
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002111 if (node->hasCondition())
2112 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002113 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002114 return true;
2115 }
2116 else
2117 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002118 out << "default:\n";
2119 return false;
2120 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002121}
2122
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002123void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2124{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002125 TInfoSinkBase &out = getInfoSink();
2126 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002127}
2128
2129bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2130{
Nicolas Capens655fe362014-04-11 13:12:34 -04002131 mNestedLoopDepth++;
2132
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002133 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002134 mInsideDiscontinuousLoop =
2135 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002136
Jamie Madill8c46ab12015-12-07 16:39:19 -05002137 TInfoSinkBase &out = getInfoSink();
2138
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002139 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002140 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002141 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002142 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002143 mInsideDiscontinuousLoop = wasDiscontinuous;
2144 mNestedLoopDepth--;
2145
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002146 return false;
2147 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002148 }
2149
Corentin Wallez1239ee92015-03-19 14:38:02 -07002150 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002151 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002153 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002154
Jamie Madill8c46ab12015-12-07 16:39:19 -05002155 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002156 }
2157 else
2158 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002159 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002160
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002161 if (node->getInit())
2162 {
2163 node->getInit()->traverse(this);
2164 }
2165
2166 out << "; ";
2167
alokp@chromium.org52813552010-11-16 18:36:09 +00002168 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002169 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002170 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 }
2172
2173 out << "; ";
2174
alokp@chromium.org52813552010-11-16 18:36:09 +00002175 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002176 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002177 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 }
2179
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002180 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002181
Jamie Madill8c46ab12015-12-07 16:39:19 -05002182 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 }
2184
2185 if (node->getBody())
2186 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002187 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002188 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002189 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002190 else
2191 {
2192 // TODO(oetuaho): Check if the semicolon inside is necessary.
2193 // It's there as a result of conservative refactoring of the output.
2194 out << "{;}\n";
2195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002196
Jamie Madill8c46ab12015-12-07 16:39:19 -05002197 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198
alokp@chromium.org52813552010-11-16 18:36:09 +00002199 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002201 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 out << "while(\n";
2203
alokp@chromium.org52813552010-11-16 18:36:09 +00002204 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002205
daniel@transgaming.com73536982012-03-21 20:45:49 +00002206 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207 }
2208
daniel@transgaming.com73536982012-03-21 20:45:49 +00002209 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002210
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002211 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002212 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002213
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002214 return false;
2215}
2216
2217bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2218{
Jamie Madill32aab012015-01-27 14:12:26 -05002219 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002220
2221 switch (node->getFlowOp())
2222 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002223 case EOpKill:
2224 outputTriplet(out, visit, "discard;\n", "", "");
2225 break;
2226 case EOpBreak:
2227 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002228 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002229 if (mNestedLoopDepth > 1)
2230 {
2231 mUsesNestedBreak = true;
2232 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002233
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002234 if (mExcessiveLoopIndex)
2235 {
2236 out << "{Break";
2237 mExcessiveLoopIndex->traverse(this);
2238 out << " = true; break;}\n";
2239 }
2240 else
2241 {
2242 out << "break;\n";
2243 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002244 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002245 break;
2246 case EOpContinue:
2247 outputTriplet(out, visit, "continue;\n", "", "");
2248 break;
2249 case EOpReturn:
2250 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002251 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002252 if (node->getExpression())
2253 {
2254 out << "return ";
2255 }
2256 else
2257 {
2258 out << "return;\n";
2259 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002260 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002261 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002262 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002263 if (node->getExpression())
2264 {
2265 out << ";\n";
2266 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002268 break;
2269 default:
2270 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002271 }
2272
2273 return true;
2274}
2275
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002276// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002277// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2278// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002279bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002280{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002281 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002282
2283 // Parse loops of the form:
2284 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002285 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002286 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002287 int initial = 0;
2288 int limit = 0;
2289 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002290
2291 // Parse index name and intial value
2292 if (node->getInit())
2293 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002294 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002295
2296 if (init)
2297 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002298 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002299 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002300
2301 if (variable && variable->getQualifier() == EvqTemporary)
2302 {
2303 TIntermBinary *assign = variable->getAsBinaryNode();
2304
2305 if (assign->getOp() == EOpInitialize)
2306 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002307 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002308 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2309
2310 if (symbol && constant)
2311 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002312 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002313 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002314 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002315 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002316 }
2317 }
2318 }
2319 }
2320 }
2321 }
2322
2323 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002324 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002325 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002326 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002327
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002328 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2329 {
2330 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2331
2332 if (constant)
2333 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002334 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002335 {
2336 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002337 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002338 }
2339 }
2340 }
2341 }
2342
2343 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002344 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002345 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002346 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002347 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002348
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002349 if (binaryTerminal)
2350 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002351 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002352 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2353
2354 if (constant)
2355 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002356 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002357 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002358 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002359
2360 switch (op)
2361 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002362 case EOpAddAssign:
2363 increment = value;
2364 break;
2365 case EOpSubAssign:
2366 increment = -value;
2367 break;
2368 default:
2369 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002370 }
2371 }
2372 }
2373 }
2374 else if (unaryTerminal)
2375 {
2376 TOperator op = unaryTerminal->getOp();
2377
2378 switch (op)
2379 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002380 case EOpPostIncrement:
2381 increment = 1;
2382 break;
2383 case EOpPostDecrement:
2384 increment = -1;
2385 break;
2386 case EOpPreIncrement:
2387 increment = 1;
2388 break;
2389 case EOpPreDecrement:
2390 increment = -1;
2391 break;
2392 default:
2393 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002394 }
2395 }
2396 }
2397
Yunchao He4f285442017-04-21 12:15:49 +08002398 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002399 {
2400 if (comparator == EOpLessThanEqual)
2401 {
2402 comparator = EOpLessThan;
2403 limit += 1;
2404 }
2405
2406 if (comparator == EOpLessThan)
2407 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002408 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002409
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002410 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002411 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002412 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002413 }
2414
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002415 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002416 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002417
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002418 out << "{int ";
2419 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002420 out << ";\n"
2421 "bool Break";
2422 index->traverse(this);
2423 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002424
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002425 bool firstLoopFragment = true;
2426
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002427 while (iterations > 0)
2428 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002429 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002430
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002431 if (!firstLoopFragment)
2432 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002433 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002434 index->traverse(this);
2435 out << ") {\n";
2436 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002437
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002438 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002439 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002440 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002441 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002442
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002443 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002444 const char *unroll =
2445 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002446
Corentin Wallez1239ee92015-03-19 14:38:02 -07002447 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002448 index->traverse(this);
2449 out << " = ";
2450 out << initial;
2451
2452 out << "; ";
2453 index->traverse(this);
2454 out << " < ";
2455 out << clampedLimit;
2456
2457 out << "; ";
2458 index->traverse(this);
2459 out << " += ";
2460 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002461 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002462
Jamie Madill8c46ab12015-12-07 16:39:19 -05002463 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002464 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002465
2466 if (node->getBody())
2467 {
2468 node->getBody()->traverse(this);
2469 }
2470
Jamie Madill8c46ab12015-12-07 16:39:19 -05002471 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002472 out << ";}\n";
2473
2474 if (!firstLoopFragment)
2475 {
2476 out << "}\n";
2477 }
2478
2479 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002480
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002481 initial += MAX_LOOP_ITERATIONS * increment;
2482 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002483 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002484
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002485 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002486
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002487 mExcessiveLoopIndex = restoreIndex;
2488
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002489 return true;
2490 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002491 else
2492 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002493 }
2494
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002495 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002496}
2497
Jamie Madill8c46ab12015-12-07 16:39:19 -05002498void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2499 Visit visit,
2500 const char *preString,
2501 const char *inString,
2502 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002503{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002504 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002505 {
2506 out << preString;
2507 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002508 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002509 {
2510 out << inString;
2511 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002512 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002513 {
2514 out << postString;
2515 }
2516}
2517
Jamie Madill8c46ab12015-12-07 16:39:19 -05002518void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002519{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002520 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002521 {
Jamie Madill32aab012015-01-27 14:12:26 -05002522 out << "\n";
2523 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002524
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002525 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002526 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002527 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002528 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002529
Jamie Madill32aab012015-01-27 14:12:26 -05002530 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002531 }
2532}
2533
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002534TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2535{
2536 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002537 const TType &type = symbol->getType();
2538 const TName &name = symbol->getName();
2539 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002540
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002541 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002542 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002543 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002544 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002545 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002546 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002547 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002548 }
2549
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002550 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002551 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002552 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2553 {
2554 // Samplers are passed as indices to the sampler array.
2555 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2556 return "const uint " + nameStr + ArrayString(type);
2557 }
2558 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2559 {
2560 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2561 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2562 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2563 ArrayString(type);
2564 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002565 }
2566
Olli Etuaho96963162016-03-21 11:54:33 +02002567 TStringStream argString;
2568 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2569 << ArrayString(type);
2570
2571 // If the structure parameter contains samplers, they need to be passed into the function as
2572 // separate parameters. HLSL doesn't natively support samplers in structs.
2573 if (type.isStructureContainingSamplers())
2574 {
2575 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2576 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho599555b2017-08-15 11:12:42 +03002577 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002578 for (const TIntermSymbol *sampler : samplerSymbols)
2579 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002580 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002581 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2582 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002583 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002584 }
2585 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2586 {
Olli Etuaho96963162016-03-21 11:54:33 +02002587 ASSERT(IsSampler(samplerType.getBasicType()));
2588 argString << ", " << QualifierString(qualifier) << " "
2589 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002590 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2591 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002592 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002593 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002594 }
2595 else
2596 {
Olli Etuaho96963162016-03-21 11:54:33 +02002597 ASSERT(IsSampler(samplerType.getBasicType()));
2598 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002599 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002600 }
2601 }
2602 }
2603
2604 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002605}
2606
2607TString OutputHLSL::initializer(const TType &type)
2608{
2609 TString string;
2610
Jamie Madill94bf7f22013-07-08 13:31:15 -04002611 size_t size = type.getObjectSize();
2612 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002613 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002614 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002615
Jamie Madill94bf7f22013-07-08 13:31:15 -04002616 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002617 {
2618 string += ", ";
2619 }
2620 }
2621
daniel@transgaming.comead23042010-04-29 03:35:36 +00002622 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002623}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002624
Jamie Madill8c46ab12015-12-07 16:39:19 -05002625void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2626 Visit visit,
2627 const TType &type,
2628 const char *name,
2629 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002630{
Olli Etuahof40319e2015-03-10 14:33:00 +02002631 if (type.isArray())
2632 {
2633 UNIMPLEMENTED();
2634 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002635
2636 if (visit == PreVisit)
2637 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002638 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002639
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002640 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002641 }
2642 else if (visit == InVisit)
2643 {
2644 out << ", ";
2645 }
2646 else if (visit == PostVisit)
2647 {
2648 out << ")";
2649 }
2650}
2651
Jamie Madill8c46ab12015-12-07 16:39:19 -05002652const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2653 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002654 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002655{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002656 const TConstantUnion *constUnionIterated = constUnion;
2657
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002658 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002659 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002660 {
Jamie Madill033dae62014-06-18 12:56:28 -04002661 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002662
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002663 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002664
Jamie Madill98493dd2013-07-08 14:39:03 -04002665 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002666 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002667 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002668 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002669
Jamie Madill98493dd2013-07-08 14:39:03 -04002670 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002671 {
2672 out << ", ";
2673 }
2674 }
2675
2676 out << ")";
2677 }
2678 else
2679 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002680 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002681 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002682
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002683 if (writeType)
2684 {
Jamie Madill033dae62014-06-18 12:56:28 -04002685 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002686 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002687 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002688 if (writeType)
2689 {
2690 out << ")";
2691 }
2692 }
2693
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002694 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002695}
2696
Olli Etuahod68924e2017-01-02 17:34:40 +00002697void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002698{
Olli Etuahod68924e2017-01-02 17:34:40 +00002699 if (visit == PreVisit)
2700 {
2701 const char *opStr = GetOperatorString(op);
2702 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2703 out << "(";
2704 }
2705 else
2706 {
2707 outputTriplet(out, visit, nullptr, ", ", ")");
2708 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002709}
2710
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002711bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2712 TIntermSymbol *symbolNode,
2713 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002714{
2715 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2716 expression->traverse(&searchSymbol);
2717
2718 if (searchSymbol.foundMatch())
2719 {
2720 // Type already printed
2721 out << "t" + str(mUniqueIndex) + " = ";
2722 expression->traverse(this);
2723 out << ", ";
2724 symbolNode->traverse(this);
2725 out << " = t" + str(mUniqueIndex);
2726
2727 mUniqueIndex++;
2728 return true;
2729 }
2730
2731 return false;
2732}
2733
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002734bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2735{
2736 // We support writing constant unions and constructors that only take constant unions as
2737 // parameters as HLSL literals.
Olli Etuahod4f4c112016-04-15 15:11:24 +03002738 return expression->getAsConstantUnion() ||
2739 expression->isConstructorWithOnlyConstantUnionParameters();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002740}
2741
2742bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2743 TIntermSymbol *symbolNode,
2744 TIntermTyped *expression)
2745{
2746 if (canWriteAsHLSLLiteral(expression))
2747 {
2748 symbolNode->traverse(this);
2749 if (expression->getType().isArray())
2750 {
2751 out << "[" << expression->getType().getArraySize() << "]";
2752 }
2753 out << " = {";
2754 if (expression->getAsConstantUnion())
2755 {
2756 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2757 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002758 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002759 }
2760 else
2761 {
2762 TIntermAggregate *constructor = expression->getAsAggregate();
2763 ASSERT(constructor != nullptr);
2764 for (TIntermNode *&node : *constructor->getSequence())
2765 {
2766 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2767 ASSERT(nodeConst);
2768 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002769 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002770 if (node != constructor->getSequence()->back())
2771 {
2772 out << ", ";
2773 }
2774 }
2775 }
2776 out << "}";
2777 return true;
2778 }
2779 return false;
2780}
2781
Jamie Madill55e79e02015-02-09 15:35:00 -05002782TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2783{
2784 const TFieldList &fields = structure.fields();
2785
2786 for (const auto &eqFunction : mStructEqualityFunctions)
2787 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002788 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002789 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002790 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002791 }
2792 }
2793
2794 const TString &structNameString = StructNameString(structure);
2795
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002796 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002797 function->structure = &structure;
2798 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002799
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002800 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002801
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002802 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2803 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002804 << "{\n"
2805 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002806
2807 for (size_t i = 0; i < fields.size(); i++)
2808 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002809 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002810 const TType *fieldType = field->type();
2811
2812 const TString &fieldNameA = "a." + Decorate(field->name());
2813 const TString &fieldNameB = "b." + Decorate(field->name());
2814
2815 if (i > 0)
2816 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002817 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002818 }
2819
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002820 fnOut << "(";
2821 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2822 fnOut << fieldNameA;
2823 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2824 fnOut << fieldNameB;
2825 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2826 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002827 }
2828
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002829 fnOut << ";\n"
2830 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002831
2832 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002833
2834 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002835 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002836
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002837 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002838}
2839
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002840TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002841{
2842 for (const auto &eqFunction : mArrayEqualityFunctions)
2843 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002844 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002845 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002846 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002847 }
2848 }
2849
2850 const TString &typeName = TypeString(type);
2851
Olli Etuaho12690762015-03-31 12:55:28 +03002852 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002853 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002854
2855 TInfoSinkBase fnNameOut;
2856 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002857 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002858
2859 TType nonArrayType = type;
2860 nonArrayType.clearArrayness();
2861
2862 TInfoSinkBase fnOut;
2863
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002864 fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize()
2865 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002866 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002867 " for (int i = 0; i < "
2868 << type.getArraySize() << "; ++i)\n"
2869 " {\n"
2870 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002871
2872 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2873 fnOut << "a[i]";
2874 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2875 fnOut << "b[i]";
2876 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2877
2878 fnOut << ") { return false; }\n"
2879 " }\n"
2880 " return true;\n"
2881 "}\n";
2882
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002883 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002884
2885 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002886 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002887
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002888 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002889}
2890
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002891TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002892{
2893 for (const auto &assignFunction : mArrayAssignmentFunctions)
2894 {
2895 if (assignFunction.type == type)
2896 {
2897 return assignFunction.functionName;
2898 }
2899 }
2900
2901 const TString &typeName = TypeString(type);
2902
2903 ArrayHelperFunction function;
2904 function.type = type;
2905
2906 TInfoSinkBase fnNameOut;
2907 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
2908 function.functionName = fnNameOut.c_str();
2909
2910 TInfoSinkBase fnOut;
2911
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002912 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2913 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
2914 << "{\n"
2915 " for (int i = 0; i < "
2916 << type.getArraySize() << "; ++i)\n"
2917 " {\n"
2918 " a[i] = b[i];\n"
2919 " }\n"
2920 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002921
2922 function.functionDefinition = fnOut.c_str();
2923
2924 mArrayAssignmentFunctions.push_back(function);
2925
2926 return function.functionName;
2927}
2928
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002929TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002930{
2931 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2932 {
2933 if (constructIntoFunction.type == type)
2934 {
2935 return constructIntoFunction.functionName;
2936 }
2937 }
2938
2939 const TString &typeName = TypeString(type);
2940
2941 ArrayHelperFunction function;
2942 function.type = type;
2943
2944 TInfoSinkBase fnNameOut;
2945 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2946 function.functionName = fnNameOut.c_str();
2947
2948 TInfoSinkBase fnOut;
2949
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002950 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2951 << "]";
Olli Etuaho856c4972016-08-08 11:38:39 +03002952 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002953 {
2954 fnOut << ", " << typeName << " b" << i;
2955 }
2956 fnOut << ")\n"
2957 "{\n";
2958
Olli Etuaho856c4972016-08-08 11:38:39 +03002959 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002960 {
2961 fnOut << " a[" << i << "] = b" << i << ";\n";
2962 }
2963 fnOut << "}\n";
2964
2965 function.functionDefinition = fnOut.c_str();
2966
2967 mArrayConstructIntoFunctions.push_back(function);
2968
2969 return function.functionName;
2970}
2971
Jamie Madill2e295e22015-04-29 10:41:33 -04002972void OutputHLSL::ensureStructDefined(const TType &type)
2973{
2974 TStructure *structure = type.getStruct();
2975
2976 if (structure)
2977 {
2978 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
2979 }
2980}
2981
Jamie Madill45bcc782016-11-07 13:58:48 -05002982} // namespace sh