blob: b19e81cd9502428fac0e119faaa1a6bfade25b6a [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00009#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000010#include <cfloat>
11#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000012
Jamie Madill9e0478f2015-01-13 11:13:54 -050013#include "common/angleutils.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030014#include "common/debug.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/utilities.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020016#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050017#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/FlagStd140Structs.h"
19#include "compiler/translator/InfoSink.h"
20#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020021#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/SearchSymbol.h"
23#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030024#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/UniformHLSL.h"
27#include "compiler/translator/UtilsHLSL.h"
28#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
41 for (unsigned int arraySize : type.getArraySizes())
42 {
43 fnName << arraySize << "_";
44 }
45 fnName << TypeString(type);
46 return fnName.str();
47}
48
49} // anonymous namespace
50
Olli Etuaho56a2f952016-12-08 12:16:27 +000051void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030052{
Olli Etuaho56a2f952016-12-08 12:16:27 +000053 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
54 // regardless.
55 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
56 mOutputType == SH_HLSL_4_1_OUTPUT)
57 {
58 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
59 }
60 else
61 {
62 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
63 }
64}
Olli Etuaho4785fec2015-05-18 16:09:37 +030065
Olli Etuaho56a2f952016-12-08 12:16:27 +000066void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020067{
68 ASSERT(constUnion != nullptr);
69 switch (constUnion->getType())
70 {
71 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000072 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020073 break;
74 case EbtInt:
75 out << constUnion->getIConst();
76 break;
77 case EbtUInt:
78 out << constUnion->getUConst();
79 break;
80 case EbtBool:
81 out << constUnion->getBConst();
82 break;
83 default:
84 UNREACHABLE();
85 }
86}
87
Olli Etuaho56a2f952016-12-08 12:16:27 +000088const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
89 const TConstantUnion *const constUnion,
90 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020091{
92 const TConstantUnion *constUnionIterated = constUnion;
93 for (size_t i = 0; i < size; i++, constUnionIterated++)
94 {
Olli Etuaho56a2f952016-12-08 12:16:27 +000095 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +020096
97 if (i != size - 1)
98 {
99 out << ", ";
100 }
101 }
102 return constUnionIterated;
103}
104
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800105OutputHLSL::OutputHLSL(sh::GLenum shaderType,
106 int shaderVersion,
107 const TExtensionBehavior &extensionBehavior,
108 const char *sourcePath,
109 ShShaderOutput outputType,
110 int numRenderTargets,
111 const std::vector<Uniform> &uniforms,
112 ShCompileOptions compileOptions)
Jamie Madill54ad4f82014-09-03 09:40:46 -0400113 : TIntermTraverser(true, true, true),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200114 mShaderType(shaderType),
115 mShaderVersion(shaderVersion),
116 mExtensionBehavior(extensionBehavior),
117 mSourcePath(sourcePath),
118 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700119 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000120 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700121 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000123 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000124
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500125 mUsesFragColor = false;
126 mUsesFragData = false;
127 mUsesDepthRange = false;
128 mUsesFragCoord = false;
129 mUsesPointCoord = false;
130 mUsesFrontFacing = false;
131 mUsesPointSize = false;
132 mUsesInstanceID = false;
Martin Radev41ac68e2017-06-06 12:16:58 +0300133 mHasMultiviewExtensionEnabled = IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview") ||
134 IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview2");
135 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500136 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500137 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800138 mUsesNumWorkGroups = false;
139 mUsesWorkGroupID = false;
140 mUsesLocalInvocationID = false;
141 mUsesGlobalInvocationID = false;
142 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500143 mUsesXor = false;
144 mUsesDiscardRewriting = false;
145 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530146 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000147
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000148 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000149
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500150 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000151 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500152 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000153
Yunchao Hed7297bf2017-04-19 15:27:10 +0800154 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000155
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500156 mStructureHLSL = new StructureHLSL;
157 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300158 mTextureFunctionHLSL = new TextureFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400159
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200160 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000161 {
Arun Patole63419392015-03-13 11:51:07 +0530162 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
164 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530165 // In both cases total 3 uniform registers need to be reserved.
166 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000167 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000168
Geoff Lang00140f42016-02-03 18:47:33 +0000169 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800170 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171}
172
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000173OutputHLSL::~OutputHLSL()
174{
Jamie Madill8daaba12014-06-13 10:04:33 -0400175 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400176 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300177 SafeDelete(mTextureFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200178 for (auto &eqFunction : mStructEqualityFunctions)
179 {
180 SafeDelete(eqFunction);
181 }
182 for (auto &eqFunction : mArrayEqualityFunctions)
183 {
184 SafeDelete(eqFunction);
185 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000186}
187
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200188void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000189{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500190 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400191 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000192
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200193 BuiltInFunctionEmulator builtInFunctionEmulator;
194 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800195 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
196 {
197 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
198 mShaderVersion);
199 }
200
Olli Etuahodfa75e82017-01-23 09:43:06 -0800201 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500202
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700203 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000204 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700205 ASSERT(success == CallDAG::INITDAG_SUCCESS);
206 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700207
Jamie Madill37997142015-01-28 10:06:34 -0500208 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500209 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200210 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500211 mInfoSinkStack.pop();
212
Jamie Madill37997142015-01-28 10:06:34 -0500213 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500214 mInfoSinkStack.pop();
215
Jamie Madill32aab012015-01-27 14:12:26 -0500216 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500217 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500218 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000219
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200220 objSink << mHeader.c_str();
221 objSink << mBody.c_str();
222 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200223
Olli Etuahodfa75e82017-01-23 09:43:06 -0800224 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000225}
226
Jamie Madill570e04d2013-06-21 09:15:33 -0400227void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
228{
229 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
230 {
231 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
232
Jamie Madill32aab012015-01-27 14:12:26 -0500233 TInfoSinkBase structInfoSink;
234 mInfoSinkStack.push(&structInfoSink);
235
Jamie Madill570e04d2013-06-21 09:15:33 -0400236 // This will mark the necessary block elements as referenced
237 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500238
239 TString structName(structInfoSink.c_str());
240 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400241
242 mFlaggedStructOriginalNames[flaggedNode] = structName;
243
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500244 for (size_t pos = structName.find('.'); pos != std::string::npos;
245 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400246 {
247 structName.erase(pos, 1);
248 }
249
250 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
251 }
252}
253
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800254const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400255{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800256 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400257}
258
Jamie Madill9fe25e92014-07-18 10:33:08 -0400259const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
260{
261 return mUniformHLSL->getUniformRegisterMap();
262}
263
Olli Etuahoed049ab2017-06-30 17:38:33 +0300264TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400265{
266 TString init;
267
Olli Etuahoed049ab2017-06-30 17:38:33 +0300268 TString indentString;
269 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400270 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300271 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400272 }
273
Olli Etuahoed049ab2017-06-30 17:38:33 +0300274 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400275 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300276 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300277 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400278 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300279 TStringStream indexedString;
280 indexedString << name << "[" << arrayIndex << "]";
281 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300282 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300283 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300284 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300285 {
286 init += ",";
287 }
288 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400289 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300292 else if (type.getBasicType() == EbtStruct)
293 {
294 init += indentString + "{\n";
295 const TStructure &structure = *type.getStruct();
296 const TFieldList &fields = structure.fields();
297 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
298 {
299 const TField &field = *fields[fieldIndex];
300 const TString &fieldName = name + "." + Decorate(field.name());
301 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400302
Olli Etuahoed049ab2017-06-30 17:38:33 +0300303 init += structInitializerString(indent + 1, fieldType, fieldName);
304 if (fieldIndex < fields.size() - 1)
305 {
306 init += ",";
307 }
308 init += "\n";
309 }
310 init += indentString + "}";
311 }
312 else
313 {
314 init += indentString + name;
315 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400316
317 return init;
318}
319
Jamie Madill8c46ab12015-12-07 16:39:19 -0500320void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000322 TString varyings;
323 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400324 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000325
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500326 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
327 mFlaggedStructMappedNames.begin();
328 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500330 TIntermTyped *structNode = flaggedStructIt->first;
331 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400332 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400333 const TString &originalName = mFlaggedStructOriginalNames[structNode];
334
Olli Etuahoed049ab2017-06-30 17:38:33 +0300335 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
336 if (structNode->isArray())
337 {
338 flaggedStructs += ArrayString(structNode->getType());
339 }
340 flaggedStructs += " =\n";
341 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
342 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 }
344
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500345 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
346 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000347 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500348 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000349 const TString &name = varying->second->getSymbol();
350
351 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500352 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
353 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000354 }
355
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500356 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
357 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000358 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500359 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000360 const TString &name = attribute->second->getSymbol();
361
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500362 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
363 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000364 }
365
Jamie Madill8daaba12014-06-13 10:04:33 -0400366 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400367
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200368 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800369 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400370
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200371 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500372 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200373 out << "\n// Equality functions\n\n";
374 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500375 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200376 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200377 }
378 }
Olli Etuaho12690762015-03-31 12:55:28 +0300379 if (!mArrayAssignmentFunctions.empty())
380 {
381 out << "\n// Assignment functions\n\n";
382 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
383 {
384 out << assignmentFunction.functionDefinition << "\n";
385 }
386 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300387 if (!mArrayConstructIntoFunctions.empty())
388 {
389 out << "\n// Array constructor functions\n\n";
390 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
391 {
392 out << constructIntoFunction.functionDefinition << "\n";
393 }
394 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200395
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500396 if (mUsesDiscardRewriting)
397 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400398 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500399 }
400
Nicolas Capens655fe362014-04-11 13:12:34 -0400401 if (mUsesNestedBreak)
402 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400403 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400404 }
405
Arun Patole44efa0b2015-03-04 17:11:05 +0530406 if (mRequiresIEEEStrictCompiling)
407 {
408 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
409 }
410
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400411 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
412 "#define LOOP [loop]\n"
413 "#define FLATTEN [flatten]\n"
414 "#else\n"
415 "#define LOOP\n"
416 "#define FLATTEN\n"
417 "#endif\n";
418
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200419 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200421 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500422 const bool usingMRTExtension = (iter != mExtensionBehavior.end() &&
423 (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000424
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000425 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500426 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400427 out << "\n";
428
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200429 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000430 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500431 for (ReferencedSymbols::const_iterator outputVariableIt =
432 mReferencedOutputVariables.begin();
433 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000434 {
Jamie Madill46131a32013-06-20 11:55:50 -0400435 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500436 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400437
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500438 out << "static " + TypeString(variableType) + " out_" + variableName +
439 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000440 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000441 }
Jamie Madill46131a32013-06-20 11:55:50 -0400442 else
443 {
444 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
445
446 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500447 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400448 for (unsigned int i = 0; i < numColorValues; i++)
449 {
450 out << " float4(0, 0, 0, 0)";
451 if (i + 1 != numColorValues)
452 {
453 out << ",";
454 }
455 out << "\n";
456 }
457
458 out << "};\n";
459 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000460
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400461 if (mUsesFragDepth)
462 {
463 out << "static float gl_Depth = 0.0;\n";
464 }
465
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000466 if (mUsesFragCoord)
467 {
468 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
469 }
470
471 if (mUsesPointCoord)
472 {
473 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
474 }
475
476 if (mUsesFrontFacing)
477 {
478 out << "static bool gl_FrontFacing = false;\n";
479 }
480
481 out << "\n";
482
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000483 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000484 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000485 out << "struct gl_DepthRangeParameters\n"
486 "{\n"
487 " float near;\n"
488 " float far;\n"
489 " float diff;\n"
490 "};\n"
491 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000492 }
493
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200494 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000495 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000496 out << "cbuffer DriverConstants : register(b1)\n"
497 "{\n";
498
499 if (mUsesDepthRange)
500 {
501 out << " float3 dx_DepthRange : packoffset(c0);\n";
502 }
503
504 if (mUsesFragCoord)
505 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000506 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000507 }
508
509 if (mUsesFragCoord || mUsesFrontFacing)
510 {
511 out << " float3 dx_DepthFront : packoffset(c2);\n";
512 }
513
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800514 if (mUsesFragCoord)
515 {
516 // dx_ViewScale is only used in the fragment shader to correct
517 // the value for glFragCoord if necessary
518 out << " float2 dx_ViewScale : packoffset(c3);\n";
519 }
520
Martin Radev72b4e1e2017-08-31 15:42:56 +0300521 if (mHasMultiviewExtensionEnabled)
522 {
523 // We have to add a value which we can use to keep track of which multi-view code
524 // path is to be selected in the GS.
525 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
526 }
527
Olli Etuaho618bebc2016-01-15 16:40:00 +0200528 if (mOutputType == SH_HLSL_4_1_OUTPUT)
529 {
530 mUniformHLSL->samplerMetadataUniforms(out, "c4");
531 }
532
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000533 out << "};\n";
534 }
535 else
536 {
537 if (mUsesDepthRange)
538 {
539 out << "uniform float3 dx_DepthRange : register(c0);";
540 }
541
542 if (mUsesFragCoord)
543 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000544 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000545 }
546
547 if (mUsesFragCoord || mUsesFrontFacing)
548 {
549 out << "uniform float3 dx_DepthFront : register(c2);\n";
550 }
551 }
552
553 out << "\n";
554
555 if (mUsesDepthRange)
556 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500557 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
558 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000559 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000560 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000561
Jamie Madillf91ce812014-06-13 10:04:34 -0400562 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000563 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400564 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000565 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400566 out << flaggedStructs;
567 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000568 }
569
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000570 if (usingMRTExtension && mNumRenderTargets > 1)
571 {
572 out << "#define GL_USES_MRT\n";
573 }
574
575 if (mUsesFragColor)
576 {
577 out << "#define GL_USES_FRAG_COLOR\n";
578 }
579
580 if (mUsesFragData)
581 {
582 out << "#define GL_USES_FRAG_DATA\n";
583 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584 }
Xinghua Caob1239382016-12-13 15:07:05 +0800585 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000586 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000587 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500588 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000589 out << "\n"
590 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400591
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000592 if (mUsesPointSize)
593 {
594 out << "static float gl_PointSize = float(1);\n";
595 }
596
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000597 if (mUsesInstanceID)
598 {
599 out << "static int gl_InstanceID;";
600 }
601
Corentin Wallezb076add2016-01-11 16:45:46 -0500602 if (mUsesVertexID)
603 {
604 out << "static int gl_VertexID;";
605 }
606
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000607 out << "\n"
608 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500609 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000610 out << "\n";
611
612 if (mUsesDepthRange)
613 {
614 out << "struct gl_DepthRangeParameters\n"
615 "{\n"
616 " float near;\n"
617 " float far;\n"
618 " float diff;\n"
619 "};\n"
620 "\n";
621 }
622
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200623 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000624 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800625 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500626 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800627
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000628 if (mUsesDepthRange)
629 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800630 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000631 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800632
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800633 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
634 // shaders. However, we declare it for all shaders (including Feature Level 10+).
635 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
636 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800637 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800638 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800639 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800640
Martin Radev72b4e1e2017-08-31 15:42:56 +0300641 if (mHasMultiviewExtensionEnabled)
642 {
643 // We have to add a value which we can use to keep track of which multi-view code
644 // path is to be selected in the GS.
645 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
646 }
647
Olli Etuaho618bebc2016-01-15 16:40:00 +0200648 if (mOutputType == SH_HLSL_4_1_OUTPUT)
649 {
650 mUniformHLSL->samplerMetadataUniforms(out, "c4");
651 }
652
Austin Kinross4fd18b12014-12-22 12:32:05 -0800653 out << "};\n"
654 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000655 }
656 else
657 {
658 if (mUsesDepthRange)
659 {
660 out << "uniform float3 dx_DepthRange : register(c0);\n";
661 }
662
Cooper Partine6664f02015-01-09 16:22:24 -0800663 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
664 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000665 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000666 }
667
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000668 if (mUsesDepthRange)
669 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500670 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
671 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000672 "\n";
673 }
674
Jamie Madillf91ce812014-06-13 10:04:34 -0400675 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000676 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400677 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000678 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400679 out << flaggedStructs;
680 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000681 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400682 }
Xinghua Caob1239382016-12-13 15:07:05 +0800683 else // Compute shader
684 {
685 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800686
687 out << "cbuffer DriverConstants : register(b1)\n"
688 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800689 if (mUsesNumWorkGroups)
690 {
Xinghua Caob1239382016-12-13 15:07:05 +0800691 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800692 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800693 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
694 mUniformHLSL->samplerMetadataUniforms(out, "c1");
695 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800696
697 // Follow built-in variables would be initialized in
698 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
699 // are used in compute shader.
700 if (mUsesWorkGroupID)
701 {
702 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
703 }
704
705 if (mUsesLocalInvocationID)
706 {
707 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
708 }
709
710 if (mUsesGlobalInvocationID)
711 {
712 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
713 }
714
715 if (mUsesLocalInvocationIndex)
716 {
717 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
718 }
719 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000720
Geoff Lang1fe74c72016-08-25 13:23:01 -0400721 bool getDimensionsIgnoresBaseLevel =
722 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
723 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000725 if (mUsesFragCoord)
726 {
727 out << "#define GL_USES_FRAG_COORD\n";
728 }
729
730 if (mUsesPointCoord)
731 {
732 out << "#define GL_USES_POINT_COORD\n";
733 }
734
735 if (mUsesFrontFacing)
736 {
737 out << "#define GL_USES_FRONT_FACING\n";
738 }
739
740 if (mUsesPointSize)
741 {
742 out << "#define GL_USES_POINT_SIZE\n";
743 }
744
Martin Radev41ac68e2017-06-06 12:16:58 +0300745 if (mHasMultiviewExtensionEnabled)
746 {
747 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
748 }
749
750 if (mUsesViewID)
751 {
752 out << "#define GL_USES_VIEW_ID\n";
753 }
754
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400755 if (mUsesFragDepth)
756 {
757 out << "#define GL_USES_FRAG_DEPTH\n";
758 }
759
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000760 if (mUsesDepthRange)
761 {
762 out << "#define GL_USES_DEPTH_RANGE\n";
763 }
764
Xinghua Caob1239382016-12-13 15:07:05 +0800765 if (mUsesNumWorkGroups)
766 {
767 out << "#define GL_USES_NUM_WORK_GROUPS\n";
768 }
769
770 if (mUsesWorkGroupID)
771 {
772 out << "#define GL_USES_WORK_GROUP_ID\n";
773 }
774
775 if (mUsesLocalInvocationID)
776 {
777 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
778 }
779
780 if (mUsesGlobalInvocationID)
781 {
782 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
783 }
784
785 if (mUsesLocalInvocationIndex)
786 {
787 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
788 }
789
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000790 if (mUsesXor)
791 {
792 out << "bool xor(bool p, bool q)\n"
793 "{\n"
794 " return (p || q) && !(p && q);\n"
795 "}\n"
796 "\n";
797 }
798
Olli Etuahodfa75e82017-01-23 09:43:06 -0800799 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000800}
801
802void OutputHLSL::visitSymbol(TIntermSymbol *node)
803{
Jamie Madill32aab012015-01-27 14:12:26 -0500804 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000805
Jamie Madill570e04d2013-06-21 09:15:33 -0400806 // Handle accessing std140 structs by value
807 if (mFlaggedStructMappedNames.count(node) > 0)
808 {
809 out << mFlaggedStructMappedNames[node];
810 return;
811 }
812
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813 TString name = node->getSymbol();
814
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000815 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000816 {
817 mUsesDepthRange = true;
818 out << name;
819 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820 else
821 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000822 TQualifier qualifier = node->getQualifier();
823
824 if (qualifier == EvqUniform)
825 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500826 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400827 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400828
829 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000830 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800831 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000832 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000833 else
834 {
835 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000836 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400837
Jamie Madill2e295e22015-04-29 10:41:33 -0400838 ensureStructDefined(nodeType);
839
Olli Etuahoff526f12017-06-30 12:26:54 +0300840 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000841 }
Jamie Madill19571812013-08-12 15:26:34 -0700842 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000843 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000844 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400845 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000846 }
Jamie Madill033dae62014-06-18 12:56:28 -0400847 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000848 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000849 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400850 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300851 if (name == "ViewID_OVR")
852 {
853 mUsesViewID = true;
854 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000855 }
Jamie Madill19571812013-08-12 15:26:34 -0700856 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400857 {
858 mReferencedOutputVariables[name] = node;
859 out << "out_" << name;
860 }
861 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000862 {
863 out << "gl_Color[0]";
864 mUsesFragColor = true;
865 }
866 else if (qualifier == EvqFragData)
867 {
868 out << "gl_Color";
869 mUsesFragData = true;
870 }
871 else if (qualifier == EvqFragCoord)
872 {
873 mUsesFragCoord = true;
874 out << name;
875 }
876 else if (qualifier == EvqPointCoord)
877 {
878 mUsesPointCoord = true;
879 out << name;
880 }
881 else if (qualifier == EvqFrontFacing)
882 {
883 mUsesFrontFacing = true;
884 out << name;
885 }
886 else if (qualifier == EvqPointSize)
887 {
888 mUsesPointSize = true;
889 out << name;
890 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000891 else if (qualifier == EvqInstanceID)
892 {
893 mUsesInstanceID = true;
894 out << name;
895 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500896 else if (qualifier == EvqVertexID)
897 {
898 mUsesVertexID = true;
899 out << name;
900 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300901 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400902 {
903 mUsesFragDepth = true;
904 out << "gl_Depth";
905 }
Xinghua Caob1239382016-12-13 15:07:05 +0800906 else if (qualifier == EvqNumWorkGroups)
907 {
908 mUsesNumWorkGroups = true;
909 out << name;
910 }
911 else if (qualifier == EvqWorkGroupID)
912 {
913 mUsesWorkGroupID = true;
914 out << name;
915 }
916 else if (qualifier == EvqLocalInvocationID)
917 {
918 mUsesLocalInvocationID = true;
919 out << name;
920 }
921 else if (qualifier == EvqGlobalInvocationID)
922 {
923 mUsesGlobalInvocationID = true;
924 out << name;
925 }
926 else if (qualifier == EvqLocalInvocationIndex)
927 {
928 mUsesLocalInvocationIndex = true;
929 out << name;
930 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000931 else
932 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300933 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000934 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935 }
936}
937
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400938void OutputHLSL::visitRaw(TIntermRaw *node)
939{
Jamie Madill32aab012015-01-27 14:12:26 -0500940 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400941}
942
Olli Etuaho7fb49552015-03-18 17:27:44 +0200943void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
944{
945 if (type.isScalar() && !type.isArray())
946 {
947 if (op == EOpEqual)
948 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500949 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200950 }
951 else
952 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500953 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200954 }
955 }
956 else
957 {
958 if (visit == PreVisit && op == EOpNotEqual)
959 {
960 out << "!";
961 }
962
963 if (type.isArray())
964 {
965 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500966 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200967 }
968 else if (type.getBasicType() == EbtStruct)
969 {
970 const TStructure &structure = *type.getStruct();
971 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500972 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200973 }
974 else
975 {
976 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500977 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200978 }
979 }
980}
981
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300982void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
983{
984 if (type.isArray())
985 {
986 const TString &functionName = addArrayAssignmentFunction(type);
987 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
988 }
989 else
990 {
991 outputTriplet(out, visit, "(", " = ", ")");
992 }
993}
994
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000995bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +0200996{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000997 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +0200998 {
999 TIntermNode *ancestor = getAncestorNode(n);
1000 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1001 if (ancestorBinary == nullptr)
1002 {
1003 return false;
1004 }
1005 switch (ancestorBinary->getOp())
1006 {
1007 case EOpIndexDirectStruct:
1008 {
1009 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1010 const TIntermConstantUnion *index =
1011 ancestorBinary->getRight()->getAsConstantUnion();
1012 const TField *field = structure->fields()[index->getIConst(0)];
1013 if (IsSampler(field->type()->getBasicType()))
1014 {
1015 return true;
1016 }
1017 break;
1018 }
1019 case EOpIndexDirect:
1020 break;
1021 default:
1022 // Returning a sampler from indirect indexing is not supported.
1023 return false;
1024 }
1025 }
1026 return false;
1027}
1028
Olli Etuahob6fa0432016-09-28 16:28:05 +01001029bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1030{
1031 TInfoSinkBase &out = getInfoSink();
1032 if (visit == PostVisit)
1033 {
1034 out << ".";
1035 node->writeOffsetsAsXYZW(&out);
1036 }
1037 return true;
1038}
1039
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001040bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1041{
Jamie Madill32aab012015-01-27 14:12:26 -05001042 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043
Jamie Madill570e04d2013-06-21 09:15:33 -04001044 // Handle accessing std140 structs by value
1045 if (mFlaggedStructMappedNames.count(node) > 0)
1046 {
1047 out << mFlaggedStructMappedNames[node];
1048 return false;
1049 }
1050
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001051 switch (node->getOp())
1052 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001053 case EOpComma:
1054 outputTriplet(out, visit, "(", ", ", ")");
1055 break;
1056 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001057 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001058 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001059 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1060 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001061 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001062 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1063 out << functionName << "(";
1064 node->getLeft()->traverse(this);
1065 TIntermSequence *seq = rightAgg->getSequence();
1066 for (auto &arrayElement : *seq)
1067 {
1068 out << ", ";
1069 arrayElement->traverse(this);
1070 }
1071 out << ")";
1072 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001073 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001074 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1075 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001076 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001077 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001078 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001079 break;
1080 case EOpInitialize:
1081 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001082 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001083 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1084 ASSERT(symbolNode);
1085 TIntermTyped *expression = node->getRight();
1086
1087 // Global initializers must be constant at this point.
1088 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1089 canWriteAsHLSLLiteral(expression));
1090
1091 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1092 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1093 // new variable is created before the assignment is evaluated), so we need to
1094 // convert
1095 // this to "float t = x, x = t;".
1096 if (writeSameSymbolInitializer(out, symbolNode, expression))
1097 {
1098 // Skip initializing the rest of the expression
1099 return false;
1100 }
1101 else if (writeConstantInitialization(out, symbolNode, expression))
1102 {
1103 return false;
1104 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001105 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001106 else if (visit == InVisit)
1107 {
1108 out << " = ";
1109 }
1110 break;
1111 case EOpAddAssign:
1112 outputTriplet(out, visit, "(", " += ", ")");
1113 break;
1114 case EOpSubAssign:
1115 outputTriplet(out, visit, "(", " -= ", ")");
1116 break;
1117 case EOpMulAssign:
1118 outputTriplet(out, visit, "(", " *= ", ")");
1119 break;
1120 case EOpVectorTimesScalarAssign:
1121 outputTriplet(out, visit, "(", " *= ", ")");
1122 break;
1123 case EOpMatrixTimesScalarAssign:
1124 outputTriplet(out, visit, "(", " *= ", ")");
1125 break;
1126 case EOpVectorTimesMatrixAssign:
1127 if (visit == PreVisit)
1128 {
1129 out << "(";
1130 }
1131 else if (visit == InVisit)
1132 {
1133 out << " = mul(";
1134 node->getLeft()->traverse(this);
1135 out << ", transpose(";
1136 }
1137 else
1138 {
1139 out << ")))";
1140 }
1141 break;
1142 case EOpMatrixTimesMatrixAssign:
1143 if (visit == PreVisit)
1144 {
1145 out << "(";
1146 }
1147 else if (visit == InVisit)
1148 {
1149 out << " = transpose(mul(transpose(";
1150 node->getLeft()->traverse(this);
1151 out << "), transpose(";
1152 }
1153 else
1154 {
1155 out << "))))";
1156 }
1157 break;
1158 case EOpDivAssign:
1159 outputTriplet(out, visit, "(", " /= ", ")");
1160 break;
1161 case EOpIModAssign:
1162 outputTriplet(out, visit, "(", " %= ", ")");
1163 break;
1164 case EOpBitShiftLeftAssign:
1165 outputTriplet(out, visit, "(", " <<= ", ")");
1166 break;
1167 case EOpBitShiftRightAssign:
1168 outputTriplet(out, visit, "(", " >>= ", ")");
1169 break;
1170 case EOpBitwiseAndAssign:
1171 outputTriplet(out, visit, "(", " &= ", ")");
1172 break;
1173 case EOpBitwiseXorAssign:
1174 outputTriplet(out, visit, "(", " ^= ", ")");
1175 break;
1176 case EOpBitwiseOrAssign:
1177 outputTriplet(out, visit, "(", " |= ", ")");
1178 break;
1179 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001180 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001181 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001182 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001183 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001184 if (visit == PreVisit)
1185 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001186 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001187 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001188 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001189 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001190 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001191 return false;
1192 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001193 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001194 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001195 {
1196 // All parts of an expression that access a sampler in a struct need to use _ as
1197 // separator to access the sampler variable that has been moved out of the struct.
1198 outputTriplet(out, visit, "", "_", "");
1199 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001200 else
1201 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001202 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001203 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001204 }
1205 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001206 case EOpIndexIndirect:
1207 // We do not currently support indirect references to interface blocks
1208 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1209 outputTriplet(out, visit, "", "[", "]");
1210 break;
1211 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001212 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001213 const TStructure *structure = node->getLeft()->getType().getStruct();
1214 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1215 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001216
Olli Etuaho96963162016-03-21 11:54:33 +02001217 // In cases where indexing returns a sampler, we need to access the sampler variable
1218 // that has been moved out of the struct.
1219 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1220 if (visit == PreVisit && indexingReturnsSampler)
1221 {
1222 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1223 // This prefix is only output at the beginning of the indexing expression, which
1224 // may have multiple parts.
1225 out << "angle";
1226 }
1227 if (!indexingReturnsSampler)
1228 {
1229 // All parts of an expression that access a sampler in a struct need to use _ as
1230 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001231 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001232 }
1233 if (visit == InVisit)
1234 {
1235 if (indexingReturnsSampler)
1236 {
1237 out << "_" + field->name();
1238 }
1239 else
1240 {
1241 out << "." + DecorateField(field->name(), *structure);
1242 }
1243
1244 return false;
1245 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001246 }
1247 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001248 case EOpIndexDirectInterfaceBlock:
1249 if (visit == InVisit)
1250 {
1251 const TInterfaceBlock *interfaceBlock =
1252 node->getLeft()->getType().getInterfaceBlock();
1253 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1254 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1255 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001256
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001257 return false;
1258 }
1259 break;
1260 case EOpAdd:
1261 outputTriplet(out, visit, "(", " + ", ")");
1262 break;
1263 case EOpSub:
1264 outputTriplet(out, visit, "(", " - ", ")");
1265 break;
1266 case EOpMul:
1267 outputTriplet(out, visit, "(", " * ", ")");
1268 break;
1269 case EOpDiv:
1270 outputTriplet(out, visit, "(", " / ", ")");
1271 break;
1272 case EOpIMod:
1273 outputTriplet(out, visit, "(", " % ", ")");
1274 break;
1275 case EOpBitShiftLeft:
1276 outputTriplet(out, visit, "(", " << ", ")");
1277 break;
1278 case EOpBitShiftRight:
1279 outputTriplet(out, visit, "(", " >> ", ")");
1280 break;
1281 case EOpBitwiseAnd:
1282 outputTriplet(out, visit, "(", " & ", ")");
1283 break;
1284 case EOpBitwiseXor:
1285 outputTriplet(out, visit, "(", " ^ ", ")");
1286 break;
1287 case EOpBitwiseOr:
1288 outputTriplet(out, visit, "(", " | ", ")");
1289 break;
1290 case EOpEqual:
1291 case EOpNotEqual:
1292 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1293 break;
1294 case EOpLessThan:
1295 outputTriplet(out, visit, "(", " < ", ")");
1296 break;
1297 case EOpGreaterThan:
1298 outputTriplet(out, visit, "(", " > ", ")");
1299 break;
1300 case EOpLessThanEqual:
1301 outputTriplet(out, visit, "(", " <= ", ")");
1302 break;
1303 case EOpGreaterThanEqual:
1304 outputTriplet(out, visit, "(", " >= ", ")");
1305 break;
1306 case EOpVectorTimesScalar:
1307 outputTriplet(out, visit, "(", " * ", ")");
1308 break;
1309 case EOpMatrixTimesScalar:
1310 outputTriplet(out, visit, "(", " * ", ")");
1311 break;
1312 case EOpVectorTimesMatrix:
1313 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1314 break;
1315 case EOpMatrixTimesVector:
1316 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1317 break;
1318 case EOpMatrixTimesMatrix:
1319 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1320 break;
1321 case EOpLogicalOr:
1322 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1323 // been unfolded.
1324 ASSERT(!node->getRight()->hasSideEffects());
1325 outputTriplet(out, visit, "(", " || ", ")");
1326 return true;
1327 case EOpLogicalXor:
1328 mUsesXor = true;
1329 outputTriplet(out, visit, "xor(", ", ", ")");
1330 break;
1331 case EOpLogicalAnd:
1332 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1333 // been unfolded.
1334 ASSERT(!node->getRight()->hasSideEffects());
1335 outputTriplet(out, visit, "(", " && ", ")");
1336 return true;
1337 default:
1338 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001339 }
1340
1341 return true;
1342}
1343
1344bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1345{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001346 TInfoSinkBase &out = getInfoSink();
1347
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001348 switch (node->getOp())
1349 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001350 case EOpNegative:
1351 outputTriplet(out, visit, "(-", "", ")");
1352 break;
1353 case EOpPositive:
1354 outputTriplet(out, visit, "(+", "", ")");
1355 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001356 case EOpLogicalNot:
1357 outputTriplet(out, visit, "(!", "", ")");
1358 break;
1359 case EOpBitwiseNot:
1360 outputTriplet(out, visit, "(~", "", ")");
1361 break;
1362 case EOpPostIncrement:
1363 outputTriplet(out, visit, "(", "", "++)");
1364 break;
1365 case EOpPostDecrement:
1366 outputTriplet(out, visit, "(", "", "--)");
1367 break;
1368 case EOpPreIncrement:
1369 outputTriplet(out, visit, "(++", "", ")");
1370 break;
1371 case EOpPreDecrement:
1372 outputTriplet(out, visit, "(--", "", ")");
1373 break;
1374 case EOpRadians:
1375 outputTriplet(out, visit, "radians(", "", ")");
1376 break;
1377 case EOpDegrees:
1378 outputTriplet(out, visit, "degrees(", "", ")");
1379 break;
1380 case EOpSin:
1381 outputTriplet(out, visit, "sin(", "", ")");
1382 break;
1383 case EOpCos:
1384 outputTriplet(out, visit, "cos(", "", ")");
1385 break;
1386 case EOpTan:
1387 outputTriplet(out, visit, "tan(", "", ")");
1388 break;
1389 case EOpAsin:
1390 outputTriplet(out, visit, "asin(", "", ")");
1391 break;
1392 case EOpAcos:
1393 outputTriplet(out, visit, "acos(", "", ")");
1394 break;
1395 case EOpAtan:
1396 outputTriplet(out, visit, "atan(", "", ")");
1397 break;
1398 case EOpSinh:
1399 outputTriplet(out, visit, "sinh(", "", ")");
1400 break;
1401 case EOpCosh:
1402 outputTriplet(out, visit, "cosh(", "", ")");
1403 break;
1404 case EOpTanh:
1405 outputTriplet(out, visit, "tanh(", "", ")");
1406 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001407 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001408 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001409 case EOpAtanh:
1410 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001411 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001412 break;
1413 case EOpExp:
1414 outputTriplet(out, visit, "exp(", "", ")");
1415 break;
1416 case EOpLog:
1417 outputTriplet(out, visit, "log(", "", ")");
1418 break;
1419 case EOpExp2:
1420 outputTriplet(out, visit, "exp2(", "", ")");
1421 break;
1422 case EOpLog2:
1423 outputTriplet(out, visit, "log2(", "", ")");
1424 break;
1425 case EOpSqrt:
1426 outputTriplet(out, visit, "sqrt(", "", ")");
1427 break;
1428 case EOpInverseSqrt:
1429 outputTriplet(out, visit, "rsqrt(", "", ")");
1430 break;
1431 case EOpAbs:
1432 outputTriplet(out, visit, "abs(", "", ")");
1433 break;
1434 case EOpSign:
1435 outputTriplet(out, visit, "sign(", "", ")");
1436 break;
1437 case EOpFloor:
1438 outputTriplet(out, visit, "floor(", "", ")");
1439 break;
1440 case EOpTrunc:
1441 outputTriplet(out, visit, "trunc(", "", ")");
1442 break;
1443 case EOpRound:
1444 outputTriplet(out, visit, "round(", "", ")");
1445 break;
1446 case EOpRoundEven:
1447 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001448 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001449 break;
1450 case EOpCeil:
1451 outputTriplet(out, visit, "ceil(", "", ")");
1452 break;
1453 case EOpFract:
1454 outputTriplet(out, visit, "frac(", "", ")");
1455 break;
1456 case EOpIsNan:
1457 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001458 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001459 else
1460 outputTriplet(out, visit, "isnan(", "", ")");
1461 mRequiresIEEEStrictCompiling = true;
1462 break;
1463 case EOpIsInf:
1464 outputTriplet(out, visit, "isinf(", "", ")");
1465 break;
1466 case EOpFloatBitsToInt:
1467 outputTriplet(out, visit, "asint(", "", ")");
1468 break;
1469 case EOpFloatBitsToUint:
1470 outputTriplet(out, visit, "asuint(", "", ")");
1471 break;
1472 case EOpIntBitsToFloat:
1473 outputTriplet(out, visit, "asfloat(", "", ")");
1474 break;
1475 case EOpUintBitsToFloat:
1476 outputTriplet(out, visit, "asfloat(", "", ")");
1477 break;
1478 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001479 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001480 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001481 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001482 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001483 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001484 case EOpPackUnorm4x8:
1485 case EOpPackSnorm4x8:
1486 case EOpUnpackUnorm4x8:
1487 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001488 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001489 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001490 break;
1491 case EOpLength:
1492 outputTriplet(out, visit, "length(", "", ")");
1493 break;
1494 case EOpNormalize:
1495 outputTriplet(out, visit, "normalize(", "", ")");
1496 break;
1497 case EOpDFdx:
1498 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1499 {
1500 outputTriplet(out, visit, "(", "", ", 0.0)");
1501 }
1502 else
1503 {
1504 outputTriplet(out, visit, "ddx(", "", ")");
1505 }
1506 break;
1507 case EOpDFdy:
1508 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1509 {
1510 outputTriplet(out, visit, "(", "", ", 0.0)");
1511 }
1512 else
1513 {
1514 outputTriplet(out, visit, "ddy(", "", ")");
1515 }
1516 break;
1517 case EOpFwidth:
1518 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1519 {
1520 outputTriplet(out, visit, "(", "", ", 0.0)");
1521 }
1522 else
1523 {
1524 outputTriplet(out, visit, "fwidth(", "", ")");
1525 }
1526 break;
1527 case EOpTranspose:
1528 outputTriplet(out, visit, "transpose(", "", ")");
1529 break;
1530 case EOpDeterminant:
1531 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1532 break;
1533 case EOpInverse:
1534 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001535 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001536 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001537
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001538 case EOpAny:
1539 outputTriplet(out, visit, "any(", "", ")");
1540 break;
1541 case EOpAll:
1542 outputTriplet(out, visit, "all(", "", ")");
1543 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001544 case EOpLogicalNotComponentWise:
1545 outputTriplet(out, visit, "(!", "", ")");
1546 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001547 case EOpBitfieldReverse:
1548 outputTriplet(out, visit, "reversebits(", "", ")");
1549 break;
1550 case EOpBitCount:
1551 outputTriplet(out, visit, "countbits(", "", ")");
1552 break;
1553 case EOpFindLSB:
1554 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1555 // in GLSLTest and results are consistent with GL.
1556 outputTriplet(out, visit, "firstbitlow(", "", ")");
1557 break;
1558 case EOpFindMSB:
1559 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1560 // tested in GLSLTest and results are consistent with GL.
1561 outputTriplet(out, visit, "firstbithigh(", "", ")");
1562 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001563 default:
1564 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001565 }
1566
1567 return true;
1568}
1569
Olli Etuaho96963162016-03-21 11:54:33 +02001570TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1571{
1572 if (node->getAsSymbolNode())
1573 {
1574 return node->getAsSymbolNode()->getSymbol();
1575 }
1576 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1577 switch (nodeBinary->getOp())
1578 {
1579 case EOpIndexDirect:
1580 {
1581 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1582
1583 TInfoSinkBase prefixSink;
1584 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1585 return TString(prefixSink.c_str());
1586 }
1587 case EOpIndexDirectStruct:
1588 {
1589 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1590 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1591 const TField *field = s->fields()[index];
1592
1593 TInfoSinkBase prefixSink;
1594 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1595 << field->name();
1596 return TString(prefixSink.c_str());
1597 }
1598 default:
1599 UNREACHABLE();
1600 return TString("");
1601 }
1602}
1603
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001604bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1605{
1606 TInfoSinkBase &out = getInfoSink();
1607
1608 if (mInsideFunction)
1609 {
1610 outputLineDirective(out, node->getLine().first_line);
1611 out << "{\n";
1612 }
1613
1614 for (TIntermSequence::iterator sit = node->getSequence()->begin();
1615 sit != node->getSequence()->end(); sit++)
1616 {
1617 outputLineDirective(out, (*sit)->getLine().first_line);
1618
1619 (*sit)->traverse(this);
1620
1621 // Don't output ; after case labels, they're terminated by :
1622 // This is needed especially since outputting a ; after a case statement would turn empty
1623 // case statements into non-empty case statements, disallowing fall-through from them.
1624 // Also no need to output ; after if statements or sequences. This is done just for
1625 // code clarity.
1626 if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1627 (*sit)->getAsBlock() == nullptr)
1628 out << ";\n";
1629 }
1630
1631 if (mInsideFunction)
1632 {
1633 outputLineDirective(out, node->getLine().last_line);
1634 out << "}\n";
1635 }
1636
1637 return false;
1638}
1639
Olli Etuaho336b1472016-10-05 16:37:55 +01001640bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1641{
1642 TInfoSinkBase &out = getInfoSink();
1643
1644 ASSERT(mCurrentFunctionMetadata == nullptr);
1645
1646 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1647 ASSERT(index != CallDAG::InvalidIndex);
1648 mCurrentFunctionMetadata = &mASTMetadataList[index];
1649
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001650 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001651
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001652 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001653
1654 if (node->getFunctionSymbolInfo()->isMain())
1655 {
1656 out << "gl_main(";
1657 }
1658 else
1659 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001660 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001661 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1662 }
1663
1664 for (unsigned int i = 0; i < parameters->size(); i++)
1665 {
1666 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1667
1668 if (symbol)
1669 {
1670 ensureStructDefined(symbol->getType());
1671
1672 out << argumentString(symbol);
1673
1674 if (i < parameters->size() - 1)
1675 {
1676 out << ", ";
1677 }
1678 }
1679 else
1680 UNREACHABLE();
1681 }
1682
1683 out << ")\n";
1684
1685 mInsideFunction = true;
1686 // The function body node will output braces.
1687 node->getBody()->traverse(this);
1688 mInsideFunction = false;
1689
1690 mCurrentFunctionMetadata = nullptr;
1691
1692 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1693 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1694 {
1695 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1696 mOutputLod0Function = true;
1697 node->traverse(this);
1698 mOutputLod0Function = false;
1699 }
1700
1701 return false;
1702}
1703
Olli Etuaho13389b62016-10-16 11:48:18 +01001704bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1705{
1706 TInfoSinkBase &out = getInfoSink();
1707 if (visit == PreVisit)
1708 {
1709 TIntermSequence *sequence = node->getSequence();
1710 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1711 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001712 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001713
Olli Etuaho282847e2017-07-12 14:11:01 +03001714 if ((variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Olli Etuaho13389b62016-10-16 11:48:18 +01001715 variable->getQualifier() == EvqConst))
1716 {
1717 ensureStructDefined(variable->getType());
1718
1719 if (!variable->getAsSymbolNode() ||
1720 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1721 {
1722 if (!mInsideFunction)
1723 {
1724 out << "static ";
1725 }
1726
1727 out << TypeString(variable->getType()) + " ";
1728
1729 TIntermSymbol *symbol = variable->getAsSymbolNode();
1730
1731 if (symbol)
1732 {
1733 symbol->traverse(this);
1734 out << ArrayString(symbol->getType());
1735 out << " = " + initializer(symbol->getType());
1736 }
1737 else
1738 {
1739 variable->traverse(this);
1740 }
1741 }
1742 else if (variable->getAsSymbolNode() &&
1743 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1744 {
1745 // Already added to constructor map
1746 }
1747 else
1748 UNREACHABLE();
1749 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001750 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001751 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001752 TIntermSymbol *symbol = variable->getAsSymbolNode();
1753 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001754
Olli Etuaho282847e2017-07-12 14:11:01 +03001755 // Vertex outputs which are declared but not written to should still be declared to
1756 // allow successful linking.
1757 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001758 }
1759 }
1760 return false;
1761}
1762
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001763bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1764{
1765 // Do not do any translation
1766 return false;
1767}
1768
Olli Etuaho16c745a2017-01-16 17:02:27 +00001769bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1770{
1771 TInfoSinkBase &out = getInfoSink();
1772
1773 ASSERT(visit == PreVisit);
1774 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1775 // Skip the prototype if it is not implemented (and thus not used)
1776 if (index == CallDAG::InvalidIndex)
1777 {
1778 return false;
1779 }
1780
1781 TIntermSequence *arguments = node->getSequence();
1782
Olli Etuahoff526f12017-06-30 12:26:54 +03001783 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001784 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1785 << (mOutputLod0Function ? "Lod0(" : "(");
1786
1787 for (unsigned int i = 0; i < arguments->size(); i++)
1788 {
1789 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1790 ASSERT(symbol != nullptr);
1791
1792 out << argumentString(symbol);
1793
1794 if (i < arguments->size() - 1)
1795 {
1796 out << ", ";
1797 }
1798 }
1799
1800 out << ");\n";
1801
1802 // Also prototype the Lod0 variant if needed
1803 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1804 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1805 {
1806 mOutputLod0Function = true;
1807 node->traverse(this);
1808 mOutputLod0Function = false;
1809 }
1810
1811 return false;
1812}
1813
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1815{
Jamie Madill32aab012015-01-27 14:12:26 -05001816 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001817
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001818 switch (node->getOp())
1819 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001820 case EOpCallBuiltInFunction:
1821 case EOpCallFunctionInAST:
1822 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001823 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001824 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001825
Corentin Wallez1239ee92015-03-19 14:38:02 -07001826 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001827 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001828 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001829 if (node->isArray())
1830 {
1831 UNIMPLEMENTED();
1832 }
Olli Etuahobd674552016-10-06 13:28:42 +01001833 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001834 ASSERT(index != CallDAG::InvalidIndex);
1835 lod0 &= mASTMetadataList[index].mNeedsLod0;
1836
Olli Etuahoff526f12017-06-30 12:26:54 +03001837 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001838 out << DisambiguateFunctionName(node->getSequence());
1839 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001840 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001841 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001842 {
1843 // This path is used for internal functions that don't have their definitions in the
1844 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001845 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001846 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001847 else
1848 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001849 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001850 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001851 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1852 if (arguments->size() > 1)
1853 {
1854 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1855 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001856 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1857 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1858 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001860
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001861 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001862 {
Olli Etuaho96963162016-03-21 11:54:33 +02001863 TIntermTyped *typedArg = (*arg)->getAsTyped();
1864 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001865 {
1866 out << "texture_";
1867 (*arg)->traverse(this);
1868 out << ", sampler_";
1869 }
1870
1871 (*arg)->traverse(this);
1872
Olli Etuaho96963162016-03-21 11:54:33 +02001873 if (typedArg->getType().isStructureContainingSamplers())
1874 {
1875 const TType &argType = typedArg->getType();
1876 TVector<TIntermSymbol *> samplerSymbols;
1877 TString structName = samplerNamePrefixFromStruct(typedArg);
1878 argType.createSamplerSymbols("angle_" + structName, "",
Olli Etuaho96963162016-03-21 11:54:33 +02001879 &samplerSymbols, nullptr);
1880 for (const TIntermSymbol *sampler : samplerSymbols)
1881 {
1882 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1883 {
1884 out << ", texture_" << sampler->getSymbol();
1885 out << ", sampler_" << sampler->getSymbol();
1886 }
1887 else
1888 {
1889 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1890 // of D3D9, it's the sampler variable.
1891 out << ", " + sampler->getSymbol();
1892 }
1893 }
1894 }
1895
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001896 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001897 {
1898 out << ", ";
1899 }
1900 }
1901
1902 out << ")";
1903
1904 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001905 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001906 case EOpConstruct:
1907 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001908 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001909 if (node->getType().isArray())
1910 {
1911 UNIMPLEMENTED();
1912 }
1913 const TString &structName = StructNameString(*node->getType().getStruct());
1914 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1915 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001916 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001917 else
1918 {
1919 const char *name = "";
1920 if (node->getType().getNominalSize() == 1)
1921 {
1922 switch (node->getBasicType())
1923 {
1924 case EbtFloat:
1925 name = "vec1";
1926 break;
1927 case EbtInt:
1928 name = "ivec1";
1929 break;
1930 case EbtUInt:
1931 name = "uvec1";
1932 break;
1933 case EbtBool:
1934 name = "bvec1";
1935 break;
1936 default:
1937 UNREACHABLE();
1938 }
1939 }
1940 else
1941 {
1942 name = node->getType().getBuiltInTypeNameString();
1943 }
1944 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1945 }
1946 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001947 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001948 outputTriplet(out, visit, "(", " == ", ")");
1949 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001950 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001951 outputTriplet(out, visit, "(", " != ", ")");
1952 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001953 case EOpLessThanComponentWise:
1954 outputTriplet(out, visit, "(", " < ", ")");
1955 break;
1956 case EOpGreaterThanComponentWise:
1957 outputTriplet(out, visit, "(", " > ", ")");
1958 break;
1959 case EOpLessThanEqualComponentWise:
1960 outputTriplet(out, visit, "(", " <= ", ")");
1961 break;
1962 case EOpGreaterThanEqualComponentWise:
1963 outputTriplet(out, visit, "(", " >= ", ")");
1964 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001965 case EOpMod:
1966 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001967 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001968 break;
1969 case EOpModf:
1970 outputTriplet(out, visit, "modf(", ", ", ")");
1971 break;
1972 case EOpPow:
1973 outputTriplet(out, visit, "pow(", ", ", ")");
1974 break;
1975 case EOpAtan:
1976 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1977 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001978 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01001979 break;
1980 case EOpMin:
1981 outputTriplet(out, visit, "min(", ", ", ")");
1982 break;
1983 case EOpMax:
1984 outputTriplet(out, visit, "max(", ", ", ")");
1985 break;
1986 case EOpClamp:
1987 outputTriplet(out, visit, "clamp(", ", ", ")");
1988 break;
1989 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05301990 {
1991 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1992 if (lastParamNode->getType().getBasicType() == EbtBool)
1993 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001994 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
1995 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05301996 // so use emulated version.
1997 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001998 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05301999 }
2000 else
2001 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002002 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302003 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002004 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302005 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002006 case EOpStep:
2007 outputTriplet(out, visit, "step(", ", ", ")");
2008 break;
2009 case EOpSmoothStep:
2010 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2011 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002012 case EOpFrexp:
2013 case EOpLdexp:
2014 ASSERT(node->getUseEmulatedFunction());
2015 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2016 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002017 case EOpDistance:
2018 outputTriplet(out, visit, "distance(", ", ", ")");
2019 break;
2020 case EOpDot:
2021 outputTriplet(out, visit, "dot(", ", ", ")");
2022 break;
2023 case EOpCross:
2024 outputTriplet(out, visit, "cross(", ", ", ")");
2025 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002026 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002027 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002028 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002029 break;
2030 case EOpReflect:
2031 outputTriplet(out, visit, "reflect(", ", ", ")");
2032 break;
2033 case EOpRefract:
2034 outputTriplet(out, visit, "refract(", ", ", ")");
2035 break;
2036 case EOpOuterProduct:
2037 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002038 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002039 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002040 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002041 outputTriplet(out, visit, "(", " * ", ")");
2042 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002043 case EOpBitfieldExtract:
2044 case EOpBitfieldInsert:
2045 case EOpUaddCarry:
2046 case EOpUsubBorrow:
2047 case EOpUmulExtended:
2048 case EOpImulExtended:
2049 ASSERT(node->getUseEmulatedFunction());
2050 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2051 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002052 default:
2053 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002054 }
2055
2056 return true;
2057}
2058
Olli Etuaho57961272016-09-14 13:57:46 +03002059void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002060{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002061 out << "if (";
2062
2063 node->getCondition()->traverse(this);
2064
2065 out << ")\n";
2066
Jamie Madill8c46ab12015-12-07 16:39:19 -05002067 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002068
2069 bool discard = false;
2070
2071 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002072 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002073 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002074 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002075
Olli Etuahoa6f22092015-05-08 18:31:10 +03002076 // Detect true discard
2077 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2078 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002079 else
2080 {
2081 // TODO(oetuaho): Check if the semicolon inside is necessary.
2082 // It's there as a result of conservative refactoring of the output.
2083 out << "{;}\n";
2084 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002085
Jamie Madill8c46ab12015-12-07 16:39:19 -05002086 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002087
Olli Etuahoa6f22092015-05-08 18:31:10 +03002088 if (node->getFalseBlock())
2089 {
2090 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002091
Jamie Madill8c46ab12015-12-07 16:39:19 -05002092 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002093
Olli Etuaho32db19b2016-10-04 14:43:16 +01002094 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002095 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002096
Jamie Madill8c46ab12015-12-07 16:39:19 -05002097 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002098
Olli Etuahoa6f22092015-05-08 18:31:10 +03002099 // Detect false discard
2100 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2101 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002102
Olli Etuahoa6f22092015-05-08 18:31:10 +03002103 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002104 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002105 {
2106 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002107 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002108}
2109
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002110bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2111{
2112 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2113 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2114 UNREACHABLE();
2115 return false;
2116}
2117
Olli Etuaho57961272016-09-14 13:57:46 +03002118bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002119{
2120 TInfoSinkBase &out = getInfoSink();
2121
Olli Etuaho3d932d82016-04-12 11:10:30 +03002122 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002123
2124 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002125 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002126 {
2127 out << "FLATTEN ";
2128 }
2129
Olli Etuaho57961272016-09-14 13:57:46 +03002130 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002131
2132 return false;
2133}
2134
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002135bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002136{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002137 TInfoSinkBase &out = getInfoSink();
2138
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002139 if (node->getStatementList())
2140 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002141 node->setStatementList(
2142 RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002143 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002144 // The curly braces get written when visiting the statementList aggregate
2145 }
2146 else
2147 {
2148 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002149 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002150 }
2151 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002152}
2153
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002154bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002155{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002156 TInfoSinkBase &out = getInfoSink();
2157
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002158 if (node->hasCondition())
2159 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002160 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002161 return true;
2162 }
2163 else
2164 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002165 out << "default:\n";
2166 return false;
2167 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002168}
2169
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2171{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002172 TInfoSinkBase &out = getInfoSink();
2173 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002174}
2175
2176bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2177{
Nicolas Capens655fe362014-04-11 13:12:34 -04002178 mNestedLoopDepth++;
2179
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002180 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002181 mInsideDiscontinuousLoop =
2182 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002183
Jamie Madill8c46ab12015-12-07 16:39:19 -05002184 TInfoSinkBase &out = getInfoSink();
2185
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002186 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002187 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002188 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002189 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002190 mInsideDiscontinuousLoop = wasDiscontinuous;
2191 mNestedLoopDepth--;
2192
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002193 return false;
2194 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002195 }
2196
Corentin Wallez1239ee92015-03-19 14:38:02 -07002197 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002198 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002199 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002200 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002201
Jamie Madill8c46ab12015-12-07 16:39:19 -05002202 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002203 }
2204 else
2205 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002206 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002207
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002208 if (node->getInit())
2209 {
2210 node->getInit()->traverse(this);
2211 }
2212
2213 out << "; ";
2214
alokp@chromium.org52813552010-11-16 18:36:09 +00002215 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002217 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218 }
2219
2220 out << "; ";
2221
alokp@chromium.org52813552010-11-16 18:36:09 +00002222 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002223 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002224 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002225 }
2226
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002227 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002228
Jamie Madill8c46ab12015-12-07 16:39:19 -05002229 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002230 }
2231
2232 if (node->getBody())
2233 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002234 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002235 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002236 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002237 else
2238 {
2239 // TODO(oetuaho): Check if the semicolon inside is necessary.
2240 // It's there as a result of conservative refactoring of the output.
2241 out << "{;}\n";
2242 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002243
Jamie Madill8c46ab12015-12-07 16:39:19 -05002244 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002245
alokp@chromium.org52813552010-11-16 18:36:09 +00002246 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002248 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002249 out << "while(\n";
2250
alokp@chromium.org52813552010-11-16 18:36:09 +00002251 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002252
daniel@transgaming.com73536982012-03-21 20:45:49 +00002253 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
2255
daniel@transgaming.com73536982012-03-21 20:45:49 +00002256 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002257
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002258 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002259 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002260
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002261 return false;
2262}
2263
2264bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2265{
Jamie Madill32aab012015-01-27 14:12:26 -05002266 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267
2268 switch (node->getFlowOp())
2269 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002270 case EOpKill:
2271 outputTriplet(out, visit, "discard;\n", "", "");
2272 break;
2273 case EOpBreak:
2274 if (visit == PreVisit)
Nicolas Capens655fe362014-04-11 13:12:34 -04002275 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002276 if (mNestedLoopDepth > 1)
2277 {
2278 mUsesNestedBreak = true;
2279 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002280
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002281 if (mExcessiveLoopIndex)
2282 {
2283 out << "{Break";
2284 mExcessiveLoopIndex->traverse(this);
2285 out << " = true; break;}\n";
2286 }
2287 else
2288 {
2289 out << "break;\n";
2290 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002291 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002292 break;
2293 case EOpContinue:
2294 outputTriplet(out, visit, "continue;\n", "", "");
2295 break;
2296 case EOpReturn:
2297 if (visit == PreVisit)
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002298 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002299 if (node->getExpression())
2300 {
2301 out << "return ";
2302 }
2303 else
2304 {
2305 out << "return;\n";
2306 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002307 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002308 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002310 if (node->getExpression())
2311 {
2312 out << ";\n";
2313 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002314 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002315 break;
2316 default:
2317 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002318 }
2319
2320 return true;
2321}
2322
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002323// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002324// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2325// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002326bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002327{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002328 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002329
2330 // Parse loops of the form:
2331 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002332 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002333 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002334 int initial = 0;
2335 int limit = 0;
2336 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002337
2338 // Parse index name and intial value
2339 if (node->getInit())
2340 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002341 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002342
2343 if (init)
2344 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002345 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002346 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002347
2348 if (variable && variable->getQualifier() == EvqTemporary)
2349 {
2350 TIntermBinary *assign = variable->getAsBinaryNode();
2351
2352 if (assign->getOp() == EOpInitialize)
2353 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002354 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002355 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2356
2357 if (symbol && constant)
2358 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002359 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002360 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002361 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002362 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002363 }
2364 }
2365 }
2366 }
2367 }
2368 }
2369
2370 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002371 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002372 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002373 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002374
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002375 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2376 {
2377 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2378
2379 if (constant)
2380 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002381 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002382 {
2383 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002384 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002385 }
2386 }
2387 }
2388 }
2389
2390 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002391 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002392 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002393 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002394 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002395
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002396 if (binaryTerminal)
2397 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002398 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002399 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2400
2401 if (constant)
2402 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002403 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002404 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002405 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002406
2407 switch (op)
2408 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002409 case EOpAddAssign:
2410 increment = value;
2411 break;
2412 case EOpSubAssign:
2413 increment = -value;
2414 break;
2415 default:
2416 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002417 }
2418 }
2419 }
2420 }
2421 else if (unaryTerminal)
2422 {
2423 TOperator op = unaryTerminal->getOp();
2424
2425 switch (op)
2426 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002427 case EOpPostIncrement:
2428 increment = 1;
2429 break;
2430 case EOpPostDecrement:
2431 increment = -1;
2432 break;
2433 case EOpPreIncrement:
2434 increment = 1;
2435 break;
2436 case EOpPreDecrement:
2437 increment = -1;
2438 break;
2439 default:
2440 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002441 }
2442 }
2443 }
2444
Yunchao He4f285442017-04-21 12:15:49 +08002445 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002446 {
2447 if (comparator == EOpLessThanEqual)
2448 {
2449 comparator = EOpLessThan;
2450 limit += 1;
2451 }
2452
2453 if (comparator == EOpLessThan)
2454 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002455 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002456
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002457 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002458 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002459 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002460 }
2461
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002462 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002463 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002464
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002465 out << "{int ";
2466 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002467 out << ";\n"
2468 "bool Break";
2469 index->traverse(this);
2470 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002471
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002472 bool firstLoopFragment = true;
2473
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002474 while (iterations > 0)
2475 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002476 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002478 if (!firstLoopFragment)
2479 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002480 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002481 index->traverse(this);
2482 out << ") {\n";
2483 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002484
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002485 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002486 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002487 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002488 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002489
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002490 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002491 const char *unroll =
2492 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002493
Corentin Wallez1239ee92015-03-19 14:38:02 -07002494 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002495 index->traverse(this);
2496 out << " = ";
2497 out << initial;
2498
2499 out << "; ";
2500 index->traverse(this);
2501 out << " < ";
2502 out << clampedLimit;
2503
2504 out << "; ";
2505 index->traverse(this);
2506 out << " += ";
2507 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002508 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002509
Jamie Madill8c46ab12015-12-07 16:39:19 -05002510 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002511 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002512
2513 if (node->getBody())
2514 {
2515 node->getBody()->traverse(this);
2516 }
2517
Jamie Madill8c46ab12015-12-07 16:39:19 -05002518 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002519 out << ";}\n";
2520
2521 if (!firstLoopFragment)
2522 {
2523 out << "}\n";
2524 }
2525
2526 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002527
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002528 initial += MAX_LOOP_ITERATIONS * increment;
2529 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002530 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002531
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002532 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002533
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002534 mExcessiveLoopIndex = restoreIndex;
2535
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002536 return true;
2537 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002538 else
2539 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002540 }
2541
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002542 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002543}
2544
Jamie Madill8c46ab12015-12-07 16:39:19 -05002545void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2546 Visit visit,
2547 const char *preString,
2548 const char *inString,
2549 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002550{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002551 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002552 {
2553 out << preString;
2554 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002555 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002556 {
2557 out << inString;
2558 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002559 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002560 {
2561 out << postString;
2562 }
2563}
2564
Jamie Madill8c46ab12015-12-07 16:39:19 -05002565void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002566{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002567 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002568 {
Jamie Madill32aab012015-01-27 14:12:26 -05002569 out << "\n";
2570 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002571
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002572 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002573 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002574 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002575 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002576
Jamie Madill32aab012015-01-27 14:12:26 -05002577 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002578 }
2579}
2580
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002581TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2582{
2583 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002584 const TType &type = symbol->getType();
2585 const TName &name = symbol->getName();
2586 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002587
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002588 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002589 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002590 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002591 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002592 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002593 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002594 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002595 }
2596
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002597 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002598 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002599 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2600 {
2601 // Samplers are passed as indices to the sampler array.
2602 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2603 return "const uint " + nameStr + ArrayString(type);
2604 }
2605 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2606 {
2607 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2608 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2609 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2610 ArrayString(type);
2611 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002612 }
2613
Olli Etuaho96963162016-03-21 11:54:33 +02002614 TStringStream argString;
2615 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2616 << ArrayString(type);
2617
2618 // If the structure parameter contains samplers, they need to be passed into the function as
2619 // separate parameters. HLSL doesn't natively support samplers in structs.
2620 if (type.isStructureContainingSamplers())
2621 {
2622 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2623 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho599555b2017-08-15 11:12:42 +03002624 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr);
Olli Etuaho96963162016-03-21 11:54:33 +02002625 for (const TIntermSymbol *sampler : samplerSymbols)
2626 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002627 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002628 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2629 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002630 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002631 }
2632 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2633 {
Olli Etuaho96963162016-03-21 11:54:33 +02002634 ASSERT(IsSampler(samplerType.getBasicType()));
2635 argString << ", " << QualifierString(qualifier) << " "
2636 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002637 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2638 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002639 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002640 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002641 }
2642 else
2643 {
Olli Etuaho96963162016-03-21 11:54:33 +02002644 ASSERT(IsSampler(samplerType.getBasicType()));
2645 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002646 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002647 }
2648 }
2649 }
2650
2651 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002652}
2653
2654TString OutputHLSL::initializer(const TType &type)
2655{
2656 TString string;
2657
Jamie Madill94bf7f22013-07-08 13:31:15 -04002658 size_t size = type.getObjectSize();
2659 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002660 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002661 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002662
Jamie Madill94bf7f22013-07-08 13:31:15 -04002663 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002664 {
2665 string += ", ";
2666 }
2667 }
2668
daniel@transgaming.comead23042010-04-29 03:35:36 +00002669 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002670}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002671
Jamie Madill8c46ab12015-12-07 16:39:19 -05002672void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2673 Visit visit,
2674 const TType &type,
2675 const char *name,
2676 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002677{
Olli Etuahof40319e2015-03-10 14:33:00 +02002678 if (type.isArray())
2679 {
2680 UNIMPLEMENTED();
2681 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002682
2683 if (visit == PreVisit)
2684 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002685 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002686
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002687 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002688 }
2689 else if (visit == InVisit)
2690 {
2691 out << ", ";
2692 }
2693 else if (visit == PostVisit)
2694 {
2695 out << ")";
2696 }
2697}
2698
Jamie Madill8c46ab12015-12-07 16:39:19 -05002699const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2700 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002701 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002702{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002703 const TConstantUnion *constUnionIterated = constUnion;
2704
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002705 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002706 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002707 {
Jamie Madill033dae62014-06-18 12:56:28 -04002708 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002709
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002710 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002711
Jamie Madill98493dd2013-07-08 14:39:03 -04002712 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002713 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002714 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002715 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002716
Jamie Madill98493dd2013-07-08 14:39:03 -04002717 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002718 {
2719 out << ", ";
2720 }
2721 }
2722
2723 out << ")";
2724 }
2725 else
2726 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002727 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002728 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002729
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002730 if (writeType)
2731 {
Jamie Madill033dae62014-06-18 12:56:28 -04002732 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002733 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002734 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002735 if (writeType)
2736 {
2737 out << ")";
2738 }
2739 }
2740
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002741 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002742}
2743
Olli Etuahod68924e2017-01-02 17:34:40 +00002744void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002745{
Olli Etuahod68924e2017-01-02 17:34:40 +00002746 if (visit == PreVisit)
2747 {
2748 const char *opStr = GetOperatorString(op);
2749 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2750 out << "(";
2751 }
2752 else
2753 {
2754 outputTriplet(out, visit, nullptr, ", ", ")");
2755 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002756}
2757
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002758bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2759 TIntermSymbol *symbolNode,
2760 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002761{
2762 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2763 expression->traverse(&searchSymbol);
2764
2765 if (searchSymbol.foundMatch())
2766 {
2767 // Type already printed
2768 out << "t" + str(mUniqueIndex) + " = ";
2769 expression->traverse(this);
2770 out << ", ";
2771 symbolNode->traverse(this);
2772 out << " = t" + str(mUniqueIndex);
2773
2774 mUniqueIndex++;
2775 return true;
2776 }
2777
2778 return false;
2779}
2780
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002781bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2782{
2783 // We support writing constant unions and constructors that only take constant unions as
2784 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002785 return !expression->getType().isArrayOfArrays() &&
2786 (expression->getAsConstantUnion() ||
2787 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002788}
2789
2790bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2791 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002792 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002793{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002794 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002795 {
2796 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002797 ASSERT(!symbolNode->getType().isArrayOfArrays());
2798 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002799 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002800 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002801 }
2802 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002803 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002804 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002805 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002806 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002807 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002808 }
2809 else
2810 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002811 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002812 ASSERT(constructor != nullptr);
2813 for (TIntermNode *&node : *constructor->getSequence())
2814 {
2815 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2816 ASSERT(nodeConst);
2817 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002818 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002819 if (node != constructor->getSequence()->back())
2820 {
2821 out << ", ";
2822 }
2823 }
2824 }
2825 out << "}";
2826 return true;
2827 }
2828 return false;
2829}
2830
Jamie Madill55e79e02015-02-09 15:35:00 -05002831TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2832{
2833 const TFieldList &fields = structure.fields();
2834
2835 for (const auto &eqFunction : mStructEqualityFunctions)
2836 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002837 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002838 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002839 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002840 }
2841 }
2842
2843 const TString &structNameString = StructNameString(structure);
2844
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002845 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002846 function->structure = &structure;
2847 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002848
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002849 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002850
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002851 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2852 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002853 << "{\n"
2854 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002855
2856 for (size_t i = 0; i < fields.size(); i++)
2857 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002858 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002859 const TType *fieldType = field->type();
2860
2861 const TString &fieldNameA = "a." + Decorate(field->name());
2862 const TString &fieldNameB = "b." + Decorate(field->name());
2863
2864 if (i > 0)
2865 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002866 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002867 }
2868
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002869 fnOut << "(";
2870 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2871 fnOut << fieldNameA;
2872 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2873 fnOut << fieldNameB;
2874 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2875 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002876 }
2877
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002878 fnOut << ";\n"
2879 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002880
2881 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002882
2883 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002885
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002886 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002887}
2888
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002889TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002890{
2891 for (const auto &eqFunction : mArrayEqualityFunctions)
2892 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002893 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002894 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002895 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002896 }
2897 }
2898
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002899 TType elementType(type);
2900 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002901
Olli Etuaho12690762015-03-31 12:55:28 +03002902 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002903 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002904
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002905 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002906
2907 TInfoSinkBase fnOut;
2908
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002909 const TString &typeName = TypeString(type);
2910 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2911 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002912 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002913 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002914 << type.getOutermostArraySize()
2915 << "; ++i)\n"
2916 " {\n"
2917 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002918
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002919 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002920 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002921 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002922 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002923 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002924
2925 fnOut << ") { return false; }\n"
2926 " }\n"
2927 " return true;\n"
2928 "}\n";
2929
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002930 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002931
2932 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002933 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002934
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002935 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002936}
2937
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002938TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002939{
2940 for (const auto &assignFunction : mArrayAssignmentFunctions)
2941 {
2942 if (assignFunction.type == type)
2943 {
2944 return assignFunction.functionName;
2945 }
2946 }
2947
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002948 TType elementType(type);
2949 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002950
2951 ArrayHelperFunction function;
2952 function.type = type;
2953
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002955
2956 TInfoSinkBase fnOut;
2957
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002958 const TString &typeName = TypeString(type);
2959 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2960 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002961 << "{\n"
2962 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002963 << type.getOutermostArraySize()
2964 << "; ++i)\n"
2965 " {\n"
2966 " ";
2967
2968 outputAssign(PreVisit, elementType, fnOut);
2969 fnOut << "a[i]";
2970 outputAssign(InVisit, elementType, fnOut);
2971 fnOut << "b[i]";
2972 outputAssign(PostVisit, elementType, fnOut);
2973
2974 fnOut << ";\n"
2975 " }\n"
2976 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002977
2978 function.functionDefinition = fnOut.c_str();
2979
2980 mArrayAssignmentFunctions.push_back(function);
2981
2982 return function.functionName;
2983}
2984
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002985TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03002986{
2987 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2988 {
2989 if (constructIntoFunction.type == type)
2990 {
2991 return constructIntoFunction.functionName;
2992 }
2993 }
2994
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002995 TType elementType(type);
2996 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03002997
2998 ArrayHelperFunction function;
2999 function.type = type;
3000
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003001 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003002
3003 TInfoSinkBase fnOut;
3004
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003005 const TString &typeName = TypeString(type);
3006 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3007 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003008 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003009 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003010 }
3011 fnOut << ")\n"
3012 "{\n";
3013
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003014 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003015 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003016 fnOut << " ";
3017 outputAssign(PreVisit, elementType, fnOut);
3018 fnOut << "a[" << i << "]";
3019 outputAssign(InVisit, elementType, fnOut);
3020 fnOut << "b" << i;
3021 outputAssign(PostVisit, elementType, fnOut);
3022 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003023 }
3024 fnOut << "}\n";
3025
3026 function.functionDefinition = fnOut.c_str();
3027
3028 mArrayConstructIntoFunctions.push_back(function);
3029
3030 return function.functionName;
3031}
3032
Jamie Madill2e295e22015-04-29 10:41:33 -04003033void OutputHLSL::ensureStructDefined(const TType &type)
3034{
3035 TStructure *structure = type.getStruct();
3036
3037 if (structure)
3038 {
3039 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3040 }
3041}
3042
Jamie Madill45bcc782016-11-07 13:58:48 -05003043} // namespace sh