blob: 897b26b8fd9433fcd7ea11a24f3372b7cce943b7 [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 Etuaho96963162016-03-21 11:54:33 +0200786 const TName &nameWithMetadata = node->getName();
787 out << DecorateUniform(nameWithMetadata, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000788 }
Jamie Madill19571812013-08-12 15:26:34 -0700789 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000790 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000791 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400792 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000793 }
Jamie Madill033dae62014-06-18 12:56:28 -0400794 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000795 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000796 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400797 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000798 }
Jamie Madill19571812013-08-12 15:26:34 -0700799 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400800 {
801 mReferencedOutputVariables[name] = node;
802 out << "out_" << name;
803 }
804 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000805 {
806 out << "gl_Color[0]";
807 mUsesFragColor = true;
808 }
809 else if (qualifier == EvqFragData)
810 {
811 out << "gl_Color";
812 mUsesFragData = true;
813 }
814 else if (qualifier == EvqFragCoord)
815 {
816 mUsesFragCoord = true;
817 out << name;
818 }
819 else if (qualifier == EvqPointCoord)
820 {
821 mUsesPointCoord = true;
822 out << name;
823 }
824 else if (qualifier == EvqFrontFacing)
825 {
826 mUsesFrontFacing = true;
827 out << name;
828 }
829 else if (qualifier == EvqPointSize)
830 {
831 mUsesPointSize = true;
832 out << name;
833 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000834 else if (qualifier == EvqInstanceID)
835 {
836 mUsesInstanceID = true;
837 out << name;
838 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500839 else if (qualifier == EvqVertexID)
840 {
841 mUsesVertexID = true;
842 out << name;
843 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300844 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400845 {
846 mUsesFragDepth = true;
847 out << "gl_Depth";
848 }
Xinghua Caob1239382016-12-13 15:07:05 +0800849 else if (qualifier == EvqNumWorkGroups)
850 {
851 mUsesNumWorkGroups = true;
852 out << name;
853 }
854 else if (qualifier == EvqWorkGroupID)
855 {
856 mUsesWorkGroupID = true;
857 out << name;
858 }
859 else if (qualifier == EvqLocalInvocationID)
860 {
861 mUsesLocalInvocationID = true;
862 out << name;
863 }
864 else if (qualifier == EvqGlobalInvocationID)
865 {
866 mUsesGlobalInvocationID = true;
867 out << name;
868 }
869 else if (qualifier == EvqLocalInvocationIndex)
870 {
871 mUsesLocalInvocationIndex = true;
872 out << name;
873 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000874 else
875 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +0300876 out << DecorateIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000877 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000878 }
879}
880
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400881void OutputHLSL::visitRaw(TIntermRaw *node)
882{
Jamie Madill32aab012015-01-27 14:12:26 -0500883 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400884}
885
Olli Etuaho7fb49552015-03-18 17:27:44 +0200886void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
887{
888 if (type.isScalar() && !type.isArray())
889 {
890 if (op == EOpEqual)
891 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500892 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200893 }
894 else
895 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500896 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200897 }
898 }
899 else
900 {
901 if (visit == PreVisit && op == EOpNotEqual)
902 {
903 out << "!";
904 }
905
906 if (type.isArray())
907 {
908 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500909 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200910 }
911 else if (type.getBasicType() == EbtStruct)
912 {
913 const TStructure &structure = *type.getStruct();
914 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500915 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200916 }
917 else
918 {
919 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500920 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200921 }
922 }
923}
924
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000925bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200926{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000927 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200928 {
929 TIntermNode *ancestor = getAncestorNode(n);
930 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
931 if (ancestorBinary == nullptr)
932 {
933 return false;
934 }
935 switch (ancestorBinary->getOp())
936 {
937 case EOpIndexDirectStruct:
938 {
939 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
940 const TIntermConstantUnion *index =
941 ancestorBinary->getRight()->getAsConstantUnion();
942 const TField *field = structure->fields()[index->getIConst(0)];
943 if (IsSampler(field->type()->getBasicType()))
944 {
945 return true;
946 }
947 break;
948 }
949 case EOpIndexDirect:
950 break;
951 default:
952 // Returning a sampler from indirect indexing is not supported.
953 return false;
954 }
955 }
956 return false;
957}
958
Olli Etuahob6fa0432016-09-28 16:28:05 +0100959bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
960{
961 TInfoSinkBase &out = getInfoSink();
962 if (visit == PostVisit)
963 {
964 out << ".";
965 node->writeOffsetsAsXYZW(&out);
966 }
967 return true;
968}
969
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
971{
Jamie Madill32aab012015-01-27 14:12:26 -0500972 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000973
Jamie Madill570e04d2013-06-21 09:15:33 -0400974 // Handle accessing std140 structs by value
975 if (mFlaggedStructMappedNames.count(node) > 0)
976 {
977 out << mFlaggedStructMappedNames[node];
978 return false;
979 }
980
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981 switch (node->getOp())
982 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100983 case EOpComma:
984 outputTriplet(out, visit, "(", ", ", ")");
985 break;
986 case EOpAssign:
987 if (node->getLeft()->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +0300988 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100989 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
990 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +0300991 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100992 const TString &functionName = addArrayConstructIntoFunction(node->getType());
993 out << functionName << "(";
994 node->getLeft()->traverse(this);
995 TIntermSequence *seq = rightAgg->getSequence();
996 for (auto &arrayElement : *seq)
997 {
998 out << ", ";
999 arrayElement->traverse(this);
1000 }
1001 out << ")";
1002 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001003 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001004 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1005 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001006 ASSERT(rightAgg == nullptr);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001007
1008 const TString &functionName = addArrayAssignmentFunction(node->getType());
1009 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho9638c352015-04-01 14:34:52 +03001010 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001011 else
Jamie Madill37997142015-01-28 10:06:34 -05001012 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001013 outputTriplet(out, visit, "(", " = ", ")");
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001014 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001015 break;
1016 case EOpInitialize:
1017 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001018 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001019 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1020 ASSERT(symbolNode);
1021 TIntermTyped *expression = node->getRight();
1022
1023 // Global initializers must be constant at this point.
1024 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1025 canWriteAsHLSLLiteral(expression));
1026
1027 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1028 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1029 // new variable is created before the assignment is evaluated), so we need to
1030 // convert
1031 // this to "float t = x, x = t;".
1032 if (writeSameSymbolInitializer(out, symbolNode, expression))
1033 {
1034 // Skip initializing the rest of the expression
1035 return false;
1036 }
1037 else if (writeConstantInitialization(out, symbolNode, expression))
1038 {
1039 return false;
1040 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001041 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001042 else if (visit == InVisit)
1043 {
1044 out << " = ";
1045 }
1046 break;
1047 case EOpAddAssign:
1048 outputTriplet(out, visit, "(", " += ", ")");
1049 break;
1050 case EOpSubAssign:
1051 outputTriplet(out, visit, "(", " -= ", ")");
1052 break;
1053 case EOpMulAssign:
1054 outputTriplet(out, visit, "(", " *= ", ")");
1055 break;
1056 case EOpVectorTimesScalarAssign:
1057 outputTriplet(out, visit, "(", " *= ", ")");
1058 break;
1059 case EOpMatrixTimesScalarAssign:
1060 outputTriplet(out, visit, "(", " *= ", ")");
1061 break;
1062 case EOpVectorTimesMatrixAssign:
1063 if (visit == PreVisit)
1064 {
1065 out << "(";
1066 }
1067 else if (visit == InVisit)
1068 {
1069 out << " = mul(";
1070 node->getLeft()->traverse(this);
1071 out << ", transpose(";
1072 }
1073 else
1074 {
1075 out << ")))";
1076 }
1077 break;
1078 case EOpMatrixTimesMatrixAssign:
1079 if (visit == PreVisit)
1080 {
1081 out << "(";
1082 }
1083 else if (visit == InVisit)
1084 {
1085 out << " = transpose(mul(transpose(";
1086 node->getLeft()->traverse(this);
1087 out << "), transpose(";
1088 }
1089 else
1090 {
1091 out << "))))";
1092 }
1093 break;
1094 case EOpDivAssign:
1095 outputTriplet(out, visit, "(", " /= ", ")");
1096 break;
1097 case EOpIModAssign:
1098 outputTriplet(out, visit, "(", " %= ", ")");
1099 break;
1100 case EOpBitShiftLeftAssign:
1101 outputTriplet(out, visit, "(", " <<= ", ")");
1102 break;
1103 case EOpBitShiftRightAssign:
1104 outputTriplet(out, visit, "(", " >>= ", ")");
1105 break;
1106 case EOpBitwiseAndAssign:
1107 outputTriplet(out, visit, "(", " &= ", ")");
1108 break;
1109 case EOpBitwiseXorAssign:
1110 outputTriplet(out, visit, "(", " ^= ", ")");
1111 break;
1112 case EOpBitwiseOrAssign:
1113 outputTriplet(out, visit, "(", " |= ", ")");
1114 break;
1115 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001116 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001117 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001118 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001119 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001120 if (visit == PreVisit)
1121 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001122 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001123 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001124 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] =
1125 node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001126 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001127 return false;
1128 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001129 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001130 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001131 {
1132 // All parts of an expression that access a sampler in a struct need to use _ as
1133 // separator to access the sampler variable that has been moved out of the struct.
1134 outputTriplet(out, visit, "", "_", "");
1135 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001136 else
1137 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001138 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001139 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001140 }
1141 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001142 case EOpIndexIndirect:
1143 // We do not currently support indirect references to interface blocks
1144 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1145 outputTriplet(out, visit, "", "[", "]");
1146 break;
1147 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001148 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001149 const TStructure *structure = node->getLeft()->getType().getStruct();
1150 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1151 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001152
Olli Etuaho96963162016-03-21 11:54:33 +02001153 // In cases where indexing returns a sampler, we need to access the sampler variable
1154 // that has been moved out of the struct.
1155 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1156 if (visit == PreVisit && indexingReturnsSampler)
1157 {
1158 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1159 // This prefix is only output at the beginning of the indexing expression, which
1160 // may have multiple parts.
1161 out << "angle";
1162 }
1163 if (!indexingReturnsSampler)
1164 {
1165 // All parts of an expression that access a sampler in a struct need to use _ as
1166 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001167 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001168 }
1169 if (visit == InVisit)
1170 {
1171 if (indexingReturnsSampler)
1172 {
1173 out << "_" + field->name();
1174 }
1175 else
1176 {
1177 out << "." + DecorateField(field->name(), *structure);
1178 }
1179
1180 return false;
1181 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001182 }
1183 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001184 case EOpIndexDirectInterfaceBlock:
1185 if (visit == InVisit)
1186 {
1187 const TInterfaceBlock *interfaceBlock =
1188 node->getLeft()->getType().getInterfaceBlock();
1189 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1190 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1191 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001192
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001193 return false;
1194 }
1195 break;
1196 case EOpAdd:
1197 outputTriplet(out, visit, "(", " + ", ")");
1198 break;
1199 case EOpSub:
1200 outputTriplet(out, visit, "(", " - ", ")");
1201 break;
1202 case EOpMul:
1203 outputTriplet(out, visit, "(", " * ", ")");
1204 break;
1205 case EOpDiv:
1206 outputTriplet(out, visit, "(", " / ", ")");
1207 break;
1208 case EOpIMod:
1209 outputTriplet(out, visit, "(", " % ", ")");
1210 break;
1211 case EOpBitShiftLeft:
1212 outputTriplet(out, visit, "(", " << ", ")");
1213 break;
1214 case EOpBitShiftRight:
1215 outputTriplet(out, visit, "(", " >> ", ")");
1216 break;
1217 case EOpBitwiseAnd:
1218 outputTriplet(out, visit, "(", " & ", ")");
1219 break;
1220 case EOpBitwiseXor:
1221 outputTriplet(out, visit, "(", " ^ ", ")");
1222 break;
1223 case EOpBitwiseOr:
1224 outputTriplet(out, visit, "(", " | ", ")");
1225 break;
1226 case EOpEqual:
1227 case EOpNotEqual:
1228 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1229 break;
1230 case EOpLessThan:
1231 outputTriplet(out, visit, "(", " < ", ")");
1232 break;
1233 case EOpGreaterThan:
1234 outputTriplet(out, visit, "(", " > ", ")");
1235 break;
1236 case EOpLessThanEqual:
1237 outputTriplet(out, visit, "(", " <= ", ")");
1238 break;
1239 case EOpGreaterThanEqual:
1240 outputTriplet(out, visit, "(", " >= ", ")");
1241 break;
1242 case EOpVectorTimesScalar:
1243 outputTriplet(out, visit, "(", " * ", ")");
1244 break;
1245 case EOpMatrixTimesScalar:
1246 outputTriplet(out, visit, "(", " * ", ")");
1247 break;
1248 case EOpVectorTimesMatrix:
1249 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1250 break;
1251 case EOpMatrixTimesVector:
1252 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1253 break;
1254 case EOpMatrixTimesMatrix:
1255 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1256 break;
1257 case EOpLogicalOr:
1258 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1259 // been unfolded.
1260 ASSERT(!node->getRight()->hasSideEffects());
1261 outputTriplet(out, visit, "(", " || ", ")");
1262 return true;
1263 case EOpLogicalXor:
1264 mUsesXor = true;
1265 outputTriplet(out, visit, "xor(", ", ", ")");
1266 break;
1267 case EOpLogicalAnd:
1268 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1269 // been unfolded.
1270 ASSERT(!node->getRight()->hasSideEffects());
1271 outputTriplet(out, visit, "(", " && ", ")");
1272 return true;
1273 default:
1274 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001275 }
1276
1277 return true;
1278}
1279
1280bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1281{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001282 TInfoSinkBase &out = getInfoSink();
1283
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001284 switch (node->getOp())
1285 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001286 case EOpNegative:
1287 outputTriplet(out, visit, "(-", "", ")");
1288 break;
1289 case EOpPositive:
1290 outputTriplet(out, visit, "(+", "", ")");
1291 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001292 case EOpLogicalNot:
1293 outputTriplet(out, visit, "(!", "", ")");
1294 break;
1295 case EOpBitwiseNot:
1296 outputTriplet(out, visit, "(~", "", ")");
1297 break;
1298 case EOpPostIncrement:
1299 outputTriplet(out, visit, "(", "", "++)");
1300 break;
1301 case EOpPostDecrement:
1302 outputTriplet(out, visit, "(", "", "--)");
1303 break;
1304 case EOpPreIncrement:
1305 outputTriplet(out, visit, "(++", "", ")");
1306 break;
1307 case EOpPreDecrement:
1308 outputTriplet(out, visit, "(--", "", ")");
1309 break;
1310 case EOpRadians:
1311 outputTriplet(out, visit, "radians(", "", ")");
1312 break;
1313 case EOpDegrees:
1314 outputTriplet(out, visit, "degrees(", "", ")");
1315 break;
1316 case EOpSin:
1317 outputTriplet(out, visit, "sin(", "", ")");
1318 break;
1319 case EOpCos:
1320 outputTriplet(out, visit, "cos(", "", ")");
1321 break;
1322 case EOpTan:
1323 outputTriplet(out, visit, "tan(", "", ")");
1324 break;
1325 case EOpAsin:
1326 outputTriplet(out, visit, "asin(", "", ")");
1327 break;
1328 case EOpAcos:
1329 outputTriplet(out, visit, "acos(", "", ")");
1330 break;
1331 case EOpAtan:
1332 outputTriplet(out, visit, "atan(", "", ")");
1333 break;
1334 case EOpSinh:
1335 outputTriplet(out, visit, "sinh(", "", ")");
1336 break;
1337 case EOpCosh:
1338 outputTriplet(out, visit, "cosh(", "", ")");
1339 break;
1340 case EOpTanh:
1341 outputTriplet(out, visit, "tanh(", "", ")");
1342 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001343 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001344 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001345 case EOpAtanh:
1346 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001347 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001348 break;
1349 case EOpExp:
1350 outputTriplet(out, visit, "exp(", "", ")");
1351 break;
1352 case EOpLog:
1353 outputTriplet(out, visit, "log(", "", ")");
1354 break;
1355 case EOpExp2:
1356 outputTriplet(out, visit, "exp2(", "", ")");
1357 break;
1358 case EOpLog2:
1359 outputTriplet(out, visit, "log2(", "", ")");
1360 break;
1361 case EOpSqrt:
1362 outputTriplet(out, visit, "sqrt(", "", ")");
1363 break;
1364 case EOpInverseSqrt:
1365 outputTriplet(out, visit, "rsqrt(", "", ")");
1366 break;
1367 case EOpAbs:
1368 outputTriplet(out, visit, "abs(", "", ")");
1369 break;
1370 case EOpSign:
1371 outputTriplet(out, visit, "sign(", "", ")");
1372 break;
1373 case EOpFloor:
1374 outputTriplet(out, visit, "floor(", "", ")");
1375 break;
1376 case EOpTrunc:
1377 outputTriplet(out, visit, "trunc(", "", ")");
1378 break;
1379 case EOpRound:
1380 outputTriplet(out, visit, "round(", "", ")");
1381 break;
1382 case EOpRoundEven:
1383 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001384 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001385 break;
1386 case EOpCeil:
1387 outputTriplet(out, visit, "ceil(", "", ")");
1388 break;
1389 case EOpFract:
1390 outputTriplet(out, visit, "frac(", "", ")");
1391 break;
1392 case EOpIsNan:
1393 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001394 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001395 else
1396 outputTriplet(out, visit, "isnan(", "", ")");
1397 mRequiresIEEEStrictCompiling = true;
1398 break;
1399 case EOpIsInf:
1400 outputTriplet(out, visit, "isinf(", "", ")");
1401 break;
1402 case EOpFloatBitsToInt:
1403 outputTriplet(out, visit, "asint(", "", ")");
1404 break;
1405 case EOpFloatBitsToUint:
1406 outputTriplet(out, visit, "asuint(", "", ")");
1407 break;
1408 case EOpIntBitsToFloat:
1409 outputTriplet(out, visit, "asfloat(", "", ")");
1410 break;
1411 case EOpUintBitsToFloat:
1412 outputTriplet(out, visit, "asfloat(", "", ")");
1413 break;
1414 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001415 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001417 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001418 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001419 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001420 case EOpPackUnorm4x8:
1421 case EOpPackSnorm4x8:
1422 case EOpUnpackUnorm4x8:
1423 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001424 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001425 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001426 break;
1427 case EOpLength:
1428 outputTriplet(out, visit, "length(", "", ")");
1429 break;
1430 case EOpNormalize:
1431 outputTriplet(out, visit, "normalize(", "", ")");
1432 break;
1433 case EOpDFdx:
1434 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1435 {
1436 outputTriplet(out, visit, "(", "", ", 0.0)");
1437 }
1438 else
1439 {
1440 outputTriplet(out, visit, "ddx(", "", ")");
1441 }
1442 break;
1443 case EOpDFdy:
1444 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1445 {
1446 outputTriplet(out, visit, "(", "", ", 0.0)");
1447 }
1448 else
1449 {
1450 outputTriplet(out, visit, "ddy(", "", ")");
1451 }
1452 break;
1453 case EOpFwidth:
1454 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1455 {
1456 outputTriplet(out, visit, "(", "", ", 0.0)");
1457 }
1458 else
1459 {
1460 outputTriplet(out, visit, "fwidth(", "", ")");
1461 }
1462 break;
1463 case EOpTranspose:
1464 outputTriplet(out, visit, "transpose(", "", ")");
1465 break;
1466 case EOpDeterminant:
1467 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1468 break;
1469 case EOpInverse:
1470 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001471 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001472 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001473
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001474 case EOpAny:
1475 outputTriplet(out, visit, "any(", "", ")");
1476 break;
1477 case EOpAll:
1478 outputTriplet(out, visit, "all(", "", ")");
1479 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001480 case EOpLogicalNotComponentWise:
1481 outputTriplet(out, visit, "(!", "", ")");
1482 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001483 case EOpBitfieldReverse:
1484 outputTriplet(out, visit, "reversebits(", "", ")");
1485 break;
1486 case EOpBitCount:
1487 outputTriplet(out, visit, "countbits(", "", ")");
1488 break;
1489 case EOpFindLSB:
1490 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1491 // in GLSLTest and results are consistent with GL.
1492 outputTriplet(out, visit, "firstbitlow(", "", ")");
1493 break;
1494 case EOpFindMSB:
1495 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1496 // tested in GLSLTest and results are consistent with GL.
1497 outputTriplet(out, visit, "firstbithigh(", "", ")");
1498 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001499 default:
1500 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001501 }
1502
1503 return true;
1504}
1505
Olli Etuaho96963162016-03-21 11:54:33 +02001506TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1507{
1508 if (node->getAsSymbolNode())
1509 {
1510 return node->getAsSymbolNode()->getSymbol();
1511 }
1512 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1513 switch (nodeBinary->getOp())
1514 {
1515 case EOpIndexDirect:
1516 {
1517 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1518
1519 TInfoSinkBase prefixSink;
1520 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1521 return TString(prefixSink.c_str());
1522 }
1523 case EOpIndexDirectStruct:
1524 {
1525 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1526 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1527 const TField *field = s->fields()[index];
1528
1529 TInfoSinkBase prefixSink;
1530 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1531 << field->name();
1532 return TString(prefixSink.c_str());
1533 }
1534 default:
1535 UNREACHABLE();
1536 return TString("");
1537 }
1538}
1539
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001540bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1541{
1542 TInfoSinkBase &out = getInfoSink();
1543
1544 if (mInsideFunction)
1545 {
1546 outputLineDirective(out, node->getLine().first_line);
1547 out << "{\n";
1548 }
1549
1550 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1551 sit != node->getSequence()->end(); sit++)
1552 {
1553 outputLineDirective(out, (*sit)->getLine().first_line);
1554
1555 (*sit)->traverse(this);
1556
1557 // Don't output ; after case labels, they're terminated by :
1558 // This is needed especially since outputting a ; after a case statement would turn empty
1559 // case statements into non-empty case statements, disallowing fall-through from them.
1560 // Also no need to output ; after if statements or sequences. This is done just for
1561 // code clarity.
1562 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1563 (*sit)->getAsBlock() == nullptr)
1564 out << ";\n";
1565 }
1566
1567 if (mInsideFunction)
1568 {
1569 outputLineDirective(out, node->getLine().last_line);
1570 out << "}\n";
1571 }
1572
1573 return false;
1574}
1575
Olli Etuaho336b1472016-10-05 16:37:55 +01001576bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1577{
1578 TInfoSinkBase &out = getInfoSink();
1579
1580 ASSERT(mCurrentFunctionMetadata == nullptr);
1581
1582 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1583 ASSERT(index != CallDAG::InvalidIndex);
1584 mCurrentFunctionMetadata = &mASTMetadataList[index];
1585
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001586 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001587
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001588 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001589
1590 if (node->getFunctionSymbolInfo()->isMain())
1591 {
1592 out << "gl_main(";
1593 }
1594 else
1595 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001596 out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001597 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1598 }
1599
1600 for (unsigned int i = 0; i < parameters->size(); i++)
1601 {
1602 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1603
1604 if (symbol)
1605 {
1606 ensureStructDefined(symbol->getType());
1607
1608 out << argumentString(symbol);
1609
1610 if (i < parameters->size() - 1)
1611 {
1612 out << ", ";
1613 }
1614 }
1615 else
1616 UNREACHABLE();
1617 }
1618
1619 out << ")\n";
1620
1621 mInsideFunction = true;
1622 // The function body node will output braces.
1623 node->getBody()->traverse(this);
1624 mInsideFunction = false;
1625
1626 mCurrentFunctionMetadata = nullptr;
1627
1628 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1629 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1630 {
1631 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1632 mOutputLod0Function = true;
1633 node->traverse(this);
1634 mOutputLod0Function = false;
1635 }
1636
1637 return false;
1638}
1639
Olli Etuaho13389b62016-10-16 11:48:18 +01001640bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1641{
1642 TInfoSinkBase &out = getInfoSink();
1643 if (visit == PreVisit)
1644 {
1645 TIntermSequence *sequence = node->getSequence();
1646 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1647 ASSERT(sequence->size() == 1);
1648
1649 if (variable &&
1650 (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
1651 variable->getQualifier() == EvqConst))
1652 {
1653 ensureStructDefined(variable->getType());
1654
1655 if (!variable->getAsSymbolNode() ||
1656 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1657 {
1658 if (!mInsideFunction)
1659 {
1660 out << "static ";
1661 }
1662
1663 out << TypeString(variable->getType()) + " ";
1664
1665 TIntermSymbol *symbol = variable->getAsSymbolNode();
1666
1667 if (symbol)
1668 {
1669 symbol->traverse(this);
1670 out << ArrayString(symbol->getType());
1671 out << " = " + initializer(symbol->getType());
1672 }
1673 else
1674 {
1675 variable->traverse(this);
1676 }
1677 }
1678 else if (variable->getAsSymbolNode() &&
1679 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1680 {
1681 // Already added to constructor map
1682 }
1683 else
1684 UNREACHABLE();
1685 }
1686 else if (variable && IsVaryingOut(variable->getQualifier()))
1687 {
1688 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
1689 {
1690 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1691
1692 if (symbol)
1693 {
1694 // Vertex (output) varyings which are declared but not written to should
1695 // still be declared to allow successful linking
1696 mReferencedVaryings[symbol->getSymbol()] = symbol;
1697 }
1698 else
1699 {
1700 (*sit)->traverse(this);
1701 }
1702 }
1703 }
1704 }
1705 return false;
1706}
1707
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001708bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1709{
1710 // Do not do any translation
1711 return false;
1712}
1713
Olli Etuaho16c745a2017-01-16 17:02:27 +00001714bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1715{
1716 TInfoSinkBase &out = getInfoSink();
1717
1718 ASSERT(visit == PreVisit);
1719 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1720 // Skip the prototype if it is not implemented (and thus not used)
1721 if (index == CallDAG::InvalidIndex)
1722 {
1723 return false;
1724 }
1725
1726 TIntermSequence *arguments = node->getSequence();
1727
Olli Etuahoec9232b2017-03-27 17:01:37 +03001728 TString name = DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001729 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1730 << (mOutputLod0Function ? "Lod0(" : "(");
1731
1732 for (unsigned int i = 0; i < arguments->size(); i++)
1733 {
1734 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1735 ASSERT(symbol != nullptr);
1736
1737 out << argumentString(symbol);
1738
1739 if (i < arguments->size() - 1)
1740 {
1741 out << ", ";
1742 }
1743 }
1744
1745 out << ");\n";
1746
1747 // Also prototype the Lod0 variant if needed
1748 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1749 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1750 {
1751 mOutputLod0Function = true;
1752 node->traverse(this);
1753 mOutputLod0Function = false;
1754 }
1755
1756 return false;
1757}
1758
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001759bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1760{
Jamie Madill32aab012015-01-27 14:12:26 -05001761 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001762
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001763 switch (node->getOp())
1764 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001765 case EOpCallBuiltInFunction:
1766 case EOpCallFunctionInAST:
1767 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001768 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001769 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001770
Corentin Wallez1239ee92015-03-19 14:38:02 -07001771 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001772 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001773 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001774 if (node->isArray())
1775 {
1776 UNIMPLEMENTED();
1777 }
Olli Etuahobd674552016-10-06 13:28:42 +01001778 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001779 ASSERT(index != CallDAG::InvalidIndex);
1780 lod0 &= mASTMetadataList[index].mNeedsLod0;
1781
Olli Etuahoec9232b2017-03-27 17:01:37 +03001782 out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001783 out << DisambiguateFunctionName(node->getSequence());
1784 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001786 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001787 {
1788 // This path is used for internal functions that don't have their definitions in the
1789 // AST, such as precision emulation functions.
Olli Etuahoec9232b2017-03-27 17:01:37 +03001790 out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001791 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001792 else
1793 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001794 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001795 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001796 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1797 if (arguments->size() > 1)
1798 {
1799 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1800 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001801 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1802 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1803 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001804 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001805
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001806 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001807 {
Olli Etuaho96963162016-03-21 11:54:33 +02001808 TIntermTyped *typedArg = (*arg)->getAsTyped();
1809 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001810 {
1811 out << "texture_";
1812 (*arg)->traverse(this);
1813 out << ", sampler_";
1814 }
1815
1816 (*arg)->traverse(this);
1817
Olli Etuaho96963162016-03-21 11:54:33 +02001818 if (typedArg->getType().isStructureContainingSamplers())
1819 {
1820 const TType &argType = typedArg->getType();
1821 TVector<TIntermSymbol *> samplerSymbols;
1822 TString structName = samplerNamePrefixFromStruct(typedArg);
1823 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho856c4972016-08-08 11:38:39 +03001824 argType.isArray() ? argType.getArraySize() : 0u,
Olli Etuaho96963162016-03-21 11:54:33 +02001825 &samplerSymbols, nullptr);
1826 for (const TIntermSymbol *sampler : samplerSymbols)
1827 {
1828 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1829 {
1830 out << ", texture_" << sampler->getSymbol();
1831 out << ", sampler_" << sampler->getSymbol();
1832 }
1833 else
1834 {
1835 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1836 // of D3D9, it's the sampler variable.
1837 out << ", " + sampler->getSymbol();
1838 }
1839 }
1840 }
1841
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001842 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001843 {
1844 out << ", ";
1845 }
1846 }
1847
1848 out << ")";
1849
1850 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001851 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001852 case EOpConstruct:
1853 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001854 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001855 if (node->getType().isArray())
1856 {
1857 UNIMPLEMENTED();
1858 }
1859 const TString &structName = StructNameString(*node->getType().getStruct());
1860 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1861 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001862 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001863 else
1864 {
1865 const char *name = "";
1866 if (node->getType().getNominalSize() == 1)
1867 {
1868 switch (node->getBasicType())
1869 {
1870 case EbtFloat:
1871 name = "vec1";
1872 break;
1873 case EbtInt:
1874 name = "ivec1";
1875 break;
1876 case EbtUInt:
1877 name = "uvec1";
1878 break;
1879 case EbtBool:
1880 name = "bvec1";
1881 break;
1882 default:
1883 UNREACHABLE();
1884 }
1885 }
1886 else
1887 {
1888 name = node->getType().getBuiltInTypeNameString();
1889 }
1890 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1891 }
1892 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001893 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001894 outputTriplet(out, visit, "(", " == ", ")");
1895 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001896 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001897 outputTriplet(out, visit, "(", " != ", ")");
1898 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001899 case EOpLessThanComponentWise:
1900 outputTriplet(out, visit, "(", " < ", ")");
1901 break;
1902 case EOpGreaterThanComponentWise:
1903 outputTriplet(out, visit, "(", " > ", ")");
1904 break;
1905 case EOpLessThanEqualComponentWise:
1906 outputTriplet(out, visit, "(", " <= ", ")");
1907 break;
1908 case EOpGreaterThanEqualComponentWise:
1909 outputTriplet(out, visit, "(", " >= ", ")");
1910 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001911 case EOpMod:
1912 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001913 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001914 break;
1915 case EOpModf:
1916 outputTriplet(out, visit, "modf(", ", ", ")");
1917 break;
1918 case EOpPow:
1919 outputTriplet(out, visit, "pow(", ", ", ")");
1920 break;
1921 case EOpAtan:
1922 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1923 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001924 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001925 break;
1926 case EOpMin:
1927 outputTriplet(out, visit, "min(", ", ", ")");
1928 break;
1929 case EOpMax:
1930 outputTriplet(out, visit, "max(", ", ", ")");
1931 break;
1932 case EOpClamp:
1933 outputTriplet(out, visit, "clamp(", ", ", ")");
1934 break;
1935 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301936 {
1937 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1938 if (lastParamNode->getType().getBasicType() == EbtBool)
1939 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001940 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1941 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301942 // so use emulated version.
1943 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001944 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301945 }
1946 else
1947 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001948 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301949 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001950 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301951 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001952 case EOpStep:
1953 outputTriplet(out, visit, "step(", ", ", ")");
1954 break;
1955 case EOpSmoothStep:
1956 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1957 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001958 case EOpFrexp:
1959 case EOpLdexp:
1960 ASSERT(node->getUseEmulatedFunction());
1961 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1962 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001963 case EOpDistance:
1964 outputTriplet(out, visit, "distance(", ", ", ")");
1965 break;
1966 case EOpDot:
1967 outputTriplet(out, visit, "dot(", ", ", ")");
1968 break;
1969 case EOpCross:
1970 outputTriplet(out, visit, "cross(", ", ", ")");
1971 break;
Jamie Madille72595b2017-06-06 15:12:26 -04001972 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01001973 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;
1976 case EOpReflect:
1977 outputTriplet(out, visit, "reflect(", ", ", ")");
1978 break;
1979 case EOpRefract:
1980 outputTriplet(out, visit, "refract(", ", ", ")");
1981 break;
1982 case EOpOuterProduct:
1983 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001984 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001985 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001986 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01001987 outputTriplet(out, visit, "(", " * ", ")");
1988 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001989 case EOpBitfieldExtract:
1990 case EOpBitfieldInsert:
1991 case EOpUaddCarry:
1992 case EOpUsubBorrow:
1993 case EOpUmulExtended:
1994 case EOpImulExtended:
1995 ASSERT(node->getUseEmulatedFunction());
1996 writeEmulatedFunctionTriplet(out, visit, node->getOp());
1997 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001998 default:
1999 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002000 }
2001
2002 return true;
2003}
2004
Olli Etuaho57961272016-09-14 13:57:46 +03002005void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002006{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002007 out << "if (";
2008
2009 node->getCondition()->traverse(this);
2010
2011 out << ")\n";
2012
Jamie Madill8c46ab12015-12-07 16:39:19 -05002013 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002014
2015 bool discard = false;
2016
2017 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002018 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002019 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002020 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002021
Olli Etuahoa6f22092015-05-08 18:31:10 +03002022 // Detect true discard
2023 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2024 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002025 else
2026 {
2027 // TODO(oetuaho): Check if the semicolon inside is necessary.
2028 // It's there as a result of conservative refactoring of the output.
2029 out << "{;}\n";
2030 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002031
Jamie Madill8c46ab12015-12-07 16:39:19 -05002032 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002033
Olli Etuahoa6f22092015-05-08 18:31:10 +03002034 if (node->getFalseBlock())
2035 {
2036 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002037
Jamie Madill8c46ab12015-12-07 16:39:19 -05002038 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002039
Olli Etuaho32db19b2016-10-04 14:43:16 +01002040 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002041 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002042
Jamie Madill8c46ab12015-12-07 16:39:19 -05002043 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002044
Olli Etuahoa6f22092015-05-08 18:31:10 +03002045 // Detect false discard
2046 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2047 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002048
Olli Etuahoa6f22092015-05-08 18:31:10 +03002049 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002050 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002051 {
2052 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002053 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002054}
2055
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002056bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2057{
2058 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2059 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2060 UNREACHABLE();
2061 return false;
2062}
2063
Olli Etuaho57961272016-09-14 13:57:46 +03002064bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002065{
2066 TInfoSinkBase &out = getInfoSink();
2067
Olli Etuaho3d932d82016-04-12 11:10:30 +03002068 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002069
2070 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002071 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002072 {
2073 out << "FLATTEN ";
2074 }
2075
Olli Etuaho57961272016-09-14 13:57:46 +03002076 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002077
2078 return false;
2079}
2080
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002081bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002082{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002083 TInfoSinkBase &out = getInfoSink();
2084
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002085 if (node->getStatementList())
2086 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002087 node->setStatementList(
2088 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002089 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002090 // The curly braces get written when visiting the statementList aggregate
2091 }
2092 else
2093 {
2094 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002095 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002096 }
2097 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002098}
2099
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002100bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002101{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002102 TInfoSinkBase &out = getInfoSink();
2103
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002104 if (node->hasCondition())
2105 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002106 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002107 return true;
2108 }
2109 else
2110 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002111 out << "default:\n";
2112 return false;
2113 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002114}
2115
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002116void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2117{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002118 TInfoSinkBase &out = getInfoSink();
2119 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002120}
2121
2122bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2123{
Nicolas Capens655fe362014-04-11 13:12:34 -04002124 mNestedLoopDepth++;
2125
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002126 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002127 mInsideDiscontinuousLoop =
2128 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002129
Jamie Madill8c46ab12015-12-07 16:39:19 -05002130 TInfoSinkBase &out = getInfoSink();
2131
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002132 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002133 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002134 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002135 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002136 mInsideDiscontinuousLoop = wasDiscontinuous;
2137 mNestedLoopDepth--;
2138
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002139 return false;
2140 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002141 }
2142
Corentin Wallez1239ee92015-03-19 14:38:02 -07002143 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002144 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002145 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002146 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002147
Jamie Madill8c46ab12015-12-07 16:39:19 -05002148 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002149 }
2150 else
2151 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002152 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002153
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154 if (node->getInit())
2155 {
2156 node->getInit()->traverse(this);
2157 }
2158
2159 out << "; ";
2160
alokp@chromium.org52813552010-11-16 18:36:09 +00002161 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002162 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002163 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002164 }
2165
2166 out << "; ";
2167
alokp@chromium.org52813552010-11-16 18:36:09 +00002168 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002169 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002170 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 }
2172
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002173 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002174
Jamie Madill8c46ab12015-12-07 16:39:19 -05002175 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002176 }
2177
2178 if (node->getBody())
2179 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002180 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002181 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002182 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002183 else
2184 {
2185 // TODO(oetuaho): Check if the semicolon inside is necessary.
2186 // It's there as a result of conservative refactoring of the output.
2187 out << "{;}\n";
2188 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002189
Jamie Madill8c46ab12015-12-07 16:39:19 -05002190 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002191
alokp@chromium.org52813552010-11-16 18:36:09 +00002192 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002193 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002194 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002195 out << "while(\n";
2196
alokp@chromium.org52813552010-11-16 18:36:09 +00002197 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198
daniel@transgaming.com73536982012-03-21 20:45:49 +00002199 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 }
2201
daniel@transgaming.com73536982012-03-21 20:45:49 +00002202 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002203
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002204 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002205 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002206
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207 return false;
2208}
2209
2210bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2211{
Jamie Madill32aab012015-01-27 14:12:26 -05002212 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002213
2214 switch (node->getFlowOp())
2215 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002216 case EOpKill:
2217 outputTriplet(out, visit, "discard;\n", "", "");
2218 break;
2219 case EOpBreak:
2220 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002221 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002222 if (mNestedLoopDepth > 1)
2223 {
2224 mUsesNestedBreak = true;
2225 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002226
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002227 if (mExcessiveLoopIndex)
2228 {
2229 out << "{Break";
2230 mExcessiveLoopIndex->traverse(this);
2231 out << " = true; break;}\n";
2232 }
2233 else
2234 {
2235 out << "break;\n";
2236 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002237 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002238 break;
2239 case EOpContinue:
2240 outputTriplet(out, visit, "continue;\n", "", "");
2241 break;
2242 case EOpReturn:
2243 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002244 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002245 if (node->getExpression())
2246 {
2247 out << "return ";
2248 }
2249 else
2250 {
2251 out << "return;\n";
2252 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002253 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002254 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002255 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002256 if (node->getExpression())
2257 {
2258 out << ";\n";
2259 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002261 break;
2262 default:
2263 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002264 }
2265
2266 return true;
2267}
2268
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002269// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002270// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2271// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002272bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002273{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002274 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002275
2276 // Parse loops of the form:
2277 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002278 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002279 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002280 int initial = 0;
2281 int limit = 0;
2282 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002283
2284 // Parse index name and intial value
2285 if (node->getInit())
2286 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002287 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002288
2289 if (init)
2290 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002291 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002292 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002293
2294 if (variable && variable->getQualifier() == EvqTemporary)
2295 {
2296 TIntermBinary *assign = variable->getAsBinaryNode();
2297
2298 if (assign->getOp() == EOpInitialize)
2299 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002300 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002301 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2302
2303 if (symbol && constant)
2304 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002305 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002306 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002307 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002308 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002309 }
2310 }
2311 }
2312 }
2313 }
2314 }
2315
2316 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002317 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002318 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002319 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002320
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002321 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2322 {
2323 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2324
2325 if (constant)
2326 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002327 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002328 {
2329 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002330 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002331 }
2332 }
2333 }
2334 }
2335
2336 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002337 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002338 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002339 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002340 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002341
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002342 if (binaryTerminal)
2343 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002344 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002345 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2346
2347 if (constant)
2348 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002349 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002350 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002351 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002352
2353 switch (op)
2354 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002355 case EOpAddAssign:
2356 increment = value;
2357 break;
2358 case EOpSubAssign:
2359 increment = -value;
2360 break;
2361 default:
2362 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002363 }
2364 }
2365 }
2366 }
2367 else if (unaryTerminal)
2368 {
2369 TOperator op = unaryTerminal->getOp();
2370
2371 switch (op)
2372 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002373 case EOpPostIncrement:
2374 increment = 1;
2375 break;
2376 case EOpPostDecrement:
2377 increment = -1;
2378 break;
2379 case EOpPreIncrement:
2380 increment = 1;
2381 break;
2382 case EOpPreDecrement:
2383 increment = -1;
2384 break;
2385 default:
2386 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002387 }
2388 }
2389 }
2390
Yunchao He4f285442017-04-21 12:15:49 +08002391 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002392 {
2393 if (comparator == EOpLessThanEqual)
2394 {
2395 comparator = EOpLessThan;
2396 limit += 1;
2397 }
2398
2399 if (comparator == EOpLessThan)
2400 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002401 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002402
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002403 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002404 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002405 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002406 }
2407
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002408 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002409 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002410
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002411 out << "{int ";
2412 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002413 out << ";\n"
2414 "bool Break";
2415 index->traverse(this);
2416 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002417
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002418 bool firstLoopFragment = true;
2419
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002420 while (iterations > 0)
2421 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002422 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002423
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002424 if (!firstLoopFragment)
2425 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002426 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002427 index->traverse(this);
2428 out << ") {\n";
2429 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002430
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002431 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002432 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002433 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002434 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002435
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002436 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002437 const char *unroll =
2438 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002439
Corentin Wallez1239ee92015-03-19 14:38:02 -07002440 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002441 index->traverse(this);
2442 out << " = ";
2443 out << initial;
2444
2445 out << "; ";
2446 index->traverse(this);
2447 out << " < ";
2448 out << clampedLimit;
2449
2450 out << "; ";
2451 index->traverse(this);
2452 out << " += ";
2453 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002454 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002455
Jamie Madill8c46ab12015-12-07 16:39:19 -05002456 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002457 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002458
2459 if (node->getBody())
2460 {
2461 node->getBody()->traverse(this);
2462 }
2463
Jamie Madill8c46ab12015-12-07 16:39:19 -05002464 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002465 out << ";}\n";
2466
2467 if (!firstLoopFragment)
2468 {
2469 out << "}\n";
2470 }
2471
2472 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002473
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002474 initial += MAX_LOOP_ITERATIONS * increment;
2475 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002476 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002477
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002478 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002480 mExcessiveLoopIndex = restoreIndex;
2481
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002482 return true;
2483 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002484 else
2485 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002486 }
2487
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002488 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002489}
2490
Jamie Madill8c46ab12015-12-07 16:39:19 -05002491void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2492 Visit visit,
2493 const char *preString,
2494 const char *inString,
2495 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002496{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002497 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002498 {
2499 out << preString;
2500 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002501 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002502 {
2503 out << inString;
2504 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002505 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002506 {
2507 out << postString;
2508 }
2509}
2510
Jamie Madill8c46ab12015-12-07 16:39:19 -05002511void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002512{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002513 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002514 {
Jamie Madill32aab012015-01-27 14:12:26 -05002515 out << "\n";
2516 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002517
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002518 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002519 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002520 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002521 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002522
Jamie Madill32aab012015-01-27 14:12:26 -05002523 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002524 }
2525}
2526
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002527TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2528{
2529 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002530 const TType &type = symbol->getType();
2531 const TName &name = symbol->getName();
2532 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002533
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002534 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002535 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002536 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002537 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002538 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002539 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002540 nameStr = DecorateIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002541 }
2542
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002543 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002544 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002545 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2546 {
2547 // Samplers are passed as indices to the sampler array.
2548 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2549 return "const uint " + nameStr + ArrayString(type);
2550 }
2551 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2552 {
2553 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2554 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2555 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2556 ArrayString(type);
2557 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002558 }
2559
Olli Etuaho96963162016-03-21 11:54:33 +02002560 TStringStream argString;
2561 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2562 << ArrayString(type);
2563
2564 // If the structure parameter contains samplers, they need to be passed into the function as
2565 // separate parameters. HLSL doesn't natively support samplers in structs.
2566 if (type.isStructureContainingSamplers())
2567 {
2568 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2569 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho856c4972016-08-08 11:38:39 +03002570 type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002571 for (const TIntermSymbol *sampler : samplerSymbols)
2572 {
2573 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2574 {
2575 argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
2576 }
2577 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2578 {
2579 const TType &samplerType = sampler->getType();
2580 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2581 type.getArraySize() == samplerType.getArraySize());
2582 ASSERT(IsSampler(samplerType.getBasicType()));
2583 argString << ", " << QualifierString(qualifier) << " "
2584 << TextureString(samplerType.getBasicType()) << " texture_"
2585 << sampler->getSymbol() << ArrayString(type) << ", "
2586 << QualifierString(qualifier) << " "
2587 << SamplerString(samplerType.getBasicType()) << " sampler_"
2588 << sampler->getSymbol() << ArrayString(type);
2589 }
2590 else
2591 {
2592 const TType &samplerType = sampler->getType();
2593 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2594 type.getArraySize() == samplerType.getArraySize());
2595 ASSERT(IsSampler(samplerType.getBasicType()));
2596 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
2597 << " " << sampler->getSymbol() << ArrayString(type);
2598 }
2599 }
2600 }
2601
2602 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002603}
2604
2605TString OutputHLSL::initializer(const TType &type)
2606{
2607 TString string;
2608
Jamie Madill94bf7f22013-07-08 13:31:15 -04002609 size_t size = type.getObjectSize();
2610 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002611 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002612 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002613
Jamie Madill94bf7f22013-07-08 13:31:15 -04002614 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002615 {
2616 string += ", ";
2617 }
2618 }
2619
daniel@transgaming.comead23042010-04-29 03:35:36 +00002620 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002621}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002622
Jamie Madill8c46ab12015-12-07 16:39:19 -05002623void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2624 Visit visit,
2625 const TType &type,
2626 const char *name,
2627 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002628{
Olli Etuahof40319e2015-03-10 14:33:00 +02002629 if (type.isArray())
2630 {
2631 UNIMPLEMENTED();
2632 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002633
2634 if (visit == PreVisit)
2635 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002636 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002637
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002638 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002639 }
2640 else if (visit == InVisit)
2641 {
2642 out << ", ";
2643 }
2644 else if (visit == PostVisit)
2645 {
2646 out << ")";
2647 }
2648}
2649
Jamie Madill8c46ab12015-12-07 16:39:19 -05002650const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2651 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002652 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002653{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002654 const TConstantUnion *constUnionIterated = constUnion;
2655
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002656 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002657 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002658 {
Jamie Madill033dae62014-06-18 12:56:28 -04002659 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002660
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002661 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002662
Jamie Madill98493dd2013-07-08 14:39:03 -04002663 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002664 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002665 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002666 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002667
Jamie Madill98493dd2013-07-08 14:39:03 -04002668 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002669 {
2670 out << ", ";
2671 }
2672 }
2673
2674 out << ")";
2675 }
2676 else
2677 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002678 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002679 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002680
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002681 if (writeType)
2682 {
Jamie Madill033dae62014-06-18 12:56:28 -04002683 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002684 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002685 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002686 if (writeType)
2687 {
2688 out << ")";
2689 }
2690 }
2691
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002692 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002693}
2694
Olli Etuahod68924e2017-01-02 17:34:40 +00002695void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002696{
Olli Etuahod68924e2017-01-02 17:34:40 +00002697 if (visit == PreVisit)
2698 {
2699 const char *opStr = GetOperatorString(op);
2700 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2701 out << "(";
2702 }
2703 else
2704 {
2705 outputTriplet(out, visit, nullptr, ", ", ")");
2706 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002707}
2708
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002709bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2710 TIntermSymbol *symbolNode,
2711 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002712{
2713 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2714 expression->traverse(&searchSymbol);
2715
2716 if (searchSymbol.foundMatch())
2717 {
2718 // Type already printed
2719 out << "t" + str(mUniqueIndex) + " = ";
2720 expression->traverse(this);
2721 out << ", ";
2722 symbolNode->traverse(this);
2723 out << " = t" + str(mUniqueIndex);
2724
2725 mUniqueIndex++;
2726 return true;
2727 }
2728
2729 return false;
2730}
2731
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002732bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2733{
2734 // We support writing constant unions and constructors that only take constant unions as
2735 // parameters as HLSL literals.
Olli Etuahod4f4c112016-04-15 15:11:24 +03002736 return expression->getAsConstantUnion() ||
2737 expression->isConstructorWithOnlyConstantUnionParameters();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002738}
2739
2740bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2741 TIntermSymbol *symbolNode,
2742 TIntermTyped *expression)
2743{
2744 if (canWriteAsHLSLLiteral(expression))
2745 {
2746 symbolNode->traverse(this);
2747 if (expression->getType().isArray())
2748 {
2749 out << "[" << expression->getType().getArraySize() << "]";
2750 }
2751 out << " = {";
2752 if (expression->getAsConstantUnion())
2753 {
2754 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2755 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002756 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002757 }
2758 else
2759 {
2760 TIntermAggregate *constructor = expression->getAsAggregate();
2761 ASSERT(constructor != nullptr);
2762 for (TIntermNode *&node : *constructor->getSequence())
2763 {
2764 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2765 ASSERT(nodeConst);
2766 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002767 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002768 if (node != constructor->getSequence()->back())
2769 {
2770 out << ", ";
2771 }
2772 }
2773 }
2774 out << "}";
2775 return true;
2776 }
2777 return false;
2778}
2779
Jamie Madill55e79e02015-02-09 15:35:00 -05002780TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2781{
2782 const TFieldList &fields = structure.fields();
2783
2784 for (const auto &eqFunction : mStructEqualityFunctions)
2785 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002786 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002787 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002788 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002789 }
2790 }
2791
2792 const TString &structNameString = StructNameString(structure);
2793
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002794 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002795 function->structure = &structure;
2796 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002797
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002798 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002799
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002800 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2801 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002802 << "{\n"
2803 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002804
2805 for (size_t i = 0; i < fields.size(); i++)
2806 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002807 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002808 const TType *fieldType = field->type();
2809
2810 const TString &fieldNameA = "a." + Decorate(field->name());
2811 const TString &fieldNameB = "b." + Decorate(field->name());
2812
2813 if (i > 0)
2814 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002815 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002816 }
2817
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002818 fnOut << "(";
2819 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2820 fnOut << fieldNameA;
2821 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2822 fnOut << fieldNameB;
2823 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2824 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002825 }
2826
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002827 fnOut << ";\n"
2828 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002829
2830 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002831
2832 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002833 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002834
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002835 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002836}
2837
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002838TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002839{
2840 for (const auto &eqFunction : mArrayEqualityFunctions)
2841 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002842 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002843 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002844 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002845 }
2846 }
2847
2848 const TString &typeName = TypeString(type);
2849
Olli Etuaho12690762015-03-31 12:55:28 +03002850 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002851 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002852
2853 TInfoSinkBase fnNameOut;
2854 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002855 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002856
2857 TType nonArrayType = type;
2858 nonArrayType.clearArrayness();
2859
2860 TInfoSinkBase fnOut;
2861
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002862 fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize()
2863 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002864 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002865 " for (int i = 0; i < "
2866 << type.getArraySize() << "; ++i)\n"
2867 " {\n"
2868 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002869
2870 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2871 fnOut << "a[i]";
2872 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2873 fnOut << "b[i]";
2874 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2875
2876 fnOut << ") { return false; }\n"
2877 " }\n"
2878 " return true;\n"
2879 "}\n";
2880
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002881 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002882
2883 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002885
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002886 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002887}
2888
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002889TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002890{
2891 for (const auto &assignFunction : mArrayAssignmentFunctions)
2892 {
2893 if (assignFunction.type == type)
2894 {
2895 return assignFunction.functionName;
2896 }
2897 }
2898
2899 const TString &typeName = TypeString(type);
2900
2901 ArrayHelperFunction function;
2902 function.type = type;
2903
2904 TInfoSinkBase fnNameOut;
2905 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
2906 function.functionName = fnNameOut.c_str();
2907
2908 TInfoSinkBase fnOut;
2909
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002910 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2911 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
2912 << "{\n"
2913 " for (int i = 0; i < "
2914 << type.getArraySize() << "; ++i)\n"
2915 " {\n"
2916 " a[i] = b[i];\n"
2917 " }\n"
2918 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002919
2920 function.functionDefinition = fnOut.c_str();
2921
2922 mArrayAssignmentFunctions.push_back(function);
2923
2924 return function.functionName;
2925}
2926
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002927TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002928{
2929 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2930 {
2931 if (constructIntoFunction.type == type)
2932 {
2933 return constructIntoFunction.functionName;
2934 }
2935 }
2936
2937 const TString &typeName = TypeString(type);
2938
2939 ArrayHelperFunction function;
2940 function.type = type;
2941
2942 TInfoSinkBase fnNameOut;
2943 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2944 function.functionName = fnNameOut.c_str();
2945
2946 TInfoSinkBase fnOut;
2947
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002948 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2949 << "]";
Olli Etuaho856c4972016-08-08 11:38:39 +03002950 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002951 {
2952 fnOut << ", " << typeName << " b" << i;
2953 }
2954 fnOut << ")\n"
2955 "{\n";
2956
Olli Etuaho856c4972016-08-08 11:38:39 +03002957 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002958 {
2959 fnOut << " a[" << i << "] = b" << i << ";\n";
2960 }
2961 fnOut << "}\n";
2962
2963 function.functionDefinition = fnOut.c_str();
2964
2965 mArrayConstructIntoFunctions.push_back(function);
2966
2967 return function.functionName;
2968}
2969
Jamie Madill2e295e22015-04-29 10:41:33 -04002970void OutputHLSL::ensureStructDefined(const TType &type)
2971{
2972 TStructure *structure = type.getStruct();
2973
2974 if (structure)
2975 {
2976 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
2977 }
2978}
2979
Jamie Madill45bcc782016-11-07 13:58:48 -05002980} // namespace sh