blob: f4342b4084e8e78ed04a78008117c02f037c01bd [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"
Olli Etuaho4728bdc2017-12-20 17:51:08 +020018#include "compiler/translator/FindSymbolNode.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/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030024#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050026#include "compiler/translator/UniformHLSL.h"
27#include "compiler/translator/UtilsHLSL.h"
28#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080041 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030042 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080043 for (unsigned int arraySize : *type.getArraySizes())
44 {
45 fnName << arraySize << "_";
46 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030047 }
48 fnName << TypeString(type);
49 return fnName.str();
50}
51
Olli Etuaho40dbdd62017-10-13 13:34:19 +030052bool IsDeclarationWrittenOut(TIntermDeclaration *node)
53{
54 TIntermSequence *sequence = node->getSequence();
55 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
56 ASSERT(sequence->size() == 1);
57 ASSERT(variable);
58 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
59 variable->getQualifier() == EvqConst);
60}
61
Olli Etuaho2ef23e22017-11-01 16:39:11 +020062bool IsInStd140InterfaceBlock(TIntermTyped *node)
63{
64 TIntermBinary *binaryNode = node->getAsBinaryNode();
65
66 if (binaryNode)
67 {
68 return IsInStd140InterfaceBlock(binaryNode->getLeft());
69 }
70
71 const TType &type = node->getType();
72
73 // determine if we are in the standard layout
74 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
75 if (interfaceBlock)
76 {
77 return (interfaceBlock->blockStorage() == EbsStd140);
78 }
79
80 return false;
81}
82
Olli Etuaho96f6adf2017-08-16 11:18:54 +030083} // anonymous namespace
84
Olli Etuaho56a2f952016-12-08 12:16:27 +000085void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +030086{
Olli Etuaho56a2f952016-12-08 12:16:27 +000087 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
88 // regardless.
89 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
90 mOutputType == SH_HLSL_4_1_OUTPUT)
91 {
92 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
93 }
94 else
95 {
96 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
97 }
98}
Olli Etuaho4785fec2015-05-18 16:09:37 +030099
Olli Etuaho56a2f952016-12-08 12:16:27 +0000100void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200101{
102 ASSERT(constUnion != nullptr);
103 switch (constUnion->getType())
104 {
105 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000106 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200107 break;
108 case EbtInt:
109 out << constUnion->getIConst();
110 break;
111 case EbtUInt:
112 out << constUnion->getUConst();
113 break;
114 case EbtBool:
115 out << constUnion->getBConst();
116 break;
117 default:
118 UNREACHABLE();
119 }
120}
121
Olli Etuaho56a2f952016-12-08 12:16:27 +0000122const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
123 const TConstantUnion *const constUnion,
124 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200125{
126 const TConstantUnion *constUnionIterated = constUnion;
127 for (size_t i = 0; i < size; i++, constUnionIterated++)
128 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000129 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200130
131 if (i != size - 1)
132 {
133 out << ", ";
134 }
135 }
136 return constUnionIterated;
137}
138
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800139OutputHLSL::OutputHLSL(sh::GLenum shaderType,
140 int shaderVersion,
141 const TExtensionBehavior &extensionBehavior,
142 const char *sourcePath,
143 ShShaderOutput outputType,
144 int numRenderTargets,
145 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300146 ShCompileOptions compileOptions,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300147 TSymbolTable *symbolTable,
148 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300149 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200150 mShaderType(shaderType),
151 mShaderVersion(shaderVersion),
152 mExtensionBehavior(extensionBehavior),
153 mSourcePath(sourcePath),
154 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700155 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000156 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300157 mCurrentFunctionMetadata(nullptr),
158 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000160 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000161
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500162 mUsesFragColor = false;
163 mUsesFragData = false;
164 mUsesDepthRange = false;
165 mUsesFragCoord = false;
166 mUsesPointCoord = false;
167 mUsesFrontFacing = false;
168 mUsesPointSize = false;
169 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300170 mHasMultiviewExtensionEnabled =
171 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300172 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500173 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800175 mUsesNumWorkGroups = false;
176 mUsesWorkGroupID = false;
177 mUsesLocalInvocationID = false;
178 mUsesGlobalInvocationID = false;
179 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500180 mUsesXor = false;
181 mUsesDiscardRewriting = false;
182 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530183 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000184
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000185 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000186
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000188 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500189 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000190
Yunchao Hed7297bf2017-04-19 15:27:10 +0800191 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000192
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500193 mStructureHLSL = new StructureHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800194 mUniformHLSL = new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300195 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800196 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400197
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200198 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000199 {
Arun Patole63419392015-03-13 11:51:07 +0530200 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500201 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
202 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530203 // In both cases total 3 uniform registers need to be reserved.
204 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000205 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000206
Geoff Lang00140f42016-02-03 18:47:33 +0000207 // Reserve registers for the default uniform block and driver constants
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800208 mUniformHLSL->reserveUniformBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209}
210
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000211OutputHLSL::~OutputHLSL()
212{
Jamie Madill8daaba12014-06-13 10:04:33 -0400213 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400214 SafeDelete(mUniformHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300215 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800216 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200217 for (auto &eqFunction : mStructEqualityFunctions)
218 {
219 SafeDelete(eqFunction);
220 }
221 for (auto &eqFunction : mArrayEqualityFunctions)
222 {
223 SafeDelete(eqFunction);
224 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000225}
226
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200227void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000228{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200229 BuiltInFunctionEmulator builtInFunctionEmulator;
230 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800231 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
232 {
233 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
234 mShaderVersion);
235 }
236
Olli Etuahodfa75e82017-01-23 09:43:06 -0800237 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500238
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700239 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000240 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700241 ASSERT(success == CallDAG::INITDAG_SUCCESS);
242 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700243
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200244 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
245 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
246 // the shader code. When we add shader storage blocks we might also consider an alternative
247 // solution, since the struct mapping won't work very well for shader storage blocks.
248
Jamie Madill37997142015-01-28 10:06:34 -0500249 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500250 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200251 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500252 mInfoSinkStack.pop();
253
Jamie Madill37997142015-01-28 10:06:34 -0500254 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500255 mInfoSinkStack.pop();
256
Jamie Madill32aab012015-01-27 14:12:26 -0500257 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200258 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500259 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000260
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200261 objSink << mHeader.c_str();
262 objSink << mBody.c_str();
263 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200264
Olli Etuahodfa75e82017-01-23 09:43:06 -0800265 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000266}
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 Etuaho2ef23e22017-11-01 16:39:11 +0200278TString OutputHLSL::structInitializerString(int indent,
279 const TType &type,
280 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400281{
282 TString init;
283
Olli Etuahoed049ab2017-06-30 17:38:33 +0300284 TString indentString;
285 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400286 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300287 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400288 }
289
Olli Etuahoed049ab2017-06-30 17:38:33 +0300290 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300292 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300293 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400294 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300295 TStringStream indexedString;
296 indexedString << name << "[" << arrayIndex << "]";
297 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300298 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300299 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300300 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300301 {
302 init += ",";
303 }
304 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400305 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300306 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400307 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300308 else if (type.getBasicType() == EbtStruct)
309 {
310 init += indentString + "{\n";
311 const TStructure &structure = *type.getStruct();
312 const TFieldList &fields = structure.fields();
313 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
314 {
315 const TField &field = *fields[fieldIndex];
316 const TString &fieldName = name + "." + Decorate(field.name());
317 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400318
Olli Etuahoed049ab2017-06-30 17:38:33 +0300319 init += structInitializerString(indent + 1, fieldType, fieldName);
320 if (fieldIndex < fields.size() - 1)
321 {
322 init += ",";
323 }
324 init += "\n";
325 }
326 init += indentString + "}";
327 }
328 else
329 {
330 init += indentString + name;
331 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400332
333 return init;
334}
335
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200336TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
337{
338 TString mappedStructs;
339
340 for (auto &mappedStruct : std140Structs)
341 {
342 TInterfaceBlock *interfaceBlock =
343 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200344 const TName &instanceName = mappedStruct.blockDeclarator->getName();
Olli Etuahobed35d72017-12-20 16:36:26 +0200345 if (mReferencedUniformBlocks.count(interfaceBlock->name()) == 0)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200346 {
347 continue;
348 }
349
350 unsigned int instanceCount = 1u;
351 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
352 if (isInstanceArray)
353 {
354 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
355 }
356
357 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
358 ++instanceArrayIndex)
359 {
360 TString originalName;
361 TString mappedName("map");
362
363 if (instanceName.getString() != "")
364 {
365 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
366 if (isInstanceArray)
367 instanceStringArrayIndex = instanceArrayIndex;
Olli Etuaho12a18ad2017-12-01 16:59:47 +0200368 TString instanceString = mUniformHLSL->UniformBlockInstanceString(
369 instanceName.getString(), instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200370 originalName += instanceString;
371 mappedName += instanceString;
372 originalName += ".";
373 mappedName += "_";
374 }
375
376 TString fieldName = Decorate(mappedStruct.field->name());
377 originalName += fieldName;
378 mappedName += fieldName;
379
380 TType *structType = mappedStruct.field->type();
381 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200382 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200383
384 if (structType->isArray())
385 {
386 mappedStructs += ArrayString(*mappedStruct.field->type());
387 }
388
389 mappedStructs += " =\n";
390 mappedStructs += structInitializerString(0, *structType, originalName);
391 mappedStructs += ";\n";
392 }
393 }
394 return mappedStructs;
395}
396
397void OutputHLSL::header(TInfoSinkBase &out,
398 const std::vector<MappedStruct> &std140Structs,
399 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000401 TString varyings;
402 TString attributes;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200403 TString mappedStructs = generateStructMapping(std140Structs);
Jamie Madill570e04d2013-06-21 09:15:33 -0400404
Olli Etuahob8cb9392017-12-20 14:23:19 +0200405 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000406 {
Olli Etuahob8cb9392017-12-20 14:23:19 +0200407 const TType &type = varying.second->variable().getType();
408 const TString &name = varying.second->getSymbol();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000409
410 // Program linking depends on this exact format
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500411 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) +
412 " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000413 }
414
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500415 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin();
416 attribute != mReferencedAttributes.end(); attribute++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000417 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500418 const TType &type = attribute->second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000419 const TString &name = attribute->second->getSymbol();
420
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500421 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) +
422 " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000423 }
424
Jamie Madill8daaba12014-06-13 10:04:33 -0400425 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400426
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300427 mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800428 out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Jamie Madillf91ce812014-06-13 10:04:34 -0400429
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200430 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500431 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200432 out << "\n// Equality functions\n\n";
433 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500434 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200435 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200436 }
437 }
Olli Etuaho12690762015-03-31 12:55:28 +0300438 if (!mArrayAssignmentFunctions.empty())
439 {
440 out << "\n// Assignment functions\n\n";
441 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
442 {
443 out << assignmentFunction.functionDefinition << "\n";
444 }
445 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300446 if (!mArrayConstructIntoFunctions.empty())
447 {
448 out << "\n// Array constructor functions\n\n";
449 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
450 {
451 out << constructIntoFunction.functionDefinition << "\n";
452 }
453 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200454
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500455 if (mUsesDiscardRewriting)
456 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400457 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500458 }
459
Nicolas Capens655fe362014-04-11 13:12:34 -0400460 if (mUsesNestedBreak)
461 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400462 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400463 }
464
Arun Patole44efa0b2015-03-04 17:11:05 +0530465 if (mRequiresIEEEStrictCompiling)
466 {
467 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
468 }
469
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400470 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
471 "#define LOOP [loop]\n"
472 "#define FLATTEN [flatten]\n"
473 "#else\n"
474 "#define LOOP\n"
475 "#define FLATTEN\n"
476 "#endif\n";
477
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200478 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300480 const bool usingMRTExtension =
481 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000482
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000483 out << "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500484 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400485 out << "\n";
486
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200487 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000488 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500489 for (ReferencedSymbols::const_iterator outputVariableIt =
490 mReferencedOutputVariables.begin();
491 outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000492 {
Jamie Madill46131a32013-06-20 11:55:50 -0400493 const TString &variableName = outputVariableIt->first;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500494 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400495
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500496 out << "static " + TypeString(variableType) + " out_" + variableName +
497 ArrayString(variableType) + " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000498 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000499 }
Jamie Madill46131a32013-06-20 11:55:50 -0400500 else
501 {
502 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
503
504 out << "static float4 gl_Color[" << numColorValues << "] =\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500505 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400506 for (unsigned int i = 0; i < numColorValues; i++)
507 {
508 out << " float4(0, 0, 0, 0)";
509 if (i + 1 != numColorValues)
510 {
511 out << ",";
512 }
513 out << "\n";
514 }
515
516 out << "};\n";
517 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000518
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400519 if (mUsesFragDepth)
520 {
521 out << "static float gl_Depth = 0.0;\n";
522 }
523
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000524 if (mUsesFragCoord)
525 {
526 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
527 }
528
529 if (mUsesPointCoord)
530 {
531 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
532 }
533
534 if (mUsesFrontFacing)
535 {
536 out << "static bool gl_FrontFacing = false;\n";
537 }
538
539 out << "\n";
540
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000541 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000542 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000543 out << "struct gl_DepthRangeParameters\n"
544 "{\n"
545 " float near;\n"
546 " float far;\n"
547 " float diff;\n"
548 "};\n"
549 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000550 }
551
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200552 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000553 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000554 out << "cbuffer DriverConstants : register(b1)\n"
555 "{\n";
556
557 if (mUsesDepthRange)
558 {
559 out << " float3 dx_DepthRange : packoffset(c0);\n";
560 }
561
562 if (mUsesFragCoord)
563 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000564 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000565 }
566
567 if (mUsesFragCoord || mUsesFrontFacing)
568 {
569 out << " float3 dx_DepthFront : packoffset(c2);\n";
570 }
571
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800572 if (mUsesFragCoord)
573 {
574 // dx_ViewScale is only used in the fragment shader to correct
575 // the value for glFragCoord if necessary
576 out << " float2 dx_ViewScale : packoffset(c3);\n";
577 }
578
Martin Radev72b4e1e2017-08-31 15:42:56 +0300579 if (mHasMultiviewExtensionEnabled)
580 {
581 // We have to add a value which we can use to keep track of which multi-view code
582 // path is to be selected in the GS.
583 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
584 }
585
Olli Etuaho618bebc2016-01-15 16:40:00 +0200586 if (mOutputType == SH_HLSL_4_1_OUTPUT)
587 {
588 mUniformHLSL->samplerMetadataUniforms(out, "c4");
589 }
590
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000591 out << "};\n";
592 }
593 else
594 {
595 if (mUsesDepthRange)
596 {
597 out << "uniform float3 dx_DepthRange : register(c0);";
598 }
599
600 if (mUsesFragCoord)
601 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000602 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000603 }
604
605 if (mUsesFragCoord || mUsesFrontFacing)
606 {
607 out << "uniform float3 dx_DepthFront : register(c2);\n";
608 }
609 }
610
611 out << "\n";
612
613 if (mUsesDepthRange)
614 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500615 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
616 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000617 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000618 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000619
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200620 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000621 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200622 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000623 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200624 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400625 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000626 }
627
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000628 if (usingMRTExtension && mNumRenderTargets > 1)
629 {
630 out << "#define GL_USES_MRT\n";
631 }
632
633 if (mUsesFragColor)
634 {
635 out << "#define GL_USES_FRAG_COLOR\n";
636 }
637
638 if (mUsesFragData)
639 {
640 out << "#define GL_USES_FRAG_DATA\n";
641 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642 }
Xinghua Caob1239382016-12-13 15:07:05 +0800643 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000645 out << "// Attributes\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500646 out << attributes;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000647 out << "\n"
648 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400649
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000650 if (mUsesPointSize)
651 {
652 out << "static float gl_PointSize = float(1);\n";
653 }
654
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000655 if (mUsesInstanceID)
656 {
657 out << "static int gl_InstanceID;";
658 }
659
Corentin Wallezb076add2016-01-11 16:45:46 -0500660 if (mUsesVertexID)
661 {
662 out << "static int gl_VertexID;";
663 }
664
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000665 out << "\n"
666 "// Varyings\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500667 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000668 out << "\n";
669
670 if (mUsesDepthRange)
671 {
672 out << "struct gl_DepthRangeParameters\n"
673 "{\n"
674 " float near;\n"
675 " float far;\n"
676 " float diff;\n"
677 "};\n"
678 "\n";
679 }
680
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200681 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000682 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800683 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500684 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800685
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000686 if (mUsesDepthRange)
687 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800688 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000689 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800690
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800691 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
692 // shaders. However, we declare it for all shaders (including Feature Level 10+).
693 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
694 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800695 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800696 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800697 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800698
Martin Radev72b4e1e2017-08-31 15:42:56 +0300699 if (mHasMultiviewExtensionEnabled)
700 {
701 // We have to add a value which we can use to keep track of which multi-view code
702 // path is to be selected in the GS.
703 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
704 }
705
Olli Etuaho618bebc2016-01-15 16:40:00 +0200706 if (mOutputType == SH_HLSL_4_1_OUTPUT)
707 {
708 mUniformHLSL->samplerMetadataUniforms(out, "c4");
709 }
710
Austin Kinross4fd18b12014-12-22 12:32:05 -0800711 out << "};\n"
712 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000713 }
714 else
715 {
716 if (mUsesDepthRange)
717 {
718 out << "uniform float3 dx_DepthRange : register(c0);\n";
719 }
720
Cooper Partine6664f02015-01-09 16:22:24 -0800721 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
722 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000723 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000724 }
725
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000726 if (mUsesDepthRange)
727 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500728 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
729 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000730 "\n";
731 }
732
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200733 if (!mappedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000734 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200735 out << "// Structures from std140 blocks with padding removed\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000736 out << "\n";
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200737 out << mappedStructs;
Jamie Madillf91ce812014-06-13 10:04:34 -0400738 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000739 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400740 }
Xinghua Caob1239382016-12-13 15:07:05 +0800741 else // Compute shader
742 {
743 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800744
745 out << "cbuffer DriverConstants : register(b1)\n"
746 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800747 if (mUsesNumWorkGroups)
748 {
Xinghua Caob1239382016-12-13 15:07:05 +0800749 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800750 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800751 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
752 mUniformHLSL->samplerMetadataUniforms(out, "c1");
753 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800754
755 // Follow built-in variables would be initialized in
756 // DynamicHLSL::generateComputeShaderLinkHLSL, if they
757 // are used in compute shader.
758 if (mUsesWorkGroupID)
759 {
760 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
761 }
762
763 if (mUsesLocalInvocationID)
764 {
765 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
766 }
767
768 if (mUsesGlobalInvocationID)
769 {
770 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
771 }
772
773 if (mUsesLocalInvocationIndex)
774 {
775 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
776 }
777 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000778
Geoff Lang1fe74c72016-08-25 13:23:01 -0400779 bool getDimensionsIgnoresBaseLevel =
780 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
781 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800782 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000783
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000784 if (mUsesFragCoord)
785 {
786 out << "#define GL_USES_FRAG_COORD\n";
787 }
788
789 if (mUsesPointCoord)
790 {
791 out << "#define GL_USES_POINT_COORD\n";
792 }
793
794 if (mUsesFrontFacing)
795 {
796 out << "#define GL_USES_FRONT_FACING\n";
797 }
798
799 if (mUsesPointSize)
800 {
801 out << "#define GL_USES_POINT_SIZE\n";
802 }
803
Martin Radev41ac68e2017-06-06 12:16:58 +0300804 if (mHasMultiviewExtensionEnabled)
805 {
806 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
807 }
808
809 if (mUsesViewID)
810 {
811 out << "#define GL_USES_VIEW_ID\n";
812 }
813
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400814 if (mUsesFragDepth)
815 {
816 out << "#define GL_USES_FRAG_DEPTH\n";
817 }
818
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000819 if (mUsesDepthRange)
820 {
821 out << "#define GL_USES_DEPTH_RANGE\n";
822 }
823
Xinghua Caob1239382016-12-13 15:07:05 +0800824 if (mUsesNumWorkGroups)
825 {
826 out << "#define GL_USES_NUM_WORK_GROUPS\n";
827 }
828
829 if (mUsesWorkGroupID)
830 {
831 out << "#define GL_USES_WORK_GROUP_ID\n";
832 }
833
834 if (mUsesLocalInvocationID)
835 {
836 out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
837 }
838
839 if (mUsesGlobalInvocationID)
840 {
841 out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
842 }
843
844 if (mUsesLocalInvocationIndex)
845 {
846 out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
847 }
848
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000849 if (mUsesXor)
850 {
851 out << "bool xor(bool p, bool q)\n"
852 "{\n"
853 " return (p || q) && !(p && q);\n"
854 "}\n"
855 "\n";
856 }
857
Olli Etuahodfa75e82017-01-23 09:43:06 -0800858 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000859}
860
861void OutputHLSL::visitSymbol(TIntermSymbol *node)
862{
Jamie Madill32aab012015-01-27 14:12:26 -0500863 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000864
Jamie Madill570e04d2013-06-21 09:15:33 -0400865 // Handle accessing std140 structs by value
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200866 if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400867 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200868 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400869 }
870
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871 TString name = node->getSymbol();
872
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000873 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000874 {
875 mUsesDepthRange = true;
876 out << name;
877 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000878 else
879 {
Olli Etuahobd3cd502017-11-03 15:48:52 +0200880 const TType &nodeType = node->getType();
Olli Etuahob8cb9392017-12-20 14:23:19 +0200881 TQualifier qualifier = node->variable().getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000882
Olli Etuahobd3cd502017-11-03 15:48:52 +0200883 ensureStructDefined(nodeType);
884
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000885 if (qualifier == EvqUniform)
886 {
Jamie Madill2e295e22015-04-29 10:41:33 -0400887 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400888
889 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000890 {
Olli Etuahobed35d72017-12-20 16:36:26 +0200891 mReferencedUniformBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000892 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000893 else
894 {
895 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000896 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400897
Olli Etuahoff526f12017-06-30 12:26:54 +0300898 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000899 }
Jamie Madill19571812013-08-12 15:26:34 -0700900 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000901 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000902 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400903 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000904 }
Jamie Madill033dae62014-06-18 12:56:28 -0400905 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000906 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000907 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -0400908 out << Decorate(name);
Martin Radev41ac68e2017-06-06 12:16:58 +0300909 if (name == "ViewID_OVR")
910 {
911 mUsesViewID = true;
912 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000913 }
Jamie Madill19571812013-08-12 15:26:34 -0700914 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400915 {
916 mReferencedOutputVariables[name] = node;
917 out << "out_" << name;
918 }
919 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000920 {
921 out << "gl_Color[0]";
922 mUsesFragColor = true;
923 }
924 else if (qualifier == EvqFragData)
925 {
926 out << "gl_Color";
927 mUsesFragData = true;
928 }
929 else if (qualifier == EvqFragCoord)
930 {
931 mUsesFragCoord = true;
932 out << name;
933 }
934 else if (qualifier == EvqPointCoord)
935 {
936 mUsesPointCoord = true;
937 out << name;
938 }
939 else if (qualifier == EvqFrontFacing)
940 {
941 mUsesFrontFacing = true;
942 out << name;
943 }
944 else if (qualifier == EvqPointSize)
945 {
946 mUsesPointSize = true;
947 out << name;
948 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000949 else if (qualifier == EvqInstanceID)
950 {
951 mUsesInstanceID = true;
952 out << name;
953 }
Corentin Wallezb076add2016-01-11 16:45:46 -0500954 else if (qualifier == EvqVertexID)
955 {
956 mUsesVertexID = true;
957 out << name;
958 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300959 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400960 {
961 mUsesFragDepth = true;
962 out << "gl_Depth";
963 }
Xinghua Caob1239382016-12-13 15:07:05 +0800964 else if (qualifier == EvqNumWorkGroups)
965 {
966 mUsesNumWorkGroups = true;
967 out << name;
968 }
969 else if (qualifier == EvqWorkGroupID)
970 {
971 mUsesWorkGroupID = true;
972 out << name;
973 }
974 else if (qualifier == EvqLocalInvocationID)
975 {
976 mUsesLocalInvocationID = true;
977 out << name;
978 }
979 else if (qualifier == EvqGlobalInvocationID)
980 {
981 mUsesGlobalInvocationID = true;
982 out << name;
983 }
984 else if (qualifier == EvqLocalInvocationIndex)
985 {
986 mUsesLocalInvocationIndex = true;
987 out << name;
988 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000989 else
990 {
Olli Etuahoff526f12017-06-30 12:26:54 +0300991 out << DecorateVariableIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000992 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993 }
994}
995
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400996void OutputHLSL::visitRaw(TIntermRaw *node)
997{
Jamie Madill32aab012015-01-27 14:12:26 -0500998 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400999}
1000
Olli Etuaho7fb49552015-03-18 17:27:44 +02001001void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1002{
1003 if (type.isScalar() && !type.isArray())
1004 {
1005 if (op == EOpEqual)
1006 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001007 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001008 }
1009 else
1010 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001011 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001012 }
1013 }
1014 else
1015 {
1016 if (visit == PreVisit && op == EOpNotEqual)
1017 {
1018 out << "!";
1019 }
1020
1021 if (type.isArray())
1022 {
1023 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001024 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001025 }
1026 else if (type.getBasicType() == EbtStruct)
1027 {
1028 const TStructure &structure = *type.getStruct();
1029 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001030 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001031 }
1032 else
1033 {
1034 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001035 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001036 }
1037 }
1038}
1039
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001040void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1041{
1042 if (type.isArray())
1043 {
1044 const TString &functionName = addArrayAssignmentFunction(type);
1045 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1046 }
1047 else
1048 {
1049 outputTriplet(out, visit, "(", " = ", ")");
1050 }
1051}
1052
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001053bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001054{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001055 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001056 {
1057 TIntermNode *ancestor = getAncestorNode(n);
1058 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1059 if (ancestorBinary == nullptr)
1060 {
1061 return false;
1062 }
1063 switch (ancestorBinary->getOp())
1064 {
1065 case EOpIndexDirectStruct:
1066 {
1067 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1068 const TIntermConstantUnion *index =
1069 ancestorBinary->getRight()->getAsConstantUnion();
1070 const TField *field = structure->fields()[index->getIConst(0)];
1071 if (IsSampler(field->type()->getBasicType()))
1072 {
1073 return true;
1074 }
1075 break;
1076 }
1077 case EOpIndexDirect:
1078 break;
1079 default:
1080 // Returning a sampler from indirect indexing is not supported.
1081 return false;
1082 }
1083 }
1084 return false;
1085}
1086
Olli Etuahob6fa0432016-09-28 16:28:05 +01001087bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1088{
1089 TInfoSinkBase &out = getInfoSink();
1090 if (visit == PostVisit)
1091 {
1092 out << ".";
1093 node->writeOffsetsAsXYZW(&out);
1094 }
1095 return true;
1096}
1097
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1099{
Jamie Madill32aab012015-01-27 14:12:26 -05001100 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101
1102 switch (node->getOp())
1103 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001104 case EOpComma:
1105 outputTriplet(out, visit, "(", ", ", ")");
1106 break;
1107 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001108 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001109 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001110 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1111 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001112 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001113 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1114 out << functionName << "(";
1115 node->getLeft()->traverse(this);
1116 TIntermSequence *seq = rightAgg->getSequence();
1117 for (auto &arrayElement : *seq)
1118 {
1119 out << ", ";
1120 arrayElement->traverse(this);
1121 }
1122 out << ")";
1123 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001124 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001125 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1126 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001127 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001128 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001129 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001130 break;
1131 case EOpInitialize:
1132 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001133 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001134 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1135 ASSERT(symbolNode);
1136 TIntermTyped *expression = node->getRight();
1137
1138 // Global initializers must be constant at this point.
1139 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
1140 canWriteAsHLSLLiteral(expression));
1141
1142 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1143 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1144 // new variable is created before the assignment is evaluated), so we need to
1145 // convert
1146 // this to "float t = x, x = t;".
1147 if (writeSameSymbolInitializer(out, symbolNode, expression))
1148 {
1149 // Skip initializing the rest of the expression
1150 return false;
1151 }
1152 else if (writeConstantInitialization(out, symbolNode, expression))
1153 {
1154 return false;
1155 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001156 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001157 else if (visit == InVisit)
1158 {
1159 out << " = ";
1160 }
1161 break;
1162 case EOpAddAssign:
1163 outputTriplet(out, visit, "(", " += ", ")");
1164 break;
1165 case EOpSubAssign:
1166 outputTriplet(out, visit, "(", " -= ", ")");
1167 break;
1168 case EOpMulAssign:
1169 outputTriplet(out, visit, "(", " *= ", ")");
1170 break;
1171 case EOpVectorTimesScalarAssign:
1172 outputTriplet(out, visit, "(", " *= ", ")");
1173 break;
1174 case EOpMatrixTimesScalarAssign:
1175 outputTriplet(out, visit, "(", " *= ", ")");
1176 break;
1177 case EOpVectorTimesMatrixAssign:
1178 if (visit == PreVisit)
1179 {
1180 out << "(";
1181 }
1182 else if (visit == InVisit)
1183 {
1184 out << " = mul(";
1185 node->getLeft()->traverse(this);
1186 out << ", transpose(";
1187 }
1188 else
1189 {
1190 out << ")))";
1191 }
1192 break;
1193 case EOpMatrixTimesMatrixAssign:
1194 if (visit == PreVisit)
1195 {
1196 out << "(";
1197 }
1198 else if (visit == InVisit)
1199 {
1200 out << " = transpose(mul(transpose(";
1201 node->getLeft()->traverse(this);
1202 out << "), transpose(";
1203 }
1204 else
1205 {
1206 out << "))))";
1207 }
1208 break;
1209 case EOpDivAssign:
1210 outputTriplet(out, visit, "(", " /= ", ")");
1211 break;
1212 case EOpIModAssign:
1213 outputTriplet(out, visit, "(", " %= ", ")");
1214 break;
1215 case EOpBitShiftLeftAssign:
1216 outputTriplet(out, visit, "(", " <<= ", ")");
1217 break;
1218 case EOpBitShiftRightAssign:
1219 outputTriplet(out, visit, "(", " >>= ", ")");
1220 break;
1221 case EOpBitwiseAndAssign:
1222 outputTriplet(out, visit, "(", " &= ", ")");
1223 break;
1224 case EOpBitwiseXorAssign:
1225 outputTriplet(out, visit, "(", " ^= ", ")");
1226 break;
1227 case EOpBitwiseOrAssign:
1228 outputTriplet(out, visit, "(", " |= ", ")");
1229 break;
1230 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001231 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001232 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001233 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001234 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001235 if (visit == PreVisit)
1236 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001237 TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Olli Etuaho12a18ad2017-12-01 16:59:47 +02001238 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahobed35d72017-12-20 16:36:26 +02001239 mReferencedUniformBlocks[interfaceBlock->name()] = instanceArraySymbol;
Jamie Madill98493dd2013-07-08 14:39:03 -04001240 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Olli Etuaho12a18ad2017-12-01 16:59:47 +02001241 out << mUniformHLSL->UniformBlockInstanceString(
1242 instanceArraySymbol->getSymbol(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001243 return false;
1244 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001245 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001246 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001247 {
1248 // All parts of an expression that access a sampler in a struct need to use _ as
1249 // separator to access the sampler variable that has been moved out of the struct.
1250 outputTriplet(out, visit, "", "_", "");
1251 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001252 else
1253 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001254 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001255 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001256 }
1257 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001258 case EOpIndexIndirect:
1259 // We do not currently support indirect references to interface blocks
1260 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1261 outputTriplet(out, visit, "", "[", "]");
1262 break;
1263 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001264 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001265 const TStructure *structure = node->getLeft()->getType().getStruct();
1266 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1267 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001268
Olli Etuaho96963162016-03-21 11:54:33 +02001269 // In cases where indexing returns a sampler, we need to access the sampler variable
1270 // that has been moved out of the struct.
1271 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1272 if (visit == PreVisit && indexingReturnsSampler)
1273 {
1274 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1275 // This prefix is only output at the beginning of the indexing expression, which
1276 // may have multiple parts.
1277 out << "angle";
1278 }
1279 if (!indexingReturnsSampler)
1280 {
1281 // All parts of an expression that access a sampler in a struct need to use _ as
1282 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001283 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001284 }
1285 if (visit == InVisit)
1286 {
1287 if (indexingReturnsSampler)
1288 {
1289 out << "_" + field->name();
1290 }
1291 else
1292 {
1293 out << "." + DecorateField(field->name(), *structure);
1294 }
1295
1296 return false;
1297 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001298 }
1299 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001300 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001301 {
1302 bool structInStd140Block =
1303 node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft());
1304 if (visit == PreVisit && structInStd140Block)
1305 {
1306 out << "map";
1307 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001308 if (visit == InVisit)
1309 {
1310 const TInterfaceBlock *interfaceBlock =
1311 node->getLeft()->getType().getInterfaceBlock();
1312 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1313 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001314 if (structInStd140Block)
1315 {
1316 out << "_";
1317 }
1318 else
1319 {
1320 out << ".";
1321 }
1322 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001323
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001324 return false;
1325 }
1326 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001327 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001328 case EOpAdd:
1329 outputTriplet(out, visit, "(", " + ", ")");
1330 break;
1331 case EOpSub:
1332 outputTriplet(out, visit, "(", " - ", ")");
1333 break;
1334 case EOpMul:
1335 outputTriplet(out, visit, "(", " * ", ")");
1336 break;
1337 case EOpDiv:
1338 outputTriplet(out, visit, "(", " / ", ")");
1339 break;
1340 case EOpIMod:
1341 outputTriplet(out, visit, "(", " % ", ")");
1342 break;
1343 case EOpBitShiftLeft:
1344 outputTriplet(out, visit, "(", " << ", ")");
1345 break;
1346 case EOpBitShiftRight:
1347 outputTriplet(out, visit, "(", " >> ", ")");
1348 break;
1349 case EOpBitwiseAnd:
1350 outputTriplet(out, visit, "(", " & ", ")");
1351 break;
1352 case EOpBitwiseXor:
1353 outputTriplet(out, visit, "(", " ^ ", ")");
1354 break;
1355 case EOpBitwiseOr:
1356 outputTriplet(out, visit, "(", " | ", ")");
1357 break;
1358 case EOpEqual:
1359 case EOpNotEqual:
1360 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1361 break;
1362 case EOpLessThan:
1363 outputTriplet(out, visit, "(", " < ", ")");
1364 break;
1365 case EOpGreaterThan:
1366 outputTriplet(out, visit, "(", " > ", ")");
1367 break;
1368 case EOpLessThanEqual:
1369 outputTriplet(out, visit, "(", " <= ", ")");
1370 break;
1371 case EOpGreaterThanEqual:
1372 outputTriplet(out, visit, "(", " >= ", ")");
1373 break;
1374 case EOpVectorTimesScalar:
1375 outputTriplet(out, visit, "(", " * ", ")");
1376 break;
1377 case EOpMatrixTimesScalar:
1378 outputTriplet(out, visit, "(", " * ", ")");
1379 break;
1380 case EOpVectorTimesMatrix:
1381 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1382 break;
1383 case EOpMatrixTimesVector:
1384 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1385 break;
1386 case EOpMatrixTimesMatrix:
1387 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1388 break;
1389 case EOpLogicalOr:
1390 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1391 // been unfolded.
1392 ASSERT(!node->getRight()->hasSideEffects());
1393 outputTriplet(out, visit, "(", " || ", ")");
1394 return true;
1395 case EOpLogicalXor:
1396 mUsesXor = true;
1397 outputTriplet(out, visit, "xor(", ", ", ")");
1398 break;
1399 case EOpLogicalAnd:
1400 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1401 // been unfolded.
1402 ASSERT(!node->getRight()->hasSideEffects());
1403 outputTriplet(out, visit, "(", " && ", ")");
1404 return true;
1405 default:
1406 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001407 }
1408
1409 return true;
1410}
1411
1412bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1413{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001414 TInfoSinkBase &out = getInfoSink();
1415
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001416 switch (node->getOp())
1417 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001418 case EOpNegative:
1419 outputTriplet(out, visit, "(-", "", ")");
1420 break;
1421 case EOpPositive:
1422 outputTriplet(out, visit, "(+", "", ")");
1423 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001424 case EOpLogicalNot:
1425 outputTriplet(out, visit, "(!", "", ")");
1426 break;
1427 case EOpBitwiseNot:
1428 outputTriplet(out, visit, "(~", "", ")");
1429 break;
1430 case EOpPostIncrement:
1431 outputTriplet(out, visit, "(", "", "++)");
1432 break;
1433 case EOpPostDecrement:
1434 outputTriplet(out, visit, "(", "", "--)");
1435 break;
1436 case EOpPreIncrement:
1437 outputTriplet(out, visit, "(++", "", ")");
1438 break;
1439 case EOpPreDecrement:
1440 outputTriplet(out, visit, "(--", "", ")");
1441 break;
1442 case EOpRadians:
1443 outputTriplet(out, visit, "radians(", "", ")");
1444 break;
1445 case EOpDegrees:
1446 outputTriplet(out, visit, "degrees(", "", ")");
1447 break;
1448 case EOpSin:
1449 outputTriplet(out, visit, "sin(", "", ")");
1450 break;
1451 case EOpCos:
1452 outputTriplet(out, visit, "cos(", "", ")");
1453 break;
1454 case EOpTan:
1455 outputTriplet(out, visit, "tan(", "", ")");
1456 break;
1457 case EOpAsin:
1458 outputTriplet(out, visit, "asin(", "", ")");
1459 break;
1460 case EOpAcos:
1461 outputTriplet(out, visit, "acos(", "", ")");
1462 break;
1463 case EOpAtan:
1464 outputTriplet(out, visit, "atan(", "", ")");
1465 break;
1466 case EOpSinh:
1467 outputTriplet(out, visit, "sinh(", "", ")");
1468 break;
1469 case EOpCosh:
1470 outputTriplet(out, visit, "cosh(", "", ")");
1471 break;
1472 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001473 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001474 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001475 case EOpAtanh:
1476 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001477 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001478 break;
1479 case EOpExp:
1480 outputTriplet(out, visit, "exp(", "", ")");
1481 break;
1482 case EOpLog:
1483 outputTriplet(out, visit, "log(", "", ")");
1484 break;
1485 case EOpExp2:
1486 outputTriplet(out, visit, "exp2(", "", ")");
1487 break;
1488 case EOpLog2:
1489 outputTriplet(out, visit, "log2(", "", ")");
1490 break;
1491 case EOpSqrt:
1492 outputTriplet(out, visit, "sqrt(", "", ")");
1493 break;
1494 case EOpInverseSqrt:
1495 outputTriplet(out, visit, "rsqrt(", "", ")");
1496 break;
1497 case EOpAbs:
1498 outputTriplet(out, visit, "abs(", "", ")");
1499 break;
1500 case EOpSign:
1501 outputTriplet(out, visit, "sign(", "", ")");
1502 break;
1503 case EOpFloor:
1504 outputTriplet(out, visit, "floor(", "", ")");
1505 break;
1506 case EOpTrunc:
1507 outputTriplet(out, visit, "trunc(", "", ")");
1508 break;
1509 case EOpRound:
1510 outputTriplet(out, visit, "round(", "", ")");
1511 break;
1512 case EOpRoundEven:
1513 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001514 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001515 break;
1516 case EOpCeil:
1517 outputTriplet(out, visit, "ceil(", "", ")");
1518 break;
1519 case EOpFract:
1520 outputTriplet(out, visit, "frac(", "", ")");
1521 break;
1522 case EOpIsNan:
1523 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001524 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001525 else
1526 outputTriplet(out, visit, "isnan(", "", ")");
1527 mRequiresIEEEStrictCompiling = true;
1528 break;
1529 case EOpIsInf:
1530 outputTriplet(out, visit, "isinf(", "", ")");
1531 break;
1532 case EOpFloatBitsToInt:
1533 outputTriplet(out, visit, "asint(", "", ")");
1534 break;
1535 case EOpFloatBitsToUint:
1536 outputTriplet(out, visit, "asuint(", "", ")");
1537 break;
1538 case EOpIntBitsToFloat:
1539 outputTriplet(out, visit, "asfloat(", "", ")");
1540 break;
1541 case EOpUintBitsToFloat:
1542 outputTriplet(out, visit, "asfloat(", "", ")");
1543 break;
1544 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001546 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001547 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001548 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001550 case EOpPackUnorm4x8:
1551 case EOpPackSnorm4x8:
1552 case EOpUnpackUnorm4x8:
1553 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001555 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001556 break;
1557 case EOpLength:
1558 outputTriplet(out, visit, "length(", "", ")");
1559 break;
1560 case EOpNormalize:
1561 outputTriplet(out, visit, "normalize(", "", ")");
1562 break;
1563 case EOpDFdx:
1564 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1565 {
1566 outputTriplet(out, visit, "(", "", ", 0.0)");
1567 }
1568 else
1569 {
1570 outputTriplet(out, visit, "ddx(", "", ")");
1571 }
1572 break;
1573 case EOpDFdy:
1574 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1575 {
1576 outputTriplet(out, visit, "(", "", ", 0.0)");
1577 }
1578 else
1579 {
1580 outputTriplet(out, visit, "ddy(", "", ")");
1581 }
1582 break;
1583 case EOpFwidth:
1584 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1585 {
1586 outputTriplet(out, visit, "(", "", ", 0.0)");
1587 }
1588 else
1589 {
1590 outputTriplet(out, visit, "fwidth(", "", ")");
1591 }
1592 break;
1593 case EOpTranspose:
1594 outputTriplet(out, visit, "transpose(", "", ")");
1595 break;
1596 case EOpDeterminant:
1597 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1598 break;
1599 case EOpInverse:
1600 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001601 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001603
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 case EOpAny:
1605 outputTriplet(out, visit, "any(", "", ")");
1606 break;
1607 case EOpAll:
1608 outputTriplet(out, visit, "all(", "", ")");
1609 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001610 case EOpLogicalNotComponentWise:
1611 outputTriplet(out, visit, "(!", "", ")");
1612 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001613 case EOpBitfieldReverse:
1614 outputTriplet(out, visit, "reversebits(", "", ")");
1615 break;
1616 case EOpBitCount:
1617 outputTriplet(out, visit, "countbits(", "", ")");
1618 break;
1619 case EOpFindLSB:
1620 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1621 // in GLSLTest and results are consistent with GL.
1622 outputTriplet(out, visit, "firstbitlow(", "", ")");
1623 break;
1624 case EOpFindMSB:
1625 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1626 // tested in GLSLTest and results are consistent with GL.
1627 outputTriplet(out, visit, "firstbithigh(", "", ")");
1628 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001629 default:
1630 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001631 }
1632
1633 return true;
1634}
1635
Olli Etuaho96963162016-03-21 11:54:33 +02001636TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1637{
1638 if (node->getAsSymbolNode())
1639 {
1640 return node->getAsSymbolNode()->getSymbol();
1641 }
1642 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1643 switch (nodeBinary->getOp())
1644 {
1645 case EOpIndexDirect:
1646 {
1647 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1648
1649 TInfoSinkBase prefixSink;
1650 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1651 return TString(prefixSink.c_str());
1652 }
1653 case EOpIndexDirectStruct:
1654 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001655 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001656 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1657 const TField *field = s->fields()[index];
1658
1659 TInfoSinkBase prefixSink;
1660 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1661 << field->name();
1662 return TString(prefixSink.c_str());
1663 }
1664 default:
1665 UNREACHABLE();
1666 return TString("");
1667 }
1668}
1669
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001670bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1671{
1672 TInfoSinkBase &out = getInfoSink();
1673
1674 if (mInsideFunction)
1675 {
1676 outputLineDirective(out, node->getLine().first_line);
1677 out << "{\n";
1678 }
1679
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001680 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001681 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001682 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001683
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001684 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001685
1686 // Don't output ; after case labels, they're terminated by :
1687 // This is needed especially since outputting a ; after a case statement would turn empty
1688 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001689 // Also the output code is clearer if we don't output ; after statements where it is not
1690 // needed:
1691 // * if statements
1692 // * switch statements
1693 // * blocks
1694 // * function definitions
1695 // * loops (do-while loops output the semicolon in VisitLoop)
1696 // * declarations that don't generate output.
1697 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1698 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1699 statement->getAsSwitchNode() == nullptr &&
1700 statement->getAsFunctionDefinition() == nullptr &&
1701 (statement->getAsDeclarationNode() == nullptr ||
1702 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1703 statement->getAsInvariantDeclarationNode() == nullptr)
1704 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001705 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001706 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001707 }
1708
1709 if (mInsideFunction)
1710 {
1711 outputLineDirective(out, node->getLine().last_line);
1712 out << "}\n";
1713 }
1714
1715 return false;
1716}
1717
Olli Etuaho336b1472016-10-05 16:37:55 +01001718bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1719{
1720 TInfoSinkBase &out = getInfoSink();
1721
1722 ASSERT(mCurrentFunctionMetadata == nullptr);
1723
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001724 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001725 ASSERT(index != CallDAG::InvalidIndex);
1726 mCurrentFunctionMetadata = &mASTMetadataList[index];
1727
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001728 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuaho336b1472016-10-05 16:37:55 +01001729
Olli Etuaho8ad9e752017-01-16 19:55:20 +00001730 TIntermSequence *parameters = node->getFunctionPrototype()->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +01001731
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001732 if (node->getFunction()->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001733 {
1734 out << "gl_main(";
1735 }
1736 else
1737 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001738 out << DecorateFunctionIfNeeded(node->getFunction()) << DisambiguateFunctionName(parameters)
1739 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001740 }
1741
1742 for (unsigned int i = 0; i < parameters->size(); i++)
1743 {
1744 TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1745
1746 if (symbol)
1747 {
1748 ensureStructDefined(symbol->getType());
1749
1750 out << argumentString(symbol);
1751
1752 if (i < parameters->size() - 1)
1753 {
1754 out << ", ";
1755 }
1756 }
1757 else
1758 UNREACHABLE();
1759 }
1760
1761 out << ")\n";
1762
1763 mInsideFunction = true;
1764 // The function body node will output braces.
1765 node->getBody()->traverse(this);
1766 mInsideFunction = false;
1767
1768 mCurrentFunctionMetadata = nullptr;
1769
1770 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1771 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1772 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001773 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001774 mOutputLod0Function = true;
1775 node->traverse(this);
1776 mOutputLod0Function = false;
1777 }
1778
1779 return false;
1780}
1781
Olli Etuaho13389b62016-10-16 11:48:18 +01001782bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1783{
Olli Etuaho13389b62016-10-16 11:48:18 +01001784 if (visit == PreVisit)
1785 {
1786 TIntermSequence *sequence = node->getSequence();
1787 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1788 ASSERT(sequence->size() == 1);
Olli Etuaho282847e2017-07-12 14:11:01 +03001789 ASSERT(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001790
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001791 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001792 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001793 TInfoSinkBase &out = getInfoSink();
Olli Etuaho13389b62016-10-16 11:48:18 +01001794 ensureStructDefined(variable->getType());
1795
1796 if (!variable->getAsSymbolNode() ||
1797 variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1798 {
1799 if (!mInsideFunction)
1800 {
1801 out << "static ";
1802 }
1803
1804 out << TypeString(variable->getType()) + " ";
1805
1806 TIntermSymbol *symbol = variable->getAsSymbolNode();
1807
1808 if (symbol)
1809 {
1810 symbol->traverse(this);
1811 out << ArrayString(symbol->getType());
1812 out << " = " + initializer(symbol->getType());
1813 }
1814 else
1815 {
1816 variable->traverse(this);
1817 }
1818 }
1819 else if (variable->getAsSymbolNode() &&
1820 variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1821 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001822 ASSERT(variable->getBasicType() == EbtStruct);
1823 // ensureStructDefined has already been called.
Olli Etuaho13389b62016-10-16 11:48:18 +01001824 }
1825 else
1826 UNREACHABLE();
1827 }
Olli Etuaho282847e2017-07-12 14:11:01 +03001828 else if (IsVaryingOut(variable->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01001829 {
Olli Etuaho282847e2017-07-12 14:11:01 +03001830 TIntermSymbol *symbol = variable->getAsSymbolNode();
1831 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01001832
Olli Etuaho282847e2017-07-12 14:11:01 +03001833 // Vertex outputs which are declared but not written to should still be declared to
1834 // allow successful linking.
1835 mReferencedVaryings[symbol->getSymbol()] = symbol;
Olli Etuaho13389b62016-10-16 11:48:18 +01001836 }
1837 }
1838 return false;
1839}
1840
Olli Etuahobf4e1b72016-12-09 11:30:15 +00001841bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
1842{
1843 // Do not do any translation
1844 return false;
1845}
1846
Olli Etuaho16c745a2017-01-16 17:02:27 +00001847bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
1848{
1849 TInfoSinkBase &out = getInfoSink();
1850
1851 ASSERT(visit == PreVisit);
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001852 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001853 // Skip the prototype if it is not implemented (and thus not used)
1854 if (index == CallDAG::InvalidIndex)
1855 {
1856 return false;
1857 }
1858
1859 TIntermSequence *arguments = node->getSequence();
1860
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001861 TString name = DecorateFunctionIfNeeded(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +00001862 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
1863 << (mOutputLod0Function ? "Lod0(" : "(");
1864
1865 for (unsigned int i = 0; i < arguments->size(); i++)
1866 {
1867 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1868 ASSERT(symbol != nullptr);
1869
1870 out << argumentString(symbol);
1871
1872 if (i < arguments->size() - 1)
1873 {
1874 out << ", ";
1875 }
1876 }
1877
1878 out << ");\n";
1879
1880 // Also prototype the Lod0 variant if needed
1881 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1882 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1883 {
1884 mOutputLod0Function = true;
1885 node->traverse(this);
1886 mOutputLod0Function = false;
1887 }
1888
1889 return false;
1890}
1891
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001892bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1893{
Jamie Madill32aab012015-01-27 14:12:26 -05001894 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001895
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001896 switch (node->getOp())
1897 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001898 case EOpCallBuiltInFunction:
1899 case EOpCallFunctionInAST:
1900 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001901 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001902 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001903
Corentin Wallez1239ee92015-03-19 14:38:02 -07001904 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001905 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001906 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001907 if (node->isArray())
1908 {
1909 UNIMPLEMENTED();
1910 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001911 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07001912 ASSERT(index != CallDAG::InvalidIndex);
1913 lod0 &= mASTMetadataList[index].mNeedsLod0;
1914
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001915 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02001916 out << DisambiguateFunctionName(node->getSequence());
1917 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001918 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001919 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03001920 {
1921 // This path is used for internal functions that don't have their definitions in the
1922 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001923 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03001924 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02001925 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08001926 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001927 const TString &name = node->getFunction()->name();
Xinghua Cao711b7a12017-10-09 13:38:12 +08001928 TType type = (*arguments)[0]->getAsTyped()->getType();
1929 TString imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02001930 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08001931 type.getMemoryQualifier().readonly);
1932 out << imageFunctionName << "(";
1933 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001934 else
1935 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001936 const TString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001937 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00001938 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
1939 if (arguments->size() > 1)
1940 {
1941 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1942 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001943 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02001944 name, samplerType, coords, arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001945 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001946 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001947
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001948 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001949 {
Olli Etuaho96963162016-03-21 11:54:33 +02001950 TIntermTyped *typedArg = (*arg)->getAsTyped();
1951 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001952 {
1953 out << "texture_";
1954 (*arg)->traverse(this);
1955 out << ", sampler_";
1956 }
1957
1958 (*arg)->traverse(this);
1959
Olli Etuaho96963162016-03-21 11:54:33 +02001960 if (typedArg->getType().isStructureContainingSamplers())
1961 {
1962 const TType &argType = typedArg->getType();
1963 TVector<TIntermSymbol *> samplerSymbols;
1964 TString structName = samplerNamePrefixFromStruct(typedArg);
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03001965 argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols,
1966 nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02001967 for (const TIntermSymbol *sampler : samplerSymbols)
1968 {
1969 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1970 {
1971 out << ", texture_" << sampler->getSymbol();
1972 out << ", sampler_" << sampler->getSymbol();
1973 }
1974 else
1975 {
1976 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1977 // of D3D9, it's the sampler variable.
1978 out << ", " + sampler->getSymbol();
1979 }
1980 }
1981 }
1982
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001983 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00001984 {
1985 out << ", ";
1986 }
1987 }
1988
1989 out << ")";
1990
1991 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001992 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03001993 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02001994 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03001995 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001996 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001997 outputTriplet(out, visit, "(", " == ", ")");
1998 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00001999 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002000 outputTriplet(out, visit, "(", " != ", ")");
2001 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002002 case EOpLessThanComponentWise:
2003 outputTriplet(out, visit, "(", " < ", ")");
2004 break;
2005 case EOpGreaterThanComponentWise:
2006 outputTriplet(out, visit, "(", " > ", ")");
2007 break;
2008 case EOpLessThanEqualComponentWise:
2009 outputTriplet(out, visit, "(", " <= ", ")");
2010 break;
2011 case EOpGreaterThanEqualComponentWise:
2012 outputTriplet(out, visit, "(", " >= ", ")");
2013 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002014 case EOpMod:
2015 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002016 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002017 break;
2018 case EOpModf:
2019 outputTriplet(out, visit, "modf(", ", ", ")");
2020 break;
2021 case EOpPow:
2022 outputTriplet(out, visit, "pow(", ", ", ")");
2023 break;
2024 case EOpAtan:
2025 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2026 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002027 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002028 break;
2029 case EOpMin:
2030 outputTriplet(out, visit, "min(", ", ", ")");
2031 break;
2032 case EOpMax:
2033 outputTriplet(out, visit, "max(", ", ", ")");
2034 break;
2035 case EOpClamp:
2036 outputTriplet(out, visit, "clamp(", ", ", ")");
2037 break;
2038 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302039 {
2040 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2041 if (lastParamNode->getType().getBasicType() == EbtBool)
2042 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002043 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2044 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302045 // so use emulated version.
2046 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002047 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302048 }
2049 else
2050 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002051 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302052 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002053 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302054 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002055 case EOpStep:
2056 outputTriplet(out, visit, "step(", ", ", ")");
2057 break;
2058 case EOpSmoothStep:
2059 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2060 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002061 case EOpFrexp:
2062 case EOpLdexp:
2063 ASSERT(node->getUseEmulatedFunction());
2064 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2065 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002066 case EOpDistance:
2067 outputTriplet(out, visit, "distance(", ", ", ")");
2068 break;
2069 case EOpDot:
2070 outputTriplet(out, visit, "dot(", ", ", ")");
2071 break;
2072 case EOpCross:
2073 outputTriplet(out, visit, "cross(", ", ", ")");
2074 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002075 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002076 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002077 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002078 break;
2079 case EOpReflect:
2080 outputTriplet(out, visit, "reflect(", ", ", ")");
2081 break;
2082 case EOpRefract:
2083 outputTriplet(out, visit, "refract(", ", ", ")");
2084 break;
2085 case EOpOuterProduct:
2086 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002087 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002088 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002089 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002090 outputTriplet(out, visit, "(", " * ", ")");
2091 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002092 case EOpBitfieldExtract:
2093 case EOpBitfieldInsert:
2094 case EOpUaddCarry:
2095 case EOpUsubBorrow:
2096 case EOpUmulExtended:
2097 case EOpImulExtended:
2098 ASSERT(node->getUseEmulatedFunction());
2099 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2100 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002101 default:
2102 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002103 }
2104
2105 return true;
2106}
2107
Olli Etuaho57961272016-09-14 13:57:46 +03002108void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002109{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002110 out << "if (";
2111
2112 node->getCondition()->traverse(this);
2113
2114 out << ")\n";
2115
Jamie Madill8c46ab12015-12-07 16:39:19 -05002116 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002117
2118 bool discard = false;
2119
2120 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002121 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002122 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002123 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002124
Olli Etuahoa6f22092015-05-08 18:31:10 +03002125 // Detect true discard
2126 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2127 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002128 else
2129 {
2130 // TODO(oetuaho): Check if the semicolon inside is necessary.
2131 // It's there as a result of conservative refactoring of the output.
2132 out << "{;}\n";
2133 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002134
Jamie Madill8c46ab12015-12-07 16:39:19 -05002135 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002136
Olli Etuahoa6f22092015-05-08 18:31:10 +03002137 if (node->getFalseBlock())
2138 {
2139 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002140
Jamie Madill8c46ab12015-12-07 16:39:19 -05002141 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002142
Olli Etuaho32db19b2016-10-04 14:43:16 +01002143 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002144 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002145
Jamie Madill8c46ab12015-12-07 16:39:19 -05002146 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002147
Olli Etuahoa6f22092015-05-08 18:31:10 +03002148 // Detect false discard
2149 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2150 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002151
Olli Etuahoa6f22092015-05-08 18:31:10 +03002152 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002153 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002154 {
2155 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002156 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002157}
2158
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002159bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2160{
2161 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2162 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2163 UNREACHABLE();
2164 return false;
2165}
2166
Olli Etuaho57961272016-09-14 13:57:46 +03002167bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002168{
2169 TInfoSinkBase &out = getInfoSink();
2170
Olli Etuaho3d932d82016-04-12 11:10:30 +03002171 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002172
2173 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002174 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002175 {
2176 out << "FLATTEN ";
2177 }
2178
Olli Etuaho57961272016-09-14 13:57:46 +03002179 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002180
2181 return false;
2182}
2183
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002184bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002185{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002186 TInfoSinkBase &out = getInfoSink();
2187
Olli Etuaho923ecef2017-10-11 12:01:38 +03002188 ASSERT(node->getStatementList());
2189 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002190 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002191 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002192 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002193 outputTriplet(out, visit, "switch (", ") ", "");
2194 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002195 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002196}
2197
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002198bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002199{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002200 TInfoSinkBase &out = getInfoSink();
2201
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002202 if (node->hasCondition())
2203 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002204 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002205 return true;
2206 }
2207 else
2208 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002209 out << "default:\n";
2210 return false;
2211 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002212}
2213
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002214void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2215{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002216 TInfoSinkBase &out = getInfoSink();
2217 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218}
2219
2220bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2221{
Nicolas Capens655fe362014-04-11 13:12:34 -04002222 mNestedLoopDepth++;
2223
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002224 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002225 mInsideDiscontinuousLoop =
2226 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002227
Jamie Madill8c46ab12015-12-07 16:39:19 -05002228 TInfoSinkBase &out = getInfoSink();
2229
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002230 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002231 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002232 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002233 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002234 mInsideDiscontinuousLoop = wasDiscontinuous;
2235 mNestedLoopDepth--;
2236
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002237 return false;
2238 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002239 }
2240
Corentin Wallez1239ee92015-03-19 14:38:02 -07002241 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002242 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002243 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002244 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002245
Jamie Madill8c46ab12015-12-07 16:39:19 -05002246 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002247 }
2248 else
2249 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002250 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002251
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002252 if (node->getInit())
2253 {
2254 node->getInit()->traverse(this);
2255 }
2256
2257 out << "; ";
2258
alokp@chromium.org52813552010-11-16 18:36:09 +00002259 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002261 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002262 }
2263
2264 out << "; ";
2265
alokp@chromium.org52813552010-11-16 18:36:09 +00002266 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002268 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002269 }
2270
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002271 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002272
Jamie Madill8c46ab12015-12-07 16:39:19 -05002273 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002274 }
2275
2276 if (node->getBody())
2277 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002278 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002279 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002280 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002281 else
2282 {
2283 // TODO(oetuaho): Check if the semicolon inside is necessary.
2284 // It's there as a result of conservative refactoring of the output.
2285 out << "{;}\n";
2286 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002287
Jamie Madill8c46ab12015-12-07 16:39:19 -05002288 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002289
alokp@chromium.org52813552010-11-16 18:36:09 +00002290 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002291 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002292 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002293 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002294
alokp@chromium.org52813552010-11-16 18:36:09 +00002295 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002296
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002297 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298 }
2299
daniel@transgaming.com73536982012-03-21 20:45:49 +00002300 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002301
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002302 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002303 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002304
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002305 return false;
2306}
2307
2308bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2309{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002310 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002311 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002312 TInfoSinkBase &out = getInfoSink();
2313
2314 switch (node->getFlowOp())
2315 {
2316 case EOpKill:
2317 out << "discard";
2318 break;
2319 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002320 if (mNestedLoopDepth > 1)
2321 {
2322 mUsesNestedBreak = true;
2323 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002324
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002325 if (mExcessiveLoopIndex)
2326 {
2327 out << "{Break";
2328 mExcessiveLoopIndex->traverse(this);
2329 out << " = true; break;}\n";
2330 }
2331 else
2332 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002333 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002334 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002335 break;
2336 case EOpContinue:
2337 out << "continue";
2338 break;
2339 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002340 if (node->getExpression())
2341 {
2342 out << "return ";
2343 }
2344 else
2345 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002346 out << "return";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002347 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002348 break;
2349 default:
2350 UNREACHABLE();
2351 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002352 }
2353
2354 return true;
2355}
2356
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002357// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002358// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2359// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002360bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002361{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002362 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002363
2364 // Parse loops of the form:
2365 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002366 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002367 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002368 int initial = 0;
2369 int limit = 0;
2370 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002371
2372 // Parse index name and intial value
2373 if (node->getInit())
2374 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002375 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002376
2377 if (init)
2378 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002379 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002380 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002381
2382 if (variable && variable->getQualifier() == EvqTemporary)
2383 {
2384 TIntermBinary *assign = variable->getAsBinaryNode();
2385
2386 if (assign->getOp() == EOpInitialize)
2387 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002388 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002389 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2390
2391 if (symbol && constant)
2392 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002393 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002394 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002395 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002396 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002397 }
2398 }
2399 }
2400 }
2401 }
2402 }
2403
2404 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002405 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002406 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002407 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002408
Olli Etuahob6af22b2017-12-15 14:05:44 +02002409 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002410 {
2411 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2412
2413 if (constant)
2414 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002415 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002416 {
2417 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002418 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002419 }
2420 }
2421 }
2422 }
2423
2424 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002425 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002426 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002427 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002428 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002429
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002430 if (binaryTerminal)
2431 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002432 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002433 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2434
2435 if (constant)
2436 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002437 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002438 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002439 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002440
2441 switch (op)
2442 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002443 case EOpAddAssign:
2444 increment = value;
2445 break;
2446 case EOpSubAssign:
2447 increment = -value;
2448 break;
2449 default:
2450 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002451 }
2452 }
2453 }
2454 }
2455 else if (unaryTerminal)
2456 {
2457 TOperator op = unaryTerminal->getOp();
2458
2459 switch (op)
2460 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002461 case EOpPostIncrement:
2462 increment = 1;
2463 break;
2464 case EOpPostDecrement:
2465 increment = -1;
2466 break;
2467 case EOpPreIncrement:
2468 increment = 1;
2469 break;
2470 case EOpPreDecrement:
2471 increment = -1;
2472 break;
2473 default:
2474 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002475 }
2476 }
2477 }
2478
Yunchao He4f285442017-04-21 12:15:49 +08002479 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002480 {
2481 if (comparator == EOpLessThanEqual)
2482 {
2483 comparator = EOpLessThan;
2484 limit += 1;
2485 }
2486
2487 if (comparator == EOpLessThan)
2488 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002489 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002490
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002491 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002492 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002493 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002494 }
2495
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002496 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002497 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002498
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002499 out << "{int ";
2500 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002501 out << ";\n"
2502 "bool Break";
2503 index->traverse(this);
2504 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002505
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002506 bool firstLoopFragment = true;
2507
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002508 while (iterations > 0)
2509 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002510 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002511
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002512 if (!firstLoopFragment)
2513 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002514 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002515 index->traverse(this);
2516 out << ") {\n";
2517 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002518
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002519 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002520 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002521 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002522 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002523
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002524 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002525 const char *unroll =
2526 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002527
Corentin Wallez1239ee92015-03-19 14:38:02 -07002528 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002529 index->traverse(this);
2530 out << " = ";
2531 out << initial;
2532
2533 out << "; ";
2534 index->traverse(this);
2535 out << " < ";
2536 out << clampedLimit;
2537
2538 out << "; ";
2539 index->traverse(this);
2540 out << " += ";
2541 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002542 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002543
Jamie Madill8c46ab12015-12-07 16:39:19 -05002544 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002545 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002546
2547 if (node->getBody())
2548 {
2549 node->getBody()->traverse(this);
2550 }
2551
Jamie Madill8c46ab12015-12-07 16:39:19 -05002552 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002553 out << ";}\n";
2554
2555 if (!firstLoopFragment)
2556 {
2557 out << "}\n";
2558 }
2559
2560 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002561
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002562 initial += MAX_LOOP_ITERATIONS * increment;
2563 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002564 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002565
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002566 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002567
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002568 mExcessiveLoopIndex = restoreIndex;
2569
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002570 return true;
2571 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002572 else
2573 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002574 }
2575
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002576 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002577}
2578
Jamie Madill8c46ab12015-12-07 16:39:19 -05002579void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2580 Visit visit,
2581 const char *preString,
2582 const char *inString,
2583 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002584{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002585 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002586 {
2587 out << preString;
2588 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002589 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002590 {
2591 out << inString;
2592 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002593 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002594 {
2595 out << postString;
2596 }
2597}
2598
Jamie Madill8c46ab12015-12-07 16:39:19 -05002599void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002600{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002601 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002602 {
Jamie Madill32aab012015-01-27 14:12:26 -05002603 out << "\n";
2604 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002605
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002606 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002607 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002608 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002609 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002610
Jamie Madill32aab012015-01-27 14:12:26 -05002611 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002612 }
2613}
2614
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002615TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2616{
2617 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002618 const TType &type = symbol->getType();
2619 const TName &name = symbol->getName();
2620 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002621
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002622 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002623 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002624 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002625 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002626 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002627 {
Olli Etuahoff526f12017-06-30 12:26:54 +03002628 nameStr = DecorateVariableIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002629 }
2630
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002631 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002632 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002633 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2634 {
2635 // Samplers are passed as indices to the sampler array.
2636 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2637 return "const uint " + nameStr + ArrayString(type);
2638 }
2639 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2640 {
2641 return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2642 " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2643 " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2644 ArrayString(type);
2645 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002646 }
2647
Olli Etuaho96963162016-03-21 11:54:33 +02002648 TStringStream argString;
2649 argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2650 << ArrayString(type);
2651
2652 // If the structure parameter contains samplers, they need to be passed into the function as
2653 // separate parameters. HLSL doesn't natively support samplers in structs.
2654 if (type.isStructureContainingSamplers())
2655 {
2656 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2657 TVector<TIntermSymbol *> samplerSymbols;
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002658 type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable);
Olli Etuaho96963162016-03-21 11:54:33 +02002659 for (const TIntermSymbol *sampler : samplerSymbols)
2660 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002661 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002662 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2663 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002664 argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002665 }
2666 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2667 {
Olli Etuaho96963162016-03-21 11:54:33 +02002668 ASSERT(IsSampler(samplerType.getBasicType()));
2669 argString << ", " << QualifierString(qualifier) << " "
2670 << TextureString(samplerType.getBasicType()) << " texture_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002671 << sampler->getSymbol() << ArrayString(samplerType) << ", "
2672 << QualifierString(qualifier) << " "
Olli Etuaho96963162016-03-21 11:54:33 +02002673 << SamplerString(samplerType.getBasicType()) << " sampler_"
Olli Etuaho28839f02017-08-15 11:38:16 +03002674 << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002675 }
2676 else
2677 {
Olli Etuaho96963162016-03-21 11:54:33 +02002678 ASSERT(IsSampler(samplerType.getBasicType()));
2679 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
Olli Etuaho28839f02017-08-15 11:38:16 +03002680 << " " << sampler->getSymbol() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002681 }
2682 }
2683 }
2684
2685 return argString.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002686}
2687
2688TString OutputHLSL::initializer(const TType &type)
2689{
2690 TString string;
2691
Jamie Madill94bf7f22013-07-08 13:31:15 -04002692 size_t size = type.getObjectSize();
2693 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002694 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002695 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002696
Jamie Madill94bf7f22013-07-08 13:31:15 -04002697 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002698 {
2699 string += ", ";
2700 }
2701 }
2702
daniel@transgaming.comead23042010-04-29 03:35:36 +00002703 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002704}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002705
Olli Etuahobd3cd502017-11-03 15:48:52 +02002706void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002707{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002708 // Array constructors should have been already pruned from the code.
2709 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002710
2711 if (visit == PreVisit)
2712 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002713 TString constructorName;
2714 if (node->getBasicType() == EbtStruct)
2715 {
2716 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2717 }
2718 else
2719 {
2720 constructorName =
2721 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2722 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002723 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002724 }
2725 else if (visit == InVisit)
2726 {
2727 out << ", ";
2728 }
2729 else if (visit == PostVisit)
2730 {
2731 out << ")";
2732 }
2733}
2734
Jamie Madill8c46ab12015-12-07 16:39:19 -05002735const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2736 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002737 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002738{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002739 const TConstantUnion *constUnionIterated = constUnion;
2740
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002741 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002742 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002743 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002744 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002745
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002747
Jamie Madill98493dd2013-07-08 14:39:03 -04002748 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002749 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002750 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002751 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002752
Jamie Madill98493dd2013-07-08 14:39:03 -04002753 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002754 {
2755 out << ", ";
2756 }
2757 }
2758
2759 out << ")";
2760 }
2761 else
2762 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002763 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002764 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002765
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002766 if (writeType)
2767 {
Jamie Madill033dae62014-06-18 12:56:28 -04002768 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002769 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002770 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002771 if (writeType)
2772 {
2773 out << ")";
2774 }
2775 }
2776
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002777 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002778}
2779
Olli Etuahod68924e2017-01-02 17:34:40 +00002780void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002781{
Olli Etuahod68924e2017-01-02 17:34:40 +00002782 if (visit == PreVisit)
2783 {
2784 const char *opStr = GetOperatorString(op);
2785 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
2786 out << "(";
2787 }
2788 else
2789 {
2790 outputTriplet(out, visit, nullptr, ", ", ")");
2791 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02002792}
2793
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002794bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
2795 TIntermSymbol *symbolNode,
2796 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05002797{
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002798 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getSymbol());
Jamie Madill37997142015-01-28 10:06:34 -05002799
Olli Etuaho4728bdc2017-12-20 17:51:08 +02002800 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05002801 {
2802 // Type already printed
2803 out << "t" + str(mUniqueIndex) + " = ";
2804 expression->traverse(this);
2805 out << ", ";
2806 symbolNode->traverse(this);
2807 out << " = t" + str(mUniqueIndex);
2808
2809 mUniqueIndex++;
2810 return true;
2811 }
2812
2813 return false;
2814}
2815
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002816bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2817{
2818 // We support writing constant unions and constructors that only take constant unions as
2819 // parameters as HLSL literals.
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002820 return !expression->getType().isArrayOfArrays() &&
2821 (expression->getAsConstantUnion() ||
2822 expression->isConstructorWithOnlyConstantUnionParameters());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002823}
2824
2825bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2826 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002827 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002828{
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002829 if (canWriteAsHLSLLiteral(initializer))
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002830 {
2831 symbolNode->traverse(this);
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002832 ASSERT(!symbolNode->getType().isArrayOfArrays());
2833 if (symbolNode->getType().isArray())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002834 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002835 out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002836 }
2837 out << " = {";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002838 if (initializer->getAsConstantUnion())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002839 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002840 TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002841 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002842 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002843 }
2844 else
2845 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002846 TIntermAggregate *constructor = initializer->getAsAggregate();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002847 ASSERT(constructor != nullptr);
2848 for (TIntermNode *&node : *constructor->getSequence())
2849 {
2850 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2851 ASSERT(nodeConst);
2852 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
Olli Etuaho56a2f952016-12-08 12:16:27 +00002853 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002854 if (node != constructor->getSequence()->back())
2855 {
2856 out << ", ";
2857 }
2858 }
2859 }
2860 out << "}";
2861 return true;
2862 }
2863 return false;
2864}
2865
Jamie Madill55e79e02015-02-09 15:35:00 -05002866TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2867{
2868 const TFieldList &fields = structure.fields();
2869
2870 for (const auto &eqFunction : mStructEqualityFunctions)
2871 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002872 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05002873 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002874 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002875 }
2876 }
2877
2878 const TString &structNameString = StructNameString(structure);
2879
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002880 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002881 function->structure = &structure;
2882 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05002883
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002884 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05002885
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002886 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
2887 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002888 << "{\n"
2889 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002890
2891 for (size_t i = 0; i < fields.size(); i++)
2892 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002893 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05002894 const TType *fieldType = field->type();
2895
2896 const TString &fieldNameA = "a." + Decorate(field->name());
2897 const TString &fieldNameB = "b." + Decorate(field->name());
2898
2899 if (i > 0)
2900 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002901 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05002902 }
2903
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002904 fnOut << "(";
2905 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2906 fnOut << fieldNameA;
2907 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2908 fnOut << fieldNameB;
2909 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2910 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05002911 }
2912
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002913 fnOut << ";\n"
2914 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002915
2916 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05002917
2918 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002919 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05002920
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002921 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05002922}
2923
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002924TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002925{
2926 for (const auto &eqFunction : mArrayEqualityFunctions)
2927 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002928 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02002929 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002930 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002931 }
2932 }
2933
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002934 TType elementType(type);
2935 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002936
Olli Etuaho12690762015-03-31 12:55:28 +03002937 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002938 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002939
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002940 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002941
2942 TInfoSinkBase fnOut;
2943
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002944 const TString &typeName = TypeString(type);
2945 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
2946 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02002947 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002948 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002949 << type.getOutermostArraySize()
2950 << "; ++i)\n"
2951 " {\n"
2952 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02002953
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002954 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002955 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002956 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002957 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002958 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002959
2960 fnOut << ") { return false; }\n"
2961 " }\n"
2962 " return true;\n"
2963 "}\n";
2964
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002965 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02002966
2967 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002968 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02002969
Olli Etuahoae37a5c2015-03-20 16:50:15 +02002970 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02002971}
2972
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002973TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03002974{
2975 for (const auto &assignFunction : mArrayAssignmentFunctions)
2976 {
2977 if (assignFunction.type == type)
2978 {
2979 return assignFunction.functionName;
2980 }
2981 }
2982
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002983 TType elementType(type);
2984 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03002985
2986 ArrayHelperFunction function;
2987 function.type = type;
2988
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002989 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03002990
2991 TInfoSinkBase fnOut;
2992
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002993 const TString &typeName = TypeString(type);
2994 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
2995 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002996 << "{\n"
2997 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03002998 << type.getOutermostArraySize()
2999 << "; ++i)\n"
3000 " {\n"
3001 " ";
3002
3003 outputAssign(PreVisit, elementType, fnOut);
3004 fnOut << "a[i]";
3005 outputAssign(InVisit, elementType, fnOut);
3006 fnOut << "b[i]";
3007 outputAssign(PostVisit, elementType, fnOut);
3008
3009 fnOut << ";\n"
3010 " }\n"
3011 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003012
3013 function.functionDefinition = fnOut.c_str();
3014
3015 mArrayAssignmentFunctions.push_back(function);
3016
3017 return function.functionName;
3018}
3019
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003020TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003021{
3022 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3023 {
3024 if (constructIntoFunction.type == type)
3025 {
3026 return constructIntoFunction.functionName;
3027 }
3028 }
3029
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003030 TType elementType(type);
3031 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003032
3033 ArrayHelperFunction function;
3034 function.type = type;
3035
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003036 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003037
3038 TInfoSinkBase fnOut;
3039
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003040 const TString &typeName = TypeString(type);
3041 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3042 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003043 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003044 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003045 }
3046 fnOut << ")\n"
3047 "{\n";
3048
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003049 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003050 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003051 fnOut << " ";
3052 outputAssign(PreVisit, elementType, fnOut);
3053 fnOut << "a[" << i << "]";
3054 outputAssign(InVisit, elementType, fnOut);
3055 fnOut << "b" << i;
3056 outputAssign(PostVisit, elementType, fnOut);
3057 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003058 }
3059 fnOut << "}\n";
3060
3061 function.functionDefinition = fnOut.c_str();
3062
3063 mArrayConstructIntoFunctions.push_back(function);
3064
3065 return function.functionName;
3066}
3067
Jamie Madill2e295e22015-04-29 10:41:33 -04003068void OutputHLSL::ensureStructDefined(const TType &type)
3069{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003070 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003071 if (structure)
3072 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003073 ASSERT(type.getBasicType() == EbtStruct);
3074 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003075 }
3076}
3077
Jamie Madill45bcc782016-11-07 13:58:48 -05003078} // namespace sh