blob: 54427a9af773eb1256dacaae4dba9bcfcc95ab18 [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"
Xinghua Cao711b7a12017-10-09 13:38:12 +080019#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/InfoSink.h"
21#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020022#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/SearchSymbol.h"
24#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030025#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050027#include "compiler/translator/UniformHLSL.h"
28#include "compiler/translator/UtilsHLSL.h"
29#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050030#include "compiler/translator/util.h"
31
Jamie Madill45bcc782016-11-07 13:58:48 -050032namespace sh
33{
34
Olli Etuaho96f6adf2017-08-16 11:18:54 +030035namespace
36{
37
38TString ArrayHelperFunctionName(const char *prefix, const TType &type)
39{
40 TStringStream fnName;
41 fnName << prefix << "_";
42 for (unsigned int arraySize : type.getArraySizes())
43 {
44 fnName << arraySize << "_";
45 }
46 fnName << TypeString(type);
47 return fnName.str();
48}
49
Olli Etuaho40dbdd62017-10-13 13:34:19 +030050bool IsDeclarationWrittenOut(TIntermDeclaration *node)
51{
52 TIntermSequence *sequence = node->getSequence();
53 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
54 ASSERT(sequence->size() == 1);
55 ASSERT(variable);
56 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
57 variable->getQualifier() == EvqConst);
58}
59
Olli Etuaho96f6adf2017-08-16 11:18:54 +030060} // anonymous namespace
61
Olli Etuaho56a2f952016-12-08 12:16:27 +000062void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030063{
Olli Etuaho56a2f952016-12-08 12:16:27 +000064 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
65 // regardless.
66 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
67 mOutputType == SH_HLSL_4_1_OUTPUT)
68 {
69 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
70 }
71 else
72 {
73 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
74 }
75}
Olli Etuaho4785fec2015-05-18 16:09:37 +030076
Olli Etuaho56a2f952016-12-08 12:16:27 +000077void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +020078{
79 ASSERT(constUnion != nullptr);
80 switch (constUnion->getType())
81 {
82 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +000083 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +020084 break;
85 case EbtInt:
86 out << constUnion->getIConst();
87 break;
88 case EbtUInt:
89 out << constUnion->getUConst();
90 break;
91 case EbtBool:
92 out << constUnion->getBConst();
93 break;
94 default:
95 UNREACHABLE();
96 }
97}
98
Olli Etuaho56a2f952016-12-08 12:16:27 +000099const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
100 const TConstantUnion *const constUnion,
101 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200102{
103 const TConstantUnion *constUnionIterated = constUnion;
104 for (size_t i = 0; i < size; i++, constUnionIterated++)
105 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000106 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200107
108 if (i != size - 1)
109 {
110 out << ", ";
111 }
112 }
113 return constUnionIterated;
114}
115
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800116OutputHLSL::OutputHLSL(sh::GLenum shaderType,
117 int shaderVersion,
118 const TExtensionBehavior &extensionBehavior,
119 const char *sourcePath,
120 ShShaderOutput outputType,
121 int numRenderTargets,
122 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300123 ShCompileOptions compileOptions,
124 TSymbolTable *symbolTable)
125 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200126 mShaderType(shaderType),
127 mShaderVersion(shaderVersion),
128 mExtensionBehavior(extensionBehavior),
129 mSourcePath(sourcePath),
130 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700131 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000132 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700133 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000135 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000136
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500137 mUsesFragColor = false;
138 mUsesFragData = false;
139 mUsesDepthRange = false;
140 mUsesFragCoord = false;
141 mUsesPointCoord = false;
142 mUsesFrontFacing = false;
143 mUsesPointSize = false;
144 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300145 mHasMultiviewExtensionEnabled =
146 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300147 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500148 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500149 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800150 mUsesNumWorkGroups = false;
151 mUsesWorkGroupID = false;
152 mUsesLocalInvocationID = false;
153 mUsesGlobalInvocationID = false;
154 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500155 mUsesXor = false;
156 mUsesDiscardRewriting = false;
157 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530158 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000159
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000160 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000161
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000163 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500164 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000165
Yunchao Hed7297bf2017-04-19 15:27:10 +0800166 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000167
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500168 mStructureHLSL = new StructureHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800169 mUniformHLSL = new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300170 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800171 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400172
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200173 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000174 {
Arun Patole63419392015-03-13 11:51:07 +0530175 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500176 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
177 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530178 // In both cases total 3 uniform registers need to be reserved.
179 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000180 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000181
Geoff Lang00140f42016-02-03 18:47:33 +0000182 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800183 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184}
185
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000186OutputHLSL::~OutputHLSL()
187{
Jamie Madill8daaba12014-06-13 10:04:33 -0400188 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400189 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300190 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800191 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200192 for (auto &eqFunction : mStructEqualityFunctions)
193 {
194 SafeDelete(eqFunction);
195 }
196 for (auto &eqFunction : mArrayEqualityFunctions)
197 {
198 SafeDelete(eqFunction);
199 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000200}
201
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200202void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000203{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500204 const std::vector<TIntermTyped *> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400205 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000206
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200207 BuiltInFunctionEmulator builtInFunctionEmulator;
208 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800209 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
210 {
211 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
212 mShaderVersion);
213 }
214
Olli Etuahodfa75e82017-01-23 09:43:06 -0800215 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500216
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700217 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000218 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700219 ASSERT(success == CallDAG::INITDAG_SUCCESS);
220 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700221
Jamie Madill37997142015-01-28 10:06:34 -0500222 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500223 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200224 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500225 mInfoSinkStack.pop();
226
Jamie Madill37997142015-01-28 10:06:34 -0500227 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500228 mInfoSinkStack.pop();
229
Jamie Madill32aab012015-01-27 14:12:26 -0500230 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500231 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500232 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000233
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200234 objSink << mHeader.c_str();
235 objSink << mBody.c_str();
236 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200237
Olli Etuahodfa75e82017-01-23 09:43:06 -0800238 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000239}
240
Jamie Madill570e04d2013-06-21 09:15:33 -0400241void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
242{
243 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
244 {
245 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
246
Jamie Madill32aab012015-01-27 14:12:26 -0500247 TInfoSinkBase structInfoSink;
248 mInfoSinkStack.push(&structInfoSink);
249
Jamie Madill570e04d2013-06-21 09:15:33 -0400250 // This will mark the necessary block elements as referenced
251 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500252
253 TString structName(structInfoSink.c_str());
254 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400255
256 mFlaggedStructOriginalNames[flaggedNode] = structName;
257
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500258 for (size_t pos = structName.find('.'); pos != std::string::npos;
259 pos = structName.find('.'))
Jamie Madill570e04d2013-06-21 09:15:33 -0400260 {
261 structName.erase(pos, 1);
262 }
263
264 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
265 }
266}
267
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800268const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400269{
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800270 return mUniformHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400271}
272
Jamie Madill9fe25e92014-07-18 10:33:08 -0400273const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
274{
275 return mUniformHLSL->getUniformRegisterMap();
276}
277
Olli Etuahoed049ab2017-06-30 17:38:33 +0300278TString OutputHLSL::structInitializerString(int indent, const TType &type, const TString &name)
Jamie Madill570e04d2013-06-21 09:15:33 -0400279{
280 TString init;
281
Olli Etuahoed049ab2017-06-30 17:38:33 +0300282 TString indentString;
283 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400284 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300285 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400286 }
287
Olli Etuahoed049ab2017-06-30 17:38:33 +0300288 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400289 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300291 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400292 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300293 TStringStream indexedString;
294 indexedString << name << "[" << arrayIndex << "]";
295 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300296 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300297 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300298 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 {
300 init += ",";
301 }
302 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400303 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300304 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400305 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300306 else if (type.getBasicType() == EbtStruct)
307 {
308 init += indentString + "{\n";
309 const TStructure &structure = *type.getStruct();
310 const TFieldList &fields = structure.fields();
311 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
312 {
313 const TField &field = *fields[fieldIndex];
314 const TString &fieldName = name + "." + Decorate(field.name());
315 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400316
Olli Etuahoed049ab2017-06-30 17:38:33 +0300317 init += structInitializerString(indent + 1, fieldType, fieldName);
318 if (fieldIndex < fields.size() - 1)
319 {
320 init += ",";
321 }
322 init += "\n";
323 }
324 init += indentString + "}";
325 }
326 else
327 {
328 init += indentString + name;
329 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400330
331 return init;
332}
333
Jamie Madill8c46ab12015-12-07 16:39:19 -0500334void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000336 TString varyings;
337 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400338 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000339
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500340 for (std::map<TIntermTyped *, TString>::const_iterator flaggedStructIt =
341 mFlaggedStructMappedNames.begin();
342 flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500344 TIntermTyped *structNode = flaggedStructIt->first;
345 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400346 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400347 const TString &originalName = mFlaggedStructOriginalNames[structNode];
348
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName;
350 if (structNode->isArray())
351 {
352 flaggedStructs += ArrayString(structNode->getType());
353 }
354 flaggedStructs += " =\n";
355 flaggedStructs += structInitializerString(0, structNode->getType(), originalName);
356 flaggedStructs += ";\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400357 }
358
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500359 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin();
360 varying != mReferencedVaryings.end(); varying++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000361 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500362 const TType &type = varying->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000363 const TString &name = varying->second->getSymbol();
364
365 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500366 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
367 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000368 }
369
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500370 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
371 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000372 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500373 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000374 const TString &name = attribute->second->getSymbol();
375
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500376 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
377 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000378 }
379
Jamie Madill8daaba12014-06-13 10:04:33 -0400380 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400381
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300382 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800383 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400384
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200385 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500386 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200387 out << "\n// Equality functions\n\n";
388 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500389 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200390 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200391 }
392 }
Olli Etuaho12690762015-03-31 12:55:28 +0300393 if (!mArrayAssignmentFunctions.empty())
394 {
395 out << "\n// Assignment functions\n\n";
396 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
397 {
398 out << assignmentFunction.functionDefinition << "\n";
399 }
400 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300401 if (!mArrayConstructIntoFunctions.empty())
402 {
403 out << "\n// Array constructor functions\n\n";
404 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
405 {
406 out << constructIntoFunction.functionDefinition << "\n";
407 }
408 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200409
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500410 if (mUsesDiscardRewriting)
411 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400412 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500413 }
414
Nicolas Capens655fe362014-04-11 13:12:34 -0400415 if (mUsesNestedBreak)
416 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400417 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400418 }
419
Arun Patole44efa0b2015-03-04 17:11:05 +0530420 if (mRequiresIEEEStrictCompiling)
421 {
422 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
423 }
424
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400425 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
426 "#define LOOP [loop]\n"
427 "#define FLATTEN [flatten]\n"
428 "#else\n"
429 "#define LOOP\n"
430 "#define FLATTEN\n"
431 "#endif\n";
432
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200433 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000434 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300435 const bool usingMRTExtension =
436 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000437
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000438 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500439 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400440 out << "\n";
441
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200442 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000443 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500444 for (ReferencedSymbols::const_iterator outputVariableIt =
445 mReferencedOutputVariables.begin();
446 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000447 {
Jamie Madill46131a32013-06-20 11:55:50 -0400448 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500449 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400450
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500451 out << "static " + TypeString(variableType) + " out_" + variableName +
452 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000453 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000454 }
Jamie Madill46131a32013-06-20 11:55:50 -0400455 else
456 {
457 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
458
459 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500460 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400461 for (unsigned int i = 0; i < numColorValues; i++)
462 {
463 out << " float4(0, 0, 0, 0)";
464 if (i + 1 != numColorValues)
465 {
466 out << ",";
467 }
468 out << "\n";
469 }
470
471 out << "};\n";
472 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000473
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400474 if (mUsesFragDepth)
475 {
476 out << "static float gl_Depth = 0.0;\n";
477 }
478
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000479 if (mUsesFragCoord)
480 {
481 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
482 }
483
484 if (mUsesPointCoord)
485 {
486 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
487 }
488
489 if (mUsesFrontFacing)
490 {
491 out << "static bool gl_FrontFacing = false;\n";
492 }
493
494 out << "\n";
495
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000496 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000497 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000498 out << "struct gl_DepthRangeParameters\n"
499 "{\n"
500 " float near;\n"
501 " float far;\n"
502 " float diff;\n"
503 "};\n"
504 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000505 }
506
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200507 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000508 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000509 out << "cbuffer DriverConstants : register(b1)\n"
510 "{\n";
511
512 if (mUsesDepthRange)
513 {
514 out << " float3 dx_DepthRange : packoffset(c0);\n";
515 }
516
517 if (mUsesFragCoord)
518 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000519 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000520 }
521
522 if (mUsesFragCoord || mUsesFrontFacing)
523 {
524 out << " float3 dx_DepthFront : packoffset(c2);\n";
525 }
526
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800527 if (mUsesFragCoord)
528 {
529 // dx_ViewScale is only used in the fragment shader to correct
530 // the value for glFragCoord if necessary
531 out << " float2 dx_ViewScale : packoffset(c3);\n";
532 }
533
Martin Radev72b4e1e2017-08-31 15:42:56 +0300534 if (mHasMultiviewExtensionEnabled)
535 {
536 // We have to add a value which we can use to keep track of which multi-view code
537 // path is to be selected in the GS.
538 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
539 }
540
Olli Etuaho618bebc2016-01-15 16:40:00 +0200541 if (mOutputType == SH_HLSL_4_1_OUTPUT)
542 {
543 mUniformHLSL->samplerMetadataUniforms(out, "c4");
544 }
545
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000546 out << "};\n";
547 }
548 else
549 {
550 if (mUsesDepthRange)
551 {
552 out << "uniform float3 dx_DepthRange : register(c0);";
553 }
554
555 if (mUsesFragCoord)
556 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000557 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000558 }
559
560 if (mUsesFragCoord || mUsesFrontFacing)
561 {
562 out << "uniform float3 dx_DepthFront : register(c2);\n";
563 }
564 }
565
566 out << "\n";
567
568 if (mUsesDepthRange)
569 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500570 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
571 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000572 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000573 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000574
Jamie Madillf91ce812014-06-13 10:04:34 -0400575 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000576 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400577 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000578 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400579 out << flaggedStructs;
580 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000581 }
582
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000583 if (usingMRTExtension && mNumRenderTargets > 1)
584 {
585 out << "#define GL_USES_MRT\n";
586 }
587
588 if (mUsesFragColor)
589 {
590 out << "#define GL_USES_FRAG_COLOR\n";
591 }
592
593 if (mUsesFragData)
594 {
595 out << "#define GL_USES_FRAG_DATA\n";
596 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597 }
Xinghua Caob1239382016-12-13 15:07:05 +0800598 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000600 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500601 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000602 out << "\n"
603 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400604
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000605 if (mUsesPointSize)
606 {
607 out << "static float gl_PointSize = float(1);\n";
608 }
609
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000610 if (mUsesInstanceID)
611 {
612 out << "static int gl_InstanceID;";
613 }
614
Corentin Wallezb076add2016-01-11 16:45:46 -0500615 if (mUsesVertexID)
616 {
617 out << "static int gl_VertexID;";
618 }
619
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000620 out << "\n"
621 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500622 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000623 out << "\n";
624
625 if (mUsesDepthRange)
626 {
627 out << "struct gl_DepthRangeParameters\n"
628 "{\n"
629 " float near;\n"
630 " float far;\n"
631 " float diff;\n"
632 "};\n"
633 "\n";
634 }
635
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200636 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000637 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800638 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500639 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800640
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000641 if (mUsesDepthRange)
642 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800643 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000644 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800645
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800646 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
647 // shaders. However, we declare it for all shaders (including Feature Level 10+).
648 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
649 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800650 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800651 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800652 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800653
Martin Radev72b4e1e2017-08-31 15:42:56 +0300654 if (mHasMultiviewExtensionEnabled)
655 {
656 // We have to add a value which we can use to keep track of which multi-view code
657 // path is to be selected in the GS.
658 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
659 }
660
Olli Etuaho618bebc2016-01-15 16:40:00 +0200661 if (mOutputType == SH_HLSL_4_1_OUTPUT)
662 {
663 mUniformHLSL->samplerMetadataUniforms(out, "c4");
664 }
665
Austin Kinross4fd18b12014-12-22 12:32:05 -0800666 out << "};\n"
667 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000668 }
669 else
670 {
671 if (mUsesDepthRange)
672 {
673 out << "uniform float3 dx_DepthRange : register(c0);\n";
674 }
675
Cooper Partine6664f02015-01-09 16:22:24 -0800676 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
677 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000678 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000679 }
680
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000681 if (mUsesDepthRange)
682 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500683 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
684 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000685 "\n";
686 }
687
Jamie Madillf91ce812014-06-13 10:04:34 -0400688 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000689 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400690 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000691 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400692 out << flaggedStructs;
693 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000694 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400695 }
Xinghua Caob1239382016-12-13 15:07:05 +0800696 else // Compute shader
697 {
698 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800699
700 out << "cbuffer DriverConstants : register(b1)\n"
701 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800702 if (mUsesNumWorkGroups)
703 {
Xinghua Caob1239382016-12-13 15:07:05 +0800704 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800705 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800706 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
707 mUniformHLSL->samplerMetadataUniforms(out, "c1");
708 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800709
710 // Follow built-in variables would be initialized in
711 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
712 // are used in compute shader.
713 if (mUsesWorkGroupID)
714 {
715 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
716 }
717
718 if (mUsesLocalInvocationID)
719 {
720 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
721 }
722
723 if (mUsesGlobalInvocationID)
724 {
725 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
726 }
727
728 if (mUsesLocalInvocationIndex)
729 {
730 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
731 }
732 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000733
Geoff Lang1fe74c72016-08-25 13:23:01 -0400734 bool getDimensionsIgnoresBaseLevel =
735 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
736 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800737 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000739 if (mUsesFragCoord)
740 {
741 out << "#define GL_USES_FRAG_COORD\n";
742 }
743
744 if (mUsesPointCoord)
745 {
746 out << "#define GL_USES_POINT_COORD\n";
747 }
748
749 if (mUsesFrontFacing)
750 {
751 out << "#define GL_USES_FRONT_FACING\n";
752 }
753
754 if (mUsesPointSize)
755 {
756 out << "#define GL_USES_POINT_SIZE\n";
757 }
758
Martin Radev41ac68e2017-06-06 12:16:58 +0300759 if (mHasMultiviewExtensionEnabled)
760 {
761 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
762 }
763
764 if (mUsesViewID)
765 {
766 out << "#define GL_USES_VIEW_ID\n";
767 }
768
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400769 if (mUsesFragDepth)
770 {
771 out << "#define GL_USES_FRAG_DEPTH\n";
772 }
773
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000774 if (mUsesDepthRange)
775 {
776 out << "#define GL_USES_DEPTH_RANGE\n";
777 }
778
Xinghua Caob1239382016-12-13 15:07:05 +0800779 if (mUsesNumWorkGroups)
780 {
781 out << "#define GL_USES_NUM_WORK_GROUPS\n";
782 }
783
784 if (mUsesWorkGroupID)
785 {
786 out << "#define GL_USES_WORK_GROUP_ID\n";
787 }
788
789 if (mUsesLocalInvocationID)
790 {
791 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
792 }
793
794 if (mUsesGlobalInvocationID)
795 {
796 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
797 }
798
799 if (mUsesLocalInvocationIndex)
800 {
801 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
802 }
803
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000804 if (mUsesXor)
805 {
806 out << "bool xor(bool p, bool q)\n"
807 "{\n"
808 " return (p || q) && !(p && q);\n"
809 "}\n"
810 "\n";
811 }
812
Olli Etuahodfa75e82017-01-23 09:43:06 -0800813 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814}
815
816void OutputHLSL::visitSymbol(TIntermSymbol *node)
817{
Jamie Madill32aab012015-01-27 14:12:26 -0500818 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000819
Jamie Madill570e04d2013-06-21 09:15:33 -0400820 // Handle accessing std140 structs by value
821 if (mFlaggedStructMappedNames.count(node) > 0)
822 {
823 out << mFlaggedStructMappedNames[node];
824 return;
825 }
826
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000827 TString name = node->getSymbol();
828
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000829 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000830 {
831 mUsesDepthRange = true;
832 out << name;
833 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000834 else
835 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000836 TQualifier qualifier = node->getQualifier();
837
838 if (qualifier == EvqUniform)
839 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500840 const TType &nodeType = node->getType();
Jamie Madill2e295e22015-04-29 10:41:33 -0400841 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400842
843 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000844 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800845 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000846 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000847 else
848 {
849 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000850 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400851
Jamie Madill2e295e22015-04-29 10:41:33 -0400852 ensureStructDefined(nodeType);
853
Olli Etuahoff526f12017-06-30 12:26:54 +0300854 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000855 }
Jamie Madill19571812013-08-12 15:26:34 -0700856 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000857 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000858 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400859 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000860 }
Jamie Madill033dae62014-06-18 12:56:28 -0400861 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000862 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000863 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400864 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300865 if (name == "ViewID_OVR")
866 {
867 mUsesViewID = true;
868 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000869 }
Jamie Madill19571812013-08-12 15:26:34 -0700870 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400871 {
872 mReferencedOutputVariables[name] = node;
873 out << "out_" << name;
874 }
875 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000876 {
877 out << "gl_Color[0]";
878 mUsesFragColor = true;
879 }
880 else if (qualifier == EvqFragData)
881 {
882 out << "gl_Color";
883 mUsesFragData = true;
884 }
885 else if (qualifier == EvqFragCoord)
886 {
887 mUsesFragCoord = true;
888 out << name;
889 }
890 else if (qualifier == EvqPointCoord)
891 {
892 mUsesPointCoord = true;
893 out << name;
894 }
895 else if (qualifier == EvqFrontFacing)
896 {
897 mUsesFrontFacing = true;
898 out << name;
899 }
900 else if (qualifier == EvqPointSize)
901 {
902 mUsesPointSize = true;
903 out << name;
904 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000905 else if (qualifier == EvqInstanceID)
906 {
907 mUsesInstanceID = true;
908 out << name;
909 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500910 else if (qualifier == EvqVertexID)
911 {
912 mUsesVertexID = true;
913 out << name;
914 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300915 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400916 {
917 mUsesFragDepth = true;
918 out << "gl_Depth";
919 }
Xinghua Caob1239382016-12-13 15:07:05 +0800920 else if (qualifier == EvqNumWorkGroups)
921 {
922 mUsesNumWorkGroups = true;
923 out << name;
924 }
925 else if (qualifier == EvqWorkGroupID)
926 {
927 mUsesWorkGroupID = true;
928 out << name;
929 }
930 else if (qualifier == EvqLocalInvocationID)
931 {
932 mUsesLocalInvocationID = true;
933 out << name;
934 }
935 else if (qualifier == EvqGlobalInvocationID)
936 {
937 mUsesGlobalInvocationID = true;
938 out << name;
939 }
940 else if (qualifier == EvqLocalInvocationIndex)
941 {
942 mUsesLocalInvocationIndex = true;
943 out << name;
944 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000945 else
946 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300947 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000948 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949 }
950}
951
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400952void OutputHLSL::visitRaw(TIntermRaw *node)
953{
Jamie Madill32aab012015-01-27 14:12:26 -0500954 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400955}
956
Olli Etuaho7fb49552015-03-18 17:27:44 +0200957void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
958{
959 if (type.isScalar() && !type.isArray())
960 {
961 if (op == EOpEqual)
962 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500963 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200964 }
965 else
966 {
Jamie Madill8c46ab12015-12-07 16:39:19 -0500967 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200968 }
969 }
970 else
971 {
972 if (visit == PreVisit && op == EOpNotEqual)
973 {
974 out << "!";
975 }
976
977 if (type.isArray())
978 {
979 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500980 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200981 }
982 else if (type.getBasicType() == EbtStruct)
983 {
984 const TStructure &structure = *type.getStruct();
985 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500986 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200987 }
988 else
989 {
990 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -0500991 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +0200992 }
993 }
994}
995
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300996void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
997{
998 if (type.isArray())
999 {
1000 const TString &functionName = addArrayAssignmentFunction(type);
1001 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1002 }
1003 else
1004 {
1005 outputTriplet(out, visit, "(", " = ", ")");
1006 }
1007}
1008
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001009bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001010{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001011 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001012 {
1013 TIntermNode *ancestor = getAncestorNode(n);
1014 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1015 if (ancestorBinary == nullptr)
1016 {
1017 return false;
1018 }
1019 switch (ancestorBinary->getOp())
1020 {
1021 case EOpIndexDirectStruct:
1022 {
1023 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1024 const TIntermConstantUnion *index =
1025 ancestorBinary->getRight()->getAsConstantUnion();
1026 const TField *field = structure->fields()[index->getIConst(0)];
1027 if (IsSampler(field->type()->getBasicType()))
1028 {
1029 return true;
1030 }
1031 break;
1032 }
1033 case EOpIndexDirect:
1034 break;
1035 default:
1036 // Returning a sampler from indirect indexing is not supported.
1037 return false;
1038 }
1039 }
1040 return false;
1041}
1042
Olli Etuahob6fa0432016-09-28 16:28:05 +01001043bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1044{
1045 TInfoSinkBase &out = getInfoSink();
1046 if (visit == PostVisit)
1047 {
1048 out << ".";
1049 node->writeOffsetsAsXYZW(&out);
1050 }
1051 return true;
1052}
1053
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001054bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1055{
Jamie Madill32aab012015-01-27 14:12:26 -05001056 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001057
Jamie Madill570e04d2013-06-21 09:15:33 -04001058 // Handle accessing std140 structs by value
1059 if (mFlaggedStructMappedNames.count(node) > 0)
1060 {
1061 out << mFlaggedStructMappedNames[node];
1062 return false;
1063 }
1064
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065 switch (node->getOp())
1066 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001067 case EOpComma:
1068 outputTriplet(out, visit, "(", ", ", ")");
1069 break;
1070 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001071 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001072 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001073 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1074 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001075 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001076 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1077 out << functionName << "(";
1078 node->getLeft()->traverse(this);
1079 TIntermSequence *seq = rightAgg->getSequence();
1080 for (auto &arrayElement : *seq)
1081 {
1082 out << ", ";
1083 arrayElement->traverse(this);
1084 }
1085 out << ")";
1086 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001087 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001088 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1089 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001090 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001091 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001092 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001093 break;
1094 case EOpInitialize:
1095 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001096 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001097 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1098 ASSERT(symbolNode);
1099 TIntermTyped *expression = node->getRight();
1100
1101 // Global initializers must be constant at this point.
1102 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1103 canWriteAsHLSLLiteral(expression));
1104
1105 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1106 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1107 // new variable is created before the assignment is evaluated), so we need to
1108 // convert
1109 // this to "float t = x, x = t;".
1110 if (writeSameSymbolInitializer(out, symbolNode, expression))
1111 {
1112 // Skip initializing the rest of the expression
1113 return false;
1114 }
1115 else if (writeConstantInitialization(out, symbolNode, expression))
1116 {
1117 return false;
1118 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001119 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001120 else if (visit == InVisit)
1121 {
1122 out << " = ";
1123 }
1124 break;
1125 case EOpAddAssign:
1126 outputTriplet(out, visit, "(", " += ", ")");
1127 break;
1128 case EOpSubAssign:
1129 outputTriplet(out, visit, "(", " -= ", ")");
1130 break;
1131 case EOpMulAssign:
1132 outputTriplet(out, visit, "(", " *= ", ")");
1133 break;
1134 case EOpVectorTimesScalarAssign:
1135 outputTriplet(out, visit, "(", " *= ", ")");
1136 break;
1137 case EOpMatrixTimesScalarAssign:
1138 outputTriplet(out, visit, "(", " *= ", ")");
1139 break;
1140 case EOpVectorTimesMatrixAssign:
1141 if (visit == PreVisit)
1142 {
1143 out << "(";
1144 }
1145 else if (visit == InVisit)
1146 {
1147 out << " = mul(";
1148 node->getLeft()->traverse(this);
1149 out << ", transpose(";
1150 }
1151 else
1152 {
1153 out << ")))";
1154 }
1155 break;
1156 case EOpMatrixTimesMatrixAssign:
1157 if (visit == PreVisit)
1158 {
1159 out << "(";
1160 }
1161 else if (visit == InVisit)
1162 {
1163 out << " = transpose(mul(transpose(";
1164 node->getLeft()->traverse(this);
1165 out << "), transpose(";
1166 }
1167 else
1168 {
1169 out << "))))";
1170 }
1171 break;
1172 case EOpDivAssign:
1173 outputTriplet(out, visit, "(", " /= ", ")");
1174 break;
1175 case EOpIModAssign:
1176 outputTriplet(out, visit, "(", " %= ", ")");
1177 break;
1178 case EOpBitShiftLeftAssign:
1179 outputTriplet(out, visit, "(", " <<= ", ")");
1180 break;
1181 case EOpBitShiftRightAssign:
1182 outputTriplet(out, visit, "(", " >>= ", ")");
1183 break;
1184 case EOpBitwiseAndAssign:
1185 outputTriplet(out, visit, "(", " &= ", ")");
1186 break;
1187 case EOpBitwiseXorAssign:
1188 outputTriplet(out, visit, "(", " ^= ", ")");
1189 break;
1190 case EOpBitwiseOrAssign:
1191 outputTriplet(out, visit, "(", " |= ", ")");
1192 break;
1193 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001194 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001195 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001196 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001197 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001198 if (visit == PreVisit)
1199 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001200 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001201 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001202 mReferencedUniformBlocks[interfaceBlock->instanceName()] =
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001203 node->getLeft()->getAsSymbolNode();
Jiajia Qin9b11ea42017-07-11 16:50:08 +08001204 out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001205 return false;
1206 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001207 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001208 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001209 {
1210 // All parts of an expression that access a sampler in a struct need to use _ as
1211 // separator to access the sampler variable that has been moved out of the struct.
1212 outputTriplet(out, visit, "", "_", "");
1213 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001214 else
1215 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001216 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001217 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001218 }
1219 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001220 case EOpIndexIndirect:
1221 // We do not currently support indirect references to interface blocks
1222 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1223 outputTriplet(out, visit, "", "[", "]");
1224 break;
1225 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001226 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001227 const TStructure *structure = node->getLeft()->getType().getStruct();
1228 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1229 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001230
Olli Etuaho96963162016-03-21 11:54:33 +02001231 // In cases where indexing returns a sampler, we need to access the sampler variable
1232 // that has been moved out of the struct.
1233 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1234 if (visit == PreVisit && indexingReturnsSampler)
1235 {
1236 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1237 // This prefix is only output at the beginning of the indexing expression, which
1238 // may have multiple parts.
1239 out << "angle";
1240 }
1241 if (!indexingReturnsSampler)
1242 {
1243 // All parts of an expression that access a sampler in a struct need to use _ as
1244 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001245 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001246 }
1247 if (visit == InVisit)
1248 {
1249 if (indexingReturnsSampler)
1250 {
1251 out << "_" + field->name();
1252 }
1253 else
1254 {
1255 out << "." + DecorateField(field->name(), *structure);
1256 }
1257
1258 return false;
1259 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001260 }
1261 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001262 case EOpIndexDirectInterfaceBlock:
1263 if (visit == InVisit)
1264 {
1265 const TInterfaceBlock *interfaceBlock =
1266 node->getLeft()->getType().getInterfaceBlock();
1267 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1268 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
1269 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001270
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001271 return false;
1272 }
1273 break;
1274 case EOpAdd:
1275 outputTriplet(out, visit, "(", " + ", ")");
1276 break;
1277 case EOpSub:
1278 outputTriplet(out, visit, "(", " - ", ")");
1279 break;
1280 case EOpMul:
1281 outputTriplet(out, visit, "(", " * ", ")");
1282 break;
1283 case EOpDiv:
1284 outputTriplet(out, visit, "(", " / ", ")");
1285 break;
1286 case EOpIMod:
1287 outputTriplet(out, visit, "(", " % ", ")");
1288 break;
1289 case EOpBitShiftLeft:
1290 outputTriplet(out, visit, "(", " << ", ")");
1291 break;
1292 case EOpBitShiftRight:
1293 outputTriplet(out, visit, "(", " >> ", ")");
1294 break;
1295 case EOpBitwiseAnd:
1296 outputTriplet(out, visit, "(", " & ", ")");
1297 break;
1298 case EOpBitwiseXor:
1299 outputTriplet(out, visit, "(", " ^ ", ")");
1300 break;
1301 case EOpBitwiseOr:
1302 outputTriplet(out, visit, "(", " | ", ")");
1303 break;
1304 case EOpEqual:
1305 case EOpNotEqual:
1306 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1307 break;
1308 case EOpLessThan:
1309 outputTriplet(out, visit, "(", " < ", ")");
1310 break;
1311 case EOpGreaterThan:
1312 outputTriplet(out, visit, "(", " > ", ")");
1313 break;
1314 case EOpLessThanEqual:
1315 outputTriplet(out, visit, "(", " <= ", ")");
1316 break;
1317 case EOpGreaterThanEqual:
1318 outputTriplet(out, visit, "(", " >= ", ")");
1319 break;
1320 case EOpVectorTimesScalar:
1321 outputTriplet(out, visit, "(", " * ", ")");
1322 break;
1323 case EOpMatrixTimesScalar:
1324 outputTriplet(out, visit, "(", " * ", ")");
1325 break;
1326 case EOpVectorTimesMatrix:
1327 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1328 break;
1329 case EOpMatrixTimesVector:
1330 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1331 break;
1332 case EOpMatrixTimesMatrix:
1333 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1334 break;
1335 case EOpLogicalOr:
1336 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1337 // been unfolded.
1338 ASSERT(!node->getRight()->hasSideEffects());
1339 outputTriplet(out, visit, "(", " || ", ")");
1340 return true;
1341 case EOpLogicalXor:
1342 mUsesXor = true;
1343 outputTriplet(out, visit, "xor(", ", ", ")");
1344 break;
1345 case EOpLogicalAnd:
1346 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1347 // been unfolded.
1348 ASSERT(!node->getRight()->hasSideEffects());
1349 outputTriplet(out, visit, "(", " && ", ")");
1350 return true;
1351 default:
1352 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353 }
1354
1355 return true;
1356}
1357
1358bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1359{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001360 TInfoSinkBase &out = getInfoSink();
1361
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001362 switch (node->getOp())
1363 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001364 case EOpNegative:
1365 outputTriplet(out, visit, "(-", "", ")");
1366 break;
1367 case EOpPositive:
1368 outputTriplet(out, visit, "(+", "", ")");
1369 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001370 case EOpLogicalNot:
1371 outputTriplet(out, visit, "(!", "", ")");
1372 break;
1373 case EOpBitwiseNot:
1374 outputTriplet(out, visit, "(~", "", ")");
1375 break;
1376 case EOpPostIncrement:
1377 outputTriplet(out, visit, "(", "", "++)");
1378 break;
1379 case EOpPostDecrement:
1380 outputTriplet(out, visit, "(", "", "--)");
1381 break;
1382 case EOpPreIncrement:
1383 outputTriplet(out, visit, "(++", "", ")");
1384 break;
1385 case EOpPreDecrement:
1386 outputTriplet(out, visit, "(--", "", ")");
1387 break;
1388 case EOpRadians:
1389 outputTriplet(out, visit, "radians(", "", ")");
1390 break;
1391 case EOpDegrees:
1392 outputTriplet(out, visit, "degrees(", "", ")");
1393 break;
1394 case EOpSin:
1395 outputTriplet(out, visit, "sin(", "", ")");
1396 break;
1397 case EOpCos:
1398 outputTriplet(out, visit, "cos(", "", ")");
1399 break;
1400 case EOpTan:
1401 outputTriplet(out, visit, "tan(", "", ")");
1402 break;
1403 case EOpAsin:
1404 outputTriplet(out, visit, "asin(", "", ")");
1405 break;
1406 case EOpAcos:
1407 outputTriplet(out, visit, "acos(", "", ")");
1408 break;
1409 case EOpAtan:
1410 outputTriplet(out, visit, "atan(", "", ")");
1411 break;
1412 case EOpSinh:
1413 outputTriplet(out, visit, "sinh(", "", ")");
1414 break;
1415 case EOpCosh:
1416 outputTriplet(out, visit, "cosh(", "", ")");
1417 break;
1418 case EOpTanh:
1419 outputTriplet(out, visit, "tanh(", "", ")");
1420 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001421 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001422 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001423 case EOpAtanh:
1424 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001425 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001426 break;
1427 case EOpExp:
1428 outputTriplet(out, visit, "exp(", "", ")");
1429 break;
1430 case EOpLog:
1431 outputTriplet(out, visit, "log(", "", ")");
1432 break;
1433 case EOpExp2:
1434 outputTriplet(out, visit, "exp2(", "", ")");
1435 break;
1436 case EOpLog2:
1437 outputTriplet(out, visit, "log2(", "", ")");
1438 break;
1439 case EOpSqrt:
1440 outputTriplet(out, visit, "sqrt(", "", ")");
1441 break;
1442 case EOpInverseSqrt:
1443 outputTriplet(out, visit, "rsqrt(", "", ")");
1444 break;
1445 case EOpAbs:
1446 outputTriplet(out, visit, "abs(", "", ")");
1447 break;
1448 case EOpSign:
1449 outputTriplet(out, visit, "sign(", "", ")");
1450 break;
1451 case EOpFloor:
1452 outputTriplet(out, visit, "floor(", "", ")");
1453 break;
1454 case EOpTrunc:
1455 outputTriplet(out, visit, "trunc(", "", ")");
1456 break;
1457 case EOpRound:
1458 outputTriplet(out, visit, "round(", "", ")");
1459 break;
1460 case EOpRoundEven:
1461 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001462 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001463 break;
1464 case EOpCeil:
1465 outputTriplet(out, visit, "ceil(", "", ")");
1466 break;
1467 case EOpFract:
1468 outputTriplet(out, visit, "frac(", "", ")");
1469 break;
1470 case EOpIsNan:
1471 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001472 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001473 else
1474 outputTriplet(out, visit, "isnan(", "", ")");
1475 mRequiresIEEEStrictCompiling = true;
1476 break;
1477 case EOpIsInf:
1478 outputTriplet(out, visit, "isinf(", "", ")");
1479 break;
1480 case EOpFloatBitsToInt:
1481 outputTriplet(out, visit, "asint(", "", ")");
1482 break;
1483 case EOpFloatBitsToUint:
1484 outputTriplet(out, visit, "asuint(", "", ")");
1485 break;
1486 case EOpIntBitsToFloat:
1487 outputTriplet(out, visit, "asfloat(", "", ")");
1488 break;
1489 case EOpUintBitsToFloat:
1490 outputTriplet(out, visit, "asfloat(", "", ")");
1491 break;
1492 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001493 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001495 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001497 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001498 case EOpPackUnorm4x8:
1499 case EOpPackSnorm4x8:
1500 case EOpUnpackUnorm4x8:
1501 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001502 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001503 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001504 break;
1505 case EOpLength:
1506 outputTriplet(out, visit, "length(", "", ")");
1507 break;
1508 case EOpNormalize:
1509 outputTriplet(out, visit, "normalize(", "", ")");
1510 break;
1511 case EOpDFdx:
1512 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1513 {
1514 outputTriplet(out, visit, "(", "", ", 0.0)");
1515 }
1516 else
1517 {
1518 outputTriplet(out, visit, "ddx(", "", ")");
1519 }
1520 break;
1521 case EOpDFdy:
1522 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1523 {
1524 outputTriplet(out, visit, "(", "", ", 0.0)");
1525 }
1526 else
1527 {
1528 outputTriplet(out, visit, "ddy(", "", ")");
1529 }
1530 break;
1531 case EOpFwidth:
1532 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1533 {
1534 outputTriplet(out, visit, "(", "", ", 0.0)");
1535 }
1536 else
1537 {
1538 outputTriplet(out, visit, "fwidth(", "", ")");
1539 }
1540 break;
1541 case EOpTranspose:
1542 outputTriplet(out, visit, "transpose(", "", ")");
1543 break;
1544 case EOpDeterminant:
1545 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1546 break;
1547 case EOpInverse:
1548 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001549 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001550 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001551
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001552 case EOpAny:
1553 outputTriplet(out, visit, "any(", "", ")");
1554 break;
1555 case EOpAll:
1556 outputTriplet(out, visit, "all(", "", ")");
1557 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001558 case EOpLogicalNotComponentWise:
1559 outputTriplet(out, visit, "(!", "", ")");
1560 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001561 case EOpBitfieldReverse:
1562 outputTriplet(out, visit, "reversebits(", "", ")");
1563 break;
1564 case EOpBitCount:
1565 outputTriplet(out, visit, "countbits(", "", ")");
1566 break;
1567 case EOpFindLSB:
1568 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1569 // in GLSLTest and results are consistent with GL.
1570 outputTriplet(out, visit, "firstbitlow(", "", ")");
1571 break;
1572 case EOpFindMSB:
1573 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1574 // tested in GLSLTest and results are consistent with GL.
1575 outputTriplet(out, visit, "firstbithigh(", "", ")");
1576 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001577 default:
1578 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001579 }
1580
1581 return true;
1582}
1583
Olli Etuaho96963162016-03-21 11:54:33 +02001584TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1585{
1586 if (node->getAsSymbolNode())
1587 {
1588 return node->getAsSymbolNode()->getSymbol();
1589 }
1590 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1591 switch (nodeBinary->getOp())
1592 {
1593 case EOpIndexDirect:
1594 {
1595 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1596
1597 TInfoSinkBase prefixSink;
1598 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1599 return TString(prefixSink.c_str());
1600 }
1601 case EOpIndexDirectStruct:
1602 {
1603 TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1604 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1605 const TField *field = s->fields()[index];
1606
1607 TInfoSinkBase prefixSink;
1608 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1609 << field->name();
1610 return TString(prefixSink.c_str());
1611 }
1612 default:
1613 UNREACHABLE();
1614 return TString("");
1615 }
1616}
1617
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001618bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1619{
1620 TInfoSinkBase &out = getInfoSink();
1621
1622 if (mInsideFunction)
1623 {
1624 outputLineDirective(out, node->getLine().first_line);
1625 out << "{\n";
1626 }
1627
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001628 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001629 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001630 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001631
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001632 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001633
1634 // Don't output ; after case labels, they're terminated by :
1635 // This is needed especially since outputting a ; after a case statement would turn empty
1636 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001637 // Also the output code is clearer if we don't output ; after statements where it is not
1638 // needed:
1639 // * if statements
1640 // * switch statements
1641 // * blocks
1642 // * function definitions
1643 // * loops (do-while loops output the semicolon in VisitLoop)
1644 // * declarations that don't generate output.
1645 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1646 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1647 statement->getAsSwitchNode() == nullptr &&
1648 statement->getAsFunctionDefinition() == nullptr &&
1649 (statement->getAsDeclarationNode() == nullptr ||
1650 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1651 statement->getAsInvariantDeclarationNode() == nullptr)
1652 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001653 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001654 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001655 }
1656
1657 if (mInsideFunction)
1658 {
1659 outputLineDirective(out, node->getLine().last_line);
1660 out << "}\n";
1661 }
1662
1663 return false;
1664}
1665
Olli Etuaho336b1472016-10-05 16:37:55 +01001666bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1667{
1668 TInfoSinkBase &out = getInfoSink();
1669
1670 ASSERT(mCurrentFunctionMetadata == nullptr);
1671
1672 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1673 ASSERT(index != CallDAG::InvalidIndex);
1674 mCurrentFunctionMetadata = &mASTMetadataList[index];
1675
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001676 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001677
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001678 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001679
1680 if (node->getFunctionSymbolInfo()->isMain())
1681 {
1682 out << "gl_main(";
1683 }
1684 else
1685 {
Olli Etuahoff526f12017-06-30 12:26:54 +03001686 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
Olli Etuaho336b1472016-10-05 16:37:55 +01001687 << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1688 }
1689
1690 for (unsigned int i = 0; i < parameters->size(); i++)
1691 {
1692 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1693
1694 if (symbol)
1695 {
1696 ensureStructDefined(symbol->getType());
1697
1698 out << argumentString(symbol);
1699
1700 if (i < parameters->size() - 1)
1701 {
1702 out << ", ";
1703 }
1704 }
1705 else
1706 UNREACHABLE();
1707 }
1708
1709 out << ")\n";
1710
1711 mInsideFunction = true;
1712 // The function body node will output braces.
1713 node->getBody()->traverse(this);
1714 mInsideFunction = false;
1715
1716 mCurrentFunctionMetadata = nullptr;
1717
1718 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1719 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1720 {
1721 ASSERT(!node->getFunctionSymbolInfo()->isMain());
1722 mOutputLod0Function = true;
1723 node->traverse(this);
1724 mOutputLod0Function = false;
1725 }
1726
1727 return false;
1728}
1729
Olli Etuaho13389b62016-10-16 11:48:18 +01001730bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1731{
Olli Etuaho13389b62016-10-16 11:48:18 +01001732 if (visit == PreVisit)
1733 {
1734 TIntermSequence *sequence = node->getSequence();
1735 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1736 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001737 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001738
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001739 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001740 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001741 TInfoSinkBase &out = getInfoSink();
Olli Etuaho13389b62016-10-16 11:48:18 +01001742 ensureStructDefined(variable->getType());
1743
1744 if (!variable->getAsSymbolNode() ||
1745 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1746 {
1747 if (!mInsideFunction)
1748 {
1749 out << "static ";
1750 }
1751
1752 out << TypeString(variable->getType()) + " ";
1753
1754 TIntermSymbol *symbol = variable->getAsSymbolNode();
1755
1756 if (symbol)
1757 {
1758 symbol->traverse(this);
1759 out << ArrayString(symbol->getType());
1760 out << " = " + initializer(symbol->getType());
1761 }
1762 else
1763 {
1764 variable->traverse(this);
1765 }
1766 }
1767 else if (variable->getAsSymbolNode() &&
1768 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1769 {
1770 // Already added to constructor map
1771 }
1772 else
1773 UNREACHABLE();
1774 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001775 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001776 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001777 TIntermSymbol *symbol = variable->getAsSymbolNode();
1778 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001779
Olli Etuaho282847e2017-07-12 14:11:01 +03001780 // Vertex outputs which are declared but not written to should still be declared to
1781 // allow successful linking.
1782 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001783 }
1784 }
1785 return false;
1786}
1787
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001788bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1789{
1790 // Do not do any translation
1791 return false;
1792}
1793
Olli Etuaho16c745a2017-01-16 17:02:27 +00001794bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1795{
1796 TInfoSinkBase &out = getInfoSink();
1797
1798 ASSERT(visit == PreVisit);
1799 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1800 // Skip the prototype if it is not implemented (and thus not used)
1801 if (index == CallDAG::InvalidIndex)
1802 {
1803 return false;
1804 }
1805
1806 TIntermSequence *arguments = node->getSequence();
1807
Olli Etuahoff526f12017-06-30 12:26:54 +03001808 TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001809 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1810 << (mOutputLod0Function ? "Lod0(" : "(");
1811
1812 for (unsigned int i = 0; i < arguments->size(); i++)
1813 {
1814 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1815 ASSERT(symbol != nullptr);
1816
1817 out << argumentString(symbol);
1818
1819 if (i < arguments->size() - 1)
1820 {
1821 out << ", ";
1822 }
1823 }
1824
1825 out << ");\n";
1826
1827 // Also prototype the Lod0 variant if needed
1828 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1829 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1830 {
1831 mOutputLod0Function = true;
1832 node->traverse(this);
1833 mOutputLod0Function = false;
1834 }
1835
1836 return false;
1837}
1838
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001839bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1840{
Jamie Madill32aab012015-01-27 14:12:26 -05001841 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001842
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001843 switch (node->getOp())
1844 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001845 case EOpCallBuiltInFunction:
1846 case EOpCallFunctionInAST:
1847 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001848 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001849 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001850
Corentin Wallez1239ee92015-03-19 14:38:02 -07001851 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001852 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001853 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001854 if (node->isArray())
1855 {
1856 UNIMPLEMENTED();
1857 }
Olli Etuahobd674552016-10-06 13:28:42 +01001858 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001859 ASSERT(index != CallDAG::InvalidIndex);
1860 lod0 &= mASTMetadataList[index].mNeedsLod0;
1861
Olli Etuahoff526f12017-06-30 12:26:54 +03001862 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001863 out << DisambiguateFunctionName(node->getSequence());
1864 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001865 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001866 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001867 {
1868 // This path is used for internal functions that don't have their definitions in the
1869 // AST, such as precision emulation functions.
Olli Etuahoff526f12017-06-30 12:26:54 +03001870 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001871 }
Xinghua Cao711b7a12017-10-09 13:38:12 +08001872 else if (node->getFunctionSymbolInfo()->isImageFunction())
1873 {
1874 TString name = node->getFunctionSymbolInfo()->getName();
1875 TType type = (*arguments)[0]->getAsTyped()->getType();
1876 TString imageFunctionName = mImageFunctionHLSL->useImageFunction(
1877 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
1878 type.getMemoryQualifier().readonly);
1879 out << imageFunctionName << "(";
1880 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001881 else
1882 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001883 const TString &name = node->getFunctionSymbolInfo()->getName();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001884 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001885 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1886 if (arguments->size() > 1)
1887 {
1888 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1889 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001890 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1891 name, samplerType, coords, arguments->size(), lod0, mShaderType);
1892 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001893 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001894
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001895 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001896 {
Olli Etuaho96963162016-03-21 11:54:33 +02001897 TIntermTyped *typedArg = (*arg)->getAsTyped();
1898 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001899 {
1900 out << "texture_";
1901 (*arg)->traverse(this);
1902 out << ", sampler_";
1903 }
1904
1905 (*arg)->traverse(this);
1906
Olli Etuaho96963162016-03-21 11:54:33 +02001907 if (typedArg->getType().isStructureContainingSamplers())
1908 {
1909 const TType &argType = typedArg->getType();
1910 TVector<TIntermSymbol *> samplerSymbols;
1911 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001912 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1913 nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02001914 for (const TIntermSymbol *sampler : samplerSymbols)
1915 {
1916 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1917 {
1918 out << ", texture_" << sampler->getSymbol();
1919 out << ", sampler_" << sampler->getSymbol();
1920 }
1921 else
1922 {
1923 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1924 // of D3D9, it's the sampler variable.
1925 out << ", " + sampler->getSymbol();
1926 }
1927 }
1928 }
1929
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001930 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001931 {
1932 out << ", ";
1933 }
1934 }
1935
1936 out << ")";
1937
1938 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001939 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001940 case EOpConstruct:
1941 if (node->getBasicType() == EbtStruct)
Olli Etuahof40319e2015-03-10 14:33:00 +02001942 {
Olli Etuaho8fab3202017-05-08 18:22:22 +03001943 if (node->getType().isArray())
1944 {
1945 UNIMPLEMENTED();
1946 }
1947 const TString &structName = StructNameString(*node->getType().getStruct());
1948 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1949 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Olli Etuahof40319e2015-03-10 14:33:00 +02001950 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001951 else
1952 {
1953 const char *name = "";
1954 if (node->getType().getNominalSize() == 1)
1955 {
1956 switch (node->getBasicType())
1957 {
1958 case EbtFloat:
1959 name = "vec1";
1960 break;
1961 case EbtInt:
1962 name = "ivec1";
1963 break;
1964 case EbtUInt:
1965 name = "uvec1";
1966 break;
1967 case EbtBool:
1968 name = "bvec1";
1969 break;
1970 default:
1971 UNREACHABLE();
1972 }
1973 }
1974 else
1975 {
1976 name = node->getType().getBuiltInTypeNameString();
1977 }
1978 outputConstructor(out, visit, node->getType(), name, node->getSequence());
1979 }
1980 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001981 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001982 outputTriplet(out, visit, "(", " == ", ")");
1983 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001984 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001985 outputTriplet(out, visit, "(", " != ", ")");
1986 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001987 case EOpLessThanComponentWise:
1988 outputTriplet(out, visit, "(", " < ", ")");
1989 break;
1990 case EOpGreaterThanComponentWise:
1991 outputTriplet(out, visit, "(", " > ", ")");
1992 break;
1993 case EOpLessThanEqualComponentWise:
1994 outputTriplet(out, visit, "(", " <= ", ")");
1995 break;
1996 case EOpGreaterThanEqualComponentWise:
1997 outputTriplet(out, visit, "(", " >= ", ")");
1998 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01001999 case EOpMod:
2000 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002001 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002002 break;
2003 case EOpModf:
2004 outputTriplet(out, visit, "modf(", ", ", ")");
2005 break;
2006 case EOpPow:
2007 outputTriplet(out, visit, "pow(", ", ", ")");
2008 break;
2009 case EOpAtan:
2010 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2011 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002012 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002013 break;
2014 case EOpMin:
2015 outputTriplet(out, visit, "min(", ", ", ")");
2016 break;
2017 case EOpMax:
2018 outputTriplet(out, visit, "max(", ", ", ")");
2019 break;
2020 case EOpClamp:
2021 outputTriplet(out, visit, "clamp(", ", ", ")");
2022 break;
2023 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302024 {
2025 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2026 if (lastParamNode->getType().getBasicType() == EbtBool)
2027 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002028 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2029 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302030 // so use emulated version.
2031 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002032 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302033 }
2034 else
2035 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002036 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302037 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002038 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302039 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002040 case EOpStep:
2041 outputTriplet(out, visit, "step(", ", ", ")");
2042 break;
2043 case EOpSmoothStep:
2044 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2045 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002046 case EOpFrexp:
2047 case EOpLdexp:
2048 ASSERT(node->getUseEmulatedFunction());
2049 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2050 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002051 case EOpDistance:
2052 outputTriplet(out, visit, "distance(", ", ", ")");
2053 break;
2054 case EOpDot:
2055 outputTriplet(out, visit, "dot(", ", ", ")");
2056 break;
2057 case EOpCross:
2058 outputTriplet(out, visit, "cross(", ", ", ")");
2059 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002060 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002061 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002062 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002063 break;
2064 case EOpReflect:
2065 outputTriplet(out, visit, "reflect(", ", ", ")");
2066 break;
2067 case EOpRefract:
2068 outputTriplet(out, visit, "refract(", ", ", ")");
2069 break;
2070 case EOpOuterProduct:
2071 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002072 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002073 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002074 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002075 outputTriplet(out, visit, "(", " * ", ")");
2076 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002077 case EOpBitfieldExtract:
2078 case EOpBitfieldInsert:
2079 case EOpUaddCarry:
2080 case EOpUsubBorrow:
2081 case EOpUmulExtended:
2082 case EOpImulExtended:
2083 ASSERT(node->getUseEmulatedFunction());
2084 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2085 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002086 default:
2087 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002088 }
2089
2090 return true;
2091}
2092
Olli Etuaho57961272016-09-14 13:57:46 +03002093void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002094{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002095 out << "if (";
2096
2097 node->getCondition()->traverse(this);
2098
2099 out << ")\n";
2100
Jamie Madill8c46ab12015-12-07 16:39:19 -05002101 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002102
2103 bool discard = false;
2104
2105 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002106 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002107 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002108 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002109
Olli Etuahoa6f22092015-05-08 18:31:10 +03002110 // Detect true discard
2111 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2112 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002113 else
2114 {
2115 // TODO(oetuaho): Check if the semicolon inside is necessary.
2116 // It's there as a result of conservative refactoring of the output.
2117 out << "{;}\n";
2118 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002119
Jamie Madill8c46ab12015-12-07 16:39:19 -05002120 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002121
Olli Etuahoa6f22092015-05-08 18:31:10 +03002122 if (node->getFalseBlock())
2123 {
2124 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002125
Jamie Madill8c46ab12015-12-07 16:39:19 -05002126 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002127
Olli Etuaho32db19b2016-10-04 14:43:16 +01002128 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002129 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002130
Jamie Madill8c46ab12015-12-07 16:39:19 -05002131 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002132
Olli Etuahoa6f22092015-05-08 18:31:10 +03002133 // Detect false discard
2134 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2135 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002136
Olli Etuahoa6f22092015-05-08 18:31:10 +03002137 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002138 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002139 {
2140 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002141 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002142}
2143
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002144bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2145{
2146 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2147 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2148 UNREACHABLE();
2149 return false;
2150}
2151
Olli Etuaho57961272016-09-14 13:57:46 +03002152bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002153{
2154 TInfoSinkBase &out = getInfoSink();
2155
Olli Etuaho3d932d82016-04-12 11:10:30 +03002156 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002157
2158 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002159 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002160 {
2161 out << "FLATTEN ";
2162 }
2163
Olli Etuaho57961272016-09-14 13:57:46 +03002164 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002165
2166 return false;
2167}
2168
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002169bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002170{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002171 TInfoSinkBase &out = getInfoSink();
2172
Olli Etuaho923ecef2017-10-11 12:01:38 +03002173 ASSERT(node->getStatementList());
2174 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002175 {
Olli Etuaho923ecef2017-10-11 12:01:38 +03002176 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList()));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002177 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002178 outputTriplet(out, visit, "switch (", ") ", "");
2179 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002180 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002181}
2182
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002183bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002184{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002185 TInfoSinkBase &out = getInfoSink();
2186
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002187 if (node->hasCondition())
2188 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002189 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002190 return true;
2191 }
2192 else
2193 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002194 out << "default:\n";
2195 return false;
2196 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002197}
2198
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002199void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2200{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002201 TInfoSinkBase &out = getInfoSink();
2202 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002203}
2204
2205bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2206{
Nicolas Capens655fe362014-04-11 13:12:34 -04002207 mNestedLoopDepth++;
2208
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002209 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002210 mInsideDiscontinuousLoop =
2211 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002212
Jamie Madill8c46ab12015-12-07 16:39:19 -05002213 TInfoSinkBase &out = getInfoSink();
2214
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002215 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002216 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002217 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002218 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002219 mInsideDiscontinuousLoop = wasDiscontinuous;
2220 mNestedLoopDepth--;
2221
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002222 return false;
2223 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002224 }
2225
Corentin Wallez1239ee92015-03-19 14:38:02 -07002226 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002227 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002228 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002229 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002230
Jamie Madill8c46ab12015-12-07 16:39:19 -05002231 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002232 }
2233 else
2234 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002235 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002236
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002237 if (node->getInit())
2238 {
2239 node->getInit()->traverse(this);
2240 }
2241
2242 out << "; ";
2243
alokp@chromium.org52813552010-11-16 18:36:09 +00002244 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002245 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002246 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 }
2248
2249 out << "; ";
2250
alokp@chromium.org52813552010-11-16 18:36:09 +00002251 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002252 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002253 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
2255
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002256 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002257
Jamie Madill8c46ab12015-12-07 16:39:19 -05002258 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002259 }
2260
2261 if (node->getBody())
2262 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002263 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002264 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002265 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002266 else
2267 {
2268 // TODO(oetuaho): Check if the semicolon inside is necessary.
2269 // It's there as a result of conservative refactoring of the output.
2270 out << "{;}\n";
2271 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002272
Jamie Madill8c46ab12015-12-07 16:39:19 -05002273 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002274
alokp@chromium.org52813552010-11-16 18:36:09 +00002275 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002276 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002277 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002278 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002279
alokp@chromium.org52813552010-11-16 18:36:09 +00002280 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002281
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002282 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002283 }
2284
daniel@transgaming.com73536982012-03-21 20:45:49 +00002285 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002286
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002287 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002288 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002289
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002290 return false;
2291}
2292
2293bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2294{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002295 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002296 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002297 TInfoSinkBase &out = getInfoSink();
2298
2299 switch (node->getFlowOp())
2300 {
2301 case EOpKill:
2302 out << "discard";
2303 break;
2304 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002305 if (mNestedLoopDepth > 1)
2306 {
2307 mUsesNestedBreak = true;
2308 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002309
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002310 if (mExcessiveLoopIndex)
2311 {
2312 out << "{Break";
2313 mExcessiveLoopIndex->traverse(this);
2314 out << " = true; break;}\n";
2315 }
2316 else
2317 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002318 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002319 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002320 break;
2321 case EOpContinue:
2322 out << "continue";
2323 break;
2324 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002325 if (node->getExpression())
2326 {
2327 out << "return ";
2328 }
2329 else
2330 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002331 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002332 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002333 break;
2334 default:
2335 UNREACHABLE();
2336 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002337 }
2338
2339 return true;
2340}
2341
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002342// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002343// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2344// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002345bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002346{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002347 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002348
2349 // Parse loops of the form:
2350 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002351 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002352 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002353 int initial = 0;
2354 int limit = 0;
2355 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002356
2357 // Parse index name and intial value
2358 if (node->getInit())
2359 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002360 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002361
2362 if (init)
2363 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002364 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002365 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002366
2367 if (variable && variable->getQualifier() == EvqTemporary)
2368 {
2369 TIntermBinary *assign = variable->getAsBinaryNode();
2370
2371 if (assign->getOp() == EOpInitialize)
2372 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002373 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002374 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2375
2376 if (symbol && constant)
2377 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002378 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002379 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002380 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002381 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002382 }
2383 }
2384 }
2385 }
2386 }
2387 }
2388
2389 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002390 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002391 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002392 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002393
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002394 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2395 {
2396 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2397
2398 if (constant)
2399 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002400 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002401 {
2402 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002403 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002404 }
2405 }
2406 }
2407 }
2408
2409 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002410 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002411 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002412 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002413 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002414
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002415 if (binaryTerminal)
2416 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002417 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002418 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2419
2420 if (constant)
2421 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002422 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002423 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002424 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002425
2426 switch (op)
2427 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002428 case EOpAddAssign:
2429 increment = value;
2430 break;
2431 case EOpSubAssign:
2432 increment = -value;
2433 break;
2434 default:
2435 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002436 }
2437 }
2438 }
2439 }
2440 else if (unaryTerminal)
2441 {
2442 TOperator op = unaryTerminal->getOp();
2443
2444 switch (op)
2445 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002446 case EOpPostIncrement:
2447 increment = 1;
2448 break;
2449 case EOpPostDecrement:
2450 increment = -1;
2451 break;
2452 case EOpPreIncrement:
2453 increment = 1;
2454 break;
2455 case EOpPreDecrement:
2456 increment = -1;
2457 break;
2458 default:
2459 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002460 }
2461 }
2462 }
2463
Yunchao He4f285442017-04-21 12:15:49 +08002464 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002465 {
2466 if (comparator == EOpLessThanEqual)
2467 {
2468 comparator = EOpLessThan;
2469 limit += 1;
2470 }
2471
2472 if (comparator == EOpLessThan)
2473 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002474 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002475
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002476 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002478 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002479 }
2480
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002481 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002482 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002483
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002484 out << "{int ";
2485 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002486 out << ";\n"
2487 "bool Break";
2488 index->traverse(this);
2489 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002490
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002491 bool firstLoopFragment = true;
2492
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002493 while (iterations > 0)
2494 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002495 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002496
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002497 if (!firstLoopFragment)
2498 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002499 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002500 index->traverse(this);
2501 out << ") {\n";
2502 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002503
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002504 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002505 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002506 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002507 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002508
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002509 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002510 const char *unroll =
2511 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002512
Corentin Wallez1239ee92015-03-19 14:38:02 -07002513 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002514 index->traverse(this);
2515 out << " = ";
2516 out << initial;
2517
2518 out << "; ";
2519 index->traverse(this);
2520 out << " < ";
2521 out << clampedLimit;
2522
2523 out << "; ";
2524 index->traverse(this);
2525 out << " += ";
2526 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002527 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002528
Jamie Madill8c46ab12015-12-07 16:39:19 -05002529 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002530 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002531
2532 if (node->getBody())
2533 {
2534 node->getBody()->traverse(this);
2535 }
2536
Jamie Madill8c46ab12015-12-07 16:39:19 -05002537 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002538 out << ";}\n";
2539
2540 if (!firstLoopFragment)
2541 {
2542 out << "}\n";
2543 }
2544
2545 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002546
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002547 initial += MAX_LOOP_ITERATIONS * increment;
2548 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002549 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002550
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002551 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002552
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002553 mExcessiveLoopIndex = restoreIndex;
2554
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002555 return true;
2556 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002557 else
2558 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002559 }
2560
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002561 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002562}
2563
Jamie Madill8c46ab12015-12-07 16:39:19 -05002564void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2565 Visit visit,
2566 const char *preString,
2567 const char *inString,
2568 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002569{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002570 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002571 {
2572 out << preString;
2573 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002574 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002575 {
2576 out << inString;
2577 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002578 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002579 {
2580 out << postString;
2581 }
2582}
2583
Jamie Madill8c46ab12015-12-07 16:39:19 -05002584void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002585{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002586 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002587 {
Jamie Madill32aab012015-01-27 14:12:26 -05002588 out << "\n";
2589 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002590
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002591 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002592 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002593 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002594 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002595
Jamie Madill32aab012015-01-27 14:12:26 -05002596 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002597 }
2598}
2599
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002600TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2601{
2602 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002603 const TType &type = symbol->getType();
2604 const TName &name = symbol->getName();
2605 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002606
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002607 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002608 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002609 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002610 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002611 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002612 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002613 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002614 }
2615
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002616 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002617 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002618 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2619 {
2620 // Samplers are passed as indices to the sampler array.
2621 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2622 return "const uint " + nameStr + ArrayString(type);
2623 }
2624 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2625 {
2626 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2627 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2628 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2629 ArrayString(type);
2630 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002631 }
2632
Olli Etuaho96963162016-03-21 11:54:33 +02002633 TStringStream argString;
2634 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2635 << ArrayString(type);
2636
2637 // If the structure parameter contains samplers, they need to be passed into the function as
2638 // separate parameters. HLSL doesn't natively support samplers in structs.
2639 if (type.isStructureContainingSamplers())
2640 {
2641 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2642 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002643 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02002644 for (const TIntermSymbol *sampler : samplerSymbols)
2645 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002646 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002647 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2648 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002649 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002650 }
2651 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2652 {
Olli Etuaho96963162016-03-21 11:54:33 +02002653 ASSERT(IsSampler(samplerType.getBasicType()));
2654 argString << ", " << QualifierString(qualifier) << " "
2655 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002656 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2657 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002658 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002659 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002660 }
2661 else
2662 {
Olli Etuaho96963162016-03-21 11:54:33 +02002663 ASSERT(IsSampler(samplerType.getBasicType()));
2664 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002665 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002666 }
2667 }
2668 }
2669
2670 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002671}
2672
2673TString OutputHLSL::initializer(const TType &type)
2674{
2675 TString string;
2676
Jamie Madill94bf7f22013-07-08 13:31:15 -04002677 size_t size = type.getObjectSize();
2678 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002679 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002680 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002681
Jamie Madill94bf7f22013-07-08 13:31:15 -04002682 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002683 {
2684 string += ", ";
2685 }
2686 }
2687
daniel@transgaming.comead23042010-04-29 03:35:36 +00002688 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002689}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002690
Jamie Madill8c46ab12015-12-07 16:39:19 -05002691void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2692 Visit visit,
2693 const TType &type,
2694 const char *name,
2695 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002696{
Olli Etuahof40319e2015-03-10 14:33:00 +02002697 if (type.isArray())
2698 {
2699 UNIMPLEMENTED();
2700 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002701
2702 if (visit == PreVisit)
2703 {
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002704 TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002705
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002706 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002707 }
2708 else if (visit == InVisit)
2709 {
2710 out << ", ";
2711 }
2712 else if (visit == PostVisit)
2713 {
2714 out << ")";
2715 }
2716}
2717
Jamie Madill8c46ab12015-12-07 16:39:19 -05002718const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2719 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002720 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002721{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002722 const TConstantUnion *constUnionIterated = constUnion;
2723
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002724 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002725 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002726 {
Jamie Madill033dae62014-06-18 12:56:28 -04002727 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002728
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002729 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002730
Jamie Madill98493dd2013-07-08 14:39:03 -04002731 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002732 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002733 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002734 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002735
Jamie Madill98493dd2013-07-08 14:39:03 -04002736 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002737 {
2738 out << ", ";
2739 }
2740 }
2741
2742 out << ")";
2743 }
2744 else
2745 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002747 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002748
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002749 if (writeType)
2750 {
Jamie Madill033dae62014-06-18 12:56:28 -04002751 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002752 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002753 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002754 if (writeType)
2755 {
2756 out << ")";
2757 }
2758 }
2759
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002760 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002761}
2762
Olli Etuahod68924e2017-01-02 17:34:40 +00002763void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002764{
Olli Etuahod68924e2017-01-02 17:34:40 +00002765 if (visit == PreVisit)
2766 {
2767 const char *opStr = GetOperatorString(op);
2768 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2769 out << "(";
2770 }
2771 else
2772 {
2773 outputTriplet(out, visit, nullptr, ", ", ")");
2774 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002775}
2776
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002777bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2778 TIntermSymbol *symbolNode,
2779 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002780{
2781 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2782 expression->traverse(&searchSymbol);
2783
2784 if (searchSymbol.foundMatch())
2785 {
2786 // Type already printed
2787 out << "t" + str(mUniqueIndex) + " = ";
2788 expression->traverse(this);
2789 out << ", ";
2790 symbolNode->traverse(this);
2791 out << " = t" + str(mUniqueIndex);
2792
2793 mUniqueIndex++;
2794 return true;
2795 }
2796
2797 return false;
2798}
2799
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002800bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2801{
2802 // We support writing constant unions and constructors that only take constant unions as
2803 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002804 return !expression->getType().isArrayOfArrays() &&
2805 (expression->getAsConstantUnion() ||
2806 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002807}
2808
2809bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2810 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002811 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002812{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002813 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002814 {
2815 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002816 ASSERT(!symbolNode->getType().isArrayOfArrays());
2817 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002818 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002819 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002820 }
2821 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002822 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002823 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002824 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002825 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002826 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002827 }
2828 else
2829 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002830 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002831 ASSERT(constructor != nullptr);
2832 for (TIntermNode *&node : *constructor->getSequence())
2833 {
2834 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2835 ASSERT(nodeConst);
2836 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002837 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002838 if (node != constructor->getSequence()->back())
2839 {
2840 out << ", ";
2841 }
2842 }
2843 }
2844 out << "}";
2845 return true;
2846 }
2847 return false;
2848}
2849
Jamie Madill55e79e02015-02-09 15:35:00 -05002850TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2851{
2852 const TFieldList &fields = structure.fields();
2853
2854 for (const auto &eqFunction : mStructEqualityFunctions)
2855 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002856 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002857 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002858 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002859 }
2860 }
2861
2862 const TString &structNameString = StructNameString(structure);
2863
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002864 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002865 function->structure = &structure;
2866 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002867
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002868 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002869
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002870 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2871 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002872 << "{\n"
2873 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002874
2875 for (size_t i = 0; i < fields.size(); i++)
2876 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002877 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002878 const TType *fieldType = field->type();
2879
2880 const TString &fieldNameA = "a." + Decorate(field->name());
2881 const TString &fieldNameB = "b." + Decorate(field->name());
2882
2883 if (i > 0)
2884 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002885 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002886 }
2887
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002888 fnOut << "(";
2889 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2890 fnOut << fieldNameA;
2891 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2892 fnOut << fieldNameB;
2893 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2894 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002895 }
2896
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002897 fnOut << ";\n"
2898 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002899
2900 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002901
2902 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002903 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002904
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002905 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002906}
2907
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002908TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002909{
2910 for (const auto &eqFunction : mArrayEqualityFunctions)
2911 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002912 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002913 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002914 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002915 }
2916 }
2917
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002918 TType elementType(type);
2919 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002920
Olli Etuaho12690762015-03-31 12:55:28 +03002921 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002922 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002923
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002924 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002925
2926 TInfoSinkBase fnOut;
2927
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002928 const TString &typeName = TypeString(type);
2929 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2930 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002931 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002932 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002933 << type.getOutermostArraySize()
2934 << "; ++i)\n"
2935 " {\n"
2936 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002937
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002938 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002939 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002940 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002941 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002942 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002943
2944 fnOut << ") { return false; }\n"
2945 " }\n"
2946 " return true;\n"
2947 "}\n";
2948
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002949 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002950
2951 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002952 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002953
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002954 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002955}
2956
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002957TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002958{
2959 for (const auto &assignFunction : mArrayAssignmentFunctions)
2960 {
2961 if (assignFunction.type == type)
2962 {
2963 return assignFunction.functionName;
2964 }
2965 }
2966
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002967 TType elementType(type);
2968 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002969
2970 ArrayHelperFunction function;
2971 function.type = type;
2972
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002973 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002974
2975 TInfoSinkBase fnOut;
2976
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002977 const TString &typeName = TypeString(type);
2978 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2979 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002980 << "{\n"
2981 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002982 << type.getOutermostArraySize()
2983 << "; ++i)\n"
2984 " {\n"
2985 " ";
2986
2987 outputAssign(PreVisit, elementType, fnOut);
2988 fnOut << "a[i]";
2989 outputAssign(InVisit, elementType, fnOut);
2990 fnOut << "b[i]";
2991 outputAssign(PostVisit, elementType, fnOut);
2992
2993 fnOut << ";\n"
2994 " }\n"
2995 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03002996
2997 function.functionDefinition = fnOut.c_str();
2998
2999 mArrayAssignmentFunctions.push_back(function);
3000
3001 return function.functionName;
3002}
3003
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003004TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003005{
3006 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3007 {
3008 if (constructIntoFunction.type == type)
3009 {
3010 return constructIntoFunction.functionName;
3011 }
3012 }
3013
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003014 TType elementType(type);
3015 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003016
3017 ArrayHelperFunction function;
3018 function.type = type;
3019
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003020 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003021
3022 TInfoSinkBase fnOut;
3023
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003024 const TString &typeName = TypeString(type);
3025 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3026 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003027 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003028 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003029 }
3030 fnOut << ")\n"
3031 "{\n";
3032
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003033 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003034 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003035 fnOut << " ";
3036 outputAssign(PreVisit, elementType, fnOut);
3037 fnOut << "a[" << i << "]";
3038 outputAssign(InVisit, elementType, fnOut);
3039 fnOut << "b" << i;
3040 outputAssign(PostVisit, elementType, fnOut);
3041 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003042 }
3043 fnOut << "}\n";
3044
3045 function.functionDefinition = fnOut.c_str();
3046
3047 mArrayConstructIntoFunctions.push_back(function);
3048
3049 return function.functionName;
3050}
3051
Jamie Madill2e295e22015-04-29 10:41:33 -04003052void OutputHLSL::ensureStructDefined(const TType &type)
3053{
3054 TStructure *structure = type.getStruct();
3055
3056 if (structure)
3057 {
3058 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3059 }
3060}
3061
Jamie Madill45bcc782016-11-07 13:58:48 -05003062} // namespace sh