blob: 9bcfe8ce0b771abdb8884114b68aacbb0d4c0d34 [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 Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
41 for (unsigned int arraySize : type.getArraySizes())
42 {
43 fnName << arraySize << "_";
44 }
45 fnName << TypeString(type);
46 return fnName.str();
47}
48
49} // anonymous namespace
50
Olli Etuaho56a2f952016-12-08 12:16:27 +000051void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030052{
Olli Etuaho56a2f952016-12-08 12:16:27 +000053 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
54 // regardless.
55 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
56 mOutputType == SH_HLSL_4_1_OUTPUT)
57 {
58 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
59 }
60 else
61 {
62 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
63 }
64}
Olli Etuaho4785fec2015-05-18 16:09:37 +030065
Olli Etuaho56a2f952016-12-08 12:16:27 +000066void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020067{
68 ASSERT(constUnion != nullptr);
69 switch (constUnion->getType())
70 {
71 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000072 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020073 break;
74 case EbtInt:
75 out << constUnion->getIConst();
76 break;
77 case EbtUInt:
78 out << constUnion->getUConst();
79 break;
80 case EbtBool:
81 out << constUnion->getBConst();
82 break;
83 default:
84 UNREACHABLE();
85 }
86}
87
Olli Etuaho56a2f952016-12-08 12:16:27 +000088const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
89 const TConstantUnion *const constUnion,
90 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020091{
92 const TConstantUnion *constUnionIterated = constUnion;
93 for (size_t i = 0; i < size; i++, constUnionIterated++)
94 {
Olli Etuaho56a2f952016-12-08 12:16:27 +000095 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +020096
97 if (i != size - 1)
98 {
99 out << ", ";
100 }
101 }
102 return constUnionIterated;
103}
104
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800105OutputHLSL::OutputHLSL(sh::GLenum shaderType,
106 int shaderVersion,
107 const TExtensionBehavior &extensionBehavior,
108 const char *sourcePath,
109 ShShaderOutput outputType,
110 int numRenderTargets,
111 const std::vector<Uniform> &uniforms,
112 ShCompileOptions compileOptions)
Jamie Madill54ad4f82014-09-03 09:40:46 -0400113 : TIntermTraverser(true, true, true),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200114 mShaderType(shaderType),
115 mShaderVersion(shaderVersion),
116 mExtensionBehavior(extensionBehavior),
117 mSourcePath(sourcePath),
118 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700119 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000120 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700121 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000123 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000124
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500125 mUsesFragColor = false;
126 mUsesFragData = false;
127 mUsesDepthRange = false;
128 mUsesFragCoord = false;
129 mUsesPointCoord = false;
130 mUsesFrontFacing = false;
131 mUsesPointSize = false;
132 mUsesInstanceID = false;
Martin Radev41ac68e2017-06-06 12:16:58 +0300133 mHasMultiviewExtensionEnabled = IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview") ||
134 IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview2");
135 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500136 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500137 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800138 mUsesNumWorkGroups = false;
139 mUsesWorkGroupID = false;
140 mUsesLocalInvocationID = false;
141 mUsesGlobalInvocationID = false;
142 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500143 mUsesXor = false;
144 mUsesDiscardRewriting = false;
145 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530146 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000147
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000148 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000149
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500150 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000151 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500152 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000153
Yunchao Hed7297bf2017-04-19 15:27:10 +0800154 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000155
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500156 mStructureHLSL = new StructureHLSL;
157 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300158 mTextureFunctionHLSL = new TextureFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400159
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200160 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000161 {
Arun Patole63419392015-03-13 11:51:07 +0530162 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
164 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530165 // In both cases total 3 uniform registers need to be reserved.
166 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000167 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000168
Geoff Lang00140f42016-02-03 18:47:33 +0000169 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800170 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171}
172
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000173OutputHLSL::~OutputHLSL()
174{
Jamie Madill8daaba12014-06-13 10:04:33 -0400175 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400176 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300177 SafeDelete(mTextureFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200178 for (auto &eqFunction : mStructEqualityFunctions)
179 {
180 SafeDelete(eqFunction);
181 }
182 for (auto &eqFunction : mArrayEqualityFunctions)
183 {
184 SafeDelete(eqFunction);
185 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000186}
187
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200188void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000189{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500190 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400191 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000192
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200193 BuiltInFunctionEmulator builtInFunctionEmulator;
194 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800195 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
196 {
197 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
198 mShaderVersion);
199 }
200
Olli Etuahodfa75e82017-01-23 09:43:06 -0800201 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500202
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700203 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000204 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700205 ASSERT(success == CallDAG::INITDAG_SUCCESS);
206 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700207
Jamie Madill37997142015-01-28 10:06:34 -0500208 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500209 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200210 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500211 mInfoSinkStack.pop();
212
Jamie Madill37997142015-01-28 10:06:34 -0500213 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500214 mInfoSinkStack.pop();
215
Jamie Madill32aab012015-01-27 14:12:26 -0500216 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500217 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500218 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000219
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200220 objSink << mHeader.c_str();
221 objSink << mBody.c_str();
222 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200223
Olli Etuahodfa75e82017-01-23 09:43:06 -0800224 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000225}
226
Jamie Madill570e04d2013-06-21 09:15:33 -0400227void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
228{
229 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
230 {
231 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
232
Jamie Madill32aab012015-01-27 14:12:26 -0500233 TInfoSinkBase structInfoSink;
234 mInfoSinkStack.push(&structInfoSink);
235
Jamie Madill570e04d2013-06-21 09:15:33 -0400236 // This will mark the necessary block elements as referenced
237 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500238
239 TString structName(structInfoSink.c_str());
240 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400241
242 mFlaggedStructOriginalNames[flaggedNode] = structName;
243
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500244 for (size_t pos = structName.find('.'); pos != std::string::npos;
245 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400246 {
247 structName.erase(pos, 1);
248 }
249
250 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
251 }
252}
253
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800254const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400255{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800256 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400257}
258
Jamie Madill9fe25e92014-07-18 10:33:08 -0400259const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
260{
261 return mUniformHLSL->getUniformRegisterMap();
262}
263
Olli Etuahoed049ab2017-06-30 17:38:33 +0300264TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400265{
266 TString init;
267
Olli Etuahoed049ab2017-06-30 17:38:33 +0300268 TString indentString;
269 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400270 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300271 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400272 }
273
Olli Etuahoed049ab2017-06-30 17:38:33 +0300274 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400275 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300276 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300277 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400278 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300279 TStringStream indexedString;
280 indexedString << name << "[" << arrayIndex << "]";
281 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300282 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300283 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300284 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300285 {
286 init += ",";
287 }
288 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400289 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300292 else if (type.getBasicType() == EbtStruct)
293 {
294 init += indentString + "{\n";
295 const TStructure &structure = *type.getStruct();
296 const TFieldList &fields = structure.fields();
297 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
298 {
299 const TField &field = *fields[fieldIndex];
300 const TString &fieldName = name + "." + Decorate(field.name());
301 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400302
Olli Etuahoed049ab2017-06-30 17:38:33 +0300303 init += structInitializerString(indent + 1, fieldType, fieldName);
304 if (fieldIndex < fields.size() - 1)
305 {
306 init += ",";
307 }
308 init += "\n";
309 }
310 init += indentString + "}";
311 }
312 else
313 {
314 init += indentString + name;
315 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400316
317 return init;
318}
319
Jamie Madill8c46ab12015-12-07 16:39:19 -0500320void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000322 TString varyings;
323 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400324 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000325
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500326 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
327 mFlaggedStructMappedNames.begin();
328 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500330 TIntermTyped *structNode = flaggedStructIt->first;
331 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400332 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400333 const TString &originalName = mFlaggedStructOriginalNames[structNode];
334
Olli Etuahoed049ab2017-06-30 17:38:33 +0300335 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
336 if (structNode->isArray())
337 {
338 flaggedStructs += ArrayString(structNode->getType());
339 }
340 flaggedStructs += " =\n";
341 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
342 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 }
344
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500345 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
346 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000347 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500348 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000349 const TString &name = varying->second->getSymbol();
350
351 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500352 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
353 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000354 }
355
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500356 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
357 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000358 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500359 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000360 const TString &name = attribute->second->getSymbol();
361
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500362 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
363 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000364 }
365
Jamie Madill8daaba12014-06-13 10:04:33 -0400366 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400367
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200368 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800369 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400370
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200371 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500372 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200373 out << "\n// Equality functions\n\n";
374 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500375 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200376 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200377 }
378 }
Olli Etuaho12690762015-03-31 12:55:28 +0300379 if (!mArrayAssignmentFunctions.empty())
380 {
381 out << "\n// Assignment functions\n\n";
382 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
383 {
384 out << assignmentFunction.functionDefinition << "\n";
385 }
386 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300387 if (!mArrayConstructIntoFunctions.empty())
388 {
389 out << "\n// Array constructor functions\n\n";
390 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
391 {
392 out << constructIntoFunction.functionDefinition << "\n";
393 }
394 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200395
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500396 if (mUsesDiscardRewriting)
397 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400398 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500399 }
400
Nicolas Capens655fe362014-04-11 13:12:34 -0400401 if (mUsesNestedBreak)
402 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400403 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400404 }
405
Arun Patole44efa0b2015-03-04 17:11:05 +0530406 if (mRequiresIEEEStrictCompiling)
407 {
408 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
409 }
410
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400411 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
412 "#define LOOP [loop]\n"
413 "#define FLATTEN [flatten]\n"
414 "#else\n"
415 "#define LOOP\n"
416 "#define FLATTEN\n"
417 "#endif\n";
418
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200419 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200421 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500422 const bool usingMRTExtension = (iter != mExtensionBehavior.end() &&
423 (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000424
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000425 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500426 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400427 out << "\n";
428
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200429 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000430 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500431 for (ReferencedSymbols::const_iterator outputVariableIt =
432 mReferencedOutputVariables.begin();
433 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000434 {
Jamie Madill46131a32013-06-20 11:55:50 -0400435 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500436 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400437
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500438 out << "static " + TypeString(variableType) + " out_" + variableName +
439 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000440 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000441 }
Jamie Madill46131a32013-06-20 11:55:50 -0400442 else
443 {
444 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
445
446 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500447 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400448 for (unsigned int i = 0; i < numColorValues; i++)
449 {
450 out << " float4(0, 0, 0, 0)";
451 if (i + 1 != numColorValues)
452 {
453 out << ",";
454 }
455 out << "\n";
456 }
457
458 out << "};\n";
459 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000460
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400461 if (mUsesFragDepth)
462 {
463 out << "static float gl_Depth = 0.0;\n";
464 }
465
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000466 if (mUsesFragCoord)
467 {
468 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
469 }
470
471 if (mUsesPointCoord)
472 {
473 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
474 }
475
476 if (mUsesFrontFacing)
477 {
478 out << "static bool gl_FrontFacing = false;\n";
479 }
480
481 out << "\n";
482
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000483 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000484 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000485 out << "struct gl_DepthRangeParameters\n"
486 "{\n"
487 " float near;\n"
488 " float far;\n"
489 " float diff;\n"
490 "};\n"
491 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000492 }
493
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200494 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000495 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000496 out << "cbuffer DriverConstants : register(b1)\n"
497 "{\n";
498
499 if (mUsesDepthRange)
500 {
501 out << " float3 dx_DepthRange : packoffset(c0);\n";
502 }
503
504 if (mUsesFragCoord)
505 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000506 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000507 }
508
509 if (mUsesFragCoord || mUsesFrontFacing)
510 {
511 out << " float3 dx_DepthFront : packoffset(c2);\n";
512 }
513
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800514 if (mUsesFragCoord)
515 {
516 // dx_ViewScale is only used in the fragment shader to correct
517 // the value for glFragCoord if necessary
518 out << " float2 dx_ViewScale : packoffset(c3);\n";
519 }
520
Olli Etuaho618bebc2016-01-15 16:40:00 +0200521 if (mOutputType == SH_HLSL_4_1_OUTPUT)
522 {
523 mUniformHLSL->samplerMetadataUniforms(out, "c4");
524 }
525
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000526 out << "};\n";
527 }
528 else
529 {
530 if (mUsesDepthRange)
531 {
532 out << "uniform float3 dx_DepthRange : register(c0);";
533 }
534
535 if (mUsesFragCoord)
536 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000537 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000538 }
539
540 if (mUsesFragCoord || mUsesFrontFacing)
541 {
542 out << "uniform float3 dx_DepthFront : register(c2);\n";
543 }
544 }
545
546 out << "\n";
547
548 if (mUsesDepthRange)
549 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500550 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
551 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000552 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000553 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000554
Jamie Madillf91ce812014-06-13 10:04:34 -0400555 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000556 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400557 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000558 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400559 out << flaggedStructs;
560 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000561 }
562
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000563 if (usingMRTExtension && mNumRenderTargets > 1)
564 {
565 out << "#define GL_USES_MRT\n";
566 }
567
568 if (mUsesFragColor)
569 {
570 out << "#define GL_USES_FRAG_COLOR\n";
571 }
572
573 if (mUsesFragData)
574 {
575 out << "#define GL_USES_FRAG_DATA\n";
576 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000577 }
Xinghua Caob1239382016-12-13 15:07:05 +0800578 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000580 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500581 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000582 out << "\n"
583 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400584
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000585 if (mUsesPointSize)
586 {
587 out << "static float gl_PointSize = float(1);\n";
588 }
589
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000590 if (mUsesInstanceID)
591 {
592 out << "static int gl_InstanceID;";
593 }
594
Corentin Wallezb076add2016-01-11 16:45:46 -0500595 if (mUsesVertexID)
596 {
597 out << "static int gl_VertexID;";
598 }
599
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000600 out << "\n"
601 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500602 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000603 out << "\n";
604
605 if (mUsesDepthRange)
606 {
607 out << "struct gl_DepthRangeParameters\n"
608 "{\n"
609 " float near;\n"
610 " float far;\n"
611 " float diff;\n"
612 "};\n"
613 "\n";
614 }
615
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200616 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000617 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800618 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500619 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800620
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000621 if (mUsesDepthRange)
622 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800623 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000624 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800625
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800626 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
627 // shaders. However, we declare it for all shaders (including Feature Level 10+).
628 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
629 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800630 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800631 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800632 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800633
Olli Etuaho618bebc2016-01-15 16:40:00 +0200634 if (mOutputType == SH_HLSL_4_1_OUTPUT)
635 {
636 mUniformHLSL->samplerMetadataUniforms(out, "c4");
637 }
638
Austin Kinross4fd18b12014-12-22 12:32:05 -0800639 out << "};\n"
640 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000641 }
642 else
643 {
644 if (mUsesDepthRange)
645 {
646 out << "uniform float3 dx_DepthRange : register(c0);\n";
647 }
648
Cooper Partine6664f02015-01-09 16:22:24 -0800649 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
650 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000651 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000652 }
653
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000654 if (mUsesDepthRange)
655 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500656 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
657 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000658 "\n";
659 }
660
Jamie Madillf91ce812014-06-13 10:04:34 -0400661 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000662 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400663 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000664 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400665 out << flaggedStructs;
666 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000667 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400668 }
Xinghua Caob1239382016-12-13 15:07:05 +0800669 else // Compute shader
670 {
671 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800672
673 out << "cbuffer DriverConstants : register(b1)\n"
674 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800675 if (mUsesNumWorkGroups)
676 {
Xinghua Caob1239382016-12-13 15:07:05 +0800677 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800678 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800679 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
680 mUniformHLSL->samplerMetadataUniforms(out, "c1");
681 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800682
683 // Follow built-in variables would be initialized in
684 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
685 // are used in compute shader.
686 if (mUsesWorkGroupID)
687 {
688 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
689 }
690
691 if (mUsesLocalInvocationID)
692 {
693 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
694 }
695
696 if (mUsesGlobalInvocationID)
697 {
698 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
699 }
700
701 if (mUsesLocalInvocationIndex)
702 {
703 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
704 }
705 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000706
Geoff Lang1fe74c72016-08-25 13:23:01 -0400707 bool getDimensionsIgnoresBaseLevel =
708 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
709 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000710
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000711 if (mUsesFragCoord)
712 {
713 out << "#define GL_USES_FRAG_COORD\n";
714 }
715
716 if (mUsesPointCoord)
717 {
718 out << "#define GL_USES_POINT_COORD\n";
719 }
720
721 if (mUsesFrontFacing)
722 {
723 out << "#define GL_USES_FRONT_FACING\n";
724 }
725
726 if (mUsesPointSize)
727 {
728 out << "#define GL_USES_POINT_SIZE\n";
729 }
730
Martin Radev41ac68e2017-06-06 12:16:58 +0300731 if (mHasMultiviewExtensionEnabled)
732 {
733 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
734 }
735
736 if (mUsesViewID)
737 {
738 out << "#define GL_USES_VIEW_ID\n";
739 }
740
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400741 if (mUsesFragDepth)
742 {
743 out << "#define GL_USES_FRAG_DEPTH\n";
744 }
745
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000746 if (mUsesDepthRange)
747 {
748 out << "#define GL_USES_DEPTH_RANGE\n";
749 }
750
Xinghua Caob1239382016-12-13 15:07:05 +0800751 if (mUsesNumWorkGroups)
752 {
753 out << "#define GL_USES_NUM_WORK_GROUPS\n";
754 }
755
756 if (mUsesWorkGroupID)
757 {
758 out << "#define GL_USES_WORK_GROUP_ID\n";
759 }
760
761 if (mUsesLocalInvocationID)
762 {
763 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
764 }
765
766 if (mUsesGlobalInvocationID)
767 {
768 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
769 }
770
771 if (mUsesLocalInvocationIndex)
772 {
773 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
774 }
775
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000776 if (mUsesXor)
777 {
778 out << "bool xor(bool p, bool q)\n"
779 "{\n"
780 " return (p || q) && !(p && q);\n"
781 "}\n"
782 "\n";
783 }
784
Olli Etuahodfa75e82017-01-23 09:43:06 -0800785 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000786}
787
788void OutputHLSL::visitSymbol(TIntermSymbol *node)
789{
Jamie Madill32aab012015-01-27 14:12:26 -0500790 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000791
Jamie Madill570e04d2013-06-21 09:15:33 -0400792 // Handle accessing std140 structs by value
793 if (mFlaggedStructMappedNames.count(node) > 0)
794 {
795 out << mFlaggedStructMappedNames[node];
796 return;
797 }
798
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000799 TString name = node->getSymbol();
800
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000801 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000802 {
803 mUsesDepthRange = true;
804 out << name;
805 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806 else
807 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000808 TQualifier qualifier = node->getQualifier();
809
810 if (qualifier == EvqUniform)
811 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500812 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400813 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400814
815 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000816 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800817 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000818 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000819 else
820 {
821 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000822 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400823
Jamie Madill2e295e22015-04-29 10:41:33 -0400824 ensureStructDefined(nodeType);
825
Olli Etuahoff526f12017-06-30 12:26:54 +0300826 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000827 }
Jamie Madill19571812013-08-12 15:26:34 -0700828 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000829 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000830 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400831 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000832 }
Jamie Madill033dae62014-06-18 12:56:28 -0400833 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000834 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000835 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400836 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300837 if (name == "ViewID_OVR")
838 {
839 mUsesViewID = true;
840 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000841 }
Jamie Madill19571812013-08-12 15:26:34 -0700842 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400843 {
844 mReferencedOutputVariables[name] = node;
845 out << "out_" << name;
846 }
847 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000848 {
849 out << "gl_Color[0]";
850 mUsesFragColor = true;
851 }
852 else if (qualifier == EvqFragData)
853 {
854 out << "gl_Color";
855 mUsesFragData = true;
856 }
857 else if (qualifier == EvqFragCoord)
858 {
859 mUsesFragCoord = true;
860 out << name;
861 }
862 else if (qualifier == EvqPointCoord)
863 {
864 mUsesPointCoord = true;
865 out << name;
866 }
867 else if (qualifier == EvqFrontFacing)
868 {
869 mUsesFrontFacing = true;
870 out << name;
871 }
872 else if (qualifier == EvqPointSize)
873 {
874 mUsesPointSize = true;
875 out << name;
876 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000877 else if (qualifier == EvqInstanceID)
878 {
879 mUsesInstanceID = true;
880 out << name;
881 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500882 else if (qualifier == EvqVertexID)
883 {
884 mUsesVertexID = true;
885 out << name;
886 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300887 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400888 {
889 mUsesFragDepth = true;
890 out << "gl_Depth";
891 }
Xinghua Caob1239382016-12-13 15:07:05 +0800892 else if (qualifier == EvqNumWorkGroups)
893 {
894 mUsesNumWorkGroups = true;
895 out << name;
896 }
897 else if (qualifier == EvqWorkGroupID)
898 {
899 mUsesWorkGroupID = true;
900 out << name;
901 }
902 else if (qualifier == EvqLocalInvocationID)
903 {
904 mUsesLocalInvocationID = true;
905 out << name;
906 }
907 else if (qualifier == EvqGlobalInvocationID)
908 {
909 mUsesGlobalInvocationID = true;
910 out << name;
911 }
912 else if (qualifier == EvqLocalInvocationIndex)
913 {
914 mUsesLocalInvocationIndex = true;
915 out << name;
916 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000917 else
918 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300919 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000920 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921 }
922}
923
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400924void OutputHLSL::visitRaw(TIntermRaw *node)
925{
Jamie Madill32aab012015-01-27 14:12:26 -0500926 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400927}
928
Olli Etuaho7fb49552015-03-18 17:27:44 +0200929void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
930{
931 if (type.isScalar() && !type.isArray())
932 {
933 if (op == EOpEqual)
934 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500935 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200936 }
937 else
938 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500939 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200940 }
941 }
942 else
943 {
944 if (visit == PreVisit && op == EOpNotEqual)
945 {
946 out << "!";
947 }
948
949 if (type.isArray())
950 {
951 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500952 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200953 }
954 else if (type.getBasicType() == EbtStruct)
955 {
956 const TStructure &structure = *type.getStruct();
957 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500958 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200959 }
960 else
961 {
962 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500963 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200964 }
965 }
966}
967
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300968void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
969{
970 if (type.isArray())
971 {
972 const TString &functionName = addArrayAssignmentFunction(type);
973 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
974 }
975 else
976 {
977 outputTriplet(out, visit, "(", " = ", ")");
978 }
979}
980
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000981bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200982{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000983 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200984 {
985 TIntermNode *ancestor = getAncestorNode(n);
986 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
987 if (ancestorBinary == nullptr)
988 {
989 return false;
990 }
991 switch (ancestorBinary->getOp())
992 {
993 case EOpIndexDirectStruct:
994 {
995 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
996 const TIntermConstantUnion *index =
997 ancestorBinary->getRight()->getAsConstantUnion();
998 const TField *field = structure->fields()[index->getIConst(0)];
999 if (IsSampler(field->type()->getBasicType()))
1000 {
1001 return true;
1002 }
1003 break;
1004 }
1005 case EOpIndexDirect:
1006 break;
1007 default:
1008 // Returning a sampler from indirect indexing is not supported.
1009 return false;
1010 }
1011 }
1012 return false;
1013}
1014
Olli Etuahob6fa0432016-09-28 16:28:05 +01001015bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1016{
1017 TInfoSinkBase &out = getInfoSink();
1018 if (visit == PostVisit)
1019 {
1020 out << ".";
1021 node->writeOffsetsAsXYZW(&out);
1022 }
1023 return true;
1024}
1025
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001026bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1027{
Jamie Madill32aab012015-01-27 14:12:26 -05001028 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029
Jamie Madill570e04d2013-06-21 09:15:33 -04001030 // Handle accessing std140 structs by value
1031 if (mFlaggedStructMappedNames.count(node) > 0)
1032 {
1033 out << mFlaggedStructMappedNames[node];
1034 return false;
1035 }
1036
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001037 switch (node->getOp())
1038 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001039 case EOpComma:
1040 outputTriplet(out, visit, "(", ", ", ")");
1041 break;
1042 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001043 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001044 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001045 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1046 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001047 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001048 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1049 out << functionName << "(";
1050 node->getLeft()->traverse(this);
1051 TIntermSequence *seq = rightAgg->getSequence();
1052 for (auto &arrayElement : *seq)
1053 {
1054 out << ", ";
1055 arrayElement->traverse(this);
1056 }
1057 out << ")";
1058 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001059 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001060 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1061 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001062 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001063 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001064 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001065 break;
1066 case EOpInitialize:
1067 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001068 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001069 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1070 ASSERT(symbolNode);
1071 TIntermTyped *expression = node->getRight();
1072
1073 // Global initializers must be constant at this point.
1074 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1075 canWriteAsHLSLLiteral(expression));
1076
1077 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1078 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1079 // new variable is created before the assignment is evaluated), so we need to
1080 // convert
1081 // this to "float t = x, x = t;".
1082 if (writeSameSymbolInitializer(out, symbolNode, expression))
1083 {
1084 // Skip initializing the rest of the expression
1085 return false;
1086 }
1087 else if (writeConstantInitialization(out, symbolNode, expression))
1088 {
1089 return false;
1090 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001091 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001092 else if (visit == InVisit)
1093 {
1094 out << " = ";
1095 }
1096 break;
1097 case EOpAddAssign:
1098 outputTriplet(out, visit, "(", " += ", ")");
1099 break;
1100 case EOpSubAssign:
1101 outputTriplet(out, visit, "(", " -= ", ")");
1102 break;
1103 case EOpMulAssign:
1104 outputTriplet(out, visit, "(", " *= ", ")");
1105 break;
1106 case EOpVectorTimesScalarAssign:
1107 outputTriplet(out, visit, "(", " *= ", ")");
1108 break;
1109 case EOpMatrixTimesScalarAssign:
1110 outputTriplet(out, visit, "(", " *= ", ")");
1111 break;
1112 case EOpVectorTimesMatrixAssign:
1113 if (visit == PreVisit)
1114 {
1115 out << "(";
1116 }
1117 else if (visit == InVisit)
1118 {
1119 out << " = mul(";
1120 node->getLeft()->traverse(this);
1121 out << ", transpose(";
1122 }
1123 else
1124 {
1125 out << ")))";
1126 }
1127 break;
1128 case EOpMatrixTimesMatrixAssign:
1129 if (visit == PreVisit)
1130 {
1131 out << "(";
1132 }
1133 else if (visit == InVisit)
1134 {
1135 out << " = transpose(mul(transpose(";
1136 node->getLeft()->traverse(this);
1137 out << "), transpose(";
1138 }
1139 else
1140 {
1141 out << "))))";
1142 }
1143 break;
1144 case EOpDivAssign:
1145 outputTriplet(out, visit, "(", " /= ", ")");
1146 break;
1147 case EOpIModAssign:
1148 outputTriplet(out, visit, "(", " %= ", ")");
1149 break;
1150 case EOpBitShiftLeftAssign:
1151 outputTriplet(out, visit, "(", " <<= ", ")");
1152 break;
1153 case EOpBitShiftRightAssign:
1154 outputTriplet(out, visit, "(", " >>= ", ")");
1155 break;
1156 case EOpBitwiseAndAssign:
1157 outputTriplet(out, visit, "(", " &= ", ")");
1158 break;
1159 case EOpBitwiseXorAssign:
1160 outputTriplet(out, visit, "(", " ^= ", ")");
1161 break;
1162 case EOpBitwiseOrAssign:
1163 outputTriplet(out, visit, "(", " |= ", ")");
1164 break;
1165 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001166 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001167 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001168 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001169 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001170 if (visit == PreVisit)
1171 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001172 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001173 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001174 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001175 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001176 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001177 return false;
1178 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001179 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001180 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001181 {
1182 // All parts of an expression that access a sampler in a struct need to use _ as
1183 // separator to access the sampler variable that has been moved out of the struct.
1184 outputTriplet(out, visit, "", "_", "");
1185 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001186 else
1187 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001188 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001189 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001190 }
1191 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001192 case EOpIndexIndirect:
1193 // We do not currently support indirect references to interface blocks
1194 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1195 outputTriplet(out, visit, "", "[", "]");
1196 break;
1197 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001198 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001199 const TStructure *structure = node->getLeft()->getType().getStruct();
1200 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1201 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001202
Olli Etuaho96963162016-03-21 11:54:33 +02001203 // In cases where indexing returns a sampler, we need to access the sampler variable
1204 // that has been moved out of the struct.
1205 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1206 if (visit == PreVisit && indexingReturnsSampler)
1207 {
1208 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1209 // This prefix is only output at the beginning of the indexing expression, which
1210 // may have multiple parts.
1211 out << "angle";
1212 }
1213 if (!indexingReturnsSampler)
1214 {
1215 // All parts of an expression that access a sampler in a struct need to use _ as
1216 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001217 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001218 }
1219 if (visit == InVisit)
1220 {
1221 if (indexingReturnsSampler)
1222 {
1223 out << "_" + field->name();
1224 }
1225 else
1226 {
1227 out << "." + DecorateField(field->name(), *structure);
1228 }
1229
1230 return false;
1231 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001232 }
1233 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001234 case EOpIndexDirectInterfaceBlock:
1235 if (visit == InVisit)
1236 {
1237 const TInterfaceBlock *interfaceBlock =
1238 node->getLeft()->getType().getInterfaceBlock();
1239 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1240 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1241 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001242
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001243 return false;
1244 }
1245 break;
1246 case EOpAdd:
1247 outputTriplet(out, visit, "(", " + ", ")");
1248 break;
1249 case EOpSub:
1250 outputTriplet(out, visit, "(", " - ", ")");
1251 break;
1252 case EOpMul:
1253 outputTriplet(out, visit, "(", " * ", ")");
1254 break;
1255 case EOpDiv:
1256 outputTriplet(out, visit, "(", " / ", ")");
1257 break;
1258 case EOpIMod:
1259 outputTriplet(out, visit, "(", " % ", ")");
1260 break;
1261 case EOpBitShiftLeft:
1262 outputTriplet(out, visit, "(", " << ", ")");
1263 break;
1264 case EOpBitShiftRight:
1265 outputTriplet(out, visit, "(", " >> ", ")");
1266 break;
1267 case EOpBitwiseAnd:
1268 outputTriplet(out, visit, "(", " & ", ")");
1269 break;
1270 case EOpBitwiseXor:
1271 outputTriplet(out, visit, "(", " ^ ", ")");
1272 break;
1273 case EOpBitwiseOr:
1274 outputTriplet(out, visit, "(", " | ", ")");
1275 break;
1276 case EOpEqual:
1277 case EOpNotEqual:
1278 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1279 break;
1280 case EOpLessThan:
1281 outputTriplet(out, visit, "(", " < ", ")");
1282 break;
1283 case EOpGreaterThan:
1284 outputTriplet(out, visit, "(", " > ", ")");
1285 break;
1286 case EOpLessThanEqual:
1287 outputTriplet(out, visit, "(", " <= ", ")");
1288 break;
1289 case EOpGreaterThanEqual:
1290 outputTriplet(out, visit, "(", " >= ", ")");
1291 break;
1292 case EOpVectorTimesScalar:
1293 outputTriplet(out, visit, "(", " * ", ")");
1294 break;
1295 case EOpMatrixTimesScalar:
1296 outputTriplet(out, visit, "(", " * ", ")");
1297 break;
1298 case EOpVectorTimesMatrix:
1299 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1300 break;
1301 case EOpMatrixTimesVector:
1302 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1303 break;
1304 case EOpMatrixTimesMatrix:
1305 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1306 break;
1307 case EOpLogicalOr:
1308 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1309 // been unfolded.
1310 ASSERT(!node->getRight()->hasSideEffects());
1311 outputTriplet(out, visit, "(", " || ", ")");
1312 return true;
1313 case EOpLogicalXor:
1314 mUsesXor = true;
1315 outputTriplet(out, visit, "xor(", ", ", ")");
1316 break;
1317 case EOpLogicalAnd:
1318 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1319 // been unfolded.
1320 ASSERT(!node->getRight()->hasSideEffects());
1321 outputTriplet(out, visit, "(", " && ", ")");
1322 return true;
1323 default:
1324 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001325 }
1326
1327 return true;
1328}
1329
1330bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1331{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001332 TInfoSinkBase &out = getInfoSink();
1333
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 switch (node->getOp())
1335 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001336 case EOpNegative:
1337 outputTriplet(out, visit, "(-", "", ")");
1338 break;
1339 case EOpPositive:
1340 outputTriplet(out, visit, "(+", "", ")");
1341 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001342 case EOpLogicalNot:
1343 outputTriplet(out, visit, "(!", "", ")");
1344 break;
1345 case EOpBitwiseNot:
1346 outputTriplet(out, visit, "(~", "", ")");
1347 break;
1348 case EOpPostIncrement:
1349 outputTriplet(out, visit, "(", "", "++)");
1350 break;
1351 case EOpPostDecrement:
1352 outputTriplet(out, visit, "(", "", "--)");
1353 break;
1354 case EOpPreIncrement:
1355 outputTriplet(out, visit, "(++", "", ")");
1356 break;
1357 case EOpPreDecrement:
1358 outputTriplet(out, visit, "(--", "", ")");
1359 break;
1360 case EOpRadians:
1361 outputTriplet(out, visit, "radians(", "", ")");
1362 break;
1363 case EOpDegrees:
1364 outputTriplet(out, visit, "degrees(", "", ")");
1365 break;
1366 case EOpSin:
1367 outputTriplet(out, visit, "sin(", "", ")");
1368 break;
1369 case EOpCos:
1370 outputTriplet(out, visit, "cos(", "", ")");
1371 break;
1372 case EOpTan:
1373 outputTriplet(out, visit, "tan(", "", ")");
1374 break;
1375 case EOpAsin:
1376 outputTriplet(out, visit, "asin(", "", ")");
1377 break;
1378 case EOpAcos:
1379 outputTriplet(out, visit, "acos(", "", ")");
1380 break;
1381 case EOpAtan:
1382 outputTriplet(out, visit, "atan(", "", ")");
1383 break;
1384 case EOpSinh:
1385 outputTriplet(out, visit, "sinh(", "", ")");
1386 break;
1387 case EOpCosh:
1388 outputTriplet(out, visit, "cosh(", "", ")");
1389 break;
1390 case EOpTanh:
1391 outputTriplet(out, visit, "tanh(", "", ")");
1392 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001393 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001394 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001395 case EOpAtanh:
1396 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001397 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001398 break;
1399 case EOpExp:
1400 outputTriplet(out, visit, "exp(", "", ")");
1401 break;
1402 case EOpLog:
1403 outputTriplet(out, visit, "log(", "", ")");
1404 break;
1405 case EOpExp2:
1406 outputTriplet(out, visit, "exp2(", "", ")");
1407 break;
1408 case EOpLog2:
1409 outputTriplet(out, visit, "log2(", "", ")");
1410 break;
1411 case EOpSqrt:
1412 outputTriplet(out, visit, "sqrt(", "", ")");
1413 break;
1414 case EOpInverseSqrt:
1415 outputTriplet(out, visit, "rsqrt(", "", ")");
1416 break;
1417 case EOpAbs:
1418 outputTriplet(out, visit, "abs(", "", ")");
1419 break;
1420 case EOpSign:
1421 outputTriplet(out, visit, "sign(", "", ")");
1422 break;
1423 case EOpFloor:
1424 outputTriplet(out, visit, "floor(", "", ")");
1425 break;
1426 case EOpTrunc:
1427 outputTriplet(out, visit, "trunc(", "", ")");
1428 break;
1429 case EOpRound:
1430 outputTriplet(out, visit, "round(", "", ")");
1431 break;
1432 case EOpRoundEven:
1433 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001434 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001435 break;
1436 case EOpCeil:
1437 outputTriplet(out, visit, "ceil(", "", ")");
1438 break;
1439 case EOpFract:
1440 outputTriplet(out, visit, "frac(", "", ")");
1441 break;
1442 case EOpIsNan:
1443 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001444 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001445 else
1446 outputTriplet(out, visit, "isnan(", "", ")");
1447 mRequiresIEEEStrictCompiling = true;
1448 break;
1449 case EOpIsInf:
1450 outputTriplet(out, visit, "isinf(", "", ")");
1451 break;
1452 case EOpFloatBitsToInt:
1453 outputTriplet(out, visit, "asint(", "", ")");
1454 break;
1455 case EOpFloatBitsToUint:
1456 outputTriplet(out, visit, "asuint(", "", ")");
1457 break;
1458 case EOpIntBitsToFloat:
1459 outputTriplet(out, visit, "asfloat(", "", ")");
1460 break;
1461 case EOpUintBitsToFloat:
1462 outputTriplet(out, visit, "asfloat(", "", ")");
1463 break;
1464 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001465 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001466 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001467 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001468 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001470 case EOpPackUnorm4x8:
1471 case EOpPackSnorm4x8:
1472 case EOpUnpackUnorm4x8:
1473 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001474 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001475 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001476 break;
1477 case EOpLength:
1478 outputTriplet(out, visit, "length(", "", ")");
1479 break;
1480 case EOpNormalize:
1481 outputTriplet(out, visit, "normalize(", "", ")");
1482 break;
1483 case EOpDFdx:
1484 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1485 {
1486 outputTriplet(out, visit, "(", "", ", 0.0)");
1487 }
1488 else
1489 {
1490 outputTriplet(out, visit, "ddx(", "", ")");
1491 }
1492 break;
1493 case EOpDFdy:
1494 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1495 {
1496 outputTriplet(out, visit, "(", "", ", 0.0)");
1497 }
1498 else
1499 {
1500 outputTriplet(out, visit, "ddy(", "", ")");
1501 }
1502 break;
1503 case EOpFwidth:
1504 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1505 {
1506 outputTriplet(out, visit, "(", "", ", 0.0)");
1507 }
1508 else
1509 {
1510 outputTriplet(out, visit, "fwidth(", "", ")");
1511 }
1512 break;
1513 case EOpTranspose:
1514 outputTriplet(out, visit, "transpose(", "", ")");
1515 break;
1516 case EOpDeterminant:
1517 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1518 break;
1519 case EOpInverse:
1520 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001521 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001522 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001523
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001524 case EOpAny:
1525 outputTriplet(out, visit, "any(", "", ")");
1526 break;
1527 case EOpAll:
1528 outputTriplet(out, visit, "all(", "", ")");
1529 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001530 case EOpLogicalNotComponentWise:
1531 outputTriplet(out, visit, "(!", "", ")");
1532 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001533 case EOpBitfieldReverse:
1534 outputTriplet(out, visit, "reversebits(", "", ")");
1535 break;
1536 case EOpBitCount:
1537 outputTriplet(out, visit, "countbits(", "", ")");
1538 break;
1539 case EOpFindLSB:
1540 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1541 // in GLSLTest and results are consistent with GL.
1542 outputTriplet(out, visit, "firstbitlow(", "", ")");
1543 break;
1544 case EOpFindMSB:
1545 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1546 // tested in GLSLTest and results are consistent with GL.
1547 outputTriplet(out, visit, "firstbithigh(", "", ")");
1548 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 default:
1550 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001551 }
1552
1553 return true;
1554}
1555
Olli Etuaho96963162016-03-21 11:54:33 +02001556TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1557{
1558 if (node->getAsSymbolNode())
1559 {
1560 return node->getAsSymbolNode()->getSymbol();
1561 }
1562 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1563 switch (nodeBinary->getOp())
1564 {
1565 case EOpIndexDirect:
1566 {
1567 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1568
1569 TInfoSinkBase prefixSink;
1570 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1571 return TString(prefixSink.c_str());
1572 }
1573 case EOpIndexDirectStruct:
1574 {
1575 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1576 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1577 const TField *field = s->fields()[index];
1578
1579 TInfoSinkBase prefixSink;
1580 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1581 << field->name();
1582 return TString(prefixSink.c_str());
1583 }
1584 default:
1585 UNREACHABLE();
1586 return TString("");
1587 }
1588}
1589
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001590bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1591{
1592 TInfoSinkBase &out = getInfoSink();
1593
1594 if (mInsideFunction)
1595 {
1596 outputLineDirective(out, node->getLine().first_line);
1597 out << "{\n";
1598 }
1599
1600 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1601 sit != node->getSequence()->end(); sit++)
1602 {
1603 outputLineDirective(out, (*sit)->getLine().first_line);
1604
1605 (*sit)->traverse(this);
1606
1607 // Don't output ; after case labels, they're terminated by :
1608 // This is needed especially since outputting a ; after a case statement would turn empty
1609 // case statements into non-empty case statements, disallowing fall-through from them.
1610 // Also no need to output ; after if statements or sequences. This is done just for
1611 // code clarity.
1612 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1613 (*sit)->getAsBlock() == nullptr)
1614 out << ";\n";
1615 }
1616
1617 if (mInsideFunction)
1618 {
1619 outputLineDirective(out, node->getLine().last_line);
1620 out << "}\n";
1621 }
1622
1623 return false;
1624}
1625
Olli Etuaho336b1472016-10-05 16:37:55 +01001626bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1627{
1628 TInfoSinkBase &out = getInfoSink();
1629
1630 ASSERT(mCurrentFunctionMetadata == nullptr);
1631
1632 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1633 ASSERT(index != CallDAG::InvalidIndex);
1634 mCurrentFunctionMetadata = &mASTMetadataList[index];
1635
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001636 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001637
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001638 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001639
1640 if (node->getFunctionSymbolInfo()->isMain())
1641 {
1642 out << "gl_main(";
1643 }
1644 else
1645 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001646 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001647 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1648 }
1649
1650 for (unsigned int i = 0; i < parameters->size(); i++)
1651 {
1652 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1653
1654 if (symbol)
1655 {
1656 ensureStructDefined(symbol->getType());
1657
1658 out << argumentString(symbol);
1659
1660 if (i < parameters->size() - 1)
1661 {
1662 out << ", ";
1663 }
1664 }
1665 else
1666 UNREACHABLE();
1667 }
1668
1669 out << ")\n";
1670
1671 mInsideFunction = true;
1672 // The function body node will output braces.
1673 node->getBody()->traverse(this);
1674 mInsideFunction = false;
1675
1676 mCurrentFunctionMetadata = nullptr;
1677
1678 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1679 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1680 {
1681 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1682 mOutputLod0Function = true;
1683 node->traverse(this);
1684 mOutputLod0Function = false;
1685 }
1686
1687 return false;
1688}
1689
Olli Etuaho13389b62016-10-16 11:48:18 +01001690bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1691{
1692 TInfoSinkBase &out = getInfoSink();
1693 if (visit == PreVisit)
1694 {
1695 TIntermSequence *sequence = node->getSequence();
1696 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1697 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001698 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001699
Olli Etuaho282847e2017-07-12 14:11:01 +03001700 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001701 variable->getQualifier() == EvqConst))
1702 {
1703 ensureStructDefined(variable->getType());
1704
1705 if (!variable->getAsSymbolNode() ||
1706 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1707 {
1708 if (!mInsideFunction)
1709 {
1710 out << "static ";
1711 }
1712
1713 out << TypeString(variable->getType()) + " ";
1714
1715 TIntermSymbol *symbol = variable->getAsSymbolNode();
1716
1717 if (symbol)
1718 {
1719 symbol->traverse(this);
1720 out << ArrayString(symbol->getType());
1721 out << " = " + initializer(symbol->getType());
1722 }
1723 else
1724 {
1725 variable->traverse(this);
1726 }
1727 }
1728 else if (variable->getAsSymbolNode() &&
1729 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1730 {
1731 // Already added to constructor map
1732 }
1733 else
1734 UNREACHABLE();
1735 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001736 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001737 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001738 TIntermSymbol *symbol = variable->getAsSymbolNode();
1739 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001740
Olli Etuaho282847e2017-07-12 14:11:01 +03001741 // Vertex outputs which are declared but not written to should still be declared to
1742 // allow successful linking.
1743 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001744 }
1745 }
1746 return false;
1747}
1748
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001749bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1750{
1751 // Do not do any translation
1752 return false;
1753}
1754
Olli Etuaho16c745a2017-01-16 17:02:27 +00001755bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1756{
1757 TInfoSinkBase &out = getInfoSink();
1758
1759 ASSERT(visit == PreVisit);
1760 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1761 // Skip the prototype if it is not implemented (and thus not used)
1762 if (index == CallDAG::InvalidIndex)
1763 {
1764 return false;
1765 }
1766
1767 TIntermSequence *arguments = node->getSequence();
1768
Olli Etuahoff526f12017-06-30 12:26:54 +03001769 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001770 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1771 << (mOutputLod0Function ? "Lod0(" : "(");
1772
1773 for (unsigned int i = 0; i < arguments->size(); i++)
1774 {
1775 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1776 ASSERT(symbol != nullptr);
1777
1778 out << argumentString(symbol);
1779
1780 if (i < arguments->size() - 1)
1781 {
1782 out << ", ";
1783 }
1784 }
1785
1786 out << ");\n";
1787
1788 // Also prototype the Lod0 variant if needed
1789 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1790 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1791 {
1792 mOutputLod0Function = true;
1793 node->traverse(this);
1794 mOutputLod0Function = false;
1795 }
1796
1797 return false;
1798}
1799
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001800bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1801{
Jamie Madill32aab012015-01-27 14:12:26 -05001802 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001803
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001804 switch (node->getOp())
1805 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001806 case EOpCallBuiltInFunction:
1807 case EOpCallFunctionInAST:
1808 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001809 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001810 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001811
Corentin Wallez1239ee92015-03-19 14:38:02 -07001812 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001813 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001815 if (node->isArray())
1816 {
1817 UNIMPLEMENTED();
1818 }
Olli Etuahobd674552016-10-06 13:28:42 +01001819 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001820 ASSERT(index != CallDAG::InvalidIndex);
1821 lod0 &= mASTMetadataList[index].mNeedsLod0;
1822
Olli Etuahoff526f12017-06-30 12:26:54 +03001823 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001824 out << DisambiguateFunctionName(node->getSequence());
1825 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001826 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001827 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001828 {
1829 // This path is used for internal functions that don't have their definitions in the
1830 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001831 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001832 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001833 else
1834 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001835 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001836 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001837 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1838 if (arguments->size() > 1)
1839 {
1840 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1841 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001842 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1843 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1844 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001845 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001846
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001847 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001848 {
Olli Etuaho96963162016-03-21 11:54:33 +02001849 TIntermTyped *typedArg = (*arg)->getAsTyped();
1850 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001851 {
1852 out << "texture_";
1853 (*arg)->traverse(this);
1854 out << ", sampler_";
1855 }
1856
1857 (*arg)->traverse(this);
1858
Olli Etuaho96963162016-03-21 11:54:33 +02001859 if (typedArg->getType().isStructureContainingSamplers())
1860 {
1861 const TType &argType = typedArg->getType();
1862 TVector<TIntermSymbol *> samplerSymbols;
1863 TString structName = samplerNamePrefixFromStruct(typedArg);
1864 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho96963162016-03-21 11:54:33 +02001865 &samplerSymbols, nullptr);
1866 for (const TIntermSymbol *sampler : samplerSymbols)
1867 {
1868 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1869 {
1870 out << ", texture_" << sampler->getSymbol();
1871 out << ", sampler_" << sampler->getSymbol();
1872 }
1873 else
1874 {
1875 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1876 // of D3D9, it's the sampler variable.
1877 out << ", " + sampler->getSymbol();
1878 }
1879 }
1880 }
1881
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001882 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001883 {
1884 out << ", ";
1885 }
1886 }
1887
1888 out << ")";
1889
1890 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001891 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001892 case EOpConstruct:
1893 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001894 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001895 if (node->getType().isArray())
1896 {
1897 UNIMPLEMENTED();
1898 }
1899 const TString &structName = StructNameString(*node->getType().getStruct());
1900 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1901 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001902 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001903 else
1904 {
1905 const char *name = "";
1906 if (node->getType().getNominalSize() == 1)
1907 {
1908 switch (node->getBasicType())
1909 {
1910 case EbtFloat:
1911 name = "vec1";
1912 break;
1913 case EbtInt:
1914 name = "ivec1";
1915 break;
1916 case EbtUInt:
1917 name = "uvec1";
1918 break;
1919 case EbtBool:
1920 name = "bvec1";
1921 break;
1922 default:
1923 UNREACHABLE();
1924 }
1925 }
1926 else
1927 {
1928 name = node->getType().getBuiltInTypeNameString();
1929 }
1930 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1931 }
1932 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001933 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001934 outputTriplet(out, visit, "(", " == ", ")");
1935 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001936 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001937 outputTriplet(out, visit, "(", " != ", ")");
1938 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001939 case EOpLessThanComponentWise:
1940 outputTriplet(out, visit, "(", " < ", ")");
1941 break;
1942 case EOpGreaterThanComponentWise:
1943 outputTriplet(out, visit, "(", " > ", ")");
1944 break;
1945 case EOpLessThanEqualComponentWise:
1946 outputTriplet(out, visit, "(", " <= ", ")");
1947 break;
1948 case EOpGreaterThanEqualComponentWise:
1949 outputTriplet(out, visit, "(", " >= ", ")");
1950 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001951 case EOpMod:
1952 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001953 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001954 break;
1955 case EOpModf:
1956 outputTriplet(out, visit, "modf(", ", ", ")");
1957 break;
1958 case EOpPow:
1959 outputTriplet(out, visit, "pow(", ", ", ")");
1960 break;
1961 case EOpAtan:
1962 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1963 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001964 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001965 break;
1966 case EOpMin:
1967 outputTriplet(out, visit, "min(", ", ", ")");
1968 break;
1969 case EOpMax:
1970 outputTriplet(out, visit, "max(", ", ", ")");
1971 break;
1972 case EOpClamp:
1973 outputTriplet(out, visit, "clamp(", ", ", ")");
1974 break;
1975 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301976 {
1977 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1978 if (lastParamNode->getType().getBasicType() == EbtBool)
1979 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001980 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1981 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301982 // so use emulated version.
1983 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001984 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301985 }
1986 else
1987 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001988 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05301989 }
Olli Etuaho5878f832016-10-07 10:14:58 +01001990 break;
Arun Patoled94f6642015-05-18 16:25:12 +05301991 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05001992 case EOpStep:
1993 outputTriplet(out, visit, "step(", ", ", ")");
1994 break;
1995 case EOpSmoothStep:
1996 outputTriplet(out, visit, "smoothstep(", ", ", ")");
1997 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00001998 case EOpFrexp:
1999 case EOpLdexp:
2000 ASSERT(node->getUseEmulatedFunction());
2001 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2002 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002003 case EOpDistance:
2004 outputTriplet(out, visit, "distance(", ", ", ")");
2005 break;
2006 case EOpDot:
2007 outputTriplet(out, visit, "dot(", ", ", ")");
2008 break;
2009 case EOpCross:
2010 outputTriplet(out, visit, "cross(", ", ", ")");
2011 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002012 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002013 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002014 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002015 break;
2016 case EOpReflect:
2017 outputTriplet(out, visit, "reflect(", ", ", ")");
2018 break;
2019 case EOpRefract:
2020 outputTriplet(out, visit, "refract(", ", ", ")");
2021 break;
2022 case EOpOuterProduct:
2023 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002024 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002025 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002026 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002027 outputTriplet(out, visit, "(", " * ", ")");
2028 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002029 case EOpBitfieldExtract:
2030 case EOpBitfieldInsert:
2031 case EOpUaddCarry:
2032 case EOpUsubBorrow:
2033 case EOpUmulExtended:
2034 case EOpImulExtended:
2035 ASSERT(node->getUseEmulatedFunction());
2036 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2037 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002038 default:
2039 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002040 }
2041
2042 return true;
2043}
2044
Olli Etuaho57961272016-09-14 13:57:46 +03002045void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002047 out << "if (";
2048
2049 node->getCondition()->traverse(this);
2050
2051 out << ")\n";
2052
Jamie Madill8c46ab12015-12-07 16:39:19 -05002053 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002054
2055 bool discard = false;
2056
2057 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002058 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002059 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002060 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002061
Olli Etuahoa6f22092015-05-08 18:31:10 +03002062 // Detect true discard
2063 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2064 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002065 else
2066 {
2067 // TODO(oetuaho): Check if the semicolon inside is necessary.
2068 // It's there as a result of conservative refactoring of the output.
2069 out << "{;}\n";
2070 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002071
Jamie Madill8c46ab12015-12-07 16:39:19 -05002072 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002073
Olli Etuahoa6f22092015-05-08 18:31:10 +03002074 if (node->getFalseBlock())
2075 {
2076 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002077
Jamie Madill8c46ab12015-12-07 16:39:19 -05002078 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002079
Olli Etuaho32db19b2016-10-04 14:43:16 +01002080 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002081 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002082
Jamie Madill8c46ab12015-12-07 16:39:19 -05002083 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002084
Olli Etuahoa6f22092015-05-08 18:31:10 +03002085 // Detect false discard
2086 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2087 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002088
Olli Etuahoa6f22092015-05-08 18:31:10 +03002089 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002090 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002091 {
2092 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002093 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002094}
2095
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002096bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2097{
2098 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2099 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2100 UNREACHABLE();
2101 return false;
2102}
2103
Olli Etuaho57961272016-09-14 13:57:46 +03002104bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002105{
2106 TInfoSinkBase &out = getInfoSink();
2107
Olli Etuaho3d932d82016-04-12 11:10:30 +03002108 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002109
2110 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002111 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002112 {
2113 out << "FLATTEN ";
2114 }
2115
Olli Etuaho57961272016-09-14 13:57:46 +03002116 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002117
2118 return false;
2119}
2120
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002121bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002122{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002123 TInfoSinkBase &out = getInfoSink();
2124
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002125 if (node->getStatementList())
2126 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002127 node->setStatementList(
2128 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002129 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002130 // The curly braces get written when visiting the statementList aggregate
2131 }
2132 else
2133 {
2134 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002135 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002136 }
2137 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002138}
2139
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002140bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002141{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002142 TInfoSinkBase &out = getInfoSink();
2143
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002144 if (node->hasCondition())
2145 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002146 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002147 return true;
2148 }
2149 else
2150 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002151 out << "default:\n";
2152 return false;
2153 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002154}
2155
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002156void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2157{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002158 TInfoSinkBase &out = getInfoSink();
2159 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160}
2161
2162bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2163{
Nicolas Capens655fe362014-04-11 13:12:34 -04002164 mNestedLoopDepth++;
2165
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002166 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002167 mInsideDiscontinuousLoop =
2168 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002169
Jamie Madill8c46ab12015-12-07 16:39:19 -05002170 TInfoSinkBase &out = getInfoSink();
2171
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002172 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002173 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002174 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002175 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002176 mInsideDiscontinuousLoop = wasDiscontinuous;
2177 mNestedLoopDepth--;
2178
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002179 return false;
2180 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002181 }
2182
Corentin Wallez1239ee92015-03-19 14:38:02 -07002183 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002184 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002185 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002186 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002187
Jamie Madill8c46ab12015-12-07 16:39:19 -05002188 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002189 }
2190 else
2191 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002192 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002193
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002194 if (node->getInit())
2195 {
2196 node->getInit()->traverse(this);
2197 }
2198
2199 out << "; ";
2200
alokp@chromium.org52813552010-11-16 18:36:09 +00002201 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002203 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002204 }
2205
2206 out << "; ";
2207
alokp@chromium.org52813552010-11-16 18:36:09 +00002208 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002209 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002210 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002211 }
2212
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002213 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002214
Jamie Madill8c46ab12015-12-07 16:39:19 -05002215 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 }
2217
2218 if (node->getBody())
2219 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002220 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002221 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002222 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002223 else
2224 {
2225 // TODO(oetuaho): Check if the semicolon inside is necessary.
2226 // It's there as a result of conservative refactoring of the output.
2227 out << "{;}\n";
2228 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229
Jamie Madill8c46ab12015-12-07 16:39:19 -05002230 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002231
alokp@chromium.org52813552010-11-16 18:36:09 +00002232 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002233 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002234 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002235 out << "while(\n";
2236
alokp@chromium.org52813552010-11-16 18:36:09 +00002237 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238
daniel@transgaming.com73536982012-03-21 20:45:49 +00002239 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002240 }
2241
daniel@transgaming.com73536982012-03-21 20:45:49 +00002242 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002243
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002244 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002245 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002246
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 return false;
2248}
2249
2250bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2251{
Jamie Madill32aab012015-01-27 14:12:26 -05002252 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002253
2254 switch (node->getFlowOp())
2255 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002256 case EOpKill:
2257 outputTriplet(out, visit, "discard;\n", "", "");
2258 break;
2259 case EOpBreak:
2260 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002261 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002262 if (mNestedLoopDepth > 1)
2263 {
2264 mUsesNestedBreak = true;
2265 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002266
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002267 if (mExcessiveLoopIndex)
2268 {
2269 out << "{Break";
2270 mExcessiveLoopIndex->traverse(this);
2271 out << " = true; break;}\n";
2272 }
2273 else
2274 {
2275 out << "break;\n";
2276 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002277 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002278 break;
2279 case EOpContinue:
2280 outputTriplet(out, visit, "continue;\n", "", "");
2281 break;
2282 case EOpReturn:
2283 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002284 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002285 if (node->getExpression())
2286 {
2287 out << "return ";
2288 }
2289 else
2290 {
2291 out << "return;\n";
2292 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002293 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002294 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002295 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002296 if (node->getExpression())
2297 {
2298 out << ";\n";
2299 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002300 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002301 break;
2302 default:
2303 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002304 }
2305
2306 return true;
2307}
2308
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002309// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002310// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2311// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002312bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002313{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002314 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002315
2316 // Parse loops of the form:
2317 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002318 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002319 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002320 int initial = 0;
2321 int limit = 0;
2322 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002323
2324 // Parse index name and intial value
2325 if (node->getInit())
2326 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002327 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002328
2329 if (init)
2330 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002331 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002332 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002333
2334 if (variable && variable->getQualifier() == EvqTemporary)
2335 {
2336 TIntermBinary *assign = variable->getAsBinaryNode();
2337
2338 if (assign->getOp() == EOpInitialize)
2339 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002340 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002341 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2342
2343 if (symbol && constant)
2344 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002345 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002346 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002347 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002348 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002349 }
2350 }
2351 }
2352 }
2353 }
2354 }
2355
2356 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002357 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002358 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002359 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002360
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002361 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2362 {
2363 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2364
2365 if (constant)
2366 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002367 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002368 {
2369 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002370 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002371 }
2372 }
2373 }
2374 }
2375
2376 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002377 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002378 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002379 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002380 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002381
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002382 if (binaryTerminal)
2383 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002384 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002385 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2386
2387 if (constant)
2388 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002389 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002390 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002391 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002392
2393 switch (op)
2394 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002395 case EOpAddAssign:
2396 increment = value;
2397 break;
2398 case EOpSubAssign:
2399 increment = -value;
2400 break;
2401 default:
2402 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002403 }
2404 }
2405 }
2406 }
2407 else if (unaryTerminal)
2408 {
2409 TOperator op = unaryTerminal->getOp();
2410
2411 switch (op)
2412 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002413 case EOpPostIncrement:
2414 increment = 1;
2415 break;
2416 case EOpPostDecrement:
2417 increment = -1;
2418 break;
2419 case EOpPreIncrement:
2420 increment = 1;
2421 break;
2422 case EOpPreDecrement:
2423 increment = -1;
2424 break;
2425 default:
2426 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002427 }
2428 }
2429 }
2430
Yunchao He4f285442017-04-21 12:15:49 +08002431 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002432 {
2433 if (comparator == EOpLessThanEqual)
2434 {
2435 comparator = EOpLessThan;
2436 limit += 1;
2437 }
2438
2439 if (comparator == EOpLessThan)
2440 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002441 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002442
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002443 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002444 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002445 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002446 }
2447
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002448 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002449 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002450
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002451 out << "{int ";
2452 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002453 out << ";\n"
2454 "bool Break";
2455 index->traverse(this);
2456 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002457
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002458 bool firstLoopFragment = true;
2459
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002460 while (iterations > 0)
2461 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002462 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002463
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002464 if (!firstLoopFragment)
2465 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002466 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002467 index->traverse(this);
2468 out << ") {\n";
2469 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002470
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002471 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002472 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002473 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002474 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002475
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002476 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002477 const char *unroll =
2478 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479
Corentin Wallez1239ee92015-03-19 14:38:02 -07002480 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002481 index->traverse(this);
2482 out << " = ";
2483 out << initial;
2484
2485 out << "; ";
2486 index->traverse(this);
2487 out << " < ";
2488 out << clampedLimit;
2489
2490 out << "; ";
2491 index->traverse(this);
2492 out << " += ";
2493 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002494 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002495
Jamie Madill8c46ab12015-12-07 16:39:19 -05002496 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002497 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002498
2499 if (node->getBody())
2500 {
2501 node->getBody()->traverse(this);
2502 }
2503
Jamie Madill8c46ab12015-12-07 16:39:19 -05002504 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002505 out << ";}\n";
2506
2507 if (!firstLoopFragment)
2508 {
2509 out << "}\n";
2510 }
2511
2512 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002513
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002514 initial += MAX_LOOP_ITERATIONS * increment;
2515 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002516 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002517
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002518 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002519
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002520 mExcessiveLoopIndex = restoreIndex;
2521
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002522 return true;
2523 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002524 else
2525 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002526 }
2527
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002528 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002529}
2530
Jamie Madill8c46ab12015-12-07 16:39:19 -05002531void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2532 Visit visit,
2533 const char *preString,
2534 const char *inString,
2535 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002536{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002537 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002538 {
2539 out << preString;
2540 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002541 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002542 {
2543 out << inString;
2544 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002545 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002546 {
2547 out << postString;
2548 }
2549}
2550
Jamie Madill8c46ab12015-12-07 16:39:19 -05002551void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002552{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002553 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002554 {
Jamie Madill32aab012015-01-27 14:12:26 -05002555 out << "\n";
2556 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002557
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002558 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002559 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002560 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002561 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002562
Jamie Madill32aab012015-01-27 14:12:26 -05002563 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002564 }
2565}
2566
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002567TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2568{
2569 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002570 const TType &type = symbol->getType();
2571 const TName &name = symbol->getName();
2572 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002573
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002574 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002575 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002576 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002577 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002578 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002579 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002580 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002581 }
2582
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002583 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002584 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002585 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2586 {
2587 // Samplers are passed as indices to the sampler array.
2588 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2589 return "const uint " + nameStr + ArrayString(type);
2590 }
2591 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2592 {
2593 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2594 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2595 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2596 ArrayString(type);
2597 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002598 }
2599
Olli Etuaho96963162016-03-21 11:54:33 +02002600 TStringStream argString;
2601 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2602 << ArrayString(type);
2603
2604 // If the structure parameter contains samplers, they need to be passed into the function as
2605 // separate parameters. HLSL doesn't natively support samplers in structs.
2606 if (type.isStructureContainingSamplers())
2607 {
2608 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2609 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho599555b2017-08-15 11:12:42 +03002610 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002611 for (const TIntermSymbol *sampler : samplerSymbols)
2612 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002613 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002614 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2615 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002616 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002617 }
2618 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2619 {
Olli Etuaho96963162016-03-21 11:54:33 +02002620 ASSERT(IsSampler(samplerType.getBasicType()));
2621 argString << ", " << QualifierString(qualifier) << " "
2622 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002623 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2624 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002625 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002626 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002627 }
2628 else
2629 {
Olli Etuaho96963162016-03-21 11:54:33 +02002630 ASSERT(IsSampler(samplerType.getBasicType()));
2631 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002632 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002633 }
2634 }
2635 }
2636
2637 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002638}
2639
2640TString OutputHLSL::initializer(const TType &type)
2641{
2642 TString string;
2643
Jamie Madill94bf7f22013-07-08 13:31:15 -04002644 size_t size = type.getObjectSize();
2645 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002646 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002647 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002648
Jamie Madill94bf7f22013-07-08 13:31:15 -04002649 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002650 {
2651 string += ", ";
2652 }
2653 }
2654
daniel@transgaming.comead23042010-04-29 03:35:36 +00002655 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002656}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002657
Jamie Madill8c46ab12015-12-07 16:39:19 -05002658void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2659 Visit visit,
2660 const TType &type,
2661 const char *name,
2662 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002663{
Olli Etuahof40319e2015-03-10 14:33:00 +02002664 if (type.isArray())
2665 {
2666 UNIMPLEMENTED();
2667 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002668
2669 if (visit == PreVisit)
2670 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002671 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002672
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002673 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002674 }
2675 else if (visit == InVisit)
2676 {
2677 out << ", ";
2678 }
2679 else if (visit == PostVisit)
2680 {
2681 out << ")";
2682 }
2683}
2684
Jamie Madill8c46ab12015-12-07 16:39:19 -05002685const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2686 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002687 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002688{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002689 const TConstantUnion *constUnionIterated = constUnion;
2690
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002691 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002692 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002693 {
Jamie Madill033dae62014-06-18 12:56:28 -04002694 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002695
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002696 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002697
Jamie Madill98493dd2013-07-08 14:39:03 -04002698 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002699 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002700 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002701 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002702
Jamie Madill98493dd2013-07-08 14:39:03 -04002703 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002704 {
2705 out << ", ";
2706 }
2707 }
2708
2709 out << ")";
2710 }
2711 else
2712 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002713 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002714 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002715
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002716 if (writeType)
2717 {
Jamie Madill033dae62014-06-18 12:56:28 -04002718 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002719 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002720 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002721 if (writeType)
2722 {
2723 out << ")";
2724 }
2725 }
2726
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002727 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002728}
2729
Olli Etuahod68924e2017-01-02 17:34:40 +00002730void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002731{
Olli Etuahod68924e2017-01-02 17:34:40 +00002732 if (visit == PreVisit)
2733 {
2734 const char *opStr = GetOperatorString(op);
2735 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2736 out << "(";
2737 }
2738 else
2739 {
2740 outputTriplet(out, visit, nullptr, ", ", ")");
2741 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002742}
2743
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002744bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2745 TIntermSymbol *symbolNode,
2746 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002747{
2748 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2749 expression->traverse(&searchSymbol);
2750
2751 if (searchSymbol.foundMatch())
2752 {
2753 // Type already printed
2754 out << "t" + str(mUniqueIndex) + " = ";
2755 expression->traverse(this);
2756 out << ", ";
2757 symbolNode->traverse(this);
2758 out << " = t" + str(mUniqueIndex);
2759
2760 mUniqueIndex++;
2761 return true;
2762 }
2763
2764 return false;
2765}
2766
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002767bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2768{
2769 // We support writing constant unions and constructors that only take constant unions as
2770 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002771 return !expression->getType().isArrayOfArrays() &&
2772 (expression->getAsConstantUnion() ||
2773 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002774}
2775
2776bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2777 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002778 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002779{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002780 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002781 {
2782 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002783 ASSERT(!symbolNode->getType().isArrayOfArrays());
2784 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002785 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002786 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002787 }
2788 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002789 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002790 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002791 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002792 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002793 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002794 }
2795 else
2796 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002797 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002798 ASSERT(constructor != nullptr);
2799 for (TIntermNode *&node : *constructor->getSequence())
2800 {
2801 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2802 ASSERT(nodeConst);
2803 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002804 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002805 if (node != constructor->getSequence()->back())
2806 {
2807 out << ", ";
2808 }
2809 }
2810 }
2811 out << "}";
2812 return true;
2813 }
2814 return false;
2815}
2816
Jamie Madill55e79e02015-02-09 15:35:00 -05002817TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2818{
2819 const TFieldList &fields = structure.fields();
2820
2821 for (const auto &eqFunction : mStructEqualityFunctions)
2822 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002823 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002824 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002825 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002826 }
2827 }
2828
2829 const TString &structNameString = StructNameString(structure);
2830
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002831 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002832 function->structure = &structure;
2833 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002834
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002835 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002836
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002837 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2838 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002839 << "{\n"
2840 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002841
2842 for (size_t i = 0; i < fields.size(); i++)
2843 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002844 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002845 const TType *fieldType = field->type();
2846
2847 const TString &fieldNameA = "a." + Decorate(field->name());
2848 const TString &fieldNameB = "b." + Decorate(field->name());
2849
2850 if (i > 0)
2851 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002852 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002853 }
2854
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002855 fnOut << "(";
2856 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2857 fnOut << fieldNameA;
2858 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2859 fnOut << fieldNameB;
2860 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2861 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002862 }
2863
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002864 fnOut << ";\n"
2865 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002866
2867 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002868
2869 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002870 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002871
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002872 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002873}
2874
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002875TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002876{
2877 for (const auto &eqFunction : mArrayEqualityFunctions)
2878 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002879 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002880 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002881 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002882 }
2883 }
2884
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002885 TType elementType(type);
2886 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002887
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
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002891 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002892
2893 TInfoSinkBase fnOut;
2894
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002895 const TString &typeName = TypeString(type);
2896 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2897 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002898 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002899 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002900 << type.getOutermostArraySize()
2901 << "; ++i)\n"
2902 " {\n"
2903 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002904
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002905 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002906 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002907 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002908 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002909 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002910
2911 fnOut << ") { return false; }\n"
2912 " }\n"
2913 " return true;\n"
2914 "}\n";
2915
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002916 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002917
2918 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002919 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002920
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002921 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002922}
2923
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002924TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002925{
2926 for (const auto &assignFunction : mArrayAssignmentFunctions)
2927 {
2928 if (assignFunction.type == type)
2929 {
2930 return assignFunction.functionName;
2931 }
2932 }
2933
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002934 TType elementType(type);
2935 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002936
2937 ArrayHelperFunction function;
2938 function.type = type;
2939
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002940 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002941
2942 TInfoSinkBase fnOut;
2943
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002944 const TString &typeName = TypeString(type);
2945 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2946 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002947 << "{\n"
2948 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002949 << type.getOutermostArraySize()
2950 << "; ++i)\n"
2951 " {\n"
2952 " ";
2953
2954 outputAssign(PreVisit, elementType, fnOut);
2955 fnOut << "a[i]";
2956 outputAssign(InVisit, elementType, fnOut);
2957 fnOut << "b[i]";
2958 outputAssign(PostVisit, elementType, fnOut);
2959
2960 fnOut << ";\n"
2961 " }\n"
2962 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002963
2964 function.functionDefinition = fnOut.c_str();
2965
2966 mArrayAssignmentFunctions.push_back(function);
2967
2968 return function.functionName;
2969}
2970
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002971TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002972{
2973 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2974 {
2975 if (constructIntoFunction.type == type)
2976 {
2977 return constructIntoFunction.functionName;
2978 }
2979 }
2980
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002981 TType elementType(type);
2982 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03002983
2984 ArrayHelperFunction function;
2985 function.type = type;
2986
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002987 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03002988
2989 TInfoSinkBase fnOut;
2990
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002991 const TString &typeName = TypeString(type);
2992 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
2993 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002994 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002995 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03002996 }
2997 fnOut << ")\n"
2998 "{\n";
2999
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003000 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003001 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003002 fnOut << " ";
3003 outputAssign(PreVisit, elementType, fnOut);
3004 fnOut << "a[" << i << "]";
3005 outputAssign(InVisit, elementType, fnOut);
3006 fnOut << "b" << i;
3007 outputAssign(PostVisit, elementType, fnOut);
3008 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003009 }
3010 fnOut << "}\n";
3011
3012 function.functionDefinition = fnOut.c_str();
3013
3014 mArrayConstructIntoFunctions.push_back(function);
3015
3016 return function.functionName;
3017}
3018
Jamie Madill2e295e22015-04-29 10:41:33 -04003019void OutputHLSL::ensureStructDefined(const TType &type)
3020{
3021 TStructure *structure = type.getStruct();
3022
3023 if (structure)
3024 {
3025 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3026 }
3027}
3028
Jamie Madill45bcc782016-11-07 13:58:48 -05003029} // namespace sh