blob: 1d8d11178156924a5fd2c48fe26c4510559a5665 [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;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300133 mHasMultiviewExtensionEnabled =
134 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300135 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 Etuaho2a1e8f92017-07-14 11:49:36 +0300421 const bool usingMRTExtension =
422 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000423
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000424 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500425 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400426 out << "\n";
427
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200428 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000429 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500430 for (ReferencedSymbols::const_iterator outputVariableIt =
431 mReferencedOutputVariables.begin();
432 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000433 {
Jamie Madill46131a32013-06-20 11:55:50 -0400434 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400436
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500437 out << "static " + TypeString(variableType) + " out_" + variableName +
438 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000439 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000440 }
Jamie Madill46131a32013-06-20 11:55:50 -0400441 else
442 {
443 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
444
445 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500446 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400447 for (unsigned int i = 0; i < numColorValues; i++)
448 {
449 out << " float4(0, 0, 0, 0)";
450 if (i + 1 != numColorValues)
451 {
452 out << ",";
453 }
454 out << "\n";
455 }
456
457 out << "};\n";
458 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000459
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400460 if (mUsesFragDepth)
461 {
462 out << "static float gl_Depth = 0.0;\n";
463 }
464
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000465 if (mUsesFragCoord)
466 {
467 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
468 }
469
470 if (mUsesPointCoord)
471 {
472 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
473 }
474
475 if (mUsesFrontFacing)
476 {
477 out << "static bool gl_FrontFacing = false;\n";
478 }
479
480 out << "\n";
481
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000482 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000483 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000484 out << "struct gl_DepthRangeParameters\n"
485 "{\n"
486 " float near;\n"
487 " float far;\n"
488 " float diff;\n"
489 "};\n"
490 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000491 }
492
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200493 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000494 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000495 out << "cbuffer DriverConstants : register(b1)\n"
496 "{\n";
497
498 if (mUsesDepthRange)
499 {
500 out << " float3 dx_DepthRange : packoffset(c0);\n";
501 }
502
503 if (mUsesFragCoord)
504 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000505 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000506 }
507
508 if (mUsesFragCoord || mUsesFrontFacing)
509 {
510 out << " float3 dx_DepthFront : packoffset(c2);\n";
511 }
512
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800513 if (mUsesFragCoord)
514 {
515 // dx_ViewScale is only used in the fragment shader to correct
516 // the value for glFragCoord if necessary
517 out << " float2 dx_ViewScale : packoffset(c3);\n";
518 }
519
Martin Radev72b4e1e2017-08-31 15:42:56 +0300520 if (mHasMultiviewExtensionEnabled)
521 {
522 // We have to add a value which we can use to keep track of which multi-view code
523 // path is to be selected in the GS.
524 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
525 }
526
Olli Etuaho618bebc2016-01-15 16:40:00 +0200527 if (mOutputType == SH_HLSL_4_1_OUTPUT)
528 {
529 mUniformHLSL->samplerMetadataUniforms(out, "c4");
530 }
531
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000532 out << "};\n";
533 }
534 else
535 {
536 if (mUsesDepthRange)
537 {
538 out << "uniform float3 dx_DepthRange : register(c0);";
539 }
540
541 if (mUsesFragCoord)
542 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000543 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000544 }
545
546 if (mUsesFragCoord || mUsesFrontFacing)
547 {
548 out << "uniform float3 dx_DepthFront : register(c2);\n";
549 }
550 }
551
552 out << "\n";
553
554 if (mUsesDepthRange)
555 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500556 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
557 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000558 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000559 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000560
Jamie Madillf91ce812014-06-13 10:04:34 -0400561 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000562 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400563 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000564 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400565 out << flaggedStructs;
566 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000567 }
568
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000569 if (usingMRTExtension && mNumRenderTargets > 1)
570 {
571 out << "#define GL_USES_MRT\n";
572 }
573
574 if (mUsesFragColor)
575 {
576 out << "#define GL_USES_FRAG_COLOR\n";
577 }
578
579 if (mUsesFragData)
580 {
581 out << "#define GL_USES_FRAG_DATA\n";
582 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583 }
Xinghua Caob1239382016-12-13 15:07:05 +0800584 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000585 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000586 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500587 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 out << "\n"
589 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400590
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000591 if (mUsesPointSize)
592 {
593 out << "static float gl_PointSize = float(1);\n";
594 }
595
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000596 if (mUsesInstanceID)
597 {
598 out << "static int gl_InstanceID;";
599 }
600
Corentin Wallezb076add2016-01-11 16:45:46 -0500601 if (mUsesVertexID)
602 {
603 out << "static int gl_VertexID;";
604 }
605
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000606 out << "\n"
607 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500608 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000609 out << "\n";
610
611 if (mUsesDepthRange)
612 {
613 out << "struct gl_DepthRangeParameters\n"
614 "{\n"
615 " float near;\n"
616 " float far;\n"
617 " float diff;\n"
618 "};\n"
619 "\n";
620 }
621
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200622 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000623 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800624 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500625 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800626
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000627 if (mUsesDepthRange)
628 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800629 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000630 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800631
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800632 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
633 // shaders. However, we declare it for all shaders (including Feature Level 10+).
634 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
635 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800636 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800637 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800638 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800639
Martin Radev72b4e1e2017-08-31 15:42:56 +0300640 if (mHasMultiviewExtensionEnabled)
641 {
642 // We have to add a value which we can use to keep track of which multi-view code
643 // path is to be selected in the GS.
644 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
645 }
646
Olli Etuaho618bebc2016-01-15 16:40:00 +0200647 if (mOutputType == SH_HLSL_4_1_OUTPUT)
648 {
649 mUniformHLSL->samplerMetadataUniforms(out, "c4");
650 }
651
Austin Kinross4fd18b12014-12-22 12:32:05 -0800652 out << "};\n"
653 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000654 }
655 else
656 {
657 if (mUsesDepthRange)
658 {
659 out << "uniform float3 dx_DepthRange : register(c0);\n";
660 }
661
Cooper Partine6664f02015-01-09 16:22:24 -0800662 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
663 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000664 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000665 }
666
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000667 if (mUsesDepthRange)
668 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500669 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
670 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000671 "\n";
672 }
673
Jamie Madillf91ce812014-06-13 10:04:34 -0400674 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000675 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400676 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000677 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400678 out << flaggedStructs;
679 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000680 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400681 }
Xinghua Caob1239382016-12-13 15:07:05 +0800682 else // Compute shader
683 {
684 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800685
686 out << "cbuffer DriverConstants : register(b1)\n"
687 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800688 if (mUsesNumWorkGroups)
689 {
Xinghua Caob1239382016-12-13 15:07:05 +0800690 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800691 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800692 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
693 mUniformHLSL->samplerMetadataUniforms(out, "c1");
694 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800695
696 // Follow built-in variables would be initialized in
697 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
698 // are used in compute shader.
699 if (mUsesWorkGroupID)
700 {
701 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
702 }
703
704 if (mUsesLocalInvocationID)
705 {
706 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
707 }
708
709 if (mUsesGlobalInvocationID)
710 {
711 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
712 }
713
714 if (mUsesLocalInvocationIndex)
715 {
716 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
717 }
718 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000719
Geoff Lang1fe74c72016-08-25 13:23:01 -0400720 bool getDimensionsIgnoresBaseLevel =
721 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
722 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000724 if (mUsesFragCoord)
725 {
726 out << "#define GL_USES_FRAG_COORD\n";
727 }
728
729 if (mUsesPointCoord)
730 {
731 out << "#define GL_USES_POINT_COORD\n";
732 }
733
734 if (mUsesFrontFacing)
735 {
736 out << "#define GL_USES_FRONT_FACING\n";
737 }
738
739 if (mUsesPointSize)
740 {
741 out << "#define GL_USES_POINT_SIZE\n";
742 }
743
Martin Radev41ac68e2017-06-06 12:16:58 +0300744 if (mHasMultiviewExtensionEnabled)
745 {
746 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
747 }
748
749 if (mUsesViewID)
750 {
751 out << "#define GL_USES_VIEW_ID\n";
752 }
753
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400754 if (mUsesFragDepth)
755 {
756 out << "#define GL_USES_FRAG_DEPTH\n";
757 }
758
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000759 if (mUsesDepthRange)
760 {
761 out << "#define GL_USES_DEPTH_RANGE\n";
762 }
763
Xinghua Caob1239382016-12-13 15:07:05 +0800764 if (mUsesNumWorkGroups)
765 {
766 out << "#define GL_USES_NUM_WORK_GROUPS\n";
767 }
768
769 if (mUsesWorkGroupID)
770 {
771 out << "#define GL_USES_WORK_GROUP_ID\n";
772 }
773
774 if (mUsesLocalInvocationID)
775 {
776 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
777 }
778
779 if (mUsesGlobalInvocationID)
780 {
781 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
782 }
783
784 if (mUsesLocalInvocationIndex)
785 {
786 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
787 }
788
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000789 if (mUsesXor)
790 {
791 out << "bool xor(bool p, bool q)\n"
792 "{\n"
793 " return (p || q) && !(p && q);\n"
794 "}\n"
795 "\n";
796 }
797
Olli Etuahodfa75e82017-01-23 09:43:06 -0800798 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000799}
800
801void OutputHLSL::visitSymbol(TIntermSymbol *node)
802{
Jamie Madill32aab012015-01-27 14:12:26 -0500803 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804
Jamie Madill570e04d2013-06-21 09:15:33 -0400805 // Handle accessing std140 structs by value
806 if (mFlaggedStructMappedNames.count(node) > 0)
807 {
808 out << mFlaggedStructMappedNames[node];
809 return;
810 }
811
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812 TString name = node->getSymbol();
813
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000814 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000815 {
816 mUsesDepthRange = true;
817 out << name;
818 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000819 else
820 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000821 TQualifier qualifier = node->getQualifier();
822
823 if (qualifier == EvqUniform)
824 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500825 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400826 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400827
828 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000829 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800830 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000831 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000832 else
833 {
834 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000835 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400836
Jamie Madill2e295e22015-04-29 10:41:33 -0400837 ensureStructDefined(nodeType);
838
Olli Etuahoff526f12017-06-30 12:26:54 +0300839 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000840 }
Jamie Madill19571812013-08-12 15:26:34 -0700841 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000842 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000843 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400844 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000845 }
Jamie Madill033dae62014-06-18 12:56:28 -0400846 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000847 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000848 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400849 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300850 if (name == "ViewID_OVR")
851 {
852 mUsesViewID = true;
853 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000854 }
Jamie Madill19571812013-08-12 15:26:34 -0700855 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400856 {
857 mReferencedOutputVariables[name] = node;
858 out << "out_" << name;
859 }
860 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000861 {
862 out << "gl_Color[0]";
863 mUsesFragColor = true;
864 }
865 else if (qualifier == EvqFragData)
866 {
867 out << "gl_Color";
868 mUsesFragData = true;
869 }
870 else if (qualifier == EvqFragCoord)
871 {
872 mUsesFragCoord = true;
873 out << name;
874 }
875 else if (qualifier == EvqPointCoord)
876 {
877 mUsesPointCoord = true;
878 out << name;
879 }
880 else if (qualifier == EvqFrontFacing)
881 {
882 mUsesFrontFacing = true;
883 out << name;
884 }
885 else if (qualifier == EvqPointSize)
886 {
887 mUsesPointSize = true;
888 out << name;
889 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000890 else if (qualifier == EvqInstanceID)
891 {
892 mUsesInstanceID = true;
893 out << name;
894 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500895 else if (qualifier == EvqVertexID)
896 {
897 mUsesVertexID = true;
898 out << name;
899 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300900 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400901 {
902 mUsesFragDepth = true;
903 out << "gl_Depth";
904 }
Xinghua Caob1239382016-12-13 15:07:05 +0800905 else if (qualifier == EvqNumWorkGroups)
906 {
907 mUsesNumWorkGroups = true;
908 out << name;
909 }
910 else if (qualifier == EvqWorkGroupID)
911 {
912 mUsesWorkGroupID = true;
913 out << name;
914 }
915 else if (qualifier == EvqLocalInvocationID)
916 {
917 mUsesLocalInvocationID = true;
918 out << name;
919 }
920 else if (qualifier == EvqGlobalInvocationID)
921 {
922 mUsesGlobalInvocationID = true;
923 out << name;
924 }
925 else if (qualifier == EvqLocalInvocationIndex)
926 {
927 mUsesLocalInvocationIndex = true;
928 out << name;
929 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000930 else
931 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300932 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000933 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000934 }
935}
936
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400937void OutputHLSL::visitRaw(TIntermRaw *node)
938{
Jamie Madill32aab012015-01-27 14:12:26 -0500939 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400940}
941
Olli Etuaho7fb49552015-03-18 17:27:44 +0200942void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
943{
944 if (type.isScalar() && !type.isArray())
945 {
946 if (op == EOpEqual)
947 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500948 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200949 }
950 else
951 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500952 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200953 }
954 }
955 else
956 {
957 if (visit == PreVisit && op == EOpNotEqual)
958 {
959 out << "!";
960 }
961
962 if (type.isArray())
963 {
964 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500965 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200966 }
967 else if (type.getBasicType() == EbtStruct)
968 {
969 const TStructure &structure = *type.getStruct();
970 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500971 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200972 }
973 else
974 {
975 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500976 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200977 }
978 }
979}
980
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300981void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
982{
983 if (type.isArray())
984 {
985 const TString &functionName = addArrayAssignmentFunction(type);
986 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
987 }
988 else
989 {
990 outputTriplet(out, visit, "(", " = ", ")");
991 }
992}
993
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000994bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200995{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000996 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200997 {
998 TIntermNode *ancestor = getAncestorNode(n);
999 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1000 if (ancestorBinary == nullptr)
1001 {
1002 return false;
1003 }
1004 switch (ancestorBinary->getOp())
1005 {
1006 case EOpIndexDirectStruct:
1007 {
1008 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1009 const TIntermConstantUnion *index =
1010 ancestorBinary->getRight()->getAsConstantUnion();
1011 const TField *field = structure->fields()[index->getIConst(0)];
1012 if (IsSampler(field->type()->getBasicType()))
1013 {
1014 return true;
1015 }
1016 break;
1017 }
1018 case EOpIndexDirect:
1019 break;
1020 default:
1021 // Returning a sampler from indirect indexing is not supported.
1022 return false;
1023 }
1024 }
1025 return false;
1026}
1027
Olli Etuahob6fa0432016-09-28 16:28:05 +01001028bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1029{
1030 TInfoSinkBase &out = getInfoSink();
1031 if (visit == PostVisit)
1032 {
1033 out << ".";
1034 node->writeOffsetsAsXYZW(&out);
1035 }
1036 return true;
1037}
1038
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001039bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1040{
Jamie Madill32aab012015-01-27 14:12:26 -05001041 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001042
Jamie Madill570e04d2013-06-21 09:15:33 -04001043 // Handle accessing std140 structs by value
1044 if (mFlaggedStructMappedNames.count(node) > 0)
1045 {
1046 out << mFlaggedStructMappedNames[node];
1047 return false;
1048 }
1049
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050 switch (node->getOp())
1051 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001052 case EOpComma:
1053 outputTriplet(out, visit, "(", ", ", ")");
1054 break;
1055 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001056 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001057 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001058 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1059 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001060 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001061 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1062 out << functionName << "(";
1063 node->getLeft()->traverse(this);
1064 TIntermSequence *seq = rightAgg->getSequence();
1065 for (auto &arrayElement : *seq)
1066 {
1067 out << ", ";
1068 arrayElement->traverse(this);
1069 }
1070 out << ")";
1071 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001072 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001073 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1074 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001075 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001076 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001077 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001078 break;
1079 case EOpInitialize:
1080 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001081 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001082 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1083 ASSERT(symbolNode);
1084 TIntermTyped *expression = node->getRight();
1085
1086 // Global initializers must be constant at this point.
1087 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1088 canWriteAsHLSLLiteral(expression));
1089
1090 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1091 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1092 // new variable is created before the assignment is evaluated), so we need to
1093 // convert
1094 // this to "float t = x, x = t;".
1095 if (writeSameSymbolInitializer(out, symbolNode, expression))
1096 {
1097 // Skip initializing the rest of the expression
1098 return false;
1099 }
1100 else if (writeConstantInitialization(out, symbolNode, expression))
1101 {
1102 return false;
1103 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001104 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001105 else if (visit == InVisit)
1106 {
1107 out << " = ";
1108 }
1109 break;
1110 case EOpAddAssign:
1111 outputTriplet(out, visit, "(", " += ", ")");
1112 break;
1113 case EOpSubAssign:
1114 outputTriplet(out, visit, "(", " -= ", ")");
1115 break;
1116 case EOpMulAssign:
1117 outputTriplet(out, visit, "(", " *= ", ")");
1118 break;
1119 case EOpVectorTimesScalarAssign:
1120 outputTriplet(out, visit, "(", " *= ", ")");
1121 break;
1122 case EOpMatrixTimesScalarAssign:
1123 outputTriplet(out, visit, "(", " *= ", ")");
1124 break;
1125 case EOpVectorTimesMatrixAssign:
1126 if (visit == PreVisit)
1127 {
1128 out << "(";
1129 }
1130 else if (visit == InVisit)
1131 {
1132 out << " = mul(";
1133 node->getLeft()->traverse(this);
1134 out << ", transpose(";
1135 }
1136 else
1137 {
1138 out << ")))";
1139 }
1140 break;
1141 case EOpMatrixTimesMatrixAssign:
1142 if (visit == PreVisit)
1143 {
1144 out << "(";
1145 }
1146 else if (visit == InVisit)
1147 {
1148 out << " = transpose(mul(transpose(";
1149 node->getLeft()->traverse(this);
1150 out << "), transpose(";
1151 }
1152 else
1153 {
1154 out << "))))";
1155 }
1156 break;
1157 case EOpDivAssign:
1158 outputTriplet(out, visit, "(", " /= ", ")");
1159 break;
1160 case EOpIModAssign:
1161 outputTriplet(out, visit, "(", " %= ", ")");
1162 break;
1163 case EOpBitShiftLeftAssign:
1164 outputTriplet(out, visit, "(", " <<= ", ")");
1165 break;
1166 case EOpBitShiftRightAssign:
1167 outputTriplet(out, visit, "(", " >>= ", ")");
1168 break;
1169 case EOpBitwiseAndAssign:
1170 outputTriplet(out, visit, "(", " &= ", ")");
1171 break;
1172 case EOpBitwiseXorAssign:
1173 outputTriplet(out, visit, "(", " ^= ", ")");
1174 break;
1175 case EOpBitwiseOrAssign:
1176 outputTriplet(out, visit, "(", " |= ", ")");
1177 break;
1178 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001179 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001180 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001181 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001182 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001183 if (visit == PreVisit)
1184 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001185 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001186 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001187 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001188 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001189 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001190 return false;
1191 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001192 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001193 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001194 {
1195 // All parts of an expression that access a sampler in a struct need to use _ as
1196 // separator to access the sampler variable that has been moved out of the struct.
1197 outputTriplet(out, visit, "", "_", "");
1198 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001199 else
1200 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001201 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001202 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001203 }
1204 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001205 case EOpIndexIndirect:
1206 // We do not currently support indirect references to interface blocks
1207 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1208 outputTriplet(out, visit, "", "[", "]");
1209 break;
1210 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001211 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001212 const TStructure *structure = node->getLeft()->getType().getStruct();
1213 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1214 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001215
Olli Etuaho96963162016-03-21 11:54:33 +02001216 // In cases where indexing returns a sampler, we need to access the sampler variable
1217 // that has been moved out of the struct.
1218 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1219 if (visit == PreVisit && indexingReturnsSampler)
1220 {
1221 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1222 // This prefix is only output at the beginning of the indexing expression, which
1223 // may have multiple parts.
1224 out << "angle";
1225 }
1226 if (!indexingReturnsSampler)
1227 {
1228 // All parts of an expression that access a sampler in a struct need to use _ as
1229 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001230 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001231 }
1232 if (visit == InVisit)
1233 {
1234 if (indexingReturnsSampler)
1235 {
1236 out << "_" + field->name();
1237 }
1238 else
1239 {
1240 out << "." + DecorateField(field->name(), *structure);
1241 }
1242
1243 return false;
1244 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001245 }
1246 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001247 case EOpIndexDirectInterfaceBlock:
1248 if (visit == InVisit)
1249 {
1250 const TInterfaceBlock *interfaceBlock =
1251 node->getLeft()->getType().getInterfaceBlock();
1252 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1253 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1254 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001255
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001256 return false;
1257 }
1258 break;
1259 case EOpAdd:
1260 outputTriplet(out, visit, "(", " + ", ")");
1261 break;
1262 case EOpSub:
1263 outputTriplet(out, visit, "(", " - ", ")");
1264 break;
1265 case EOpMul:
1266 outputTriplet(out, visit, "(", " * ", ")");
1267 break;
1268 case EOpDiv:
1269 outputTriplet(out, visit, "(", " / ", ")");
1270 break;
1271 case EOpIMod:
1272 outputTriplet(out, visit, "(", " % ", ")");
1273 break;
1274 case EOpBitShiftLeft:
1275 outputTriplet(out, visit, "(", " << ", ")");
1276 break;
1277 case EOpBitShiftRight:
1278 outputTriplet(out, visit, "(", " >> ", ")");
1279 break;
1280 case EOpBitwiseAnd:
1281 outputTriplet(out, visit, "(", " & ", ")");
1282 break;
1283 case EOpBitwiseXor:
1284 outputTriplet(out, visit, "(", " ^ ", ")");
1285 break;
1286 case EOpBitwiseOr:
1287 outputTriplet(out, visit, "(", " | ", ")");
1288 break;
1289 case EOpEqual:
1290 case EOpNotEqual:
1291 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1292 break;
1293 case EOpLessThan:
1294 outputTriplet(out, visit, "(", " < ", ")");
1295 break;
1296 case EOpGreaterThan:
1297 outputTriplet(out, visit, "(", " > ", ")");
1298 break;
1299 case EOpLessThanEqual:
1300 outputTriplet(out, visit, "(", " <= ", ")");
1301 break;
1302 case EOpGreaterThanEqual:
1303 outputTriplet(out, visit, "(", " >= ", ")");
1304 break;
1305 case EOpVectorTimesScalar:
1306 outputTriplet(out, visit, "(", " * ", ")");
1307 break;
1308 case EOpMatrixTimesScalar:
1309 outputTriplet(out, visit, "(", " * ", ")");
1310 break;
1311 case EOpVectorTimesMatrix:
1312 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1313 break;
1314 case EOpMatrixTimesVector:
1315 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1316 break;
1317 case EOpMatrixTimesMatrix:
1318 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1319 break;
1320 case EOpLogicalOr:
1321 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1322 // been unfolded.
1323 ASSERT(!node->getRight()->hasSideEffects());
1324 outputTriplet(out, visit, "(", " || ", ")");
1325 return true;
1326 case EOpLogicalXor:
1327 mUsesXor = true;
1328 outputTriplet(out, visit, "xor(", ", ", ")");
1329 break;
1330 case EOpLogicalAnd:
1331 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1332 // been unfolded.
1333 ASSERT(!node->getRight()->hasSideEffects());
1334 outputTriplet(out, visit, "(", " && ", ")");
1335 return true;
1336 default:
1337 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001338 }
1339
1340 return true;
1341}
1342
1343bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1344{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001345 TInfoSinkBase &out = getInfoSink();
1346
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001347 switch (node->getOp())
1348 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001349 case EOpNegative:
1350 outputTriplet(out, visit, "(-", "", ")");
1351 break;
1352 case EOpPositive:
1353 outputTriplet(out, visit, "(+", "", ")");
1354 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001355 case EOpLogicalNot:
1356 outputTriplet(out, visit, "(!", "", ")");
1357 break;
1358 case EOpBitwiseNot:
1359 outputTriplet(out, visit, "(~", "", ")");
1360 break;
1361 case EOpPostIncrement:
1362 outputTriplet(out, visit, "(", "", "++)");
1363 break;
1364 case EOpPostDecrement:
1365 outputTriplet(out, visit, "(", "", "--)");
1366 break;
1367 case EOpPreIncrement:
1368 outputTriplet(out, visit, "(++", "", ")");
1369 break;
1370 case EOpPreDecrement:
1371 outputTriplet(out, visit, "(--", "", ")");
1372 break;
1373 case EOpRadians:
1374 outputTriplet(out, visit, "radians(", "", ")");
1375 break;
1376 case EOpDegrees:
1377 outputTriplet(out, visit, "degrees(", "", ")");
1378 break;
1379 case EOpSin:
1380 outputTriplet(out, visit, "sin(", "", ")");
1381 break;
1382 case EOpCos:
1383 outputTriplet(out, visit, "cos(", "", ")");
1384 break;
1385 case EOpTan:
1386 outputTriplet(out, visit, "tan(", "", ")");
1387 break;
1388 case EOpAsin:
1389 outputTriplet(out, visit, "asin(", "", ")");
1390 break;
1391 case EOpAcos:
1392 outputTriplet(out, visit, "acos(", "", ")");
1393 break;
1394 case EOpAtan:
1395 outputTriplet(out, visit, "atan(", "", ")");
1396 break;
1397 case EOpSinh:
1398 outputTriplet(out, visit, "sinh(", "", ")");
1399 break;
1400 case EOpCosh:
1401 outputTriplet(out, visit, "cosh(", "", ")");
1402 break;
1403 case EOpTanh:
1404 outputTriplet(out, visit, "tanh(", "", ")");
1405 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001406 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001407 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001408 case EOpAtanh:
1409 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001410 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001411 break;
1412 case EOpExp:
1413 outputTriplet(out, visit, "exp(", "", ")");
1414 break;
1415 case EOpLog:
1416 outputTriplet(out, visit, "log(", "", ")");
1417 break;
1418 case EOpExp2:
1419 outputTriplet(out, visit, "exp2(", "", ")");
1420 break;
1421 case EOpLog2:
1422 outputTriplet(out, visit, "log2(", "", ")");
1423 break;
1424 case EOpSqrt:
1425 outputTriplet(out, visit, "sqrt(", "", ")");
1426 break;
1427 case EOpInverseSqrt:
1428 outputTriplet(out, visit, "rsqrt(", "", ")");
1429 break;
1430 case EOpAbs:
1431 outputTriplet(out, visit, "abs(", "", ")");
1432 break;
1433 case EOpSign:
1434 outputTriplet(out, visit, "sign(", "", ")");
1435 break;
1436 case EOpFloor:
1437 outputTriplet(out, visit, "floor(", "", ")");
1438 break;
1439 case EOpTrunc:
1440 outputTriplet(out, visit, "trunc(", "", ")");
1441 break;
1442 case EOpRound:
1443 outputTriplet(out, visit, "round(", "", ")");
1444 break;
1445 case EOpRoundEven:
1446 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001447 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001448 break;
1449 case EOpCeil:
1450 outputTriplet(out, visit, "ceil(", "", ")");
1451 break;
1452 case EOpFract:
1453 outputTriplet(out, visit, "frac(", "", ")");
1454 break;
1455 case EOpIsNan:
1456 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001457 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001458 else
1459 outputTriplet(out, visit, "isnan(", "", ")");
1460 mRequiresIEEEStrictCompiling = true;
1461 break;
1462 case EOpIsInf:
1463 outputTriplet(out, visit, "isinf(", "", ")");
1464 break;
1465 case EOpFloatBitsToInt:
1466 outputTriplet(out, visit, "asint(", "", ")");
1467 break;
1468 case EOpFloatBitsToUint:
1469 outputTriplet(out, visit, "asuint(", "", ")");
1470 break;
1471 case EOpIntBitsToFloat:
1472 outputTriplet(out, visit, "asfloat(", "", ")");
1473 break;
1474 case EOpUintBitsToFloat:
1475 outputTriplet(out, visit, "asfloat(", "", ")");
1476 break;
1477 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001478 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001480 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001481 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001483 case EOpPackUnorm4x8:
1484 case EOpPackSnorm4x8:
1485 case EOpUnpackUnorm4x8:
1486 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001487 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001488 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001489 break;
1490 case EOpLength:
1491 outputTriplet(out, visit, "length(", "", ")");
1492 break;
1493 case EOpNormalize:
1494 outputTriplet(out, visit, "normalize(", "", ")");
1495 break;
1496 case EOpDFdx:
1497 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1498 {
1499 outputTriplet(out, visit, "(", "", ", 0.0)");
1500 }
1501 else
1502 {
1503 outputTriplet(out, visit, "ddx(", "", ")");
1504 }
1505 break;
1506 case EOpDFdy:
1507 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1508 {
1509 outputTriplet(out, visit, "(", "", ", 0.0)");
1510 }
1511 else
1512 {
1513 outputTriplet(out, visit, "ddy(", "", ")");
1514 }
1515 break;
1516 case EOpFwidth:
1517 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1518 {
1519 outputTriplet(out, visit, "(", "", ", 0.0)");
1520 }
1521 else
1522 {
1523 outputTriplet(out, visit, "fwidth(", "", ")");
1524 }
1525 break;
1526 case EOpTranspose:
1527 outputTriplet(out, visit, "transpose(", "", ")");
1528 break;
1529 case EOpDeterminant:
1530 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1531 break;
1532 case EOpInverse:
1533 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001534 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001535 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001536
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001537 case EOpAny:
1538 outputTriplet(out, visit, "any(", "", ")");
1539 break;
1540 case EOpAll:
1541 outputTriplet(out, visit, "all(", "", ")");
1542 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001543 case EOpLogicalNotComponentWise:
1544 outputTriplet(out, visit, "(!", "", ")");
1545 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001546 case EOpBitfieldReverse:
1547 outputTriplet(out, visit, "reversebits(", "", ")");
1548 break;
1549 case EOpBitCount:
1550 outputTriplet(out, visit, "countbits(", "", ")");
1551 break;
1552 case EOpFindLSB:
1553 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1554 // in GLSLTest and results are consistent with GL.
1555 outputTriplet(out, visit, "firstbitlow(", "", ")");
1556 break;
1557 case EOpFindMSB:
1558 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1559 // tested in GLSLTest and results are consistent with GL.
1560 outputTriplet(out, visit, "firstbithigh(", "", ")");
1561 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001562 default:
1563 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001564 }
1565
1566 return true;
1567}
1568
Olli Etuaho96963162016-03-21 11:54:33 +02001569TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1570{
1571 if (node->getAsSymbolNode())
1572 {
1573 return node->getAsSymbolNode()->getSymbol();
1574 }
1575 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1576 switch (nodeBinary->getOp())
1577 {
1578 case EOpIndexDirect:
1579 {
1580 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1581
1582 TInfoSinkBase prefixSink;
1583 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1584 return TString(prefixSink.c_str());
1585 }
1586 case EOpIndexDirectStruct:
1587 {
1588 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1589 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1590 const TField *field = s->fields()[index];
1591
1592 TInfoSinkBase prefixSink;
1593 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1594 << field->name();
1595 return TString(prefixSink.c_str());
1596 }
1597 default:
1598 UNREACHABLE();
1599 return TString("");
1600 }
1601}
1602
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001603bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1604{
1605 TInfoSinkBase &out = getInfoSink();
1606
1607 if (mInsideFunction)
1608 {
1609 outputLineDirective(out, node->getLine().first_line);
1610 out << "{\n";
1611 }
1612
1613 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1614 sit != node->getSequence()->end(); sit++)
1615 {
1616 outputLineDirective(out, (*sit)->getLine().first_line);
1617
1618 (*sit)->traverse(this);
1619
1620 // Don't output ; after case labels, they're terminated by :
1621 // This is needed especially since outputting a ; after a case statement would turn empty
1622 // case statements into non-empty case statements, disallowing fall-through from them.
1623 // Also no need to output ; after if statements or sequences. This is done just for
1624 // code clarity.
1625 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1626 (*sit)->getAsBlock() == nullptr)
1627 out << ";\n";
1628 }
1629
1630 if (mInsideFunction)
1631 {
1632 outputLineDirective(out, node->getLine().last_line);
1633 out << "}\n";
1634 }
1635
1636 return false;
1637}
1638
Olli Etuaho336b1472016-10-05 16:37:55 +01001639bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1640{
1641 TInfoSinkBase &out = getInfoSink();
1642
1643 ASSERT(mCurrentFunctionMetadata == nullptr);
1644
1645 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1646 ASSERT(index != CallDAG::InvalidIndex);
1647 mCurrentFunctionMetadata = &mASTMetadataList[index];
1648
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001649 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001650
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001651 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001652
1653 if (node->getFunctionSymbolInfo()->isMain())
1654 {
1655 out << "gl_main(";
1656 }
1657 else
1658 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001659 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001660 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1661 }
1662
1663 for (unsigned int i = 0; i < parameters->size(); i++)
1664 {
1665 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1666
1667 if (symbol)
1668 {
1669 ensureStructDefined(symbol->getType());
1670
1671 out << argumentString(symbol);
1672
1673 if (i < parameters->size() - 1)
1674 {
1675 out << ", ";
1676 }
1677 }
1678 else
1679 UNREACHABLE();
1680 }
1681
1682 out << ")\n";
1683
1684 mInsideFunction = true;
1685 // The function body node will output braces.
1686 node->getBody()->traverse(this);
1687 mInsideFunction = false;
1688
1689 mCurrentFunctionMetadata = nullptr;
1690
1691 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1692 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1693 {
1694 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1695 mOutputLod0Function = true;
1696 node->traverse(this);
1697 mOutputLod0Function = false;
1698 }
1699
1700 return false;
1701}
1702
Olli Etuaho13389b62016-10-16 11:48:18 +01001703bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1704{
1705 TInfoSinkBase &out = getInfoSink();
1706 if (visit == PreVisit)
1707 {
1708 TIntermSequence *sequence = node->getSequence();
1709 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1710 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001711 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001712
Olli Etuaho282847e2017-07-12 14:11:01 +03001713 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001714 variable->getQualifier() == EvqConst))
1715 {
1716 ensureStructDefined(variable->getType());
1717
1718 if (!variable->getAsSymbolNode() ||
1719 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1720 {
1721 if (!mInsideFunction)
1722 {
1723 out << "static ";
1724 }
1725
1726 out << TypeString(variable->getType()) + " ";
1727
1728 TIntermSymbol *symbol = variable->getAsSymbolNode();
1729
1730 if (symbol)
1731 {
1732 symbol->traverse(this);
1733 out << ArrayString(symbol->getType());
1734 out << " = " + initializer(symbol->getType());
1735 }
1736 else
1737 {
1738 variable->traverse(this);
1739 }
1740 }
1741 else if (variable->getAsSymbolNode() &&
1742 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1743 {
1744 // Already added to constructor map
1745 }
1746 else
1747 UNREACHABLE();
1748 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001749 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001750 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001751 TIntermSymbol *symbol = variable->getAsSymbolNode();
1752 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001753
Olli Etuaho282847e2017-07-12 14:11:01 +03001754 // Vertex outputs which are declared but not written to should still be declared to
1755 // allow successful linking.
1756 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001757 }
1758 }
1759 return false;
1760}
1761
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001762bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1763{
1764 // Do not do any translation
1765 return false;
1766}
1767
Olli Etuaho16c745a2017-01-16 17:02:27 +00001768bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1769{
1770 TInfoSinkBase &out = getInfoSink();
1771
1772 ASSERT(visit == PreVisit);
1773 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1774 // Skip the prototype if it is not implemented (and thus not used)
1775 if (index == CallDAG::InvalidIndex)
1776 {
1777 return false;
1778 }
1779
1780 TIntermSequence *arguments = node->getSequence();
1781
Olli Etuahoff526f12017-06-30 12:26:54 +03001782 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001783 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1784 << (mOutputLod0Function ? "Lod0(" : "(");
1785
1786 for (unsigned int i = 0; i < arguments->size(); i++)
1787 {
1788 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1789 ASSERT(symbol != nullptr);
1790
1791 out << argumentString(symbol);
1792
1793 if (i < arguments->size() - 1)
1794 {
1795 out << ", ";
1796 }
1797 }
1798
1799 out << ");\n";
1800
1801 // Also prototype the Lod0 variant if needed
1802 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1803 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1804 {
1805 mOutputLod0Function = true;
1806 node->traverse(this);
1807 mOutputLod0Function = false;
1808 }
1809
1810 return false;
1811}
1812
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001813bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1814{
Jamie Madill32aab012015-01-27 14:12:26 -05001815 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001816
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001817 switch (node->getOp())
1818 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001819 case EOpCallBuiltInFunction:
1820 case EOpCallFunctionInAST:
1821 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001822 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001823 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001824
Corentin Wallez1239ee92015-03-19 14:38:02 -07001825 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001826 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001827 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001828 if (node->isArray())
1829 {
1830 UNIMPLEMENTED();
1831 }
Olli Etuahobd674552016-10-06 13:28:42 +01001832 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001833 ASSERT(index != CallDAG::InvalidIndex);
1834 lod0 &= mASTMetadataList[index].mNeedsLod0;
1835
Olli Etuahoff526f12017-06-30 12:26:54 +03001836 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001837 out << DisambiguateFunctionName(node->getSequence());
1838 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001839 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001840 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001841 {
1842 // This path is used for internal functions that don't have their definitions in the
1843 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001844 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001845 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001846 else
1847 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001848 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001849 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001850 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1851 if (arguments->size() > 1)
1852 {
1853 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1854 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001855 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1856 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1857 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001858 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001859
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001860 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001861 {
Olli Etuaho96963162016-03-21 11:54:33 +02001862 TIntermTyped *typedArg = (*arg)->getAsTyped();
1863 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001864 {
1865 out << "texture_";
1866 (*arg)->traverse(this);
1867 out << ", sampler_";
1868 }
1869
1870 (*arg)->traverse(this);
1871
Olli Etuaho96963162016-03-21 11:54:33 +02001872 if (typedArg->getType().isStructureContainingSamplers())
1873 {
1874 const TType &argType = typedArg->getType();
1875 TVector<TIntermSymbol *> samplerSymbols;
1876 TString structName = samplerNamePrefixFromStruct(typedArg);
1877 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho96963162016-03-21 11:54:33 +02001878 &samplerSymbols, nullptr);
1879 for (const TIntermSymbol *sampler : samplerSymbols)
1880 {
1881 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1882 {
1883 out << ", texture_" << sampler->getSymbol();
1884 out << ", sampler_" << sampler->getSymbol();
1885 }
1886 else
1887 {
1888 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1889 // of D3D9, it's the sampler variable.
1890 out << ", " + sampler->getSymbol();
1891 }
1892 }
1893 }
1894
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001895 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001896 {
1897 out << ", ";
1898 }
1899 }
1900
1901 out << ")";
1902
1903 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001904 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001905 case EOpConstruct:
1906 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001907 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001908 if (node->getType().isArray())
1909 {
1910 UNIMPLEMENTED();
1911 }
1912 const TString &structName = StructNameString(*node->getType().getStruct());
1913 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1914 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001915 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001916 else
1917 {
1918 const char *name = "";
1919 if (node->getType().getNominalSize() == 1)
1920 {
1921 switch (node->getBasicType())
1922 {
1923 case EbtFloat:
1924 name = "vec1";
1925 break;
1926 case EbtInt:
1927 name = "ivec1";
1928 break;
1929 case EbtUInt:
1930 name = "uvec1";
1931 break;
1932 case EbtBool:
1933 name = "bvec1";
1934 break;
1935 default:
1936 UNREACHABLE();
1937 }
1938 }
1939 else
1940 {
1941 name = node->getType().getBuiltInTypeNameString();
1942 }
1943 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1944 }
1945 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001946 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001947 outputTriplet(out, visit, "(", " == ", ")");
1948 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001949 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001950 outputTriplet(out, visit, "(", " != ", ")");
1951 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001952 case EOpLessThanComponentWise:
1953 outputTriplet(out, visit, "(", " < ", ")");
1954 break;
1955 case EOpGreaterThanComponentWise:
1956 outputTriplet(out, visit, "(", " > ", ")");
1957 break;
1958 case EOpLessThanEqualComponentWise:
1959 outputTriplet(out, visit, "(", " <= ", ")");
1960 break;
1961 case EOpGreaterThanEqualComponentWise:
1962 outputTriplet(out, visit, "(", " >= ", ")");
1963 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001964 case EOpMod:
1965 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001966 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001967 break;
1968 case EOpModf:
1969 outputTriplet(out, visit, "modf(", ", ", ")");
1970 break;
1971 case EOpPow:
1972 outputTriplet(out, visit, "pow(", ", ", ")");
1973 break;
1974 case EOpAtan:
1975 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1976 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001977 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001978 break;
1979 case EOpMin:
1980 outputTriplet(out, visit, "min(", ", ", ")");
1981 break;
1982 case EOpMax:
1983 outputTriplet(out, visit, "max(", ", ", ")");
1984 break;
1985 case EOpClamp:
1986 outputTriplet(out, visit, "clamp(", ", ", ")");
1987 break;
1988 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301989 {
1990 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1991 if (lastParamNode->getType().getBasicType() == EbtBool)
1992 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001993 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1994 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301995 // so use emulated version.
1996 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001997 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301998 }
1999 else
2000 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002001 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302002 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002003 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302004 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002005 case EOpStep:
2006 outputTriplet(out, visit, "step(", ", ", ")");
2007 break;
2008 case EOpSmoothStep:
2009 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2010 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002011 case EOpFrexp:
2012 case EOpLdexp:
2013 ASSERT(node->getUseEmulatedFunction());
2014 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2015 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002016 case EOpDistance:
2017 outputTriplet(out, visit, "distance(", ", ", ")");
2018 break;
2019 case EOpDot:
2020 outputTriplet(out, visit, "dot(", ", ", ")");
2021 break;
2022 case EOpCross:
2023 outputTriplet(out, visit, "cross(", ", ", ")");
2024 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002025 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002026 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002027 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002028 break;
2029 case EOpReflect:
2030 outputTriplet(out, visit, "reflect(", ", ", ")");
2031 break;
2032 case EOpRefract:
2033 outputTriplet(out, visit, "refract(", ", ", ")");
2034 break;
2035 case EOpOuterProduct:
2036 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002037 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002038 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002039 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002040 outputTriplet(out, visit, "(", " * ", ")");
2041 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002042 case EOpBitfieldExtract:
2043 case EOpBitfieldInsert:
2044 case EOpUaddCarry:
2045 case EOpUsubBorrow:
2046 case EOpUmulExtended:
2047 case EOpImulExtended:
2048 ASSERT(node->getUseEmulatedFunction());
2049 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2050 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002051 default:
2052 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002053 }
2054
2055 return true;
2056}
2057
Olli Etuaho57961272016-09-14 13:57:46 +03002058void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002059{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002060 out << "if (";
2061
2062 node->getCondition()->traverse(this);
2063
2064 out << ")\n";
2065
Jamie Madill8c46ab12015-12-07 16:39:19 -05002066 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002067
2068 bool discard = false;
2069
2070 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002071 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002072 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002073 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002074
Olli Etuahoa6f22092015-05-08 18:31:10 +03002075 // Detect true discard
2076 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2077 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002078 else
2079 {
2080 // TODO(oetuaho): Check if the semicolon inside is necessary.
2081 // It's there as a result of conservative refactoring of the output.
2082 out << "{;}\n";
2083 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002084
Jamie Madill8c46ab12015-12-07 16:39:19 -05002085 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002086
Olli Etuahoa6f22092015-05-08 18:31:10 +03002087 if (node->getFalseBlock())
2088 {
2089 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002090
Jamie Madill8c46ab12015-12-07 16:39:19 -05002091 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002092
Olli Etuaho32db19b2016-10-04 14:43:16 +01002093 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002094 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002095
Jamie Madill8c46ab12015-12-07 16:39:19 -05002096 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002097
Olli Etuahoa6f22092015-05-08 18:31:10 +03002098 // Detect false discard
2099 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2100 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002101
Olli Etuahoa6f22092015-05-08 18:31:10 +03002102 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002103 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002104 {
2105 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002106 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002107}
2108
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002109bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2110{
2111 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2112 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2113 UNREACHABLE();
2114 return false;
2115}
2116
Olli Etuaho57961272016-09-14 13:57:46 +03002117bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002118{
2119 TInfoSinkBase &out = getInfoSink();
2120
Olli Etuaho3d932d82016-04-12 11:10:30 +03002121 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002122
2123 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002124 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002125 {
2126 out << "FLATTEN ";
2127 }
2128
Olli Etuaho57961272016-09-14 13:57:46 +03002129 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002130
2131 return false;
2132}
2133
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002134bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002135{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002136 TInfoSinkBase &out = getInfoSink();
2137
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002138 if (node->getStatementList())
2139 {
Olli Etuaho852fe872017-10-10 15:13:59 +03002140 if (visit == PreVisit)
2141 {
2142 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList()));
2143 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002144 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho852fe872017-10-10 15:13:59 +03002145 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002146 }
2147 else
2148 {
2149 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002150 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002151 }
2152 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002153}
2154
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002155bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002156{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002157 TInfoSinkBase &out = getInfoSink();
2158
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002159 if (node->hasCondition())
2160 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002161 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002162 return true;
2163 }
2164 else
2165 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002166 out << "default:\n";
2167 return false;
2168 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002169}
2170
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2172{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002173 TInfoSinkBase &out = getInfoSink();
2174 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002175}
2176
2177bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2178{
Nicolas Capens655fe362014-04-11 13:12:34 -04002179 mNestedLoopDepth++;
2180
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002181 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002182 mInsideDiscontinuousLoop =
2183 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002184
Jamie Madill8c46ab12015-12-07 16:39:19 -05002185 TInfoSinkBase &out = getInfoSink();
2186
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002187 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002188 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002189 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002190 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002191 mInsideDiscontinuousLoop = wasDiscontinuous;
2192 mNestedLoopDepth--;
2193
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002194 return false;
2195 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002196 }
2197
Corentin Wallez1239ee92015-03-19 14:38:02 -07002198 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002199 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002201 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002202
Jamie Madill8c46ab12015-12-07 16:39:19 -05002203 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002204 }
2205 else
2206 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002207 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002208
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002209 if (node->getInit())
2210 {
2211 node->getInit()->traverse(this);
2212 }
2213
2214 out << "; ";
2215
alokp@chromium.org52813552010-11-16 18:36:09 +00002216 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002217 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002218 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
2220
2221 out << "; ";
2222
alokp@chromium.org52813552010-11-16 18:36:09 +00002223 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002224 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002225 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002226 }
2227
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002228 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002229
Jamie Madill8c46ab12015-12-07 16:39:19 -05002230 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002231 }
2232
2233 if (node->getBody())
2234 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002235 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002236 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002237 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002238 else
2239 {
2240 // TODO(oetuaho): Check if the semicolon inside is necessary.
2241 // It's there as a result of conservative refactoring of the output.
2242 out << "{;}\n";
2243 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002244
Jamie Madill8c46ab12015-12-07 16:39:19 -05002245 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002246
alokp@chromium.org52813552010-11-16 18:36:09 +00002247 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002248 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002249 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002250 out << "while(\n";
2251
alokp@chromium.org52813552010-11-16 18:36:09 +00002252 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002253
daniel@transgaming.com73536982012-03-21 20:45:49 +00002254 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002255 }
2256
daniel@transgaming.com73536982012-03-21 20:45:49 +00002257 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002258
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002259 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002260 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002261
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002262 return false;
2263}
2264
2265bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2266{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002267 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002268 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002269 TInfoSinkBase &out = getInfoSink();
2270
2271 switch (node->getFlowOp())
2272 {
2273 case EOpKill:
2274 out << "discard";
2275 break;
2276 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002277 if (mNestedLoopDepth > 1)
2278 {
2279 mUsesNestedBreak = true;
2280 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002281
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002282 if (mExcessiveLoopIndex)
2283 {
2284 out << "{Break";
2285 mExcessiveLoopIndex->traverse(this);
2286 out << " = true; break;}\n";
2287 }
2288 else
2289 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002290 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002291 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002292 break;
2293 case EOpContinue:
2294 out << "continue";
2295 break;
2296 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002297 if (node->getExpression())
2298 {
2299 out << "return ";
2300 }
2301 else
2302 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002303 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002304 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002305 break;
2306 default:
2307 UNREACHABLE();
2308 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309 }
2310
2311 return true;
2312}
2313
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002314// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002315// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2316// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002317bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002318{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002319 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002320
2321 // Parse loops of the form:
2322 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002323 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002324 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002325 int initial = 0;
2326 int limit = 0;
2327 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002328
2329 // Parse index name and intial value
2330 if (node->getInit())
2331 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002332 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002333
2334 if (init)
2335 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002336 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002337 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002338
2339 if (variable && variable->getQualifier() == EvqTemporary)
2340 {
2341 TIntermBinary *assign = variable->getAsBinaryNode();
2342
2343 if (assign->getOp() == EOpInitialize)
2344 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002345 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002346 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2347
2348 if (symbol && constant)
2349 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002350 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002351 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002352 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002353 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002354 }
2355 }
2356 }
2357 }
2358 }
2359 }
2360
2361 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002362 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002363 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002364 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002365
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002366 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2367 {
2368 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2369
2370 if (constant)
2371 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002372 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002373 {
2374 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002375 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002376 }
2377 }
2378 }
2379 }
2380
2381 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002382 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002383 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002384 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002385 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002386
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002387 if (binaryTerminal)
2388 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002389 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002390 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2391
2392 if (constant)
2393 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002394 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002395 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002396 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002397
2398 switch (op)
2399 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002400 case EOpAddAssign:
2401 increment = value;
2402 break;
2403 case EOpSubAssign:
2404 increment = -value;
2405 break;
2406 default:
2407 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002408 }
2409 }
2410 }
2411 }
2412 else if (unaryTerminal)
2413 {
2414 TOperator op = unaryTerminal->getOp();
2415
2416 switch (op)
2417 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002418 case EOpPostIncrement:
2419 increment = 1;
2420 break;
2421 case EOpPostDecrement:
2422 increment = -1;
2423 break;
2424 case EOpPreIncrement:
2425 increment = 1;
2426 break;
2427 case EOpPreDecrement:
2428 increment = -1;
2429 break;
2430 default:
2431 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002432 }
2433 }
2434 }
2435
Yunchao He4f285442017-04-21 12:15:49 +08002436 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002437 {
2438 if (comparator == EOpLessThanEqual)
2439 {
2440 comparator = EOpLessThan;
2441 limit += 1;
2442 }
2443
2444 if (comparator == EOpLessThan)
2445 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002446 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002447
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002448 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002449 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002450 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002451 }
2452
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002453 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002454 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002455
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002456 out << "{int ";
2457 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002458 out << ";\n"
2459 "bool Break";
2460 index->traverse(this);
2461 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002462
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002463 bool firstLoopFragment = true;
2464
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002465 while (iterations > 0)
2466 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002467 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002468
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002469 if (!firstLoopFragment)
2470 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002471 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002472 index->traverse(this);
2473 out << ") {\n";
2474 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002475
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002476 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002477 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002478 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002479 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002480
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002481 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002482 const char *unroll =
2483 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002484
Corentin Wallez1239ee92015-03-19 14:38:02 -07002485 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002486 index->traverse(this);
2487 out << " = ";
2488 out << initial;
2489
2490 out << "; ";
2491 index->traverse(this);
2492 out << " < ";
2493 out << clampedLimit;
2494
2495 out << "; ";
2496 index->traverse(this);
2497 out << " += ";
2498 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002499 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002500
Jamie Madill8c46ab12015-12-07 16:39:19 -05002501 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002502 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002503
2504 if (node->getBody())
2505 {
2506 node->getBody()->traverse(this);
2507 }
2508
Jamie Madill8c46ab12015-12-07 16:39:19 -05002509 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002510 out << ";}\n";
2511
2512 if (!firstLoopFragment)
2513 {
2514 out << "}\n";
2515 }
2516
2517 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002518
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002519 initial += MAX_LOOP_ITERATIONS * increment;
2520 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002521 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002522
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002523 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002524
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002525 mExcessiveLoopIndex = restoreIndex;
2526
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002527 return true;
2528 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002529 else
2530 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002531 }
2532
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002533 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002534}
2535
Jamie Madill8c46ab12015-12-07 16:39:19 -05002536void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2537 Visit visit,
2538 const char *preString,
2539 const char *inString,
2540 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002541{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002542 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002543 {
2544 out << preString;
2545 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002546 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002547 {
2548 out << inString;
2549 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002550 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002551 {
2552 out << postString;
2553 }
2554}
2555
Jamie Madill8c46ab12015-12-07 16:39:19 -05002556void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002557{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002558 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002559 {
Jamie Madill32aab012015-01-27 14:12:26 -05002560 out << "\n";
2561 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002562
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002563 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002564 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002565 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002566 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002567
Jamie Madill32aab012015-01-27 14:12:26 -05002568 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002569 }
2570}
2571
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002572TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2573{
2574 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002575 const TType &type = symbol->getType();
2576 const TName &name = symbol->getName();
2577 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002578
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002579 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002580 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002581 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002582 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002583 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002584 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002585 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002586 }
2587
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002588 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002589 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002590 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2591 {
2592 // Samplers are passed as indices to the sampler array.
2593 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2594 return "const uint " + nameStr + ArrayString(type);
2595 }
2596 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2597 {
2598 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2599 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2600 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2601 ArrayString(type);
2602 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002603 }
2604
Olli Etuaho96963162016-03-21 11:54:33 +02002605 TStringStream argString;
2606 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2607 << ArrayString(type);
2608
2609 // If the structure parameter contains samplers, they need to be passed into the function as
2610 // separate parameters. HLSL doesn't natively support samplers in structs.
2611 if (type.isStructureContainingSamplers())
2612 {
2613 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2614 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho599555b2017-08-15 11:12:42 +03002615 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002616 for (const TIntermSymbol *sampler : samplerSymbols)
2617 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002618 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002619 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2620 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002621 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002622 }
2623 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2624 {
Olli Etuaho96963162016-03-21 11:54:33 +02002625 ASSERT(IsSampler(samplerType.getBasicType()));
2626 argString << ", " << QualifierString(qualifier) << " "
2627 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002628 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2629 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002630 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002631 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002632 }
2633 else
2634 {
Olli Etuaho96963162016-03-21 11:54:33 +02002635 ASSERT(IsSampler(samplerType.getBasicType()));
2636 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002637 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002638 }
2639 }
2640 }
2641
2642 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002643}
2644
2645TString OutputHLSL::initializer(const TType &type)
2646{
2647 TString string;
2648
Jamie Madill94bf7f22013-07-08 13:31:15 -04002649 size_t size = type.getObjectSize();
2650 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002651 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002652 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002653
Jamie Madill94bf7f22013-07-08 13:31:15 -04002654 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002655 {
2656 string += ", ";
2657 }
2658 }
2659
daniel@transgaming.comead23042010-04-29 03:35:36 +00002660 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002661}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002662
Jamie Madill8c46ab12015-12-07 16:39:19 -05002663void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2664 Visit visit,
2665 const TType &type,
2666 const char *name,
2667 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002668{
Olli Etuahof40319e2015-03-10 14:33:00 +02002669 if (type.isArray())
2670 {
2671 UNIMPLEMENTED();
2672 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002673
2674 if (visit == PreVisit)
2675 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002676 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002677
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002678 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002679 }
2680 else if (visit == InVisit)
2681 {
2682 out << ", ";
2683 }
2684 else if (visit == PostVisit)
2685 {
2686 out << ")";
2687 }
2688}
2689
Jamie Madill8c46ab12015-12-07 16:39:19 -05002690const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2691 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002692 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002693{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002694 const TConstantUnion *constUnionIterated = constUnion;
2695
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002696 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002697 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002698 {
Jamie Madill033dae62014-06-18 12:56:28 -04002699 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002700
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002701 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002702
Jamie Madill98493dd2013-07-08 14:39:03 -04002703 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002704 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002705 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002706 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002707
Jamie Madill98493dd2013-07-08 14:39:03 -04002708 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002709 {
2710 out << ", ";
2711 }
2712 }
2713
2714 out << ")";
2715 }
2716 else
2717 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002718 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002719 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002720
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002721 if (writeType)
2722 {
Jamie Madill033dae62014-06-18 12:56:28 -04002723 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002724 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002725 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002726 if (writeType)
2727 {
2728 out << ")";
2729 }
2730 }
2731
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002732 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002733}
2734
Olli Etuahod68924e2017-01-02 17:34:40 +00002735void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002736{
Olli Etuahod68924e2017-01-02 17:34:40 +00002737 if (visit == PreVisit)
2738 {
2739 const char *opStr = GetOperatorString(op);
2740 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2741 out << "(";
2742 }
2743 else
2744 {
2745 outputTriplet(out, visit, nullptr, ", ", ")");
2746 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002747}
2748
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002749bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2750 TIntermSymbol *symbolNode,
2751 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002752{
2753 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2754 expression->traverse(&searchSymbol);
2755
2756 if (searchSymbol.foundMatch())
2757 {
2758 // Type already printed
2759 out << "t" + str(mUniqueIndex) + " = ";
2760 expression->traverse(this);
2761 out << ", ";
2762 symbolNode->traverse(this);
2763 out << " = t" + str(mUniqueIndex);
2764
2765 mUniqueIndex++;
2766 return true;
2767 }
2768
2769 return false;
2770}
2771
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002772bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2773{
2774 // We support writing constant unions and constructors that only take constant unions as
2775 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002776 return !expression->getType().isArrayOfArrays() &&
2777 (expression->getAsConstantUnion() ||
2778 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002779}
2780
2781bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2782 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002783 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002784{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002785 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002786 {
2787 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002788 ASSERT(!symbolNode->getType().isArrayOfArrays());
2789 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002790 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002791 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002792 }
2793 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002794 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002795 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002796 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002797 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002798 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002799 }
2800 else
2801 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002802 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002803 ASSERT(constructor != nullptr);
2804 for (TIntermNode *&node : *constructor->getSequence())
2805 {
2806 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2807 ASSERT(nodeConst);
2808 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002809 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002810 if (node != constructor->getSequence()->back())
2811 {
2812 out << ", ";
2813 }
2814 }
2815 }
2816 out << "}";
2817 return true;
2818 }
2819 return false;
2820}
2821
Jamie Madill55e79e02015-02-09 15:35:00 -05002822TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2823{
2824 const TFieldList &fields = structure.fields();
2825
2826 for (const auto &eqFunction : mStructEqualityFunctions)
2827 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002828 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002829 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002830 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002831 }
2832 }
2833
2834 const TString &structNameString = StructNameString(structure);
2835
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002836 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002837 function->structure = &structure;
2838 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002839
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002840 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002841
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002842 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2843 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002844 << "{\n"
2845 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002846
2847 for (size_t i = 0; i < fields.size(); i++)
2848 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002849 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002850 const TType *fieldType = field->type();
2851
2852 const TString &fieldNameA = "a." + Decorate(field->name());
2853 const TString &fieldNameB = "b." + Decorate(field->name());
2854
2855 if (i > 0)
2856 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002857 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002858 }
2859
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002860 fnOut << "(";
2861 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2862 fnOut << fieldNameA;
2863 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2864 fnOut << fieldNameB;
2865 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2866 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002867 }
2868
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002869 fnOut << ";\n"
2870 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002871
2872 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002873
2874 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002875 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002876
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002877 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002878}
2879
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002880TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002881{
2882 for (const auto &eqFunction : mArrayEqualityFunctions)
2883 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002885 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002886 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002887 }
2888 }
2889
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002890 TType elementType(type);
2891 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002892
Olli Etuaho12690762015-03-31 12:55:28 +03002893 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002894 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002895
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002896 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002897
2898 TInfoSinkBase fnOut;
2899
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002900 const TString &typeName = TypeString(type);
2901 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2902 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002903 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002904 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002905 << type.getOutermostArraySize()
2906 << "; ++i)\n"
2907 " {\n"
2908 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002909
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002910 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002911 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002912 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002913 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002914 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002915
2916 fnOut << ") { return false; }\n"
2917 " }\n"
2918 " return true;\n"
2919 "}\n";
2920
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002921 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002922
2923 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002924 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002925
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002926 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002927}
2928
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002929TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002930{
2931 for (const auto &assignFunction : mArrayAssignmentFunctions)
2932 {
2933 if (assignFunction.type == type)
2934 {
2935 return assignFunction.functionName;
2936 }
2937 }
2938
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002939 TType elementType(type);
2940 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002941
2942 ArrayHelperFunction function;
2943 function.type = type;
2944
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002945 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002946
2947 TInfoSinkBase fnOut;
2948
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002949 const TString &typeName = TypeString(type);
2950 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2951 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002952 << "{\n"
2953 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 << type.getOutermostArraySize()
2955 << "; ++i)\n"
2956 " {\n"
2957 " ";
2958
2959 outputAssign(PreVisit, elementType, fnOut);
2960 fnOut << "a[i]";
2961 outputAssign(InVisit, elementType, fnOut);
2962 fnOut << "b[i]";
2963 outputAssign(PostVisit, elementType, fnOut);
2964
2965 fnOut << ";\n"
2966 " }\n"
2967 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002968
2969 function.functionDefinition = fnOut.c_str();
2970
2971 mArrayAssignmentFunctions.push_back(function);
2972
2973 return function.functionName;
2974}
2975
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002976TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002977{
2978 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2979 {
2980 if (constructIntoFunction.type == type)
2981 {
2982 return constructIntoFunction.functionName;
2983 }
2984 }
2985
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002986 TType elementType(type);
2987 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03002988
2989 ArrayHelperFunction function;
2990 function.type = type;
2991
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002992 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03002993
2994 TInfoSinkBase fnOut;
2995
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002996 const TString &typeName = TypeString(type);
2997 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
2998 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03002999 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003000 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003001 }
3002 fnOut << ")\n"
3003 "{\n";
3004
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003005 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003006 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003007 fnOut << " ";
3008 outputAssign(PreVisit, elementType, fnOut);
3009 fnOut << "a[" << i << "]";
3010 outputAssign(InVisit, elementType, fnOut);
3011 fnOut << "b" << i;
3012 outputAssign(PostVisit, elementType, fnOut);
3013 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003014 }
3015 fnOut << "}\n";
3016
3017 function.functionDefinition = fnOut.c_str();
3018
3019 mArrayConstructIntoFunctions.push_back(function);
3020
3021 return function.functionName;
3022}
3023
Jamie Madill2e295e22015-04-29 10:41:33 -04003024void OutputHLSL::ensureStructDefined(const TType &type)
3025{
3026 TStructure *structure = type.getStruct();
3027
3028 if (structure)
3029 {
3030 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3031 }
3032}
3033
Jamie Madill45bcc782016-11-07 13:58:48 -05003034} // namespace sh