blob: 5e2c1591396d2a1a6f1d0e76f69184ca2794606a [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
150 mUniformHLSL->reserveInterfaceBlockRegisters(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
Jamie Madill4e1fd412014-07-10 17:50:10 -0400234const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
235{
236 return mUniformHLSL->getInterfaceBlockRegisterMap();
237}
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
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500252TString OutputHLSL::structInitializerString(int indent,
253 const TStructure &structure,
254 const TString &rhsStructName)
Jamie Madill570e04d2013-06-21 09:15:33 -0400255{
256 TString init;
257
258 TString preIndentString;
259 TString fullIndentString;
260
261 for (int spaces = 0; spaces < (indent * 4); spaces++)
262 {
263 preIndentString += ' ';
264 }
265
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500266 for (int spaces = 0; spaces < ((indent + 1) * 4); spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400267 {
268 fullIndentString += ' ';
269 }
270
271 init += preIndentString + "{\n";
272
Jamie Madill98493dd2013-07-08 14:39:03 -0400273 const TFieldList &fields = structure.fields();
274 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400275 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500276 const TField &field = *fields[fieldIndex];
Jamie Madill033dae62014-06-18 12:56:28 -0400277 const TString &fieldName = rhsStructName + "." + Decorate(field.name());
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500278 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400279
Jamie Madill98493dd2013-07-08 14:39:03 -0400280 if (fieldType.getStruct())
Jamie Madill570e04d2013-06-21 09:15:33 -0400281 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400282 init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400283 }
284 else
285 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400286 init += fullIndentString + fieldName + ",\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400287 }
288 }
289
290 init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
291
292 return init;
293}
294
Jamie Madill8c46ab12015-12-07 16:39:19 -0500295void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000297 TString varyings;
298 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400299 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000300
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500301 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
302 mFlaggedStructMappedNames.begin();
303 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400304 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500305 TIntermTyped *structNode = flaggedStructIt->first;
306 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400307 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400308 const TString &originalName = mFlaggedStructOriginalNames[structNode];
309
Jamie Madill033dae62014-06-18 12:56:28 -0400310 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400311 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400312 flaggedStructs += "\n";
313 }
314
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500315 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
316 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000317 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500318 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000319 const TString &name = varying->second->getSymbol();
320
321 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500322 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
323 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000324 }
325
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500326 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
327 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000328 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500329 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000330 const TString &name = attribute->second->getSymbol();
331
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500332 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
333 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000334 }
335
Jamie Madill8daaba12014-06-13 10:04:33 -0400336 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400337
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200338 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
Jamie Madillf91ce812014-06-13 10:04:34 -0400339 out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
340
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200341 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500342 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200343 out << "\n// Equality functions\n\n";
344 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500345 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200346 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200347 }
348 }
Olli Etuaho12690762015-03-31 12:55:28 +0300349 if (!mArrayAssignmentFunctions.empty())
350 {
351 out << "\n// Assignment functions\n\n";
352 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
353 {
354 out << assignmentFunction.functionDefinition << "\n";
355 }
356 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300357 if (!mArrayConstructIntoFunctions.empty())
358 {
359 out << "\n// Array constructor functions\n\n";
360 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
361 {
362 out << constructIntoFunction.functionDefinition << "\n";
363 }
364 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200365
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500366 if (mUsesDiscardRewriting)
367 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400368 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500369 }
370
Nicolas Capens655fe362014-04-11 13:12:34 -0400371 if (mUsesNestedBreak)
372 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400373 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400374 }
375
Arun Patole44efa0b2015-03-04 17:11:05 +0530376 if (mRequiresIEEEStrictCompiling)
377 {
378 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
379 }
380
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400381 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
382 "#define LOOP [loop]\n"
383 "#define FLATTEN [flatten]\n"
384 "#else\n"
385 "#define LOOP\n"
386 "#define FLATTEN\n"
387 "#endif\n";
388
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200389 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000390 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200391 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500392 const bool usingMRTExtension = (iter != mExtensionBehavior.end() &&
393 (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000394
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000395 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500396 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400397 out << "\n";
398
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200399 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000400 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500401 for (ReferencedSymbols::const_iterator outputVariableIt =
402 mReferencedOutputVariables.begin();
403 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000404 {
Jamie Madill46131a32013-06-20 11:55:50 -0400405 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500406 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400407
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500408 out << "static " + TypeString(variableType) + " out_" + variableName +
409 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000410 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000411 }
Jamie Madill46131a32013-06-20 11:55:50 -0400412 else
413 {
414 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
415
416 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500417 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400418 for (unsigned int i = 0; i < numColorValues; i++)
419 {
420 out << " float4(0, 0, 0, 0)";
421 if (i + 1 != numColorValues)
422 {
423 out << ",";
424 }
425 out << "\n";
426 }
427
428 out << "};\n";
429 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000430
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400431 if (mUsesFragDepth)
432 {
433 out << "static float gl_Depth = 0.0;\n";
434 }
435
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000436 if (mUsesFragCoord)
437 {
438 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
439 }
440
441 if (mUsesPointCoord)
442 {
443 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
444 }
445
446 if (mUsesFrontFacing)
447 {
448 out << "static bool gl_FrontFacing = false;\n";
449 }
450
451 out << "\n";
452
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000453 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000454 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000455 out << "struct gl_DepthRangeParameters\n"
456 "{\n"
457 " float near;\n"
458 " float far;\n"
459 " float diff;\n"
460 "};\n"
461 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000462 }
463
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200464 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000465 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000466 out << "cbuffer DriverConstants : register(b1)\n"
467 "{\n";
468
469 if (mUsesDepthRange)
470 {
471 out << " float3 dx_DepthRange : packoffset(c0);\n";
472 }
473
474 if (mUsesFragCoord)
475 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000476 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000477 }
478
479 if (mUsesFragCoord || mUsesFrontFacing)
480 {
481 out << " float3 dx_DepthFront : packoffset(c2);\n";
482 }
483
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800484 if (mUsesFragCoord)
485 {
486 // dx_ViewScale is only used in the fragment shader to correct
487 // the value for glFragCoord if necessary
488 out << " float2 dx_ViewScale : packoffset(c3);\n";
489 }
490
Olli Etuaho618bebc2016-01-15 16:40:00 +0200491 if (mOutputType == SH_HLSL_4_1_OUTPUT)
492 {
493 mUniformHLSL->samplerMetadataUniforms(out, "c4");
494 }
495
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000496 out << "};\n";
497 }
498 else
499 {
500 if (mUsesDepthRange)
501 {
502 out << "uniform float3 dx_DepthRange : register(c0);";
503 }
504
505 if (mUsesFragCoord)
506 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000507 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000508 }
509
510 if (mUsesFragCoord || mUsesFrontFacing)
511 {
512 out << "uniform float3 dx_DepthFront : register(c2);\n";
513 }
514 }
515
516 out << "\n";
517
518 if (mUsesDepthRange)
519 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500520 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
521 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000522 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000523 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000524
Jamie Madillf91ce812014-06-13 10:04:34 -0400525 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000526 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400527 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000528 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400529 out << flaggedStructs;
530 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000531 }
532
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000533 if (usingMRTExtension && mNumRenderTargets > 1)
534 {
535 out << "#define GL_USES_MRT\n";
536 }
537
538 if (mUsesFragColor)
539 {
540 out << "#define GL_USES_FRAG_COLOR\n";
541 }
542
543 if (mUsesFragData)
544 {
545 out << "#define GL_USES_FRAG_DATA\n";
546 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000547 }
Xinghua Caob1239382016-12-13 15:07:05 +0800548 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000550 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500551 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000552 out << "\n"
553 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400554
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000555 if (mUsesPointSize)
556 {
557 out << "static float gl_PointSize = float(1);\n";
558 }
559
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000560 if (mUsesInstanceID)
561 {
562 out << "static int gl_InstanceID;";
563 }
564
Corentin Wallezb076add2016-01-11 16:45:46 -0500565 if (mUsesVertexID)
566 {
567 out << "static int gl_VertexID;";
568 }
569
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000570 out << "\n"
571 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500572 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000573 out << "\n";
574
575 if (mUsesDepthRange)
576 {
577 out << "struct gl_DepthRangeParameters\n"
578 "{\n"
579 " float near;\n"
580 " float far;\n"
581 " float diff;\n"
582 "};\n"
583 "\n";
584 }
585
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200586 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000587 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800588 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500589 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800590
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000591 if (mUsesDepthRange)
592 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800593 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000594 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800595
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800596 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
597 // shaders. However, we declare it for all shaders (including Feature Level 10+).
598 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
599 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800600 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800601 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800602 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800603
Olli Etuaho618bebc2016-01-15 16:40:00 +0200604 if (mOutputType == SH_HLSL_4_1_OUTPUT)
605 {
606 mUniformHLSL->samplerMetadataUniforms(out, "c4");
607 }
608
Austin Kinross4fd18b12014-12-22 12:32:05 -0800609 out << "};\n"
610 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000611 }
612 else
613 {
614 if (mUsesDepthRange)
615 {
616 out << "uniform float3 dx_DepthRange : register(c0);\n";
617 }
618
Cooper Partine6664f02015-01-09 16:22:24 -0800619 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
620 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000621 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000622 }
623
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000624 if (mUsesDepthRange)
625 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500626 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
627 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000628 "\n";
629 }
630
Jamie Madillf91ce812014-06-13 10:04:34 -0400631 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000632 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400633 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000634 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400635 out << flaggedStructs;
636 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000637 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400638 }
Xinghua Caob1239382016-12-13 15:07:05 +0800639 else // Compute shader
640 {
641 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800642
643 out << "cbuffer DriverConstants : register(b1)\n"
644 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800645 if (mUsesNumWorkGroups)
646 {
Xinghua Caob1239382016-12-13 15:07:05 +0800647 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800648 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800649 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
650 mUniformHLSL->samplerMetadataUniforms(out, "c1");
651 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800652
653 // Follow built-in variables would be initialized in
654 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
655 // are used in compute shader.
656 if (mUsesWorkGroupID)
657 {
658 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
659 }
660
661 if (mUsesLocalInvocationID)
662 {
663 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
664 }
665
666 if (mUsesGlobalInvocationID)
667 {
668 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
669 }
670
671 if (mUsesLocalInvocationIndex)
672 {
673 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
674 }
675 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000676
Geoff Lang1fe74c72016-08-25 13:23:01 -0400677 bool getDimensionsIgnoresBaseLevel =
678 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
679 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000681 if (mUsesFragCoord)
682 {
683 out << "#define GL_USES_FRAG_COORD\n";
684 }
685
686 if (mUsesPointCoord)
687 {
688 out << "#define GL_USES_POINT_COORD\n";
689 }
690
691 if (mUsesFrontFacing)
692 {
693 out << "#define GL_USES_FRONT_FACING\n";
694 }
695
696 if (mUsesPointSize)
697 {
698 out << "#define GL_USES_POINT_SIZE\n";
699 }
700
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400701 if (mUsesFragDepth)
702 {
703 out << "#define GL_USES_FRAG_DEPTH\n";
704 }
705
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000706 if (mUsesDepthRange)
707 {
708 out << "#define GL_USES_DEPTH_RANGE\n";
709 }
710
Xinghua Caob1239382016-12-13 15:07:05 +0800711 if (mUsesNumWorkGroups)
712 {
713 out << "#define GL_USES_NUM_WORK_GROUPS\n";
714 }
715
716 if (mUsesWorkGroupID)
717 {
718 out << "#define GL_USES_WORK_GROUP_ID\n";
719 }
720
721 if (mUsesLocalInvocationID)
722 {
723 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
724 }
725
726 if (mUsesGlobalInvocationID)
727 {
728 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
729 }
730
731 if (mUsesLocalInvocationIndex)
732 {
733 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
734 }
735
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000736 if (mUsesXor)
737 {
738 out << "bool xor(bool p, bool q)\n"
739 "{\n"
740 " return (p || q) && !(p && q);\n"
741 "}\n"
742 "\n";
743 }
744
Olli Etuahodfa75e82017-01-23 09:43:06 -0800745 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000746}
747
748void OutputHLSL::visitSymbol(TIntermSymbol *node)
749{
Jamie Madill32aab012015-01-27 14:12:26 -0500750 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751
Jamie Madill570e04d2013-06-21 09:15:33 -0400752 // Handle accessing std140 structs by value
753 if (mFlaggedStructMappedNames.count(node) > 0)
754 {
755 out << mFlaggedStructMappedNames[node];
756 return;
757 }
758
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000759 TString name = node->getSymbol();
760
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000761 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000762 {
763 mUsesDepthRange = true;
764 out << name;
765 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766 else
767 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000768 TQualifier qualifier = node->getQualifier();
769
770 if (qualifier == EvqUniform)
771 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400773 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400774
775 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000776 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400777 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000778 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000779 else
780 {
781 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000782 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400783
Jamie Madill2e295e22015-04-29 10:41:33 -0400784 ensureStructDefined(nodeType);
785
Olli Etuahoff526f12017-06-30 12:26:54 +0300786 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000787 }
Jamie Madill19571812013-08-12 15:26:34 -0700788 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000789 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000790 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400791 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000792 }
Jamie Madill033dae62014-06-18 12:56:28 -0400793 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000794 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000795 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400796 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000797 }
Jamie Madill19571812013-08-12 15:26:34 -0700798 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400799 {
800 mReferencedOutputVariables[name] = node;
801 out << "out_" << name;
802 }
803 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000804 {
805 out << "gl_Color[0]";
806 mUsesFragColor = true;
807 }
808 else if (qualifier == EvqFragData)
809 {
810 out << "gl_Color";
811 mUsesFragData = true;
812 }
813 else if (qualifier == EvqFragCoord)
814 {
815 mUsesFragCoord = true;
816 out << name;
817 }
818 else if (qualifier == EvqPointCoord)
819 {
820 mUsesPointCoord = true;
821 out << name;
822 }
823 else if (qualifier == EvqFrontFacing)
824 {
825 mUsesFrontFacing = true;
826 out << name;
827 }
828 else if (qualifier == EvqPointSize)
829 {
830 mUsesPointSize = true;
831 out << name;
832 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000833 else if (qualifier == EvqInstanceID)
834 {
835 mUsesInstanceID = true;
836 out << name;
837 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500838 else if (qualifier == EvqVertexID)
839 {
840 mUsesVertexID = true;
841 out << name;
842 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300843 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400844 {
845 mUsesFragDepth = true;
846 out << "gl_Depth";
847 }
Xinghua Caob1239382016-12-13 15:07:05 +0800848 else if (qualifier == EvqNumWorkGroups)
849 {
850 mUsesNumWorkGroups = true;
851 out << name;
852 }
853 else if (qualifier == EvqWorkGroupID)
854 {
855 mUsesWorkGroupID = true;
856 out << name;
857 }
858 else if (qualifier == EvqLocalInvocationID)
859 {
860 mUsesLocalInvocationID = true;
861 out << name;
862 }
863 else if (qualifier == EvqGlobalInvocationID)
864 {
865 mUsesGlobalInvocationID = true;
866 out << name;
867 }
868 else if (qualifier == EvqLocalInvocationIndex)
869 {
870 mUsesLocalInvocationIndex = true;
871 out << name;
872 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000873 else
874 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300875 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000876 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000877 }
878}
879
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400880void OutputHLSL::visitRaw(TIntermRaw *node)
881{
Jamie Madill32aab012015-01-27 14:12:26 -0500882 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400883}
884
Olli Etuaho7fb49552015-03-18 17:27:44 +0200885void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
886{
887 if (type.isScalar() && !type.isArray())
888 {
889 if (op == EOpEqual)
890 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500891 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200892 }
893 else
894 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500895 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200896 }
897 }
898 else
899 {
900 if (visit == PreVisit && op == EOpNotEqual)
901 {
902 out << "!";
903 }
904
905 if (type.isArray())
906 {
907 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500908 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200909 }
910 else if (type.getBasicType() == EbtStruct)
911 {
912 const TStructure &structure = *type.getStruct();
913 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500914 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200915 }
916 else
917 {
918 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500919 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200920 }
921 }
922}
923
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000924bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200925{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000926 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200927 {
928 TIntermNode *ancestor = getAncestorNode(n);
929 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
930 if (ancestorBinary == nullptr)
931 {
932 return false;
933 }
934 switch (ancestorBinary->getOp())
935 {
936 case EOpIndexDirectStruct:
937 {
938 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
939 const TIntermConstantUnion *index =
940 ancestorBinary->getRight()->getAsConstantUnion();
941 const TField *field = structure->fields()[index->getIConst(0)];
942 if (IsSampler(field->type()->getBasicType()))
943 {
944 return true;
945 }
946 break;
947 }
948 case EOpIndexDirect:
949 break;
950 default:
951 // Returning a sampler from indirect indexing is not supported.
952 return false;
953 }
954 }
955 return false;
956}
957
Olli Etuahob6fa0432016-09-28 16:28:05 +0100958bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
959{
960 TInfoSinkBase &out = getInfoSink();
961 if (visit == PostVisit)
962 {
963 out << ".";
964 node->writeOffsetsAsXYZW(&out);
965 }
966 return true;
967}
968
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
970{
Jamie Madill32aab012015-01-27 14:12:26 -0500971 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000972
Jamie Madill570e04d2013-06-21 09:15:33 -0400973 // Handle accessing std140 structs by value
974 if (mFlaggedStructMappedNames.count(node) > 0)
975 {
976 out << mFlaggedStructMappedNames[node];
977 return false;
978 }
979
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980 switch (node->getOp())
981 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100982 case EOpComma:
983 outputTriplet(out, visit, "(", ", ", ")");
984 break;
985 case EOpAssign:
986 if (node->getLeft()->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +0300987 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100988 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
989 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +0300990 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100991 const TString &functionName = addArrayConstructIntoFunction(node->getType());
992 out << functionName << "(";
993 node->getLeft()->traverse(this);
994 TIntermSequence *seq = rightAgg->getSequence();
995 for (auto &arrayElement : *seq)
996 {
997 out << ", ";
998 arrayElement->traverse(this);
999 }
1000 out << ")";
1001 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001002 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001003 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1004 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001005 ASSERT(rightAgg == nullptr);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001006
1007 const TString &functionName = addArrayAssignmentFunction(node->getType());
1008 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho9638c352015-04-01 14:34:52 +03001009 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001010 else
Jamie Madill37997142015-01-28 10:06:34 -05001011 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001012 outputTriplet(out, visit, "(", " = ", ")");
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001013 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001014 break;
1015 case EOpInitialize:
1016 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001017 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001018 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1019 ASSERT(symbolNode);
1020 TIntermTyped *expression = node->getRight();
1021
1022 // Global initializers must be constant at this point.
1023 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1024 canWriteAsHLSLLiteral(expression));
1025
1026 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1027 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1028 // new variable is created before the assignment is evaluated), so we need to
1029 // convert
1030 // this to "float t = x, x = t;".
1031 if (writeSameSymbolInitializer(out, symbolNode, expression))
1032 {
1033 // Skip initializing the rest of the expression
1034 return false;
1035 }
1036 else if (writeConstantInitialization(out, symbolNode, expression))
1037 {
1038 return false;
1039 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001040 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001041 else if (visit == InVisit)
1042 {
1043 out << " = ";
1044 }
1045 break;
1046 case EOpAddAssign:
1047 outputTriplet(out, visit, "(", " += ", ")");
1048 break;
1049 case EOpSubAssign:
1050 outputTriplet(out, visit, "(", " -= ", ")");
1051 break;
1052 case EOpMulAssign:
1053 outputTriplet(out, visit, "(", " *= ", ")");
1054 break;
1055 case EOpVectorTimesScalarAssign:
1056 outputTriplet(out, visit, "(", " *= ", ")");
1057 break;
1058 case EOpMatrixTimesScalarAssign:
1059 outputTriplet(out, visit, "(", " *= ", ")");
1060 break;
1061 case EOpVectorTimesMatrixAssign:
1062 if (visit == PreVisit)
1063 {
1064 out << "(";
1065 }
1066 else if (visit == InVisit)
1067 {
1068 out << " = mul(";
1069 node->getLeft()->traverse(this);
1070 out << ", transpose(";
1071 }
1072 else
1073 {
1074 out << ")))";
1075 }
1076 break;
1077 case EOpMatrixTimesMatrixAssign:
1078 if (visit == PreVisit)
1079 {
1080 out << "(";
1081 }
1082 else if (visit == InVisit)
1083 {
1084 out << " = transpose(mul(transpose(";
1085 node->getLeft()->traverse(this);
1086 out << "), transpose(";
1087 }
1088 else
1089 {
1090 out << "))))";
1091 }
1092 break;
1093 case EOpDivAssign:
1094 outputTriplet(out, visit, "(", " /= ", ")");
1095 break;
1096 case EOpIModAssign:
1097 outputTriplet(out, visit, "(", " %= ", ")");
1098 break;
1099 case EOpBitShiftLeftAssign:
1100 outputTriplet(out, visit, "(", " <<= ", ")");
1101 break;
1102 case EOpBitShiftRightAssign:
1103 outputTriplet(out, visit, "(", " >>= ", ")");
1104 break;
1105 case EOpBitwiseAndAssign:
1106 outputTriplet(out, visit, "(", " &= ", ")");
1107 break;
1108 case EOpBitwiseXorAssign:
1109 outputTriplet(out, visit, "(", " ^= ", ")");
1110 break;
1111 case EOpBitwiseOrAssign:
1112 outputTriplet(out, visit, "(", " |= ", ")");
1113 break;
1114 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001115 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001116 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001117 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001118 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001119 if (visit == PreVisit)
1120 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001121 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001122 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001123 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] =
1124 node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001125 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001126 return false;
1127 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001128 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001129 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001130 {
1131 // All parts of an expression that access a sampler in a struct need to use _ as
1132 // separator to access the sampler variable that has been moved out of the struct.
1133 outputTriplet(out, visit, "", "_", "");
1134 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001135 else
1136 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001137 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001138 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001139 }
1140 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001141 case EOpIndexIndirect:
1142 // We do not currently support indirect references to interface blocks
1143 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1144 outputTriplet(out, visit, "", "[", "]");
1145 break;
1146 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001147 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001148 const TStructure *structure = node->getLeft()->getType().getStruct();
1149 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1150 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001151
Olli Etuaho96963162016-03-21 11:54:33 +02001152 // In cases where indexing returns a sampler, we need to access the sampler variable
1153 // that has been moved out of the struct.
1154 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1155 if (visit == PreVisit && indexingReturnsSampler)
1156 {
1157 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1158 // This prefix is only output at the beginning of the indexing expression, which
1159 // may have multiple parts.
1160 out << "angle";
1161 }
1162 if (!indexingReturnsSampler)
1163 {
1164 // All parts of an expression that access a sampler in a struct need to use _ as
1165 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001166 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001167 }
1168 if (visit == InVisit)
1169 {
1170 if (indexingReturnsSampler)
1171 {
1172 out << "_" + field->name();
1173 }
1174 else
1175 {
1176 out << "." + DecorateField(field->name(), *structure);
1177 }
1178
1179 return false;
1180 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001181 }
1182 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001183 case EOpIndexDirectInterfaceBlock:
1184 if (visit == InVisit)
1185 {
1186 const TInterfaceBlock *interfaceBlock =
1187 node->getLeft()->getType().getInterfaceBlock();
1188 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1189 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1190 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001191
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001192 return false;
1193 }
1194 break;
1195 case EOpAdd:
1196 outputTriplet(out, visit, "(", " + ", ")");
1197 break;
1198 case EOpSub:
1199 outputTriplet(out, visit, "(", " - ", ")");
1200 break;
1201 case EOpMul:
1202 outputTriplet(out, visit, "(", " * ", ")");
1203 break;
1204 case EOpDiv:
1205 outputTriplet(out, visit, "(", " / ", ")");
1206 break;
1207 case EOpIMod:
1208 outputTriplet(out, visit, "(", " % ", ")");
1209 break;
1210 case EOpBitShiftLeft:
1211 outputTriplet(out, visit, "(", " << ", ")");
1212 break;
1213 case EOpBitShiftRight:
1214 outputTriplet(out, visit, "(", " >> ", ")");
1215 break;
1216 case EOpBitwiseAnd:
1217 outputTriplet(out, visit, "(", " & ", ")");
1218 break;
1219 case EOpBitwiseXor:
1220 outputTriplet(out, visit, "(", " ^ ", ")");
1221 break;
1222 case EOpBitwiseOr:
1223 outputTriplet(out, visit, "(", " | ", ")");
1224 break;
1225 case EOpEqual:
1226 case EOpNotEqual:
1227 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1228 break;
1229 case EOpLessThan:
1230 outputTriplet(out, visit, "(", " < ", ")");
1231 break;
1232 case EOpGreaterThan:
1233 outputTriplet(out, visit, "(", " > ", ")");
1234 break;
1235 case EOpLessThanEqual:
1236 outputTriplet(out, visit, "(", " <= ", ")");
1237 break;
1238 case EOpGreaterThanEqual:
1239 outputTriplet(out, visit, "(", " >= ", ")");
1240 break;
1241 case EOpVectorTimesScalar:
1242 outputTriplet(out, visit, "(", " * ", ")");
1243 break;
1244 case EOpMatrixTimesScalar:
1245 outputTriplet(out, visit, "(", " * ", ")");
1246 break;
1247 case EOpVectorTimesMatrix:
1248 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1249 break;
1250 case EOpMatrixTimesVector:
1251 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1252 break;
1253 case EOpMatrixTimesMatrix:
1254 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1255 break;
1256 case EOpLogicalOr:
1257 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1258 // been unfolded.
1259 ASSERT(!node->getRight()->hasSideEffects());
1260 outputTriplet(out, visit, "(", " || ", ")");
1261 return true;
1262 case EOpLogicalXor:
1263 mUsesXor = true;
1264 outputTriplet(out, visit, "xor(", ", ", ")");
1265 break;
1266 case EOpLogicalAnd:
1267 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1268 // been unfolded.
1269 ASSERT(!node->getRight()->hasSideEffects());
1270 outputTriplet(out, visit, "(", " && ", ")");
1271 return true;
1272 default:
1273 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274 }
1275
1276 return true;
1277}
1278
1279bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1280{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001281 TInfoSinkBase &out = getInfoSink();
1282
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283 switch (node->getOp())
1284 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001285 case EOpNegative:
1286 outputTriplet(out, visit, "(-", "", ")");
1287 break;
1288 case EOpPositive:
1289 outputTriplet(out, visit, "(+", "", ")");
1290 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001291 case EOpLogicalNot:
1292 outputTriplet(out, visit, "(!", "", ")");
1293 break;
1294 case EOpBitwiseNot:
1295 outputTriplet(out, visit, "(~", "", ")");
1296 break;
1297 case EOpPostIncrement:
1298 outputTriplet(out, visit, "(", "", "++)");
1299 break;
1300 case EOpPostDecrement:
1301 outputTriplet(out, visit, "(", "", "--)");
1302 break;
1303 case EOpPreIncrement:
1304 outputTriplet(out, visit, "(++", "", ")");
1305 break;
1306 case EOpPreDecrement:
1307 outputTriplet(out, visit, "(--", "", ")");
1308 break;
1309 case EOpRadians:
1310 outputTriplet(out, visit, "radians(", "", ")");
1311 break;
1312 case EOpDegrees:
1313 outputTriplet(out, visit, "degrees(", "", ")");
1314 break;
1315 case EOpSin:
1316 outputTriplet(out, visit, "sin(", "", ")");
1317 break;
1318 case EOpCos:
1319 outputTriplet(out, visit, "cos(", "", ")");
1320 break;
1321 case EOpTan:
1322 outputTriplet(out, visit, "tan(", "", ")");
1323 break;
1324 case EOpAsin:
1325 outputTriplet(out, visit, "asin(", "", ")");
1326 break;
1327 case EOpAcos:
1328 outputTriplet(out, visit, "acos(", "", ")");
1329 break;
1330 case EOpAtan:
1331 outputTriplet(out, visit, "atan(", "", ")");
1332 break;
1333 case EOpSinh:
1334 outputTriplet(out, visit, "sinh(", "", ")");
1335 break;
1336 case EOpCosh:
1337 outputTriplet(out, visit, "cosh(", "", ")");
1338 break;
1339 case EOpTanh:
1340 outputTriplet(out, visit, "tanh(", "", ")");
1341 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001342 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001343 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001344 case EOpAtanh:
1345 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001346 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001347 break;
1348 case EOpExp:
1349 outputTriplet(out, visit, "exp(", "", ")");
1350 break;
1351 case EOpLog:
1352 outputTriplet(out, visit, "log(", "", ")");
1353 break;
1354 case EOpExp2:
1355 outputTriplet(out, visit, "exp2(", "", ")");
1356 break;
1357 case EOpLog2:
1358 outputTriplet(out, visit, "log2(", "", ")");
1359 break;
1360 case EOpSqrt:
1361 outputTriplet(out, visit, "sqrt(", "", ")");
1362 break;
1363 case EOpInverseSqrt:
1364 outputTriplet(out, visit, "rsqrt(", "", ")");
1365 break;
1366 case EOpAbs:
1367 outputTriplet(out, visit, "abs(", "", ")");
1368 break;
1369 case EOpSign:
1370 outputTriplet(out, visit, "sign(", "", ")");
1371 break;
1372 case EOpFloor:
1373 outputTriplet(out, visit, "floor(", "", ")");
1374 break;
1375 case EOpTrunc:
1376 outputTriplet(out, visit, "trunc(", "", ")");
1377 break;
1378 case EOpRound:
1379 outputTriplet(out, visit, "round(", "", ")");
1380 break;
1381 case EOpRoundEven:
1382 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001383 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001384 break;
1385 case EOpCeil:
1386 outputTriplet(out, visit, "ceil(", "", ")");
1387 break;
1388 case EOpFract:
1389 outputTriplet(out, visit, "frac(", "", ")");
1390 break;
1391 case EOpIsNan:
1392 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001393 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001394 else
1395 outputTriplet(out, visit, "isnan(", "", ")");
1396 mRequiresIEEEStrictCompiling = true;
1397 break;
1398 case EOpIsInf:
1399 outputTriplet(out, visit, "isinf(", "", ")");
1400 break;
1401 case EOpFloatBitsToInt:
1402 outputTriplet(out, visit, "asint(", "", ")");
1403 break;
1404 case EOpFloatBitsToUint:
1405 outputTriplet(out, visit, "asuint(", "", ")");
1406 break;
1407 case EOpIntBitsToFloat:
1408 outputTriplet(out, visit, "asfloat(", "", ")");
1409 break;
1410 case EOpUintBitsToFloat:
1411 outputTriplet(out, visit, "asfloat(", "", ")");
1412 break;
1413 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001414 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001415 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001417 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001418 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001419 case EOpPackUnorm4x8:
1420 case EOpPackSnorm4x8:
1421 case EOpUnpackUnorm4x8:
1422 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001423 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001424 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001425 break;
1426 case EOpLength:
1427 outputTriplet(out, visit, "length(", "", ")");
1428 break;
1429 case EOpNormalize:
1430 outputTriplet(out, visit, "normalize(", "", ")");
1431 break;
1432 case EOpDFdx:
1433 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1434 {
1435 outputTriplet(out, visit, "(", "", ", 0.0)");
1436 }
1437 else
1438 {
1439 outputTriplet(out, visit, "ddx(", "", ")");
1440 }
1441 break;
1442 case EOpDFdy:
1443 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1444 {
1445 outputTriplet(out, visit, "(", "", ", 0.0)");
1446 }
1447 else
1448 {
1449 outputTriplet(out, visit, "ddy(", "", ")");
1450 }
1451 break;
1452 case EOpFwidth:
1453 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1454 {
1455 outputTriplet(out, visit, "(", "", ", 0.0)");
1456 }
1457 else
1458 {
1459 outputTriplet(out, visit, "fwidth(", "", ")");
1460 }
1461 break;
1462 case EOpTranspose:
1463 outputTriplet(out, visit, "transpose(", "", ")");
1464 break;
1465 case EOpDeterminant:
1466 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1467 break;
1468 case EOpInverse:
1469 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001470 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001472
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001473 case EOpAny:
1474 outputTriplet(out, visit, "any(", "", ")");
1475 break;
1476 case EOpAll:
1477 outputTriplet(out, visit, "all(", "", ")");
1478 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001479 case EOpLogicalNotComponentWise:
1480 outputTriplet(out, visit, "(!", "", ")");
1481 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001482 case EOpBitfieldReverse:
1483 outputTriplet(out, visit, "reversebits(", "", ")");
1484 break;
1485 case EOpBitCount:
1486 outputTriplet(out, visit, "countbits(", "", ")");
1487 break;
1488 case EOpFindLSB:
1489 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1490 // in GLSLTest and results are consistent with GL.
1491 outputTriplet(out, visit, "firstbitlow(", "", ")");
1492 break;
1493 case EOpFindMSB:
1494 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1495 // tested in GLSLTest and results are consistent with GL.
1496 outputTriplet(out, visit, "firstbithigh(", "", ")");
1497 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001498 default:
1499 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001500 }
1501
1502 return true;
1503}
1504
Olli Etuaho96963162016-03-21 11:54:33 +02001505TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1506{
1507 if (node->getAsSymbolNode())
1508 {
1509 return node->getAsSymbolNode()->getSymbol();
1510 }
1511 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1512 switch (nodeBinary->getOp())
1513 {
1514 case EOpIndexDirect:
1515 {
1516 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1517
1518 TInfoSinkBase prefixSink;
1519 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1520 return TString(prefixSink.c_str());
1521 }
1522 case EOpIndexDirectStruct:
1523 {
1524 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1525 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1526 const TField *field = s->fields()[index];
1527
1528 TInfoSinkBase prefixSink;
1529 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1530 << field->name();
1531 return TString(prefixSink.c_str());
1532 }
1533 default:
1534 UNREACHABLE();
1535 return TString("");
1536 }
1537}
1538
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001539bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1540{
1541 TInfoSinkBase &out = getInfoSink();
1542
1543 if (mInsideFunction)
1544 {
1545 outputLineDirective(out, node->getLine().first_line);
1546 out << "{\n";
1547 }
1548
1549 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1550 sit != node->getSequence()->end(); sit++)
1551 {
1552 outputLineDirective(out, (*sit)->getLine().first_line);
1553
1554 (*sit)->traverse(this);
1555
1556 // Don't output ; after case labels, they're terminated by :
1557 // This is needed especially since outputting a ; after a case statement would turn empty
1558 // case statements into non-empty case statements, disallowing fall-through from them.
1559 // Also no need to output ; after if statements or sequences. This is done just for
1560 // code clarity.
1561 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1562 (*sit)->getAsBlock() == nullptr)
1563 out << ";\n";
1564 }
1565
1566 if (mInsideFunction)
1567 {
1568 outputLineDirective(out, node->getLine().last_line);
1569 out << "}\n";
1570 }
1571
1572 return false;
1573}
1574
Olli Etuaho336b1472016-10-05 16:37:55 +01001575bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1576{
1577 TInfoSinkBase &out = getInfoSink();
1578
1579 ASSERT(mCurrentFunctionMetadata == nullptr);
1580
1581 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1582 ASSERT(index != CallDAG::InvalidIndex);
1583 mCurrentFunctionMetadata = &mASTMetadataList[index];
1584
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001585 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001586
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001587 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001588
1589 if (node->getFunctionSymbolInfo()->isMain())
1590 {
1591 out << "gl_main(";
1592 }
1593 else
1594 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001595 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001596 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1597 }
1598
1599 for (unsigned int i = 0; i < parameters->size(); i++)
1600 {
1601 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1602
1603 if (symbol)
1604 {
1605 ensureStructDefined(symbol->getType());
1606
1607 out << argumentString(symbol);
1608
1609 if (i < parameters->size() - 1)
1610 {
1611 out << ", ";
1612 }
1613 }
1614 else
1615 UNREACHABLE();
1616 }
1617
1618 out << ")\n";
1619
1620 mInsideFunction = true;
1621 // The function body node will output braces.
1622 node->getBody()->traverse(this);
1623 mInsideFunction = false;
1624
1625 mCurrentFunctionMetadata = nullptr;
1626
1627 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1628 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1629 {
1630 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1631 mOutputLod0Function = true;
1632 node->traverse(this);
1633 mOutputLod0Function = false;
1634 }
1635
1636 return false;
1637}
1638
Olli Etuaho13389b62016-10-16 11:48:18 +01001639bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1640{
1641 TInfoSinkBase &out = getInfoSink();
1642 if (visit == PreVisit)
1643 {
1644 TIntermSequence *sequence = node->getSequence();
1645 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1646 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001647 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001648
Olli Etuaho282847e2017-07-12 14:11:01 +03001649 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001650 variable->getQualifier() == EvqConst))
1651 {
1652 ensureStructDefined(variable->getType());
1653
1654 if (!variable->getAsSymbolNode() ||
1655 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1656 {
1657 if (!mInsideFunction)
1658 {
1659 out << "static ";
1660 }
1661
1662 out << TypeString(variable->getType()) + " ";
1663
1664 TIntermSymbol *symbol = variable->getAsSymbolNode();
1665
1666 if (symbol)
1667 {
1668 symbol->traverse(this);
1669 out << ArrayString(symbol->getType());
1670 out << " = " + initializer(symbol->getType());
1671 }
1672 else
1673 {
1674 variable->traverse(this);
1675 }
1676 }
1677 else if (variable->getAsSymbolNode() &&
1678 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1679 {
1680 // Already added to constructor map
1681 }
1682 else
1683 UNREACHABLE();
1684 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001685 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001686 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001687 TIntermSymbol *symbol = variable->getAsSymbolNode();
1688 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001689
Olli Etuaho282847e2017-07-12 14:11:01 +03001690 // Vertex outputs which are declared but not written to should still be declared to
1691 // allow successful linking.
1692 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001693 }
1694 }
1695 return false;
1696}
1697
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001698bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1699{
1700 // Do not do any translation
1701 return false;
1702}
1703
Olli Etuaho16c745a2017-01-16 17:02:27 +00001704bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1705{
1706 TInfoSinkBase &out = getInfoSink();
1707
1708 ASSERT(visit == PreVisit);
1709 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1710 // Skip the prototype if it is not implemented (and thus not used)
1711 if (index == CallDAG::InvalidIndex)
1712 {
1713 return false;
1714 }
1715
1716 TIntermSequence *arguments = node->getSequence();
1717
Olli Etuahoff526f12017-06-30 12:26:54 +03001718 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001719 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1720 << (mOutputLod0Function ? "Lod0(" : "(");
1721
1722 for (unsigned int i = 0; i < arguments->size(); i++)
1723 {
1724 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1725 ASSERT(symbol != nullptr);
1726
1727 out << argumentString(symbol);
1728
1729 if (i < arguments->size() - 1)
1730 {
1731 out << ", ";
1732 }
1733 }
1734
1735 out << ");\n";
1736
1737 // Also prototype the Lod0 variant if needed
1738 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1739 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1740 {
1741 mOutputLod0Function = true;
1742 node->traverse(this);
1743 mOutputLod0Function = false;
1744 }
1745
1746 return false;
1747}
1748
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1750{
Jamie Madill32aab012015-01-27 14:12:26 -05001751 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001753 switch (node->getOp())
1754 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001755 case EOpCallBuiltInFunction:
1756 case EOpCallFunctionInAST:
1757 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001759 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001760
Corentin Wallez1239ee92015-03-19 14:38:02 -07001761 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001762 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001763 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001764 if (node->isArray())
1765 {
1766 UNIMPLEMENTED();
1767 }
Olli Etuahobd674552016-10-06 13:28:42 +01001768 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001769 ASSERT(index != CallDAG::InvalidIndex);
1770 lod0 &= mASTMetadataList[index].mNeedsLod0;
1771
Olli Etuahoff526f12017-06-30 12:26:54 +03001772 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001773 out << DisambiguateFunctionName(node->getSequence());
1774 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001776 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001777 {
1778 // This path is used for internal functions that don't have their definitions in the
1779 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001780 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001781 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001782 else
1783 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001784 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001785 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001786 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1787 if (arguments->size() > 1)
1788 {
1789 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1790 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001791 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1792 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1793 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001794 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001795
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001796 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001797 {
Olli Etuaho96963162016-03-21 11:54:33 +02001798 TIntermTyped *typedArg = (*arg)->getAsTyped();
1799 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001800 {
1801 out << "texture_";
1802 (*arg)->traverse(this);
1803 out << ", sampler_";
1804 }
1805
1806 (*arg)->traverse(this);
1807
Olli Etuaho96963162016-03-21 11:54:33 +02001808 if (typedArg->getType().isStructureContainingSamplers())
1809 {
1810 const TType &argType = typedArg->getType();
1811 TVector<TIntermSymbol *> samplerSymbols;
1812 TString structName = samplerNamePrefixFromStruct(typedArg);
1813 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho856c4972016-08-08 11:38:39 +03001814 argType.isArray() ? argType.getArraySize() : 0u,
Olli Etuaho96963162016-03-21 11:54:33 +02001815 &samplerSymbols, nullptr);
1816 for (const TIntermSymbol *sampler : samplerSymbols)
1817 {
1818 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1819 {
1820 out << ", texture_" << sampler->getSymbol();
1821 out << ", sampler_" << sampler->getSymbol();
1822 }
1823 else
1824 {
1825 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1826 // of D3D9, it's the sampler variable.
1827 out << ", " + sampler->getSymbol();
1828 }
1829 }
1830 }
1831
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001832 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001833 {
1834 out << ", ";
1835 }
1836 }
1837
1838 out << ")";
1839
1840 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001841 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001842 case EOpConstruct:
1843 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001844 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001845 if (node->getType().isArray())
1846 {
1847 UNIMPLEMENTED();
1848 }
1849 const TString &structName = StructNameString(*node->getType().getStruct());
1850 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1851 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001852 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001853 else
1854 {
1855 const char *name = "";
1856 if (node->getType().getNominalSize() == 1)
1857 {
1858 switch (node->getBasicType())
1859 {
1860 case EbtFloat:
1861 name = "vec1";
1862 break;
1863 case EbtInt:
1864 name = "ivec1";
1865 break;
1866 case EbtUInt:
1867 name = "uvec1";
1868 break;
1869 case EbtBool:
1870 name = "bvec1";
1871 break;
1872 default:
1873 UNREACHABLE();
1874 }
1875 }
1876 else
1877 {
1878 name = node->getType().getBuiltInTypeNameString();
1879 }
1880 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1881 }
1882 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001883 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001884 outputTriplet(out, visit, "(", " == ", ")");
1885 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001886 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001887 outputTriplet(out, visit, "(", " != ", ")");
1888 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001889 case EOpLessThanComponentWise:
1890 outputTriplet(out, visit, "(", " < ", ")");
1891 break;
1892 case EOpGreaterThanComponentWise:
1893 outputTriplet(out, visit, "(", " > ", ")");
1894 break;
1895 case EOpLessThanEqualComponentWise:
1896 outputTriplet(out, visit, "(", " <= ", ")");
1897 break;
1898 case EOpGreaterThanEqualComponentWise:
1899 outputTriplet(out, visit, "(", " >= ", ")");
1900 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001901 case EOpMod:
1902 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001903 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001904 break;
1905 case EOpModf:
1906 outputTriplet(out, visit, "modf(", ", ", ")");
1907 break;
1908 case EOpPow:
1909 outputTriplet(out, visit, "pow(", ", ", ")");
1910 break;
1911 case EOpAtan:
1912 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1913 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001914 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001915 break;
1916 case EOpMin:
1917 outputTriplet(out, visit, "min(", ", ", ")");
1918 break;
1919 case EOpMax:
1920 outputTriplet(out, visit, "max(", ", ", ")");
1921 break;
1922 case EOpClamp:
1923 outputTriplet(out, visit, "clamp(", ", ", ")");
1924 break;
1925 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301926 {
1927 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1928 if (lastParamNode->getType().getBasicType() == EbtBool)
1929 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001930 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1931 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301932 // so use emulated version.
1933 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001934 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301935 }
1936 else
1937 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001938 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301939 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001940 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301941 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001942 case EOpStep:
1943 outputTriplet(out, visit, "step(", ", ", ")");
1944 break;
1945 case EOpSmoothStep:
1946 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1947 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001948 case EOpFrexp:
1949 case EOpLdexp:
1950 ASSERT(node->getUseEmulatedFunction());
1951 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1952 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001953 case EOpDistance:
1954 outputTriplet(out, visit, "distance(", ", ", ")");
1955 break;
1956 case EOpDot:
1957 outputTriplet(out, visit, "dot(", ", ", ")");
1958 break;
1959 case EOpCross:
1960 outputTriplet(out, visit, "cross(", ", ", ")");
1961 break;
Jamie Madille72595b2017-06-06 15:12:26 -04001962 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01001963 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001964 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001965 break;
1966 case EOpReflect:
1967 outputTriplet(out, visit, "reflect(", ", ", ")");
1968 break;
1969 case EOpRefract:
1970 outputTriplet(out, visit, "refract(", ", ", ")");
1971 break;
1972 case EOpOuterProduct:
1973 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001974 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001975 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001976 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01001977 outputTriplet(out, visit, "(", " * ", ")");
1978 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001979 case EOpBitfieldExtract:
1980 case EOpBitfieldInsert:
1981 case EOpUaddCarry:
1982 case EOpUsubBorrow:
1983 case EOpUmulExtended:
1984 case EOpImulExtended:
1985 ASSERT(node->getUseEmulatedFunction());
1986 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1987 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001988 default:
1989 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001990 }
1991
1992 return true;
1993}
1994
Olli Etuaho57961272016-09-14 13:57:46 +03001995void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001996{
Olli Etuahoa6f22092015-05-08 18:31:10 +03001997 out << "if (";
1998
1999 node->getCondition()->traverse(this);
2000
2001 out << ")\n";
2002
Jamie Madill8c46ab12015-12-07 16:39:19 -05002003 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002004
2005 bool discard = false;
2006
2007 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002008 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002009 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002010 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002011
Olli Etuahoa6f22092015-05-08 18:31:10 +03002012 // Detect true discard
2013 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2014 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002015 else
2016 {
2017 // TODO(oetuaho): Check if the semicolon inside is necessary.
2018 // It's there as a result of conservative refactoring of the output.
2019 out << "{;}\n";
2020 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002021
Jamie Madill8c46ab12015-12-07 16:39:19 -05002022 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002023
Olli Etuahoa6f22092015-05-08 18:31:10 +03002024 if (node->getFalseBlock())
2025 {
2026 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002027
Jamie Madill8c46ab12015-12-07 16:39:19 -05002028 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002029
Olli Etuaho32db19b2016-10-04 14:43:16 +01002030 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002031 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002032
Jamie Madill8c46ab12015-12-07 16:39:19 -05002033 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002034
Olli Etuahoa6f22092015-05-08 18:31:10 +03002035 // Detect false discard
2036 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2037 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002038
Olli Etuahoa6f22092015-05-08 18:31:10 +03002039 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002040 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002041 {
2042 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002043 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002044}
2045
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002046bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2047{
2048 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2049 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2050 UNREACHABLE();
2051 return false;
2052}
2053
Olli Etuaho57961272016-09-14 13:57:46 +03002054bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002055{
2056 TInfoSinkBase &out = getInfoSink();
2057
Olli Etuaho3d932d82016-04-12 11:10:30 +03002058 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002059
2060 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002061 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002062 {
2063 out << "FLATTEN ";
2064 }
2065
Olli Etuaho57961272016-09-14 13:57:46 +03002066 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002067
2068 return false;
2069}
2070
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002071bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002072{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002073 TInfoSinkBase &out = getInfoSink();
2074
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002075 if (node->getStatementList())
2076 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002077 node->setStatementList(
2078 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002079 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002080 // The curly braces get written when visiting the statementList aggregate
2081 }
2082 else
2083 {
2084 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002085 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002086 }
2087 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002088}
2089
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002090bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002091{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002092 TInfoSinkBase &out = getInfoSink();
2093
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002094 if (node->hasCondition())
2095 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002096 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002097 return true;
2098 }
2099 else
2100 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002101 out << "default:\n";
2102 return false;
2103 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002104}
2105
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002106void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2107{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002108 TInfoSinkBase &out = getInfoSink();
2109 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002110}
2111
2112bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2113{
Nicolas Capens655fe362014-04-11 13:12:34 -04002114 mNestedLoopDepth++;
2115
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002116 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002117 mInsideDiscontinuousLoop =
2118 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002119
Jamie Madill8c46ab12015-12-07 16:39:19 -05002120 TInfoSinkBase &out = getInfoSink();
2121
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002122 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002123 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002124 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002125 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002126 mInsideDiscontinuousLoop = wasDiscontinuous;
2127 mNestedLoopDepth--;
2128
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002129 return false;
2130 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002131 }
2132
Corentin Wallez1239ee92015-03-19 14:38:02 -07002133 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002134 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002135 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002136 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002137
Jamie Madill8c46ab12015-12-07 16:39:19 -05002138 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139 }
2140 else
2141 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002142 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002143
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002144 if (node->getInit())
2145 {
2146 node->getInit()->traverse(this);
2147 }
2148
2149 out << "; ";
2150
alokp@chromium.org52813552010-11-16 18:36:09 +00002151 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002153 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154 }
2155
2156 out << "; ";
2157
alokp@chromium.org52813552010-11-16 18:36:09 +00002158 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002159 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002160 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002161 }
2162
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002163 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002164
Jamie Madill8c46ab12015-12-07 16:39:19 -05002165 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002166 }
2167
2168 if (node->getBody())
2169 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002170 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002171 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002173 else
2174 {
2175 // TODO(oetuaho): Check if the semicolon inside is necessary.
2176 // It's there as a result of conservative refactoring of the output.
2177 out << "{;}\n";
2178 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002179
Jamie Madill8c46ab12015-12-07 16:39:19 -05002180 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002181
alokp@chromium.org52813552010-11-16 18:36:09 +00002182 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002184 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002185 out << "while(\n";
2186
alokp@chromium.org52813552010-11-16 18:36:09 +00002187 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188
daniel@transgaming.com73536982012-03-21 20:45:49 +00002189 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002190 }
2191
daniel@transgaming.com73536982012-03-21 20:45:49 +00002192 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002193
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002194 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002195 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002196
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002197 return false;
2198}
2199
2200bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2201{
Jamie Madill32aab012015-01-27 14:12:26 -05002202 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002203
2204 switch (node->getFlowOp())
2205 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002206 case EOpKill:
2207 outputTriplet(out, visit, "discard;\n", "", "");
2208 break;
2209 case EOpBreak:
2210 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002211 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002212 if (mNestedLoopDepth > 1)
2213 {
2214 mUsesNestedBreak = true;
2215 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002216
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002217 if (mExcessiveLoopIndex)
2218 {
2219 out << "{Break";
2220 mExcessiveLoopIndex->traverse(this);
2221 out << " = true; break;}\n";
2222 }
2223 else
2224 {
2225 out << "break;\n";
2226 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002227 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002228 break;
2229 case EOpContinue:
2230 outputTriplet(out, visit, "continue;\n", "", "");
2231 break;
2232 case EOpReturn:
2233 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002234 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002235 if (node->getExpression())
2236 {
2237 out << "return ";
2238 }
2239 else
2240 {
2241 out << "return;\n";
2242 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002243 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002244 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002245 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002246 if (node->getExpression())
2247 {
2248 out << ";\n";
2249 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002250 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002251 break;
2252 default:
2253 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
2255
2256 return true;
2257}
2258
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002259// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002260// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2261// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002262bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002263{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002264 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002265
2266 // Parse loops of the form:
2267 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002268 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002269 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002270 int initial = 0;
2271 int limit = 0;
2272 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002273
2274 // Parse index name and intial value
2275 if (node->getInit())
2276 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002277 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002278
2279 if (init)
2280 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002281 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002282 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002283
2284 if (variable && variable->getQualifier() == EvqTemporary)
2285 {
2286 TIntermBinary *assign = variable->getAsBinaryNode();
2287
2288 if (assign->getOp() == EOpInitialize)
2289 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002290 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002291 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2292
2293 if (symbol && constant)
2294 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002295 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002296 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002297 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002298 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002299 }
2300 }
2301 }
2302 }
2303 }
2304 }
2305
2306 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002307 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002308 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002309 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002310
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002311 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2312 {
2313 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2314
2315 if (constant)
2316 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002317 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002318 {
2319 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002320 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002321 }
2322 }
2323 }
2324 }
2325
2326 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002327 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002328 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002329 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002330 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002331
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002332 if (binaryTerminal)
2333 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002334 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002335 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2336
2337 if (constant)
2338 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002339 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002340 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002341 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002342
2343 switch (op)
2344 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002345 case EOpAddAssign:
2346 increment = value;
2347 break;
2348 case EOpSubAssign:
2349 increment = -value;
2350 break;
2351 default:
2352 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002353 }
2354 }
2355 }
2356 }
2357 else if (unaryTerminal)
2358 {
2359 TOperator op = unaryTerminal->getOp();
2360
2361 switch (op)
2362 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002363 case EOpPostIncrement:
2364 increment = 1;
2365 break;
2366 case EOpPostDecrement:
2367 increment = -1;
2368 break;
2369 case EOpPreIncrement:
2370 increment = 1;
2371 break;
2372 case EOpPreDecrement:
2373 increment = -1;
2374 break;
2375 default:
2376 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002377 }
2378 }
2379 }
2380
Yunchao He4f285442017-04-21 12:15:49 +08002381 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002382 {
2383 if (comparator == EOpLessThanEqual)
2384 {
2385 comparator = EOpLessThan;
2386 limit += 1;
2387 }
2388
2389 if (comparator == EOpLessThan)
2390 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002391 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002392
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002393 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002394 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002395 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002396 }
2397
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002398 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002399 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002400
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002401 out << "{int ";
2402 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002403 out << ";\n"
2404 "bool Break";
2405 index->traverse(this);
2406 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002407
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002408 bool firstLoopFragment = true;
2409
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002410 while (iterations > 0)
2411 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002412 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002413
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002414 if (!firstLoopFragment)
2415 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002416 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002417 index->traverse(this);
2418 out << ") {\n";
2419 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002420
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002421 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002422 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002423 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002424 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002425
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002426 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002427 const char *unroll =
2428 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002429
Corentin Wallez1239ee92015-03-19 14:38:02 -07002430 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002431 index->traverse(this);
2432 out << " = ";
2433 out << initial;
2434
2435 out << "; ";
2436 index->traverse(this);
2437 out << " < ";
2438 out << clampedLimit;
2439
2440 out << "; ";
2441 index->traverse(this);
2442 out << " += ";
2443 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002444 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002445
Jamie Madill8c46ab12015-12-07 16:39:19 -05002446 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002447 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002448
2449 if (node->getBody())
2450 {
2451 node->getBody()->traverse(this);
2452 }
2453
Jamie Madill8c46ab12015-12-07 16:39:19 -05002454 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002455 out << ";}\n";
2456
2457 if (!firstLoopFragment)
2458 {
2459 out << "}\n";
2460 }
2461
2462 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002463
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002464 initial += MAX_LOOP_ITERATIONS * increment;
2465 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002466 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002467
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002468 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002469
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002470 mExcessiveLoopIndex = restoreIndex;
2471
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002472 return true;
2473 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002474 else
2475 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002476 }
2477
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002478 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479}
2480
Jamie Madill8c46ab12015-12-07 16:39:19 -05002481void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2482 Visit visit,
2483 const char *preString,
2484 const char *inString,
2485 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002486{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002487 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002488 {
2489 out << preString;
2490 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002491 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002492 {
2493 out << inString;
2494 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002495 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002496 {
2497 out << postString;
2498 }
2499}
2500
Jamie Madill8c46ab12015-12-07 16:39:19 -05002501void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002502{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002503 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002504 {
Jamie Madill32aab012015-01-27 14:12:26 -05002505 out << "\n";
2506 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002507
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002508 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002509 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002510 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002511 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002512
Jamie Madill32aab012015-01-27 14:12:26 -05002513 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002514 }
2515}
2516
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002517TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2518{
2519 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002520 const TType &type = symbol->getType();
2521 const TName &name = symbol->getName();
2522 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002523
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002524 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002525 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002526 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002527 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002528 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002529 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002530 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002531 }
2532
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002533 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002534 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002535 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2536 {
2537 // Samplers are passed as indices to the sampler array.
2538 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2539 return "const uint " + nameStr + ArrayString(type);
2540 }
2541 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2542 {
2543 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2544 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2545 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2546 ArrayString(type);
2547 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002548 }
2549
Olli Etuaho96963162016-03-21 11:54:33 +02002550 TStringStream argString;
2551 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2552 << ArrayString(type);
2553
2554 // If the structure parameter contains samplers, they need to be passed into the function as
2555 // separate parameters. HLSL doesn't natively support samplers in structs.
2556 if (type.isStructureContainingSamplers())
2557 {
2558 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2559 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho856c4972016-08-08 11:38:39 +03002560 type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002561 for (const TIntermSymbol *sampler : samplerSymbols)
2562 {
2563 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2564 {
2565 argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
2566 }
2567 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2568 {
2569 const TType &samplerType = sampler->getType();
2570 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2571 type.getArraySize() == samplerType.getArraySize());
2572 ASSERT(IsSampler(samplerType.getBasicType()));
2573 argString << ", " << QualifierString(qualifier) << " "
2574 << TextureString(samplerType.getBasicType()) << " texture_"
2575 << sampler->getSymbol() << ArrayString(type) << ", "
2576 << QualifierString(qualifier) << " "
2577 << SamplerString(samplerType.getBasicType()) << " sampler_"
2578 << sampler->getSymbol() << ArrayString(type);
2579 }
2580 else
2581 {
2582 const TType &samplerType = sampler->getType();
2583 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2584 type.getArraySize() == samplerType.getArraySize());
2585 ASSERT(IsSampler(samplerType.getBasicType()));
2586 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
2587 << " " << sampler->getSymbol() << ArrayString(type);
2588 }
2589 }
2590 }
2591
2592 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002593}
2594
2595TString OutputHLSL::initializer(const TType &type)
2596{
2597 TString string;
2598
Jamie Madill94bf7f22013-07-08 13:31:15 -04002599 size_t size = type.getObjectSize();
2600 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002601 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002602 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002603
Jamie Madill94bf7f22013-07-08 13:31:15 -04002604 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002605 {
2606 string += ", ";
2607 }
2608 }
2609
daniel@transgaming.comead23042010-04-29 03:35:36 +00002610 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002611}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002612
Jamie Madill8c46ab12015-12-07 16:39:19 -05002613void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2614 Visit visit,
2615 const TType &type,
2616 const char *name,
2617 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002618{
Olli Etuahof40319e2015-03-10 14:33:00 +02002619 if (type.isArray())
2620 {
2621 UNIMPLEMENTED();
2622 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002623
2624 if (visit == PreVisit)
2625 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002626 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002627
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002628 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002629 }
2630 else if (visit == InVisit)
2631 {
2632 out << ", ";
2633 }
2634 else if (visit == PostVisit)
2635 {
2636 out << ")";
2637 }
2638}
2639
Jamie Madill8c46ab12015-12-07 16:39:19 -05002640const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2641 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002642 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002643{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002644 const TConstantUnion *constUnionIterated = constUnion;
2645
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002646 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002647 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002648 {
Jamie Madill033dae62014-06-18 12:56:28 -04002649 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002650
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002651 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002652
Jamie Madill98493dd2013-07-08 14:39:03 -04002653 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002654 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002655 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002656 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002657
Jamie Madill98493dd2013-07-08 14:39:03 -04002658 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002659 {
2660 out << ", ";
2661 }
2662 }
2663
2664 out << ")";
2665 }
2666 else
2667 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002668 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002669 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002670
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002671 if (writeType)
2672 {
Jamie Madill033dae62014-06-18 12:56:28 -04002673 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002674 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002675 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002676 if (writeType)
2677 {
2678 out << ")";
2679 }
2680 }
2681
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002682 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002683}
2684
Olli Etuahod68924e2017-01-02 17:34:40 +00002685void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002686{
Olli Etuahod68924e2017-01-02 17:34:40 +00002687 if (visit == PreVisit)
2688 {
2689 const char *opStr = GetOperatorString(op);
2690 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2691 out << "(";
2692 }
2693 else
2694 {
2695 outputTriplet(out, visit, nullptr, ", ", ")");
2696 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002697}
2698
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002699bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2700 TIntermSymbol *symbolNode,
2701 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002702{
2703 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2704 expression->traverse(&searchSymbol);
2705
2706 if (searchSymbol.foundMatch())
2707 {
2708 // Type already printed
2709 out << "t" + str(mUniqueIndex) + " = ";
2710 expression->traverse(this);
2711 out << ", ";
2712 symbolNode->traverse(this);
2713 out << " = t" + str(mUniqueIndex);
2714
2715 mUniqueIndex++;
2716 return true;
2717 }
2718
2719 return false;
2720}
2721
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002722bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2723{
2724 // We support writing constant unions and constructors that only take constant unions as
2725 // parameters as HLSL literals.
Olli Etuahod4f4c112016-04-15 15:11:24 +03002726 return expression->getAsConstantUnion() ||
2727 expression->isConstructorWithOnlyConstantUnionParameters();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002728}
2729
2730bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2731 TIntermSymbol *symbolNode,
2732 TIntermTyped *expression)
2733{
2734 if (canWriteAsHLSLLiteral(expression))
2735 {
2736 symbolNode->traverse(this);
2737 if (expression->getType().isArray())
2738 {
2739 out << "[" << expression->getType().getArraySize() << "]";
2740 }
2741 out << " = {";
2742 if (expression->getAsConstantUnion())
2743 {
2744 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2745 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002746 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002747 }
2748 else
2749 {
2750 TIntermAggregate *constructor = expression->getAsAggregate();
2751 ASSERT(constructor != nullptr);
2752 for (TIntermNode *&node : *constructor->getSequence())
2753 {
2754 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2755 ASSERT(nodeConst);
2756 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002757 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002758 if (node != constructor->getSequence()->back())
2759 {
2760 out << ", ";
2761 }
2762 }
2763 }
2764 out << "}";
2765 return true;
2766 }
2767 return false;
2768}
2769
Jamie Madill55e79e02015-02-09 15:35:00 -05002770TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2771{
2772 const TFieldList &fields = structure.fields();
2773
2774 for (const auto &eqFunction : mStructEqualityFunctions)
2775 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002776 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002777 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002778 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002779 }
2780 }
2781
2782 const TString &structNameString = StructNameString(structure);
2783
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002784 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002785 function->structure = &structure;
2786 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002787
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002788 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002789
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002790 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2791 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002792 << "{\n"
2793 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002794
2795 for (size_t i = 0; i < fields.size(); i++)
2796 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002797 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002798 const TType *fieldType = field->type();
2799
2800 const TString &fieldNameA = "a." + Decorate(field->name());
2801 const TString &fieldNameB = "b." + Decorate(field->name());
2802
2803 if (i > 0)
2804 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002805 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002806 }
2807
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002808 fnOut << "(";
2809 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2810 fnOut << fieldNameA;
2811 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2812 fnOut << fieldNameB;
2813 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2814 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002815 }
2816
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002817 fnOut << ";\n"
2818 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002819
2820 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002821
2822 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002823 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002824
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002825 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002826}
2827
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002828TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002829{
2830 for (const auto &eqFunction : mArrayEqualityFunctions)
2831 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002832 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002833 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002834 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002835 }
2836 }
2837
2838 const TString &typeName = TypeString(type);
2839
Olli Etuaho12690762015-03-31 12:55:28 +03002840 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002841 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002842
2843 TInfoSinkBase fnNameOut;
2844 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002845 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002846
2847 TType nonArrayType = type;
2848 nonArrayType.clearArrayness();
2849
2850 TInfoSinkBase fnOut;
2851
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002852 fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize()
2853 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002854 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002855 " for (int i = 0; i < "
2856 << type.getArraySize() << "; ++i)\n"
2857 " {\n"
2858 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002859
2860 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2861 fnOut << "a[i]";
2862 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2863 fnOut << "b[i]";
2864 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2865
2866 fnOut << ") { return false; }\n"
2867 " }\n"
2868 " return true;\n"
2869 "}\n";
2870
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002871 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002872
2873 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002874 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002875
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002876 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002877}
2878
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002879TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002880{
2881 for (const auto &assignFunction : mArrayAssignmentFunctions)
2882 {
2883 if (assignFunction.type == type)
2884 {
2885 return assignFunction.functionName;
2886 }
2887 }
2888
2889 const TString &typeName = TypeString(type);
2890
2891 ArrayHelperFunction function;
2892 function.type = type;
2893
2894 TInfoSinkBase fnNameOut;
2895 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
2896 function.functionName = fnNameOut.c_str();
2897
2898 TInfoSinkBase fnOut;
2899
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002900 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2901 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
2902 << "{\n"
2903 " for (int i = 0; i < "
2904 << type.getArraySize() << "; ++i)\n"
2905 " {\n"
2906 " a[i] = b[i];\n"
2907 " }\n"
2908 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002909
2910 function.functionDefinition = fnOut.c_str();
2911
2912 mArrayAssignmentFunctions.push_back(function);
2913
2914 return function.functionName;
2915}
2916
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002917TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002918{
2919 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2920 {
2921 if (constructIntoFunction.type == type)
2922 {
2923 return constructIntoFunction.functionName;
2924 }
2925 }
2926
2927 const TString &typeName = TypeString(type);
2928
2929 ArrayHelperFunction function;
2930 function.type = type;
2931
2932 TInfoSinkBase fnNameOut;
2933 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2934 function.functionName = fnNameOut.c_str();
2935
2936 TInfoSinkBase fnOut;
2937
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002938 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2939 << "]";
Olli Etuaho856c4972016-08-08 11:38:39 +03002940 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002941 {
2942 fnOut << ", " << typeName << " b" << i;
2943 }
2944 fnOut << ")\n"
2945 "{\n";
2946
Olli Etuaho856c4972016-08-08 11:38:39 +03002947 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002948 {
2949 fnOut << " a[" << i << "] = b" << i << ";\n";
2950 }
2951 fnOut << "}\n";
2952
2953 function.functionDefinition = fnOut.c_str();
2954
2955 mArrayConstructIntoFunctions.push_back(function);
2956
2957 return function.functionName;
2958}
2959
Jamie Madill2e295e22015-04-29 10:41:33 -04002960void OutputHLSL::ensureStructDefined(const TType &type)
2961{
2962 TStructure *structure = type.getStruct();
2963
2964 if (structure)
2965 {
2966 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
2967 }
2968}
2969
Jamie Madill45bcc782016-11-07 13:58:48 -05002970} // namespace sh