blob: 60dcfd31920dbbed9f4e03411530fd8971b1bab5 [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
134 mExcessiveLoopIndex = NULL;
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);
642 if (mUsesNumWorkGroups)
643 {
644 out << "cbuffer DriverConstants : register(b1)\n"
645 "{\n";
646 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
647 out << "};\n";
648 }
649
650 // Follow built-in variables would be initialized in
651 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
652 // are used in compute shader.
653 if (mUsesWorkGroupID)
654 {
655 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
656 }
657
658 if (mUsesLocalInvocationID)
659 {
660 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
661 }
662
663 if (mUsesGlobalInvocationID)
664 {
665 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
666 }
667
668 if (mUsesLocalInvocationIndex)
669 {
670 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
671 }
672 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000673
Geoff Lang1fe74c72016-08-25 13:23:01 -0400674 bool getDimensionsIgnoresBaseLevel =
675 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
676 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000677
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000678 if (mUsesFragCoord)
679 {
680 out << "#define GL_USES_FRAG_COORD\n";
681 }
682
683 if (mUsesPointCoord)
684 {
685 out << "#define GL_USES_POINT_COORD\n";
686 }
687
688 if (mUsesFrontFacing)
689 {
690 out << "#define GL_USES_FRONT_FACING\n";
691 }
692
693 if (mUsesPointSize)
694 {
695 out << "#define GL_USES_POINT_SIZE\n";
696 }
697
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400698 if (mUsesFragDepth)
699 {
700 out << "#define GL_USES_FRAG_DEPTH\n";
701 }
702
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000703 if (mUsesDepthRange)
704 {
705 out << "#define GL_USES_DEPTH_RANGE\n";
706 }
707
Xinghua Caob1239382016-12-13 15:07:05 +0800708 if (mUsesNumWorkGroups)
709 {
710 out << "#define GL_USES_NUM_WORK_GROUPS\n";
711 }
712
713 if (mUsesWorkGroupID)
714 {
715 out << "#define GL_USES_WORK_GROUP_ID\n";
716 }
717
718 if (mUsesLocalInvocationID)
719 {
720 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
721 }
722
723 if (mUsesGlobalInvocationID)
724 {
725 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
726 }
727
728 if (mUsesLocalInvocationIndex)
729 {
730 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
731 }
732
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000733 if (mUsesXor)
734 {
735 out << "bool xor(bool p, bool q)\n"
736 "{\n"
737 " return (p || q) && !(p && q);\n"
738 "}\n"
739 "\n";
740 }
741
Olli Etuahodfa75e82017-01-23 09:43:06 -0800742 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743}
744
745void OutputHLSL::visitSymbol(TIntermSymbol *node)
746{
Jamie Madill32aab012015-01-27 14:12:26 -0500747 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000748
Jamie Madill570e04d2013-06-21 09:15:33 -0400749 // Handle accessing std140 structs by value
750 if (mFlaggedStructMappedNames.count(node) > 0)
751 {
752 out << mFlaggedStructMappedNames[node];
753 return;
754 }
755
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756 TString name = node->getSymbol();
757
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000758 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000759 {
760 mUsesDepthRange = true;
761 out << name;
762 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000763 else
764 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000765 TQualifier qualifier = node->getQualifier();
766
767 if (qualifier == EvqUniform)
768 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400770 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400771
772 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000773 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400774 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000775 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000776 else
777 {
778 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000779 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400780
Jamie Madill2e295e22015-04-29 10:41:33 -0400781 ensureStructDefined(nodeType);
782
Olli Etuaho96963162016-03-21 11:54:33 +0200783 const TName &nameWithMetadata = node->getName();
784 out << DecorateUniform(nameWithMetadata, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000785 }
Jamie Madill19571812013-08-12 15:26:34 -0700786 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000787 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000788 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400789 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000790 }
Jamie Madill033dae62014-06-18 12:56:28 -0400791 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000792 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000793 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400794 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000795 }
Jamie Madill19571812013-08-12 15:26:34 -0700796 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400797 {
798 mReferencedOutputVariables[name] = node;
799 out << "out_" << name;
800 }
801 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000802 {
803 out << "gl_Color[0]";
804 mUsesFragColor = true;
805 }
806 else if (qualifier == EvqFragData)
807 {
808 out << "gl_Color";
809 mUsesFragData = true;
810 }
811 else if (qualifier == EvqFragCoord)
812 {
813 mUsesFragCoord = true;
814 out << name;
815 }
816 else if (qualifier == EvqPointCoord)
817 {
818 mUsesPointCoord = true;
819 out << name;
820 }
821 else if (qualifier == EvqFrontFacing)
822 {
823 mUsesFrontFacing = true;
824 out << name;
825 }
826 else if (qualifier == EvqPointSize)
827 {
828 mUsesPointSize = true;
829 out << name;
830 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000831 else if (qualifier == EvqInstanceID)
832 {
833 mUsesInstanceID = true;
834 out << name;
835 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500836 else if (qualifier == EvqVertexID)
837 {
838 mUsesVertexID = true;
839 out << name;
840 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300841 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400842 {
843 mUsesFragDepth = true;
844 out << "gl_Depth";
845 }
Xinghua Caob1239382016-12-13 15:07:05 +0800846 else if (qualifier == EvqNumWorkGroups)
847 {
848 mUsesNumWorkGroups = true;
849 out << name;
850 }
851 else if (qualifier == EvqWorkGroupID)
852 {
853 mUsesWorkGroupID = true;
854 out << name;
855 }
856 else if (qualifier == EvqLocalInvocationID)
857 {
858 mUsesLocalInvocationID = true;
859 out << name;
860 }
861 else if (qualifier == EvqGlobalInvocationID)
862 {
863 mUsesGlobalInvocationID = true;
864 out << name;
865 }
866 else if (qualifier == EvqLocalInvocationIndex)
867 {
868 mUsesLocalInvocationIndex = true;
869 out << name;
870 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000871 else
872 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +0300873 out << DecorateIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000874 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000875 }
876}
877
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400878void OutputHLSL::visitRaw(TIntermRaw *node)
879{
Jamie Madill32aab012015-01-27 14:12:26 -0500880 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400881}
882
Olli Etuaho7fb49552015-03-18 17:27:44 +0200883void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
884{
885 if (type.isScalar() && !type.isArray())
886 {
887 if (op == EOpEqual)
888 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500889 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200890 }
891 else
892 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500893 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200894 }
895 }
896 else
897 {
898 if (visit == PreVisit && op == EOpNotEqual)
899 {
900 out << "!";
901 }
902
903 if (type.isArray())
904 {
905 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500906 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200907 }
908 else if (type.getBasicType() == EbtStruct)
909 {
910 const TStructure &structure = *type.getStruct();
911 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500912 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200913 }
914 else
915 {
916 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500917 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200918 }
919 }
920}
921
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000922bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200923{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000924 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200925 {
926 TIntermNode *ancestor = getAncestorNode(n);
927 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
928 if (ancestorBinary == nullptr)
929 {
930 return false;
931 }
932 switch (ancestorBinary->getOp())
933 {
934 case EOpIndexDirectStruct:
935 {
936 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
937 const TIntermConstantUnion *index =
938 ancestorBinary->getRight()->getAsConstantUnion();
939 const TField *field = structure->fields()[index->getIConst(0)];
940 if (IsSampler(field->type()->getBasicType()))
941 {
942 return true;
943 }
944 break;
945 }
946 case EOpIndexDirect:
947 break;
948 default:
949 // Returning a sampler from indirect indexing is not supported.
950 return false;
951 }
952 }
953 return false;
954}
955
Olli Etuahob6fa0432016-09-28 16:28:05 +0100956bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
957{
958 TInfoSinkBase &out = getInfoSink();
959 if (visit == PostVisit)
960 {
961 out << ".";
962 node->writeOffsetsAsXYZW(&out);
963 }
964 return true;
965}
966
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000967bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
968{
Jamie Madill32aab012015-01-27 14:12:26 -0500969 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970
Jamie Madill570e04d2013-06-21 09:15:33 -0400971 // Handle accessing std140 structs by value
972 if (mFlaggedStructMappedNames.count(node) > 0)
973 {
974 out << mFlaggedStructMappedNames[node];
975 return false;
976 }
977
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978 switch (node->getOp())
979 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100980 case EOpComma:
981 outputTriplet(out, visit, "(", ", ", ")");
982 break;
983 case EOpAssign:
984 if (node->getLeft()->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +0300985 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100986 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
987 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +0300988 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100989 const TString &functionName = addArrayConstructIntoFunction(node->getType());
990 out << functionName << "(";
991 node->getLeft()->traverse(this);
992 TIntermSequence *seq = rightAgg->getSequence();
993 for (auto &arrayElement : *seq)
994 {
995 out << ", ";
996 arrayElement->traverse(this);
997 }
998 out << ")";
999 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001000 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001001 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1002 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001003 ASSERT(rightAgg == nullptr);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001004
1005 const TString &functionName = addArrayAssignmentFunction(node->getType());
1006 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho9638c352015-04-01 14:34:52 +03001007 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001008 else
Jamie Madill37997142015-01-28 10:06:34 -05001009 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001010 outputTriplet(out, visit, "(", " = ", ")");
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001011 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001012 break;
1013 case EOpInitialize:
1014 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001015 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001016 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1017 ASSERT(symbolNode);
1018 TIntermTyped *expression = node->getRight();
1019
1020 // Global initializers must be constant at this point.
1021 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1022 canWriteAsHLSLLiteral(expression));
1023
1024 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1025 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1026 // new variable is created before the assignment is evaluated), so we need to
1027 // convert
1028 // this to "float t = x, x = t;".
1029 if (writeSameSymbolInitializer(out, symbolNode, expression))
1030 {
1031 // Skip initializing the rest of the expression
1032 return false;
1033 }
1034 else if (writeConstantInitialization(out, symbolNode, expression))
1035 {
1036 return false;
1037 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001038 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001039 else if (visit == InVisit)
1040 {
1041 out << " = ";
1042 }
1043 break;
1044 case EOpAddAssign:
1045 outputTriplet(out, visit, "(", " += ", ")");
1046 break;
1047 case EOpSubAssign:
1048 outputTriplet(out, visit, "(", " -= ", ")");
1049 break;
1050 case EOpMulAssign:
1051 outputTriplet(out, visit, "(", " *= ", ")");
1052 break;
1053 case EOpVectorTimesScalarAssign:
1054 outputTriplet(out, visit, "(", " *= ", ")");
1055 break;
1056 case EOpMatrixTimesScalarAssign:
1057 outputTriplet(out, visit, "(", " *= ", ")");
1058 break;
1059 case EOpVectorTimesMatrixAssign:
1060 if (visit == PreVisit)
1061 {
1062 out << "(";
1063 }
1064 else if (visit == InVisit)
1065 {
1066 out << " = mul(";
1067 node->getLeft()->traverse(this);
1068 out << ", transpose(";
1069 }
1070 else
1071 {
1072 out << ")))";
1073 }
1074 break;
1075 case EOpMatrixTimesMatrixAssign:
1076 if (visit == PreVisit)
1077 {
1078 out << "(";
1079 }
1080 else if (visit == InVisit)
1081 {
1082 out << " = transpose(mul(transpose(";
1083 node->getLeft()->traverse(this);
1084 out << "), transpose(";
1085 }
1086 else
1087 {
1088 out << "))))";
1089 }
1090 break;
1091 case EOpDivAssign:
1092 outputTriplet(out, visit, "(", " /= ", ")");
1093 break;
1094 case EOpIModAssign:
1095 outputTriplet(out, visit, "(", " %= ", ")");
1096 break;
1097 case EOpBitShiftLeftAssign:
1098 outputTriplet(out, visit, "(", " <<= ", ")");
1099 break;
1100 case EOpBitShiftRightAssign:
1101 outputTriplet(out, visit, "(", " >>= ", ")");
1102 break;
1103 case EOpBitwiseAndAssign:
1104 outputTriplet(out, visit, "(", " &= ", ")");
1105 break;
1106 case EOpBitwiseXorAssign:
1107 outputTriplet(out, visit, "(", " ^= ", ")");
1108 break;
1109 case EOpBitwiseOrAssign:
1110 outputTriplet(out, visit, "(", " |= ", ")");
1111 break;
1112 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001113 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001114 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001115 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001116 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001117 if (visit == PreVisit)
1118 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001119 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001120 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001121 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] =
1122 node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001123 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001124 return false;
1125 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001126 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001127 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001128 {
1129 // All parts of an expression that access a sampler in a struct need to use _ as
1130 // separator to access the sampler variable that has been moved out of the struct.
1131 outputTriplet(out, visit, "", "_", "");
1132 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001133 else
1134 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001135 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001136 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001137 }
1138 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001139 case EOpIndexIndirect:
1140 // We do not currently support indirect references to interface blocks
1141 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1142 outputTriplet(out, visit, "", "[", "]");
1143 break;
1144 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001145 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001146 const TStructure *structure = node->getLeft()->getType().getStruct();
1147 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1148 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001149
Olli Etuaho96963162016-03-21 11:54:33 +02001150 // In cases where indexing returns a sampler, we need to access the sampler variable
1151 // that has been moved out of the struct.
1152 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1153 if (visit == PreVisit && indexingReturnsSampler)
1154 {
1155 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1156 // This prefix is only output at the beginning of the indexing expression, which
1157 // may have multiple parts.
1158 out << "angle";
1159 }
1160 if (!indexingReturnsSampler)
1161 {
1162 // All parts of an expression that access a sampler in a struct need to use _ as
1163 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001164 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001165 }
1166 if (visit == InVisit)
1167 {
1168 if (indexingReturnsSampler)
1169 {
1170 out << "_" + field->name();
1171 }
1172 else
1173 {
1174 out << "." + DecorateField(field->name(), *structure);
1175 }
1176
1177 return false;
1178 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001179 }
1180 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001181 case EOpIndexDirectInterfaceBlock:
1182 if (visit == InVisit)
1183 {
1184 const TInterfaceBlock *interfaceBlock =
1185 node->getLeft()->getType().getInterfaceBlock();
1186 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1187 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1188 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001189
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001190 return false;
1191 }
1192 break;
1193 case EOpAdd:
1194 outputTriplet(out, visit, "(", " + ", ")");
1195 break;
1196 case EOpSub:
1197 outputTriplet(out, visit, "(", " - ", ")");
1198 break;
1199 case EOpMul:
1200 outputTriplet(out, visit, "(", " * ", ")");
1201 break;
1202 case EOpDiv:
1203 outputTriplet(out, visit, "(", " / ", ")");
1204 break;
1205 case EOpIMod:
1206 outputTriplet(out, visit, "(", " % ", ")");
1207 break;
1208 case EOpBitShiftLeft:
1209 outputTriplet(out, visit, "(", " << ", ")");
1210 break;
1211 case EOpBitShiftRight:
1212 outputTriplet(out, visit, "(", " >> ", ")");
1213 break;
1214 case EOpBitwiseAnd:
1215 outputTriplet(out, visit, "(", " & ", ")");
1216 break;
1217 case EOpBitwiseXor:
1218 outputTriplet(out, visit, "(", " ^ ", ")");
1219 break;
1220 case EOpBitwiseOr:
1221 outputTriplet(out, visit, "(", " | ", ")");
1222 break;
1223 case EOpEqual:
1224 case EOpNotEqual:
1225 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1226 break;
1227 case EOpLessThan:
1228 outputTriplet(out, visit, "(", " < ", ")");
1229 break;
1230 case EOpGreaterThan:
1231 outputTriplet(out, visit, "(", " > ", ")");
1232 break;
1233 case EOpLessThanEqual:
1234 outputTriplet(out, visit, "(", " <= ", ")");
1235 break;
1236 case EOpGreaterThanEqual:
1237 outputTriplet(out, visit, "(", " >= ", ")");
1238 break;
1239 case EOpVectorTimesScalar:
1240 outputTriplet(out, visit, "(", " * ", ")");
1241 break;
1242 case EOpMatrixTimesScalar:
1243 outputTriplet(out, visit, "(", " * ", ")");
1244 break;
1245 case EOpVectorTimesMatrix:
1246 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1247 break;
1248 case EOpMatrixTimesVector:
1249 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1250 break;
1251 case EOpMatrixTimesMatrix:
1252 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1253 break;
1254 case EOpLogicalOr:
1255 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1256 // been unfolded.
1257 ASSERT(!node->getRight()->hasSideEffects());
1258 outputTriplet(out, visit, "(", " || ", ")");
1259 return true;
1260 case EOpLogicalXor:
1261 mUsesXor = true;
1262 outputTriplet(out, visit, "xor(", ", ", ")");
1263 break;
1264 case EOpLogicalAnd:
1265 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1266 // been unfolded.
1267 ASSERT(!node->getRight()->hasSideEffects());
1268 outputTriplet(out, visit, "(", " && ", ")");
1269 return true;
1270 default:
1271 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001272 }
1273
1274 return true;
1275}
1276
1277bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1278{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001279 TInfoSinkBase &out = getInfoSink();
1280
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001281 switch (node->getOp())
1282 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001283 case EOpNegative:
1284 outputTriplet(out, visit, "(-", "", ")");
1285 break;
1286 case EOpPositive:
1287 outputTriplet(out, visit, "(+", "", ")");
1288 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001289 case EOpLogicalNot:
1290 outputTriplet(out, visit, "(!", "", ")");
1291 break;
1292 case EOpBitwiseNot:
1293 outputTriplet(out, visit, "(~", "", ")");
1294 break;
1295 case EOpPostIncrement:
1296 outputTriplet(out, visit, "(", "", "++)");
1297 break;
1298 case EOpPostDecrement:
1299 outputTriplet(out, visit, "(", "", "--)");
1300 break;
1301 case EOpPreIncrement:
1302 outputTriplet(out, visit, "(++", "", ")");
1303 break;
1304 case EOpPreDecrement:
1305 outputTriplet(out, visit, "(--", "", ")");
1306 break;
1307 case EOpRadians:
1308 outputTriplet(out, visit, "radians(", "", ")");
1309 break;
1310 case EOpDegrees:
1311 outputTriplet(out, visit, "degrees(", "", ")");
1312 break;
1313 case EOpSin:
1314 outputTriplet(out, visit, "sin(", "", ")");
1315 break;
1316 case EOpCos:
1317 outputTriplet(out, visit, "cos(", "", ")");
1318 break;
1319 case EOpTan:
1320 outputTriplet(out, visit, "tan(", "", ")");
1321 break;
1322 case EOpAsin:
1323 outputTriplet(out, visit, "asin(", "", ")");
1324 break;
1325 case EOpAcos:
1326 outputTriplet(out, visit, "acos(", "", ")");
1327 break;
1328 case EOpAtan:
1329 outputTriplet(out, visit, "atan(", "", ")");
1330 break;
1331 case EOpSinh:
1332 outputTriplet(out, visit, "sinh(", "", ")");
1333 break;
1334 case EOpCosh:
1335 outputTriplet(out, visit, "cosh(", "", ")");
1336 break;
1337 case EOpTanh:
1338 outputTriplet(out, visit, "tanh(", "", ")");
1339 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001340 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001341 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001342 case EOpAtanh:
1343 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001344 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001345 break;
1346 case EOpExp:
1347 outputTriplet(out, visit, "exp(", "", ")");
1348 break;
1349 case EOpLog:
1350 outputTriplet(out, visit, "log(", "", ")");
1351 break;
1352 case EOpExp2:
1353 outputTriplet(out, visit, "exp2(", "", ")");
1354 break;
1355 case EOpLog2:
1356 outputTriplet(out, visit, "log2(", "", ")");
1357 break;
1358 case EOpSqrt:
1359 outputTriplet(out, visit, "sqrt(", "", ")");
1360 break;
1361 case EOpInverseSqrt:
1362 outputTriplet(out, visit, "rsqrt(", "", ")");
1363 break;
1364 case EOpAbs:
1365 outputTriplet(out, visit, "abs(", "", ")");
1366 break;
1367 case EOpSign:
1368 outputTriplet(out, visit, "sign(", "", ")");
1369 break;
1370 case EOpFloor:
1371 outputTriplet(out, visit, "floor(", "", ")");
1372 break;
1373 case EOpTrunc:
1374 outputTriplet(out, visit, "trunc(", "", ")");
1375 break;
1376 case EOpRound:
1377 outputTriplet(out, visit, "round(", "", ")");
1378 break;
1379 case EOpRoundEven:
1380 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001381 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001382 break;
1383 case EOpCeil:
1384 outputTriplet(out, visit, "ceil(", "", ")");
1385 break;
1386 case EOpFract:
1387 outputTriplet(out, visit, "frac(", "", ")");
1388 break;
1389 case EOpIsNan:
1390 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001391 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001392 else
1393 outputTriplet(out, visit, "isnan(", "", ")");
1394 mRequiresIEEEStrictCompiling = true;
1395 break;
1396 case EOpIsInf:
1397 outputTriplet(out, visit, "isinf(", "", ")");
1398 break;
1399 case EOpFloatBitsToInt:
1400 outputTriplet(out, visit, "asint(", "", ")");
1401 break;
1402 case EOpFloatBitsToUint:
1403 outputTriplet(out, visit, "asuint(", "", ")");
1404 break;
1405 case EOpIntBitsToFloat:
1406 outputTriplet(out, visit, "asfloat(", "", ")");
1407 break;
1408 case EOpUintBitsToFloat:
1409 outputTriplet(out, visit, "asfloat(", "", ")");
1410 break;
1411 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001412 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001413 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001414 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001415 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001417 case EOpPackUnorm4x8:
1418 case EOpPackSnorm4x8:
1419 case EOpUnpackUnorm4x8:
1420 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001421 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001422 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001423 break;
1424 case EOpLength:
1425 outputTriplet(out, visit, "length(", "", ")");
1426 break;
1427 case EOpNormalize:
1428 outputTriplet(out, visit, "normalize(", "", ")");
1429 break;
1430 case EOpDFdx:
1431 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1432 {
1433 outputTriplet(out, visit, "(", "", ", 0.0)");
1434 }
1435 else
1436 {
1437 outputTriplet(out, visit, "ddx(", "", ")");
1438 }
1439 break;
1440 case EOpDFdy:
1441 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1442 {
1443 outputTriplet(out, visit, "(", "", ", 0.0)");
1444 }
1445 else
1446 {
1447 outputTriplet(out, visit, "ddy(", "", ")");
1448 }
1449 break;
1450 case EOpFwidth:
1451 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1452 {
1453 outputTriplet(out, visit, "(", "", ", 0.0)");
1454 }
1455 else
1456 {
1457 outputTriplet(out, visit, "fwidth(", "", ")");
1458 }
1459 break;
1460 case EOpTranspose:
1461 outputTriplet(out, visit, "transpose(", "", ")");
1462 break;
1463 case EOpDeterminant:
1464 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1465 break;
1466 case EOpInverse:
1467 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001468 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001470
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 case EOpAny:
1472 outputTriplet(out, visit, "any(", "", ")");
1473 break;
1474 case EOpAll:
1475 outputTriplet(out, visit, "all(", "", ")");
1476 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001477 case EOpLogicalNotComponentWise:
1478 outputTriplet(out, visit, "(!", "", ")");
1479 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001480 case EOpBitfieldReverse:
1481 outputTriplet(out, visit, "reversebits(", "", ")");
1482 break;
1483 case EOpBitCount:
1484 outputTriplet(out, visit, "countbits(", "", ")");
1485 break;
1486 case EOpFindLSB:
1487 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1488 // in GLSLTest and results are consistent with GL.
1489 outputTriplet(out, visit, "firstbitlow(", "", ")");
1490 break;
1491 case EOpFindMSB:
1492 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1493 // tested in GLSLTest and results are consistent with GL.
1494 outputTriplet(out, visit, "firstbithigh(", "", ")");
1495 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 default:
1497 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001498 }
1499
1500 return true;
1501}
1502
Olli Etuaho96963162016-03-21 11:54:33 +02001503TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1504{
1505 if (node->getAsSymbolNode())
1506 {
1507 return node->getAsSymbolNode()->getSymbol();
1508 }
1509 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1510 switch (nodeBinary->getOp())
1511 {
1512 case EOpIndexDirect:
1513 {
1514 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1515
1516 TInfoSinkBase prefixSink;
1517 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1518 return TString(prefixSink.c_str());
1519 }
1520 case EOpIndexDirectStruct:
1521 {
1522 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1523 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1524 const TField *field = s->fields()[index];
1525
1526 TInfoSinkBase prefixSink;
1527 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1528 << field->name();
1529 return TString(prefixSink.c_str());
1530 }
1531 default:
1532 UNREACHABLE();
1533 return TString("");
1534 }
1535}
1536
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001537bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1538{
1539 TInfoSinkBase &out = getInfoSink();
1540
1541 if (mInsideFunction)
1542 {
1543 outputLineDirective(out, node->getLine().first_line);
1544 out << "{\n";
1545 }
1546
1547 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1548 sit != node->getSequence()->end(); sit++)
1549 {
1550 outputLineDirective(out, (*sit)->getLine().first_line);
1551
1552 (*sit)->traverse(this);
1553
1554 // Don't output ; after case labels, they're terminated by :
1555 // This is needed especially since outputting a ; after a case statement would turn empty
1556 // case statements into non-empty case statements, disallowing fall-through from them.
1557 // Also no need to output ; after if statements or sequences. This is done just for
1558 // code clarity.
1559 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1560 (*sit)->getAsBlock() == nullptr)
1561 out << ";\n";
1562 }
1563
1564 if (mInsideFunction)
1565 {
1566 outputLineDirective(out, node->getLine().last_line);
1567 out << "}\n";
1568 }
1569
1570 return false;
1571}
1572
Olli Etuaho336b1472016-10-05 16:37:55 +01001573bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1574{
1575 TInfoSinkBase &out = getInfoSink();
1576
1577 ASSERT(mCurrentFunctionMetadata == nullptr);
1578
1579 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1580 ASSERT(index != CallDAG::InvalidIndex);
1581 mCurrentFunctionMetadata = &mASTMetadataList[index];
1582
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001583 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001584
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001585 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001586
1587 if (node->getFunctionSymbolInfo()->isMain())
1588 {
1589 out << "gl_main(";
1590 }
1591 else
1592 {
1593 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
1594 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1595 }
1596
1597 for (unsigned int i = 0; i < parameters->size(); i++)
1598 {
1599 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1600
1601 if (symbol)
1602 {
1603 ensureStructDefined(symbol->getType());
1604
1605 out << argumentString(symbol);
1606
1607 if (i < parameters->size() - 1)
1608 {
1609 out << ", ";
1610 }
1611 }
1612 else
1613 UNREACHABLE();
1614 }
1615
1616 out << ")\n";
1617
1618 mInsideFunction = true;
1619 // The function body node will output braces.
1620 node->getBody()->traverse(this);
1621 mInsideFunction = false;
1622
1623 mCurrentFunctionMetadata = nullptr;
1624
1625 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1626 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1627 {
1628 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1629 mOutputLod0Function = true;
1630 node->traverse(this);
1631 mOutputLod0Function = false;
1632 }
1633
1634 return false;
1635}
1636
Olli Etuaho13389b62016-10-16 11:48:18 +01001637bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1638{
1639 TInfoSinkBase &out = getInfoSink();
1640 if (visit == PreVisit)
1641 {
1642 TIntermSequence *sequence = node->getSequence();
1643 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1644 ASSERT(sequence->size() == 1);
1645
1646 if (variable &&
1647 (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
1648 variable->getQualifier() == EvqConst))
1649 {
1650 ensureStructDefined(variable->getType());
1651
1652 if (!variable->getAsSymbolNode() ||
1653 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1654 {
1655 if (!mInsideFunction)
1656 {
1657 out << "static ";
1658 }
1659
1660 out << TypeString(variable->getType()) + " ";
1661
1662 TIntermSymbol *symbol = variable->getAsSymbolNode();
1663
1664 if (symbol)
1665 {
1666 symbol->traverse(this);
1667 out << ArrayString(symbol->getType());
1668 out << " = " + initializer(symbol->getType());
1669 }
1670 else
1671 {
1672 variable->traverse(this);
1673 }
1674 }
1675 else if (variable->getAsSymbolNode() &&
1676 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1677 {
1678 // Already added to constructor map
1679 }
1680 else
1681 UNREACHABLE();
1682 }
1683 else if (variable && IsVaryingOut(variable->getQualifier()))
1684 {
1685 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
1686 {
1687 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1688
1689 if (symbol)
1690 {
1691 // Vertex (output) varyings which are declared but not written to should
1692 // still be declared to allow successful linking
1693 mReferencedVaryings[symbol->getSymbol()] = symbol;
1694 }
1695 else
1696 {
1697 (*sit)->traverse(this);
1698 }
1699 }
1700 }
1701 }
1702 return false;
1703}
1704
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001705bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1706{
1707 // Do not do any translation
1708 return false;
1709}
1710
Olli Etuaho16c745a2017-01-16 17:02:27 +00001711bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1712{
1713 TInfoSinkBase &out = getInfoSink();
1714
1715 ASSERT(visit == PreVisit);
1716 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1717 // Skip the prototype if it is not implemented (and thus not used)
1718 if (index == CallDAG::InvalidIndex)
1719 {
1720 return false;
1721 }
1722
1723 TIntermSequence *arguments = node->getSequence();
1724
1725 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
1726 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1727 << (mOutputLod0Function ? "Lod0(" : "(");
1728
1729 for (unsigned int i = 0; i < arguments->size(); i++)
1730 {
1731 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1732 ASSERT(symbol != nullptr);
1733
1734 out << argumentString(symbol);
1735
1736 if (i < arguments->size() - 1)
1737 {
1738 out << ", ";
1739 }
1740 }
1741
1742 out << ");\n";
1743
1744 // Also prototype the Lod0 variant if needed
1745 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1746 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1747 {
1748 mOutputLod0Function = true;
1749 node->traverse(this);
1750 mOutputLod0Function = false;
1751 }
1752
1753 return false;
1754}
1755
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1757{
Jamie Madill32aab012015-01-27 14:12:26 -05001758 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001759
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760 switch (node->getOp())
1761 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001762 case EOpCallBuiltInFunction:
1763 case EOpCallFunctionInAST:
1764 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001765 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001766 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001767
Corentin Wallez1239ee92015-03-19 14:38:02 -07001768 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001769 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001770 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001771 if (node->isArray())
1772 {
1773 UNIMPLEMENTED();
1774 }
Olli Etuahobd674552016-10-06 13:28:42 +01001775 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001776 ASSERT(index != CallDAG::InvalidIndex);
1777 lod0 &= mASTMetadataList[index].mNeedsLod0;
1778
Olli Etuahobd674552016-10-06 13:28:42 +01001779 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001780 out << DisambiguateFunctionName(node->getSequence());
1781 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001782 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001783 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001784 {
1785 // This path is used for internal functions that don't have their definitions in the
1786 // AST, such as precision emulation functions.
Olli Etuahobd674552016-10-06 13:28:42 +01001787 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001788 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789 else
1790 {
Olli Etuahobd674552016-10-06 13:28:42 +01001791 TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001792 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001793 int coords = (*arguments)[1]->getAsTyped()->getNominalSize();
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001794 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1795 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1796 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001797 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001798
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001799 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001800 {
Olli Etuaho96963162016-03-21 11:54:33 +02001801 TIntermTyped *typedArg = (*arg)->getAsTyped();
1802 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001803 {
1804 out << "texture_";
1805 (*arg)->traverse(this);
1806 out << ", sampler_";
1807 }
1808
1809 (*arg)->traverse(this);
1810
Olli Etuaho96963162016-03-21 11:54:33 +02001811 if (typedArg->getType().isStructureContainingSamplers())
1812 {
1813 const TType &argType = typedArg->getType();
1814 TVector<TIntermSymbol *> samplerSymbols;
1815 TString structName = samplerNamePrefixFromStruct(typedArg);
1816 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho856c4972016-08-08 11:38:39 +03001817 argType.isArray() ? argType.getArraySize() : 0u,
Olli Etuaho96963162016-03-21 11:54:33 +02001818 &samplerSymbols, nullptr);
1819 for (const TIntermSymbol *sampler : samplerSymbols)
1820 {
1821 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1822 {
1823 out << ", texture_" << sampler->getSymbol();
1824 out << ", sampler_" << sampler->getSymbol();
1825 }
1826 else
1827 {
1828 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1829 // of D3D9, it's the sampler variable.
1830 out << ", " + sampler->getSymbol();
1831 }
1832 }
1833 }
1834
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001835 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001836 {
1837 out << ", ";
1838 }
1839 }
1840
1841 out << ")";
1842
1843 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001844 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001845 case EOpConstructFloat:
1846 outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
1847 break;
1848 case EOpConstructVec2:
1849 outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
1850 break;
1851 case EOpConstructVec3:
1852 outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
1853 break;
1854 case EOpConstructVec4:
1855 outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
1856 break;
1857 case EOpConstructBool:
1858 outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
1859 break;
1860 case EOpConstructBVec2:
1861 outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
1862 break;
1863 case EOpConstructBVec3:
1864 outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
1865 break;
1866 case EOpConstructBVec4:
1867 outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
1868 break;
1869 case EOpConstructInt:
1870 outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
1871 break;
1872 case EOpConstructIVec2:
1873 outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
1874 break;
1875 case EOpConstructIVec3:
1876 outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
1877 break;
1878 case EOpConstructIVec4:
1879 outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
1880 break;
1881 case EOpConstructUInt:
1882 outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
1883 break;
1884 case EOpConstructUVec2:
1885 outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
1886 break;
1887 case EOpConstructUVec3:
1888 outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
1889 break;
1890 case EOpConstructUVec4:
1891 outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
1892 break;
1893 case EOpConstructMat2:
1894 outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
1895 break;
1896 case EOpConstructMat2x3:
1897 outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
1898 break;
1899 case EOpConstructMat2x4:
1900 outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
1901 break;
1902 case EOpConstructMat3x2:
1903 outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
1904 break;
1905 case EOpConstructMat3:
1906 outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
1907 break;
1908 case EOpConstructMat3x4:
1909 outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
1910 break;
1911 case EOpConstructMat4x2:
1912 outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
1913 break;
1914 case EOpConstructMat4x3:
1915 outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
1916 break;
1917 case EOpConstructMat4:
1918 outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
1919 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001920 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04001921 {
Olli Etuahof40319e2015-03-10 14:33:00 +02001922 if (node->getType().isArray())
1923 {
1924 UNIMPLEMENTED();
1925 }
Jamie Madill033dae62014-06-18 12:56:28 -04001926 const TString &structName = StructNameString(*node->getType().getStruct());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001927 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001928 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Jamie Madillbfa91f42014-06-05 15:45:18 -04001929 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001930 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001931 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001932 outputTriplet(out, visit, "(", " == ", ")");
1933 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001934 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001935 outputTriplet(out, visit, "(", " != ", ")");
1936 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001937 case EOpLessThanComponentWise:
1938 outputTriplet(out, visit, "(", " < ", ")");
1939 break;
1940 case EOpGreaterThanComponentWise:
1941 outputTriplet(out, visit, "(", " > ", ")");
1942 break;
1943 case EOpLessThanEqualComponentWise:
1944 outputTriplet(out, visit, "(", " <= ", ")");
1945 break;
1946 case EOpGreaterThanEqualComponentWise:
1947 outputTriplet(out, visit, "(", " >= ", ")");
1948 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001949 case EOpMod:
1950 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001951 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001952 break;
1953 case EOpModf:
1954 outputTriplet(out, visit, "modf(", ", ", ")");
1955 break;
1956 case EOpPow:
1957 outputTriplet(out, visit, "pow(", ", ", ")");
1958 break;
1959 case EOpAtan:
1960 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1961 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001962 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001963 break;
1964 case EOpMin:
1965 outputTriplet(out, visit, "min(", ", ", ")");
1966 break;
1967 case EOpMax:
1968 outputTriplet(out, visit, "max(", ", ", ")");
1969 break;
1970 case EOpClamp:
1971 outputTriplet(out, visit, "clamp(", ", ", ")");
1972 break;
1973 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301974 {
1975 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1976 if (lastParamNode->getType().getBasicType() == EbtBool)
1977 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001978 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1979 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301980 // so use emulated version.
1981 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001982 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301983 }
1984 else
1985 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001986 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301987 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001988 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301989 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001990 case EOpStep:
1991 outputTriplet(out, visit, "step(", ", ", ")");
1992 break;
1993 case EOpSmoothStep:
1994 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1995 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001996 case EOpFrexp:
1997 case EOpLdexp:
1998 ASSERT(node->getUseEmulatedFunction());
1999 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2000 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002001 case EOpDistance:
2002 outputTriplet(out, visit, "distance(", ", ", ")");
2003 break;
2004 case EOpDot:
2005 outputTriplet(out, visit, "dot(", ", ", ")");
2006 break;
2007 case EOpCross:
2008 outputTriplet(out, visit, "cross(", ", ", ")");
2009 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002010 case EOpFaceForward:
2011 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002012 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002013 break;
2014 case EOpReflect:
2015 outputTriplet(out, visit, "reflect(", ", ", ")");
2016 break;
2017 case EOpRefract:
2018 outputTriplet(out, visit, "refract(", ", ", ")");
2019 break;
2020 case EOpOuterProduct:
2021 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002022 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002023 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002024 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002025 outputTriplet(out, visit, "(", " * ", ")");
2026 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002027 case EOpBitfieldExtract:
2028 case EOpBitfieldInsert:
2029 case EOpUaddCarry:
2030 case EOpUsubBorrow:
2031 case EOpUmulExtended:
2032 case EOpImulExtended:
2033 ASSERT(node->getUseEmulatedFunction());
2034 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2035 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002036 default:
2037 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002038 }
2039
2040 return true;
2041}
2042
Olli Etuaho57961272016-09-14 13:57:46 +03002043void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002044{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002045 out << "if (";
2046
2047 node->getCondition()->traverse(this);
2048
2049 out << ")\n";
2050
Jamie Madill8c46ab12015-12-07 16:39:19 -05002051 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002052
2053 bool discard = false;
2054
2055 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002056 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002057 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002058 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002059
Olli Etuahoa6f22092015-05-08 18:31:10 +03002060 // Detect true discard
2061 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2062 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002063 else
2064 {
2065 // TODO(oetuaho): Check if the semicolon inside is necessary.
2066 // It's there as a result of conservative refactoring of the output.
2067 out << "{;}\n";
2068 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002069
Jamie Madill8c46ab12015-12-07 16:39:19 -05002070 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002071
Olli Etuahoa6f22092015-05-08 18:31:10 +03002072 if (node->getFalseBlock())
2073 {
2074 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002075
Jamie Madill8c46ab12015-12-07 16:39:19 -05002076 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002077
Olli Etuaho32db19b2016-10-04 14:43:16 +01002078 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002079 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002080
Jamie Madill8c46ab12015-12-07 16:39:19 -05002081 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002082
Olli Etuahoa6f22092015-05-08 18:31:10 +03002083 // Detect false discard
2084 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2085 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002086
Olli Etuahoa6f22092015-05-08 18:31:10 +03002087 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002088 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002089 {
2090 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002091 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002092}
2093
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002094bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2095{
2096 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2097 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2098 UNREACHABLE();
2099 return false;
2100}
2101
Olli Etuaho57961272016-09-14 13:57:46 +03002102bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002103{
2104 TInfoSinkBase &out = getInfoSink();
2105
Olli Etuaho3d932d82016-04-12 11:10:30 +03002106 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002107
2108 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002109 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002110 {
2111 out << "FLATTEN ";
2112 }
2113
Olli Etuaho57961272016-09-14 13:57:46 +03002114 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002115
2116 return false;
2117}
2118
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002119bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002120{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002121 TInfoSinkBase &out = getInfoSink();
2122
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002123 if (node->getStatementList())
2124 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002125 node->setStatementList(
2126 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002127 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002128 // The curly braces get written when visiting the statementList aggregate
2129 }
2130 else
2131 {
2132 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002133 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002134 }
2135 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002136}
2137
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002138bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002139{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002140 TInfoSinkBase &out = getInfoSink();
2141
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002142 if (node->hasCondition())
2143 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002144 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002145 return true;
2146 }
2147 else
2148 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002149 out << "default:\n";
2150 return false;
2151 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002152}
2153
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2155{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002156 TInfoSinkBase &out = getInfoSink();
2157 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002158}
2159
2160bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2161{
Nicolas Capens655fe362014-04-11 13:12:34 -04002162 mNestedLoopDepth++;
2163
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002164 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002165 mInsideDiscontinuousLoop =
2166 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002167
Jamie Madill8c46ab12015-12-07 16:39:19 -05002168 TInfoSinkBase &out = getInfoSink();
2169
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002170 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002171 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002172 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002173 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002174 mInsideDiscontinuousLoop = wasDiscontinuous;
2175 mNestedLoopDepth--;
2176
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002177 return false;
2178 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002179 }
2180
Corentin Wallez1239ee92015-03-19 14:38:02 -07002181 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002182 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002184 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002185
Jamie Madill8c46ab12015-12-07 16:39:19 -05002186 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002187 }
2188 else
2189 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002190 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002191
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002192 if (node->getInit())
2193 {
2194 node->getInit()->traverse(this);
2195 }
2196
2197 out << "; ";
2198
alokp@chromium.org52813552010-11-16 18:36:09 +00002199 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002201 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 }
2203
2204 out << "; ";
2205
alokp@chromium.org52813552010-11-16 18:36:09 +00002206 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002207 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002208 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002209 }
2210
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002211 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002212
Jamie Madill8c46ab12015-12-07 16:39:19 -05002213 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002214 }
2215
2216 if (node->getBody())
2217 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002218 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002219 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002220 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002221 else
2222 {
2223 // TODO(oetuaho): Check if the semicolon inside is necessary.
2224 // It's there as a result of conservative refactoring of the output.
2225 out << "{;}\n";
2226 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002227
Jamie Madill8c46ab12015-12-07 16:39:19 -05002228 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229
alokp@chromium.org52813552010-11-16 18:36:09 +00002230 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002231 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002232 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002233 out << "while(\n";
2234
alokp@chromium.org52813552010-11-16 18:36:09 +00002235 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002236
daniel@transgaming.com73536982012-03-21 20:45:49 +00002237 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238 }
2239
daniel@transgaming.com73536982012-03-21 20:45:49 +00002240 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002242 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002243 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002244
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002245 return false;
2246}
2247
2248bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2249{
Jamie Madill32aab012015-01-27 14:12:26 -05002250 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002251
2252 switch (node->getFlowOp())
2253 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002254 case EOpKill:
2255 outputTriplet(out, visit, "discard;\n", "", "");
2256 break;
2257 case EOpBreak:
2258 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002259 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002260 if (mNestedLoopDepth > 1)
2261 {
2262 mUsesNestedBreak = true;
2263 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002264
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002265 if (mExcessiveLoopIndex)
2266 {
2267 out << "{Break";
2268 mExcessiveLoopIndex->traverse(this);
2269 out << " = true; break;}\n";
2270 }
2271 else
2272 {
2273 out << "break;\n";
2274 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002275 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002276 break;
2277 case EOpContinue:
2278 outputTriplet(out, visit, "continue;\n", "", "");
2279 break;
2280 case EOpReturn:
2281 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002282 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002283 if (node->getExpression())
2284 {
2285 out << "return ";
2286 }
2287 else
2288 {
2289 out << "return;\n";
2290 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002291 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002292 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002293 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002294 if (node->getExpression())
2295 {
2296 out << ";\n";
2297 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002299 break;
2300 default:
2301 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302 }
2303
2304 return true;
2305}
2306
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002307// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002308// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2309// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002310bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002311{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002312 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002313
2314 // Parse loops of the form:
2315 // for(int index = initial; index [comparator] limit; index += increment)
2316 TIntermSymbol *index = NULL;
2317 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002318 int initial = 0;
2319 int limit = 0;
2320 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002321
2322 // Parse index name and intial value
2323 if (node->getInit())
2324 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002325 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002326
2327 if (init)
2328 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002329 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002330 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002331
2332 if (variable && variable->getQualifier() == EvqTemporary)
2333 {
2334 TIntermBinary *assign = variable->getAsBinaryNode();
2335
2336 if (assign->getOp() == EOpInitialize)
2337 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002338 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002339 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2340
2341 if (symbol && constant)
2342 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002343 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002344 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002345 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002346 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002347 }
2348 }
2349 }
2350 }
2351 }
2352 }
2353
2354 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002355 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002356 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002357 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002358
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002359 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2360 {
2361 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2362
2363 if (constant)
2364 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002365 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002366 {
2367 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002368 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002369 }
2370 }
2371 }
2372 }
2373
2374 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002375 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002376 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002377 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002378 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002379
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002380 if (binaryTerminal)
2381 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002382 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002383 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2384
2385 if (constant)
2386 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002387 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002388 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002389 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002390
2391 switch (op)
2392 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002393 case EOpAddAssign:
2394 increment = value;
2395 break;
2396 case EOpSubAssign:
2397 increment = -value;
2398 break;
2399 default:
2400 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002401 }
2402 }
2403 }
2404 }
2405 else if (unaryTerminal)
2406 {
2407 TOperator op = unaryTerminal->getOp();
2408
2409 switch (op)
2410 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002411 case EOpPostIncrement:
2412 increment = 1;
2413 break;
2414 case EOpPostDecrement:
2415 increment = -1;
2416 break;
2417 case EOpPreIncrement:
2418 increment = 1;
2419 break;
2420 case EOpPreDecrement:
2421 increment = -1;
2422 break;
2423 default:
2424 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002425 }
2426 }
2427 }
2428
2429 if (index != NULL && comparator != EOpNull && increment != 0)
2430 {
2431 if (comparator == EOpLessThanEqual)
2432 {
2433 comparator = EOpLessThan;
2434 limit += 1;
2435 }
2436
2437 if (comparator == EOpLessThan)
2438 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002439 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002440
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002441 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002442 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002443 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002444 }
2445
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002446 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002447 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002448
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002449 out << "{int ";
2450 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002451 out << ";\n"
2452 "bool Break";
2453 index->traverse(this);
2454 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002455
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002456 bool firstLoopFragment = true;
2457
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002458 while (iterations > 0)
2459 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002460 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002461
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002462 if (!firstLoopFragment)
2463 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002464 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002465 index->traverse(this);
2466 out << ") {\n";
2467 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002468
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002469 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002470 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002471 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002472 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002473
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002474 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002475 const char *unroll =
2476 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477
Corentin Wallez1239ee92015-03-19 14:38:02 -07002478 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479 index->traverse(this);
2480 out << " = ";
2481 out << initial;
2482
2483 out << "; ";
2484 index->traverse(this);
2485 out << " < ";
2486 out << clampedLimit;
2487
2488 out << "; ";
2489 index->traverse(this);
2490 out << " += ";
2491 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002492 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002493
Jamie Madill8c46ab12015-12-07 16:39:19 -05002494 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002495 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002496
2497 if (node->getBody())
2498 {
2499 node->getBody()->traverse(this);
2500 }
2501
Jamie Madill8c46ab12015-12-07 16:39:19 -05002502 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002503 out << ";}\n";
2504
2505 if (!firstLoopFragment)
2506 {
2507 out << "}\n";
2508 }
2509
2510 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002511
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002512 initial += MAX_LOOP_ITERATIONS * increment;
2513 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002514 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002515
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002516 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002517
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002518 mExcessiveLoopIndex = restoreIndex;
2519
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002520 return true;
2521 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002522 else
2523 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002524 }
2525
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002526 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002527}
2528
Jamie Madill8c46ab12015-12-07 16:39:19 -05002529void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2530 Visit visit,
2531 const char *preString,
2532 const char *inString,
2533 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002534{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002535 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002536 {
2537 out << preString;
2538 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002539 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002540 {
2541 out << inString;
2542 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002543 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002544 {
2545 out << postString;
2546 }
2547}
2548
Jamie Madill8c46ab12015-12-07 16:39:19 -05002549void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002550{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002551 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002552 {
Jamie Madill32aab012015-01-27 14:12:26 -05002553 out << "\n";
2554 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002555
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002556 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002557 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002558 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002559 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002560
Jamie Madill32aab012015-01-27 14:12:26 -05002561 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002562 }
2563}
2564
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002565TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2566{
2567 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002568 const TType &type = symbol->getType();
2569 const TName &name = symbol->getName();
2570 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002571
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002572 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002573 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002574 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002575 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002576 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002577 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002578 nameStr = DecorateIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002579 }
2580
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002581 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002582 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002583 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2584 {
2585 // Samplers are passed as indices to the sampler array.
2586 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2587 return "const uint " + nameStr + ArrayString(type);
2588 }
2589 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2590 {
2591 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2592 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2593 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2594 ArrayString(type);
2595 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002596 }
2597
Olli Etuaho96963162016-03-21 11:54:33 +02002598 TStringStream argString;
2599 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2600 << ArrayString(type);
2601
2602 // If the structure parameter contains samplers, they need to be passed into the function as
2603 // separate parameters. HLSL doesn't natively support samplers in structs.
2604 if (type.isStructureContainingSamplers())
2605 {
2606 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2607 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho856c4972016-08-08 11:38:39 +03002608 type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002609 for (const TIntermSymbol *sampler : samplerSymbols)
2610 {
2611 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2612 {
2613 argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
2614 }
2615 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2616 {
2617 const TType &samplerType = sampler->getType();
2618 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2619 type.getArraySize() == samplerType.getArraySize());
2620 ASSERT(IsSampler(samplerType.getBasicType()));
2621 argString << ", " << QualifierString(qualifier) << " "
2622 << TextureString(samplerType.getBasicType()) << " texture_"
2623 << sampler->getSymbol() << ArrayString(type) << ", "
2624 << QualifierString(qualifier) << " "
2625 << SamplerString(samplerType.getBasicType()) << " sampler_"
2626 << sampler->getSymbol() << ArrayString(type);
2627 }
2628 else
2629 {
2630 const TType &samplerType = sampler->getType();
2631 ASSERT((!type.isArray() && !samplerType.isArray()) ||
2632 type.getArraySize() == samplerType.getArraySize());
2633 ASSERT(IsSampler(samplerType.getBasicType()));
2634 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
2635 << " " << sampler->getSymbol() << ArrayString(type);
2636 }
2637 }
2638 }
2639
2640 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002641}
2642
2643TString OutputHLSL::initializer(const TType &type)
2644{
2645 TString string;
2646
Jamie Madill94bf7f22013-07-08 13:31:15 -04002647 size_t size = type.getObjectSize();
2648 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002649 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002650 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002651
Jamie Madill94bf7f22013-07-08 13:31:15 -04002652 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002653 {
2654 string += ", ";
2655 }
2656 }
2657
daniel@transgaming.comead23042010-04-29 03:35:36 +00002658 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002659}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002660
Jamie Madill8c46ab12015-12-07 16:39:19 -05002661void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2662 Visit visit,
2663 const TType &type,
2664 const char *name,
2665 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002666{
Olli Etuahof40319e2015-03-10 14:33:00 +02002667 if (type.isArray())
2668 {
2669 UNIMPLEMENTED();
2670 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002671
2672 if (visit == PreVisit)
2673 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002674 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002675
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002676 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002677 }
2678 else if (visit == InVisit)
2679 {
2680 out << ", ";
2681 }
2682 else if (visit == PostVisit)
2683 {
2684 out << ")";
2685 }
2686}
2687
Jamie Madill8c46ab12015-12-07 16:39:19 -05002688const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2689 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002690 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002691{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002692 const TConstantUnion *constUnionIterated = constUnion;
2693
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002694 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002695 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002696 {
Jamie Madill033dae62014-06-18 12:56:28 -04002697 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002698
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002699 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002700
Jamie Madill98493dd2013-07-08 14:39:03 -04002701 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002702 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002703 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002704 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002705
Jamie Madill98493dd2013-07-08 14:39:03 -04002706 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002707 {
2708 out << ", ";
2709 }
2710 }
2711
2712 out << ")";
2713 }
2714 else
2715 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002716 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002717 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002718
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002719 if (writeType)
2720 {
Jamie Madill033dae62014-06-18 12:56:28 -04002721 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002722 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002723 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002724 if (writeType)
2725 {
2726 out << ")";
2727 }
2728 }
2729
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002730 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002731}
2732
Olli Etuahod68924e2017-01-02 17:34:40 +00002733void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002734{
Olli Etuahod68924e2017-01-02 17:34:40 +00002735 if (visit == PreVisit)
2736 {
2737 const char *opStr = GetOperatorString(op);
2738 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2739 out << "(";
2740 }
2741 else
2742 {
2743 outputTriplet(out, visit, nullptr, ", ", ")");
2744 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002745}
2746
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002747bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2748 TIntermSymbol *symbolNode,
2749 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002750{
2751 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2752 expression->traverse(&searchSymbol);
2753
2754 if (searchSymbol.foundMatch())
2755 {
2756 // Type already printed
2757 out << "t" + str(mUniqueIndex) + " = ";
2758 expression->traverse(this);
2759 out << ", ";
2760 symbolNode->traverse(this);
2761 out << " = t" + str(mUniqueIndex);
2762
2763 mUniqueIndex++;
2764 return true;
2765 }
2766
2767 return false;
2768}
2769
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002770bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2771{
2772 // We support writing constant unions and constructors that only take constant unions as
2773 // parameters as HLSL literals.
Olli Etuahod4f4c112016-04-15 15:11:24 +03002774 return expression->getAsConstantUnion() ||
2775 expression->isConstructorWithOnlyConstantUnionParameters();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002776}
2777
2778bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2779 TIntermSymbol *symbolNode,
2780 TIntermTyped *expression)
2781{
2782 if (canWriteAsHLSLLiteral(expression))
2783 {
2784 symbolNode->traverse(this);
2785 if (expression->getType().isArray())
2786 {
2787 out << "[" << expression->getType().getArraySize() << "]";
2788 }
2789 out << " = {";
2790 if (expression->getAsConstantUnion())
2791 {
2792 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2793 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002794 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002795 }
2796 else
2797 {
2798 TIntermAggregate *constructor = expression->getAsAggregate();
2799 ASSERT(constructor != nullptr);
2800 for (TIntermNode *&node : *constructor->getSequence())
2801 {
2802 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2803 ASSERT(nodeConst);
2804 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002805 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002806 if (node != constructor->getSequence()->back())
2807 {
2808 out << ", ";
2809 }
2810 }
2811 }
2812 out << "}";
2813 return true;
2814 }
2815 return false;
2816}
2817
Jamie Madill55e79e02015-02-09 15:35:00 -05002818TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2819{
2820 const TFieldList &fields = structure.fields();
2821
2822 for (const auto &eqFunction : mStructEqualityFunctions)
2823 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002824 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002825 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002826 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002827 }
2828 }
2829
2830 const TString &structNameString = StructNameString(structure);
2831
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002832 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002833 function->structure = &structure;
2834 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002835
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002836 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002837
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002838 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2839 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002840 << "{\n"
2841 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002842
2843 for (size_t i = 0; i < fields.size(); i++)
2844 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002845 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002846 const TType *fieldType = field->type();
2847
2848 const TString &fieldNameA = "a." + Decorate(field->name());
2849 const TString &fieldNameB = "b." + Decorate(field->name());
2850
2851 if (i > 0)
2852 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002853 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002854 }
2855
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002856 fnOut << "(";
2857 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2858 fnOut << fieldNameA;
2859 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2860 fnOut << fieldNameB;
2861 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2862 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002863 }
2864
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002865 fnOut << ";\n"
2866 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002867
2868 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002869
2870 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002871 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002872
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002873 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002874}
2875
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002876TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002877{
2878 for (const auto &eqFunction : mArrayEqualityFunctions)
2879 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002880 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002881 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002882 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002883 }
2884 }
2885
2886 const TString &typeName = TypeString(type);
2887
Olli Etuaho12690762015-03-31 12:55:28 +03002888 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002889 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002890
2891 TInfoSinkBase fnNameOut;
2892 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002893 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002894
2895 TType nonArrayType = type;
2896 nonArrayType.clearArrayness();
2897
2898 TInfoSinkBase fnOut;
2899
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002900 fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize()
2901 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002902 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002903 " for (int i = 0; i < "
2904 << type.getArraySize() << "; ++i)\n"
2905 " {\n"
2906 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002907
2908 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2909 fnOut << "a[i]";
2910 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2911 fnOut << "b[i]";
2912 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2913
2914 fnOut << ") { return false; }\n"
2915 " }\n"
2916 " return true;\n"
2917 "}\n";
2918
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002919 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002920
2921 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002922 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002923
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002924 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002925}
2926
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002927TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002928{
2929 for (const auto &assignFunction : mArrayAssignmentFunctions)
2930 {
2931 if (assignFunction.type == type)
2932 {
2933 return assignFunction.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_assign_" << 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 << "], " << typeName << " b[" << type.getArraySize() << "])\n"
2950 << "{\n"
2951 " for (int i = 0; i < "
2952 << type.getArraySize() << "; ++i)\n"
2953 " {\n"
2954 " a[i] = b[i];\n"
2955 " }\n"
2956 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002957
2958 function.functionDefinition = fnOut.c_str();
2959
2960 mArrayAssignmentFunctions.push_back(function);
2961
2962 return function.functionName;
2963}
2964
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002965TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002966{
2967 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2968 {
2969 if (constructIntoFunction.type == type)
2970 {
2971 return constructIntoFunction.functionName;
2972 }
2973 }
2974
2975 const TString &typeName = TypeString(type);
2976
2977 ArrayHelperFunction function;
2978 function.type = type;
2979
2980 TInfoSinkBase fnNameOut;
2981 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2982 function.functionName = fnNameOut.c_str();
2983
2984 TInfoSinkBase fnOut;
2985
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002986 fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize()
2987 << "]";
Olli Etuaho856c4972016-08-08 11:38:39 +03002988 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002989 {
2990 fnOut << ", " << typeName << " b" << i;
2991 }
2992 fnOut << ")\n"
2993 "{\n";
2994
Olli Etuaho856c4972016-08-08 11:38:39 +03002995 for (unsigned int i = 0u; i < type.getArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002996 {
2997 fnOut << " a[" << i << "] = b" << i << ";\n";
2998 }
2999 fnOut << "}\n";
3000
3001 function.functionDefinition = fnOut.c_str();
3002
3003 mArrayConstructIntoFunctions.push_back(function);
3004
3005 return function.functionName;
3006}
3007
Jamie Madill2e295e22015-04-29 10:41:33 -04003008void OutputHLSL::ensureStructDefined(const TType &type)
3009{
3010 TStructure *structure = type.getStruct();
3011
3012 if (structure)
3013 {
3014 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3015 }
3016}
3017
Jamie Madill45bcc782016-11-07 13:58:48 -05003018} // namespace sh