blob: aa81c119f512cd0a38c9897647c8273cb54e6627 [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
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08009#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000010#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000011#include <cfloat>
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"
Brandon Jones4a22f4b2018-10-23 14:36:47 -070016#include "compiler/translator/AtomicCounterFunctionHLSL.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020017#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/BuiltInFunctionEmulatorHLSL.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"
Qin Jiajia3e217f62018-08-28 16:55:20 +080021#include "compiler/translator/ResourcesHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030023#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050024#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/UtilsHLSL.h"
26#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020027#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020028#include "compiler/translator/tree_util/FindSymbolNode.h"
29#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050030#include "compiler/translator/util.h"
31
Jamie Madill45bcc782016-11-07 13:58:48 -050032namespace sh
33{
34
Olli Etuaho96f6adf2017-08-16 11:18:54 +030035namespace
36{
37
38TString ArrayHelperFunctionName(const char *prefix, const TType &type)
39{
40 TStringStream fnName;
41 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080042 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030043 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080044 for (unsigned int arraySize : *type.getArraySizes())
45 {
46 fnName << arraySize << "_";
47 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030048 }
49 fnName << TypeString(type);
50 return fnName.str();
51}
52
Olli Etuaho40dbdd62017-10-13 13:34:19 +030053bool IsDeclarationWrittenOut(TIntermDeclaration *node)
54{
55 TIntermSequence *sequence = node->getSequence();
56 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
57 ASSERT(sequence->size() == 1);
58 ASSERT(variable);
59 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080060 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030061}
62
Qin Jiajiaa735ee22018-05-18 13:29:09 +080063bool IsInStd140UniformBlock(TIntermTyped *node)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020064{
65 TIntermBinary *binaryNode = node->getAsBinaryNode();
66
67 if (binaryNode)
68 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080069 return IsInStd140UniformBlock(binaryNode->getLeft());
Olli Etuaho2ef23e22017-11-01 16:39:11 +020070 }
71
72 const TType &type = node->getType();
73
Qin Jiajiaa735ee22018-05-18 13:29:09 +080074 if (type.getQualifier() == EvqUniform)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020075 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080076 // determine if we are in the standard layout
77 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
78 if (interfaceBlock)
79 {
80 return (interfaceBlock->blockStorage() == EbsStd140);
81 }
Olli Etuaho2ef23e22017-11-01 16:39:11 +020082 }
83
84 return false;
85}
86
Jiawei Shaoa6a78422018-06-28 08:32:54 +080087const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
88{
89 switch (op)
90 {
91 case EOpAtomicAdd:
92 return "InterlockedAdd(";
93 case EOpAtomicMin:
94 return "InterlockedMin(";
95 case EOpAtomicMax:
96 return "InterlockedMax(";
97 case EOpAtomicAnd:
98 return "InterlockedAnd(";
99 case EOpAtomicOr:
100 return "InterlockedOr(";
101 case EOpAtomicXor:
102 return "InterlockedXor(";
103 case EOpAtomicExchange:
104 return "InterlockedExchange(";
105 case EOpAtomicCompSwap:
106 return "InterlockedCompareExchange(";
107 default:
108 UNREACHABLE();
109 return "";
110 }
111}
112
113bool IsAtomicFunctionDirectAssign(const TIntermBinary &node)
114{
115 return node.getOp() == EOpAssign && node.getRight()->getAsAggregate() &&
116 IsAtomicFunction(node.getRight()->getAsAggregate()->getOp());
117}
118
jchen10efe061b2018-11-13 16:44:40 +0800119const char *kZeros = "_ANGLE_ZEROS_";
120constexpr int kZeroCount = 256;
121std::string DefineZeroArray()
122{
123 std::stringstream ss;
124 // For 'static', if the declaration does not include an initializer, the value is set to zero.
125 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
126 ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
127 return ss.str();
128}
129
130std::string GetZeroInitializer(size_t size)
131{
132 std::stringstream ss;
133 size_t quotient = size / kZeroCount;
134 size_t reminder = size % kZeroCount;
135
136 for (size_t i = 0; i < quotient; ++i)
137 {
138 if (i != 0)
139 {
140 ss << ", ";
141 }
142 ss << kZeros;
143 }
144
145 for (size_t i = 0; i < reminder; ++i)
146 {
147 if (quotient != 0 || i != 0)
148 {
149 ss << ", ";
150 }
151 ss << "0";
152 }
153
154 return ss.str();
155}
156
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300157} // anonymous namespace
158
Olli Etuahoc71862a2017-12-21 12:58:29 +0200159TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
160 const TVariable *aInstanceVariable)
161 : block(aBlock), instanceVariable(aInstanceVariable)
Jamie Madillb980c562018-11-27 11:34:27 -0500162{}
Olli Etuahoc71862a2017-12-21 12:58:29 +0200163
Olli Etuaho56a2f952016-12-08 12:16:27 +0000164void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300165{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000166 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
167 // regardless.
168 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
169 mOutputType == SH_HLSL_4_1_OUTPUT)
170 {
171 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
172 }
173 else
174 {
175 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
176 }
177}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300178
Olli Etuaho56a2f952016-12-08 12:16:27 +0000179void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200180{
181 ASSERT(constUnion != nullptr);
182 switch (constUnion->getType())
183 {
184 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000185 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200186 break;
187 case EbtInt:
188 out << constUnion->getIConst();
189 break;
190 case EbtUInt:
191 out << constUnion->getUConst();
192 break;
193 case EbtBool:
194 out << constUnion->getBConst();
195 break;
196 default:
197 UNREACHABLE();
198 }
199}
200
Olli Etuaho56a2f952016-12-08 12:16:27 +0000201const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
202 const TConstantUnion *const constUnion,
203 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200204{
205 const TConstantUnion *constUnionIterated = constUnion;
206 for (size_t i = 0; i < size; i++, constUnionIterated++)
207 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000208 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200209
210 if (i != size - 1)
211 {
212 out << ", ";
213 }
214 }
215 return constUnionIterated;
216}
217
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800218OutputHLSL::OutputHLSL(sh::GLenum shaderType,
219 int shaderVersion,
220 const TExtensionBehavior &extensionBehavior,
221 const char *sourcePath,
222 ShShaderOutput outputType,
223 int numRenderTargets,
224 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300225 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300226 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300227 TSymbolTable *symbolTable,
228 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300229 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200230 mShaderType(shaderType),
231 mShaderVersion(shaderVersion),
232 mExtensionBehavior(extensionBehavior),
233 mSourcePath(sourcePath),
234 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700235 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300236 mInsideFunction(false),
237 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000238 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300239 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300240 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300241 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800243 mUsesFragColor = false;
244 mUsesFragData = false;
245 mUsesDepthRange = false;
246 mUsesFragCoord = false;
247 mUsesPointCoord = false;
248 mUsesFrontFacing = false;
249 mUsesPointSize = false;
250 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300251 mHasMultiviewExtensionEnabled =
252 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300253 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500254 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800256 mUsesNumWorkGroups = false;
257 mUsesWorkGroupID = false;
258 mUsesLocalInvocationID = false;
259 mUsesGlobalInvocationID = false;
260 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500261 mUsesXor = false;
262 mUsesDiscardRewriting = false;
263 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530264 mRequiresIEEEStrictCompiling = false;
jchen10efe061b2018-11-13 16:44:40 +0800265 mUseZeroArray = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000266
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000267 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000268
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500269 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000270 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500271 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000272
Yunchao Hed7297bf2017-04-19 15:27:10 +0800273 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000274
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700275 mStructureHLSL = new StructureHLSL;
276 mTextureFunctionHLSL = new TextureFunctionHLSL;
277 mImageFunctionHLSL = new ImageFunctionHLSL;
278 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400279
Olli Etuahod8724a92017-12-29 18:40:36 +0200280 unsigned int firstUniformRegister =
281 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800282 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200283
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200284 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000285 {
Arun Patole63419392015-03-13 11:51:07 +0530286 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500287 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
288 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530289 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800290 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000291 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000292
Geoff Lang00140f42016-02-03 18:47:33 +0000293 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800294 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800295
296 mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297}
298
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000299OutputHLSL::~OutputHLSL()
300{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800301 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400302 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800303 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300304 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800305 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700306 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200307 for (auto &eqFunction : mStructEqualityFunctions)
308 {
309 SafeDelete(eqFunction);
310 }
311 for (auto &eqFunction : mArrayEqualityFunctions)
312 {
313 SafeDelete(eqFunction);
314 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000315}
316
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200317void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000318{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200319 BuiltInFunctionEmulator builtInFunctionEmulator;
320 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800321 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
322 {
323 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
324 mShaderVersion);
325 }
326
Olli Etuahodfa75e82017-01-23 09:43:06 -0800327 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500328
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700329 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000330 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700331 ASSERT(success == CallDAG::INITDAG_SUCCESS);
332 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700333
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200334 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
335 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
336 // the shader code. When we add shader storage blocks we might also consider an alternative
337 // solution, since the struct mapping won't work very well for shader storage blocks.
338
Jamie Madill37997142015-01-28 10:06:34 -0500339 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500340 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200341 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500342 mInfoSinkStack.pop();
343
Jamie Madill37997142015-01-28 10:06:34 -0500344 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500345 mInfoSinkStack.pop();
346
Jamie Madill32aab012015-01-27 14:12:26 -0500347 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200348 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500349 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000350
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200351 objSink << mHeader.c_str();
352 objSink << mBody.c_str();
353 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200354
Olli Etuahodfa75e82017-01-23 09:43:06 -0800355 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000356}
357
Qin Jiajiaa602f902018-09-11 14:40:24 +0800358const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
359{
360 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
361}
362
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800363const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400364{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800365 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400366}
367
Jamie Madill9fe25e92014-07-18 10:33:08 -0400368const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
369{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800370 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400371}
372
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200373TString OutputHLSL::structInitializerString(int indent,
374 const TType &type,
375 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400376{
377 TString init;
378
Olli Etuahoed049ab2017-06-30 17:38:33 +0300379 TString indentString;
380 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400381 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300382 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400383 }
384
Olli Etuahoed049ab2017-06-30 17:38:33 +0300385 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400386 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300387 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300388 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400389 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300390 TStringStream indexedString;
391 indexedString << name << "[" << arrayIndex << "]";
392 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300393 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300394 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300395 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300396 {
397 init += ",";
398 }
399 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400400 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300401 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400402 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300403 else if (type.getBasicType() == EbtStruct)
404 {
405 init += indentString + "{\n";
406 const TStructure &structure = *type.getStruct();
407 const TFieldList &fields = structure.fields();
408 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
409 {
410 const TField &field = *fields[fieldIndex];
411 const TString &fieldName = name + "." + Decorate(field.name());
412 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400413
Olli Etuahoed049ab2017-06-30 17:38:33 +0300414 init += structInitializerString(indent + 1, fieldType, fieldName);
415 if (fieldIndex < fields.size() - 1)
416 {
417 init += ",";
418 }
419 init += "\n";
420 }
421 init += indentString + "}";
422 }
423 else
424 {
425 init += indentString + name;
426 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400427
428 return init;
429}
430
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
432{
433 TString mappedStructs;
434
435 for (auto &mappedStruct : std140Structs)
436 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200437 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200438 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800439 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
440 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200441 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800442 case EvqUniform:
443 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
444 {
445 continue;
446 }
447 break;
448 case EvqBuffer:
449 continue;
450 default:
451 UNREACHABLE();
452 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200453 }
454
455 unsigned int instanceCount = 1u;
456 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
457 if (isInstanceArray)
458 {
459 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
460 }
461
462 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
463 ++instanceArrayIndex)
464 {
465 TString originalName;
466 TString mappedName("map");
467
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200468 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200469 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200470 const ImmutableString &instanceName =
471 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200472 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
473 if (isInstanceArray)
474 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800475 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200476 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200477 originalName += instanceString;
478 mappedName += instanceString;
479 originalName += ".";
480 mappedName += "_";
481 }
482
483 TString fieldName = Decorate(mappedStruct.field->name());
484 originalName += fieldName;
485 mappedName += fieldName;
486
487 TType *structType = mappedStruct.field->type();
488 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200489 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200490
491 if (structType->isArray())
492 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300493 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200494 }
495
496 mappedStructs += " =\n";
497 mappedStructs += structInitializerString(0, *structType, originalName);
498 mappedStructs += ";\n";
499 }
500 }
501 return mappedStructs;
502}
503
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300504void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300506 for (const auto &attribute : mReferencedAttributes)
507 {
508 const TType &type = attribute.second->getType();
509 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400510
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300511 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
512 << zeroInitializer(type) << ";\n";
513 }
514}
515
516void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
517{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200518 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000519 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800520 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000521
522 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300523 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300524 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
525 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000526 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300527}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000528
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300529void OutputHLSL::header(TInfoSinkBase &out,
530 const std::vector<MappedStruct> &std140Structs,
531 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
532{
533 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000534
Jamie Madill8daaba12014-06-13 10:04:33 -0400535 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400536
Qin Jiajia3e217f62018-08-28 16:55:20 +0800537 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
538 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800539 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400540
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200541 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500542 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200543 out << "\n// Equality functions\n\n";
544 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500545 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200546 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200547 }
548 }
Olli Etuaho12690762015-03-31 12:55:28 +0300549 if (!mArrayAssignmentFunctions.empty())
550 {
551 out << "\n// Assignment functions\n\n";
552 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
553 {
554 out << assignmentFunction.functionDefinition << "\n";
555 }
556 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300557 if (!mArrayConstructIntoFunctions.empty())
558 {
559 out << "\n// Array constructor functions\n\n";
560 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
561 {
562 out << constructIntoFunction.functionDefinition << "\n";
563 }
564 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200565
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500566 if (mUsesDiscardRewriting)
567 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400568 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500569 }
570
Nicolas Capens655fe362014-04-11 13:12:34 -0400571 if (mUsesNestedBreak)
572 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400573 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400574 }
575
Arun Patole44efa0b2015-03-04 17:11:05 +0530576 if (mRequiresIEEEStrictCompiling)
577 {
578 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
579 }
580
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400581 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
582 "#define LOOP [loop]\n"
583 "#define FLATTEN [flatten]\n"
584 "#else\n"
585 "#define LOOP\n"
586 "#define FLATTEN\n"
587 "#endif\n";
588
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700589 // array stride for atomic counter buffers is always 4 per original extension
590 // ARB_shader_atomic_counters and discussion on
591 // https://github.com/KhronosGroup/OpenGL-API/issues/5
592 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
593
jchen10efe061b2018-11-13 16:44:40 +0800594 if (mUseZeroArray)
595 {
596 out << DefineZeroArray() << "\n";
597 }
598
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200599 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300601 const bool usingMRTExtension =
602 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000603
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000604 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300605 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400606 out << "\n";
607
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200608 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000609 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200610 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000611 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200612 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800613 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400614
Olli Etuahofbb1c792018-01-19 16:26:59 +0200615 out << "static " << TypeString(variableType) << " out_" << variableName
616 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000617 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000618 }
Jamie Madill46131a32013-06-20 11:55:50 -0400619 else
620 {
621 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
622
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800623 out << "static float4 gl_Color[" << numColorValues
624 << "] =\n"
625 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400626 for (unsigned int i = 0; i < numColorValues; i++)
627 {
628 out << " float4(0, 0, 0, 0)";
629 if (i + 1 != numColorValues)
630 {
631 out << ",";
632 }
633 out << "\n";
634 }
635
636 out << "};\n";
637 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000638
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400639 if (mUsesFragDepth)
640 {
641 out << "static float gl_Depth = 0.0;\n";
642 }
643
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000644 if (mUsesFragCoord)
645 {
646 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
647 }
648
649 if (mUsesPointCoord)
650 {
651 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
652 }
653
654 if (mUsesFrontFacing)
655 {
656 out << "static bool gl_FrontFacing = false;\n";
657 }
658
659 out << "\n";
660
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000661 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000662 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000663 out << "struct gl_DepthRangeParameters\n"
664 "{\n"
665 " float near;\n"
666 " float far;\n"
667 " float diff;\n"
668 "};\n"
669 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000670 }
671
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200672 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000673 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000674 out << "cbuffer DriverConstants : register(b1)\n"
675 "{\n";
676
677 if (mUsesDepthRange)
678 {
679 out << " float3 dx_DepthRange : packoffset(c0);\n";
680 }
681
682 if (mUsesFragCoord)
683 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000684 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000685 }
686
687 if (mUsesFragCoord || mUsesFrontFacing)
688 {
689 out << " float3 dx_DepthFront : packoffset(c2);\n";
690 }
691
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800692 if (mUsesFragCoord)
693 {
694 // dx_ViewScale is only used in the fragment shader to correct
695 // the value for glFragCoord if necessary
696 out << " float2 dx_ViewScale : packoffset(c3);\n";
697 }
698
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 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800708 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200709 }
710
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000711 out << "};\n";
712 }
713 else
714 {
715 if (mUsesDepthRange)
716 {
717 out << "uniform float3 dx_DepthRange : register(c0);";
718 }
719
720 if (mUsesFragCoord)
721 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000722 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000723 }
724
725 if (mUsesFragCoord || mUsesFrontFacing)
726 {
727 out << "uniform float3 dx_DepthFront : register(c2);\n";
728 }
729 }
730
731 out << "\n";
732
733 if (mUsesDepthRange)
734 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
736 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000737 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000738 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000739
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000740 if (usingMRTExtension && mNumRenderTargets > 1)
741 {
742 out << "#define GL_USES_MRT\n";
743 }
744
745 if (mUsesFragColor)
746 {
747 out << "#define GL_USES_FRAG_COLOR\n";
748 }
749
750 if (mUsesFragData)
751 {
752 out << "#define GL_USES_FRAG_DATA\n";
753 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754 }
Xinghua Caob1239382016-12-13 15:07:05 +0800755 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000757 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300758 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000759 out << "\n"
760 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400761
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000762 if (mUsesPointSize)
763 {
764 out << "static float gl_PointSize = float(1);\n";
765 }
766
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000767 if (mUsesInstanceID)
768 {
769 out << "static int gl_InstanceID;";
770 }
771
Corentin Wallezb076add2016-01-11 16:45:46 -0500772 if (mUsesVertexID)
773 {
774 out << "static int gl_VertexID;";
775 }
776
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000777 out << "\n"
778 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300779 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000780 out << "\n";
781
782 if (mUsesDepthRange)
783 {
784 out << "struct gl_DepthRangeParameters\n"
785 "{\n"
786 " float near;\n"
787 " float far;\n"
788 " float diff;\n"
789 "};\n"
790 "\n";
791 }
792
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200793 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000794 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800795 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500796 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800797
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000798 if (mUsesDepthRange)
799 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800800 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000801 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800802
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800803 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
804 // shaders. However, we declare it for all shaders (including Feature Level 10+).
805 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
806 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800807 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800808 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800809 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800810
Martin Radev72b4e1e2017-08-31 15:42:56 +0300811 if (mHasMultiviewExtensionEnabled)
812 {
813 // We have to add a value which we can use to keep track of which multi-view code
814 // path is to be selected in the GS.
815 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
816 }
817
Olli Etuaho618bebc2016-01-15 16:40:00 +0200818 if (mOutputType == SH_HLSL_4_1_OUTPUT)
819 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800820 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200821 }
822
Austin Kinross4fd18b12014-12-22 12:32:05 -0800823 out << "};\n"
824 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000825 }
826 else
827 {
828 if (mUsesDepthRange)
829 {
830 out << "uniform float3 dx_DepthRange : register(c0);\n";
831 }
832
Cooper Partine6664f02015-01-09 16:22:24 -0800833 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
834 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000835 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000836 }
837
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000838 if (mUsesDepthRange)
839 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500840 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
841 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000842 "\n";
843 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400844 }
Xinghua Caob1239382016-12-13 15:07:05 +0800845 else // Compute shader
846 {
847 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800848
849 out << "cbuffer DriverConstants : register(b1)\n"
850 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800851 if (mUsesNumWorkGroups)
852 {
Xinghua Caob1239382016-12-13 15:07:05 +0800853 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800854 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800855 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800856 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800857 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800858
Jiawei Shao203b26f2018-07-25 10:30:43 +0800859 std::ostringstream systemValueDeclaration;
860 std::ostringstream glBuiltinInitialization;
861
862 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
863 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
864 << "{\n";
865
Xinghua Caob1239382016-12-13 15:07:05 +0800866 if (mUsesWorkGroupID)
867 {
868 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800869 systemValueDeclaration << " uint3 dx_WorkGroupID : "
870 << "SV_GroupID;\n";
871 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800872 }
873
874 if (mUsesLocalInvocationID)
875 {
876 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800877 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
878 << "SV_GroupThreadID;\n";
879 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800880 }
881
882 if (mUsesGlobalInvocationID)
883 {
884 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800885 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
886 << "SV_DispatchThreadID;\n";
887 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800888 }
889
890 if (mUsesLocalInvocationIndex)
891 {
892 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800893 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
894 << "SV_GroupIndex;\n";
895 glBuiltinInitialization
896 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800897 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800898
899 systemValueDeclaration << "};\n\n";
900 glBuiltinInitialization << "};\n\n";
901
902 out << systemValueDeclaration.str();
903 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800904 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000905
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800906 if (!mappedStructs.empty())
907 {
908 out << "// Structures from std140 blocks with padding removed\n";
909 out << "\n";
910 out << mappedStructs;
911 out << "\n";
912 }
913
Geoff Lang1fe74c72016-08-25 13:23:01 -0400914 bool getDimensionsIgnoresBaseLevel =
915 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
916 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800917 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700918 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000920 if (mUsesFragCoord)
921 {
922 out << "#define GL_USES_FRAG_COORD\n";
923 }
924
925 if (mUsesPointCoord)
926 {
927 out << "#define GL_USES_POINT_COORD\n";
928 }
929
930 if (mUsesFrontFacing)
931 {
932 out << "#define GL_USES_FRONT_FACING\n";
933 }
934
935 if (mUsesPointSize)
936 {
937 out << "#define GL_USES_POINT_SIZE\n";
938 }
939
Martin Radev41ac68e2017-06-06 12:16:58 +0300940 if (mHasMultiviewExtensionEnabled)
941 {
942 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
943 }
944
945 if (mUsesViewID)
946 {
947 out << "#define GL_USES_VIEW_ID\n";
948 }
949
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400950 if (mUsesFragDepth)
951 {
952 out << "#define GL_USES_FRAG_DEPTH\n";
953 }
954
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000955 if (mUsesDepthRange)
956 {
957 out << "#define GL_USES_DEPTH_RANGE\n";
958 }
959
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000960 if (mUsesXor)
961 {
962 out << "bool xor(bool p, bool q)\n"
963 "{\n"
964 " return (p || q) && !(p && q);\n"
965 "}\n"
966 "\n";
967 }
968
Olli Etuahodfa75e82017-01-23 09:43:06 -0800969 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970}
971
972void OutputHLSL::visitSymbol(TIntermSymbol *node)
973{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200974 const TVariable &variable = node->variable();
975
976 // Empty symbols can only appear in declarations and function arguments, and in either of those
977 // cases the symbol nodes are not visited.
978 ASSERT(variable.symbolType() != SymbolType::Empty);
979
Jamie Madill32aab012015-01-27 14:12:26 -0500980 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981
Jamie Madill570e04d2013-06-21 09:15:33 -0400982 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800983 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400984 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200985 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400986 }
987
Olli Etuahofbb1c792018-01-19 16:26:59 +0200988 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200989 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200990
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000991 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000992 {
993 mUsesDepthRange = true;
994 out << name;
995 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700996 else if (IsAtomicCounter(variable.getType().getBasicType()))
997 {
998 const TType &variableType = variable.getType();
999 if (variableType.getQualifier() == EvqUniform)
1000 {
1001 TLayoutQualifier layout = variableType.getLayoutQualifier();
1002 mReferencedUniforms[uniqueId.get()] = &variable;
1003 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1004 }
1005 else
1006 {
1007 TString varName = DecorateVariableIfNeeded(variable);
1008 out << varName << ", " << varName << "_offset";
1009 }
1010 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011 else
1012 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001013 const TType &variableType = variable.getType();
1014 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001015
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001016 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +02001017
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001018 if (qualifier == EvqUniform)
1019 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001020 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001021
1022 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001023 {
Olli Etuahoc71862a2017-12-21 12:58:29 +02001024 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1025 {
1026 const TVariable *instanceVariable = nullptr;
1027 if (variableType.isInterfaceBlock())
1028 {
1029 instanceVariable = &variable;
1030 }
1031 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1032 new TReferencedBlock(interfaceBlock, instanceVariable);
1033 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001034 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001035 else
1036 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001037 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001038 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001039
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001040 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001041 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001042 else if (qualifier == EvqBuffer)
1043 {
1044 UNREACHABLE();
1045 }
Jamie Madill19571812013-08-12 15:26:34 -07001046 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001047 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001048 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001049 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001050 }
Jamie Madill033dae62014-06-18 12:56:28 -04001051 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001052 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001053 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001054 out << DecorateVariableIfNeeded(variable);
1055 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001056 {
1057 mUsesViewID = true;
1058 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001059 }
Jamie Madill19571812013-08-12 15:26:34 -07001060 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001061 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001062 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001063 out << "out_" << name;
1064 }
1065 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001066 {
1067 out << "gl_Color[0]";
1068 mUsesFragColor = true;
1069 }
1070 else if (qualifier == EvqFragData)
1071 {
1072 out << "gl_Color";
1073 mUsesFragData = true;
1074 }
1075 else if (qualifier == EvqFragCoord)
1076 {
1077 mUsesFragCoord = true;
1078 out << name;
1079 }
1080 else if (qualifier == EvqPointCoord)
1081 {
1082 mUsesPointCoord = true;
1083 out << name;
1084 }
1085 else if (qualifier == EvqFrontFacing)
1086 {
1087 mUsesFrontFacing = true;
1088 out << name;
1089 }
1090 else if (qualifier == EvqPointSize)
1091 {
1092 mUsesPointSize = true;
1093 out << name;
1094 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001095 else if (qualifier == EvqInstanceID)
1096 {
1097 mUsesInstanceID = true;
1098 out << name;
1099 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001100 else if (qualifier == EvqVertexID)
1101 {
1102 mUsesVertexID = true;
1103 out << name;
1104 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001105 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001106 {
1107 mUsesFragDepth = true;
1108 out << "gl_Depth";
1109 }
Xinghua Caob1239382016-12-13 15:07:05 +08001110 else if (qualifier == EvqNumWorkGroups)
1111 {
1112 mUsesNumWorkGroups = true;
1113 out << name;
1114 }
1115 else if (qualifier == EvqWorkGroupID)
1116 {
1117 mUsesWorkGroupID = true;
1118 out << name;
1119 }
1120 else if (qualifier == EvqLocalInvocationID)
1121 {
1122 mUsesLocalInvocationID = true;
1123 out << name;
1124 }
1125 else if (qualifier == EvqGlobalInvocationID)
1126 {
1127 mUsesGlobalInvocationID = true;
1128 out << name;
1129 }
1130 else if (qualifier == EvqLocalInvocationIndex)
1131 {
1132 mUsesLocalInvocationIndex = true;
1133 out << name;
1134 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001135 else
1136 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001137 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001138 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139 }
1140}
1141
Olli Etuaho7fb49552015-03-18 17:27:44 +02001142void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1143{
1144 if (type.isScalar() && !type.isArray())
1145 {
1146 if (op == EOpEqual)
1147 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001148 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001149 }
1150 else
1151 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001152 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001153 }
1154 }
1155 else
1156 {
1157 if (visit == PreVisit && op == EOpNotEqual)
1158 {
1159 out << "!";
1160 }
1161
1162 if (type.isArray())
1163 {
1164 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001165 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001166 }
1167 else if (type.getBasicType() == EbtStruct)
1168 {
1169 const TStructure &structure = *type.getStruct();
1170 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001171 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001172 }
1173 else
1174 {
1175 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001176 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001177 }
1178 }
1179}
1180
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001181void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1182{
1183 if (type.isArray())
1184 {
1185 const TString &functionName = addArrayAssignmentFunction(type);
1186 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1187 }
1188 else
1189 {
1190 outputTriplet(out, visit, "(", " = ", ")");
1191 }
1192}
1193
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001194bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001195{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001196 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001197 {
1198 TIntermNode *ancestor = getAncestorNode(n);
1199 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1200 if (ancestorBinary == nullptr)
1201 {
1202 return false;
1203 }
1204 switch (ancestorBinary->getOp())
1205 {
1206 case EOpIndexDirectStruct:
1207 {
1208 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1209 const TIntermConstantUnion *index =
1210 ancestorBinary->getRight()->getAsConstantUnion();
1211 const TField *field = structure->fields()[index->getIConst(0)];
1212 if (IsSampler(field->type()->getBasicType()))
1213 {
1214 return true;
1215 }
1216 break;
1217 }
1218 case EOpIndexDirect:
1219 break;
1220 default:
1221 // Returning a sampler from indirect indexing is not supported.
1222 return false;
1223 }
1224 }
1225 return false;
1226}
1227
Olli Etuahob6fa0432016-09-28 16:28:05 +01001228bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1229{
1230 TInfoSinkBase &out = getInfoSink();
1231 if (visit == PostVisit)
1232 {
1233 out << ".";
1234 node->writeOffsetsAsXYZW(&out);
1235 }
1236 return true;
1237}
1238
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001239bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1240{
Jamie Madill32aab012015-01-27 14:12:26 -05001241 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242
1243 switch (node->getOp())
1244 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001245 case EOpComma:
1246 outputTriplet(out, visit, "(", ", ", ")");
1247 break;
1248 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001249 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001250 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001251 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1252 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001253 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001254 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1255 out << functionName << "(";
1256 node->getLeft()->traverse(this);
1257 TIntermSequence *seq = rightAgg->getSequence();
1258 for (auto &arrayElement : *seq)
1259 {
1260 out << ", ";
1261 arrayElement->traverse(this);
1262 }
1263 out << ")";
1264 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001265 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001266 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1267 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001268 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001269 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001270 // Assignment expressions with atomic functions should be transformed into atomic
1271 // function calls in HLSL.
1272 // e.g. original_value = atomicAdd(dest, value) should be translated into
1273 // InterlockedAdd(dest, value, original_value);
1274 else if (IsAtomicFunctionDirectAssign(*node))
1275 {
1276 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1277 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1278 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1279 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1280 ASSERT(argumentSeq->size() >= 2u);
1281 for (auto &argument : *argumentSeq)
1282 {
1283 argument->traverse(this);
1284 out << ", ";
1285 }
1286 node->getLeft()->traverse(this);
1287 out << ")";
1288 return false;
1289 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001290 else if (IsInShaderStorageBlock(node->getLeft()))
1291 {
1292 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1293 out << ", ";
1294 if (IsInShaderStorageBlock(node->getRight()))
1295 {
1296 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1297 }
1298 else
1299 {
1300 node->getRight()->traverse(this);
1301 }
1302
1303 out << ")";
1304 return false;
1305 }
1306 else if (IsInShaderStorageBlock(node->getRight()))
1307 {
1308 node->getLeft()->traverse(this);
1309 out << " = ";
1310 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1311 return false;
1312 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001313
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001314 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001315 break;
1316 case EOpInitialize:
1317 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001318 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001319 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1320 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001321 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001322
1323 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001324 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001325
1326 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1327 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1328 // new variable is created before the assignment is evaluated), so we need to
1329 // convert
1330 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001331 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001332 {
1333 // Skip initializing the rest of the expression
1334 return false;
1335 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001336 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001337 {
1338 return false;
1339 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001340 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001341 else if (visit == InVisit)
1342 {
1343 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001344 if (IsInShaderStorageBlock(node->getRight()))
1345 {
1346 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1347 return false;
1348 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001349 }
1350 break;
1351 case EOpAddAssign:
1352 outputTriplet(out, visit, "(", " += ", ")");
1353 break;
1354 case EOpSubAssign:
1355 outputTriplet(out, visit, "(", " -= ", ")");
1356 break;
1357 case EOpMulAssign:
1358 outputTriplet(out, visit, "(", " *= ", ")");
1359 break;
1360 case EOpVectorTimesScalarAssign:
1361 outputTriplet(out, visit, "(", " *= ", ")");
1362 break;
1363 case EOpMatrixTimesScalarAssign:
1364 outputTriplet(out, visit, "(", " *= ", ")");
1365 break;
1366 case EOpVectorTimesMatrixAssign:
1367 if (visit == PreVisit)
1368 {
1369 out << "(";
1370 }
1371 else if (visit == InVisit)
1372 {
1373 out << " = mul(";
1374 node->getLeft()->traverse(this);
1375 out << ", transpose(";
1376 }
1377 else
1378 {
1379 out << ")))";
1380 }
1381 break;
1382 case EOpMatrixTimesMatrixAssign:
1383 if (visit == PreVisit)
1384 {
1385 out << "(";
1386 }
1387 else if (visit == InVisit)
1388 {
1389 out << " = transpose(mul(transpose(";
1390 node->getLeft()->traverse(this);
1391 out << "), transpose(";
1392 }
1393 else
1394 {
1395 out << "))))";
1396 }
1397 break;
1398 case EOpDivAssign:
1399 outputTriplet(out, visit, "(", " /= ", ")");
1400 break;
1401 case EOpIModAssign:
1402 outputTriplet(out, visit, "(", " %= ", ")");
1403 break;
1404 case EOpBitShiftLeftAssign:
1405 outputTriplet(out, visit, "(", " <<= ", ")");
1406 break;
1407 case EOpBitShiftRightAssign:
1408 outputTriplet(out, visit, "(", " >>= ", ")");
1409 break;
1410 case EOpBitwiseAndAssign:
1411 outputTriplet(out, visit, "(", " &= ", ")");
1412 break;
1413 case EOpBitwiseXorAssign:
1414 outputTriplet(out, visit, "(", " ^= ", ")");
1415 break;
1416 case EOpBitwiseOrAssign:
1417 outputTriplet(out, visit, "(", " |= ", ")");
1418 break;
1419 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001420 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001421 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001422 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001423 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001424 if (visit == PreVisit)
1425 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001426 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001427 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001428
1429 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001430 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1431 {
1432 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1433 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1434 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001435 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001436 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001437 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001438 return false;
1439 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001440 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001441 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001442 {
1443 // All parts of an expression that access a sampler in a struct need to use _ as
1444 // separator to access the sampler variable that has been moved out of the struct.
1445 outputTriplet(out, visit, "", "_", "");
1446 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001447 else if (IsAtomicCounter(leftType.getBasicType()))
1448 {
1449 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1450 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001451 else
1452 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001453 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001454 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001455 }
1456 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001457 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001458 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001459 // We do not currently support indirect references to interface blocks
1460 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001461
1462 const TType &leftType = node->getLeft()->getType();
1463 if (IsAtomicCounter(leftType.getBasicType()))
1464 {
1465 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1466 }
1467 else
1468 {
1469 outputTriplet(out, visit, "", "[", "]");
1470 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001471 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001472 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001473 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001474 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001475 const TStructure *structure = node->getLeft()->getType().getStruct();
1476 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1477 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001478
Olli Etuaho96963162016-03-21 11:54:33 +02001479 // In cases where indexing returns a sampler, we need to access the sampler variable
1480 // that has been moved out of the struct.
1481 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1482 if (visit == PreVisit && indexingReturnsSampler)
1483 {
1484 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1485 // This prefix is only output at the beginning of the indexing expression, which
1486 // may have multiple parts.
1487 out << "angle";
1488 }
1489 if (!indexingReturnsSampler)
1490 {
1491 // All parts of an expression that access a sampler in a struct need to use _ as
1492 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001493 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001494 }
1495 if (visit == InVisit)
1496 {
1497 if (indexingReturnsSampler)
1498 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001499 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001500 }
1501 else
1502 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001503 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001504 }
1505
1506 return false;
1507 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001508 }
1509 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001510 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001511 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001512 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1513 bool structInStd140UniformBlock =
1514 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1515 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001516 {
1517 out << "map";
1518 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001519 if (visit == InVisit)
1520 {
1521 const TInterfaceBlock *interfaceBlock =
1522 node->getLeft()->getType().getInterfaceBlock();
1523 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1524 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001525 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001526 {
1527 out << "_";
1528 }
1529 else
1530 {
1531 out << ".";
1532 }
1533 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001534
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001535 return false;
1536 }
1537 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001538 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001539 case EOpAdd:
1540 outputTriplet(out, visit, "(", " + ", ")");
1541 break;
1542 case EOpSub:
1543 outputTriplet(out, visit, "(", " - ", ")");
1544 break;
1545 case EOpMul:
1546 outputTriplet(out, visit, "(", " * ", ")");
1547 break;
1548 case EOpDiv:
1549 outputTriplet(out, visit, "(", " / ", ")");
1550 break;
1551 case EOpIMod:
1552 outputTriplet(out, visit, "(", " % ", ")");
1553 break;
1554 case EOpBitShiftLeft:
1555 outputTriplet(out, visit, "(", " << ", ")");
1556 break;
1557 case EOpBitShiftRight:
1558 outputTriplet(out, visit, "(", " >> ", ")");
1559 break;
1560 case EOpBitwiseAnd:
1561 outputTriplet(out, visit, "(", " & ", ")");
1562 break;
1563 case EOpBitwiseXor:
1564 outputTriplet(out, visit, "(", " ^ ", ")");
1565 break;
1566 case EOpBitwiseOr:
1567 outputTriplet(out, visit, "(", " | ", ")");
1568 break;
1569 case EOpEqual:
1570 case EOpNotEqual:
1571 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1572 break;
1573 case EOpLessThan:
1574 outputTriplet(out, visit, "(", " < ", ")");
1575 break;
1576 case EOpGreaterThan:
1577 outputTriplet(out, visit, "(", " > ", ")");
1578 break;
1579 case EOpLessThanEqual:
1580 outputTriplet(out, visit, "(", " <= ", ")");
1581 break;
1582 case EOpGreaterThanEqual:
1583 outputTriplet(out, visit, "(", " >= ", ")");
1584 break;
1585 case EOpVectorTimesScalar:
1586 outputTriplet(out, visit, "(", " * ", ")");
1587 break;
1588 case EOpMatrixTimesScalar:
1589 outputTriplet(out, visit, "(", " * ", ")");
1590 break;
1591 case EOpVectorTimesMatrix:
1592 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1593 break;
1594 case EOpMatrixTimesVector:
1595 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1596 break;
1597 case EOpMatrixTimesMatrix:
1598 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1599 break;
1600 case EOpLogicalOr:
1601 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1602 // been unfolded.
1603 ASSERT(!node->getRight()->hasSideEffects());
1604 outputTriplet(out, visit, "(", " || ", ")");
1605 return true;
1606 case EOpLogicalXor:
1607 mUsesXor = true;
1608 outputTriplet(out, visit, "xor(", ", ", ")");
1609 break;
1610 case EOpLogicalAnd:
1611 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1612 // been unfolded.
1613 ASSERT(!node->getRight()->hasSideEffects());
1614 outputTriplet(out, visit, "(", " && ", ")");
1615 return true;
1616 default:
1617 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001618 }
1619
1620 return true;
1621}
1622
1623bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1624{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001625 TInfoSinkBase &out = getInfoSink();
1626
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001627 switch (node->getOp())
1628 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001629 case EOpNegative:
1630 outputTriplet(out, visit, "(-", "", ")");
1631 break;
1632 case EOpPositive:
1633 outputTriplet(out, visit, "(+", "", ")");
1634 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001635 case EOpLogicalNot:
1636 outputTriplet(out, visit, "(!", "", ")");
1637 break;
1638 case EOpBitwiseNot:
1639 outputTriplet(out, visit, "(~", "", ")");
1640 break;
1641 case EOpPostIncrement:
1642 outputTriplet(out, visit, "(", "", "++)");
1643 break;
1644 case EOpPostDecrement:
1645 outputTriplet(out, visit, "(", "", "--)");
1646 break;
1647 case EOpPreIncrement:
1648 outputTriplet(out, visit, "(++", "", ")");
1649 break;
1650 case EOpPreDecrement:
1651 outputTriplet(out, visit, "(--", "", ")");
1652 break;
1653 case EOpRadians:
1654 outputTriplet(out, visit, "radians(", "", ")");
1655 break;
1656 case EOpDegrees:
1657 outputTriplet(out, visit, "degrees(", "", ")");
1658 break;
1659 case EOpSin:
1660 outputTriplet(out, visit, "sin(", "", ")");
1661 break;
1662 case EOpCos:
1663 outputTriplet(out, visit, "cos(", "", ")");
1664 break;
1665 case EOpTan:
1666 outputTriplet(out, visit, "tan(", "", ")");
1667 break;
1668 case EOpAsin:
1669 outputTriplet(out, visit, "asin(", "", ")");
1670 break;
1671 case EOpAcos:
1672 outputTriplet(out, visit, "acos(", "", ")");
1673 break;
1674 case EOpAtan:
1675 outputTriplet(out, visit, "atan(", "", ")");
1676 break;
1677 case EOpSinh:
1678 outputTriplet(out, visit, "sinh(", "", ")");
1679 break;
1680 case EOpCosh:
1681 outputTriplet(out, visit, "cosh(", "", ")");
1682 break;
1683 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001684 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001685 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 case EOpAtanh:
1687 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001688 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001689 break;
1690 case EOpExp:
1691 outputTriplet(out, visit, "exp(", "", ")");
1692 break;
1693 case EOpLog:
1694 outputTriplet(out, visit, "log(", "", ")");
1695 break;
1696 case EOpExp2:
1697 outputTriplet(out, visit, "exp2(", "", ")");
1698 break;
1699 case EOpLog2:
1700 outputTriplet(out, visit, "log2(", "", ")");
1701 break;
1702 case EOpSqrt:
1703 outputTriplet(out, visit, "sqrt(", "", ")");
1704 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001705 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001706 outputTriplet(out, visit, "rsqrt(", "", ")");
1707 break;
1708 case EOpAbs:
1709 outputTriplet(out, visit, "abs(", "", ")");
1710 break;
1711 case EOpSign:
1712 outputTriplet(out, visit, "sign(", "", ")");
1713 break;
1714 case EOpFloor:
1715 outputTriplet(out, visit, "floor(", "", ")");
1716 break;
1717 case EOpTrunc:
1718 outputTriplet(out, visit, "trunc(", "", ")");
1719 break;
1720 case EOpRound:
1721 outputTriplet(out, visit, "round(", "", ")");
1722 break;
1723 case EOpRoundEven:
1724 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001725 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001726 break;
1727 case EOpCeil:
1728 outputTriplet(out, visit, "ceil(", "", ")");
1729 break;
1730 case EOpFract:
1731 outputTriplet(out, visit, "frac(", "", ")");
1732 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001733 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001734 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001735 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001736 else
1737 outputTriplet(out, visit, "isnan(", "", ")");
1738 mRequiresIEEEStrictCompiling = true;
1739 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001740 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001741 outputTriplet(out, visit, "isinf(", "", ")");
1742 break;
1743 case EOpFloatBitsToInt:
1744 outputTriplet(out, visit, "asint(", "", ")");
1745 break;
1746 case EOpFloatBitsToUint:
1747 outputTriplet(out, visit, "asuint(", "", ")");
1748 break;
1749 case EOpIntBitsToFloat:
1750 outputTriplet(out, visit, "asfloat(", "", ")");
1751 break;
1752 case EOpUintBitsToFloat:
1753 outputTriplet(out, visit, "asfloat(", "", ")");
1754 break;
1755 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001756 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001759 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001760 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001761 case EOpPackUnorm4x8:
1762 case EOpPackSnorm4x8:
1763 case EOpUnpackUnorm4x8:
1764 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001765 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001766 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 break;
1768 case EOpLength:
1769 outputTriplet(out, visit, "length(", "", ")");
1770 break;
1771 case EOpNormalize:
1772 outputTriplet(out, visit, "normalize(", "", ")");
1773 break;
1774 case EOpDFdx:
1775 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1776 {
1777 outputTriplet(out, visit, "(", "", ", 0.0)");
1778 }
1779 else
1780 {
1781 outputTriplet(out, visit, "ddx(", "", ")");
1782 }
1783 break;
1784 case EOpDFdy:
1785 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1786 {
1787 outputTriplet(out, visit, "(", "", ", 0.0)");
1788 }
1789 else
1790 {
1791 outputTriplet(out, visit, "ddy(", "", ")");
1792 }
1793 break;
1794 case EOpFwidth:
1795 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1796 {
1797 outputTriplet(out, visit, "(", "", ", 0.0)");
1798 }
1799 else
1800 {
1801 outputTriplet(out, visit, "fwidth(", "", ")");
1802 }
1803 break;
1804 case EOpTranspose:
1805 outputTriplet(out, visit, "transpose(", "", ")");
1806 break;
1807 case EOpDeterminant:
1808 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1809 break;
1810 case EOpInverse:
1811 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001812 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001813 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001814
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001815 case EOpAny:
1816 outputTriplet(out, visit, "any(", "", ")");
1817 break;
1818 case EOpAll:
1819 outputTriplet(out, visit, "all(", "", ")");
1820 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001821 case EOpLogicalNotComponentWise:
1822 outputTriplet(out, visit, "(!", "", ")");
1823 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001824 case EOpBitfieldReverse:
1825 outputTriplet(out, visit, "reversebits(", "", ")");
1826 break;
1827 case EOpBitCount:
1828 outputTriplet(out, visit, "countbits(", "", ")");
1829 break;
1830 case EOpFindLSB:
1831 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1832 // in GLSLTest and results are consistent with GL.
1833 outputTriplet(out, visit, "firstbitlow(", "", ")");
1834 break;
1835 case EOpFindMSB:
1836 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1837 // tested in GLSLTest and results are consistent with GL.
1838 outputTriplet(out, visit, "firstbithigh(", "", ")");
1839 break;
Qin Jiajia88faa692018-12-03 16:22:24 +08001840 case EOpArrayLength:
1841 {
1842 TIntermTyped *operand = node->getOperand();
1843 ASSERT(IsInShaderStorageBlock(operand));
1844 mSSBOOutputHLSL->outputLengthFunctionCall(operand);
1845 return false;
1846 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001847 default:
1848 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001849 }
1850
1851 return true;
1852}
1853
Olli Etuahofbb1c792018-01-19 16:26:59 +02001854ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001855{
1856 if (node->getAsSymbolNode())
1857 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001858 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1859 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001860 }
1861 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1862 switch (nodeBinary->getOp())
1863 {
1864 case EOpIndexDirect:
1865 {
1866 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1867
Olli Etuahofbb1c792018-01-19 16:26:59 +02001868 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001869 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001870 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001871 }
1872 case EOpIndexDirectStruct:
1873 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001874 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001875 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1876 const TField *field = s->fields()[index];
1877
Olli Etuahofbb1c792018-01-19 16:26:59 +02001878 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001879 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1880 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001881 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001882 }
1883 default:
1884 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001885 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001886 }
1887}
1888
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001889bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1890{
1891 TInfoSinkBase &out = getInfoSink();
1892
Olli Etuaho06235df2018-07-20 14:26:07 +03001893 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1894
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001895 if (mInsideFunction)
1896 {
1897 outputLineDirective(out, node->getLine().first_line);
1898 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001899 if (isMainBlock)
1900 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001901 if (mShaderType == GL_COMPUTE_SHADER)
1902 {
1903 out << "initGLBuiltins(input);\n";
1904 }
1905 else
1906 {
1907 out << "@@ MAIN PROLOGUE @@\n";
1908 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001909 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001910 }
1911
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001912 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001913 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001914 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001915
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001916 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001917
1918 // Don't output ; after case labels, they're terminated by :
1919 // This is needed especially since outputting a ; after a case statement would turn empty
1920 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001921 // Also the output code is clearer if we don't output ; after statements where it is not
1922 // needed:
1923 // * if statements
1924 // * switch statements
1925 // * blocks
1926 // * function definitions
1927 // * loops (do-while loops output the semicolon in VisitLoop)
1928 // * declarations that don't generate output.
1929 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1930 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1931 statement->getAsSwitchNode() == nullptr &&
1932 statement->getAsFunctionDefinition() == nullptr &&
1933 (statement->getAsDeclarationNode() == nullptr ||
1934 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1935 statement->getAsInvariantDeclarationNode() == nullptr)
1936 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001937 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001938 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001939 }
1940
1941 if (mInsideFunction)
1942 {
1943 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001944 if (isMainBlock && shaderNeedsGenerateOutput())
1945 {
1946 // We could have an empty main, a main function without a branch at the end, or a main
1947 // function with a discard statement at the end. In these cases we need to add a return
1948 // statement.
1949 bool needReturnStatement =
1950 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1951 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1952 if (needReturnStatement)
1953 {
1954 out << "return " << generateOutputCall() << ";\n";
1955 }
1956 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001957 out << "}\n";
1958 }
1959
1960 return false;
1961}
1962
Olli Etuaho336b1472016-10-05 16:37:55 +01001963bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1964{
1965 TInfoSinkBase &out = getInfoSink();
1966
1967 ASSERT(mCurrentFunctionMetadata == nullptr);
1968
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001969 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001970 ASSERT(index != CallDAG::InvalidIndex);
1971 mCurrentFunctionMetadata = &mASTMetadataList[index];
1972
Olli Etuahod4bd9632018-03-08 16:32:44 +02001973 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001974
Olli Etuahod4bd9632018-03-08 16:32:44 +02001975 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001976 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001977 // The stub strings below are replaced when shader is dynamically defined by its layout:
1978 switch (mShaderType)
1979 {
1980 case GL_VERTEX_SHADER:
1981 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1982 << "@@ VERTEX OUTPUT @@\n\n"
1983 << "VS_OUTPUT main(VS_INPUT input)";
1984 break;
1985 case GL_FRAGMENT_SHADER:
1986 out << "@@ PIXEL OUTPUT @@\n\n"
1987 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1988 break;
1989 case GL_COMPUTE_SHADER:
1990 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1991 << mWorkGroupSize[2] << ")]\n";
1992 out << "void main(CS_INPUT input)";
1993 break;
1994 default:
1995 UNREACHABLE();
1996 break;
1997 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001998 }
1999 else
2000 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002001 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02002002 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002003 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01002004
Olli Etuaho06235df2018-07-20 14:26:07 +03002005 size_t paramCount = func->getParamCount();
2006 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01002007 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002008 const TVariable *param = func->getParam(i);
2009 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01002010
Olli Etuaho06235df2018-07-20 14:26:07 +03002011 writeParameter(param, out);
2012
2013 if (i < paramCount - 1)
2014 {
2015 out << ", ";
2016 }
2017 }
2018
2019 out << ")\n";
2020 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002021
2022 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03002023 if (func->isMain())
2024 {
2025 mInsideMain = true;
2026 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002027 // The function body node will output braces.
2028 node->getBody()->traverse(this);
2029 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03002030 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01002031
2032 mCurrentFunctionMetadata = nullptr;
2033
2034 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2035 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2036 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002037 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01002038 mOutputLod0Function = true;
2039 node->traverse(this);
2040 mOutputLod0Function = false;
2041 }
2042
2043 return false;
2044}
2045
Olli Etuaho13389b62016-10-16 11:48:18 +01002046bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2047{
Olli Etuaho13389b62016-10-16 11:48:18 +01002048 if (visit == PreVisit)
2049 {
2050 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002051 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002052 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002053 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002054
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002055 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002056 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002057 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002058 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002059
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002060 if (!declarator->getAsSymbolNode() ||
2061 declarator->getAsSymbolNode()->variable().symbolType() !=
2062 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002063 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002064 if (declarator->getQualifier() == EvqShared)
2065 {
2066 out << "groupshared ";
2067 }
2068 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002069 {
2070 out << "static ";
2071 }
2072
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002073 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002074
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002075 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002076
2077 if (symbol)
2078 {
2079 symbol->traverse(this);
2080 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002081 if (declarator->getQualifier() != EvqShared ||
2082 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002083 {
2084 out << " = " + zeroInitializer(symbol->getType());
2085 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002086 }
2087 else
2088 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002089 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002090 }
2091 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002092 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002093 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002094 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002095 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002096 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002097
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002098 const TVariable &variable = symbol->variable();
2099
2100 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002101 {
2102 // Vertex outputs which are declared but not written to should still be declared to
2103 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002104 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002105 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002106 }
2107 }
2108 return false;
2109}
2110
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002111bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2112{
2113 // Do not do any translation
2114 return false;
2115}
2116
Olli Etuahod4bd9632018-03-08 16:32:44 +02002117void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002118{
2119 TInfoSinkBase &out = getInfoSink();
2120
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002121 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002122 // Skip the prototype if it is not implemented (and thus not used)
2123 if (index == CallDAG::InvalidIndex)
2124 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002125 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002126 }
2127
Olli Etuahod4bd9632018-03-08 16:32:44 +02002128 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002129
Olli Etuahod4bd9632018-03-08 16:32:44 +02002130 TString name = DecorateFunctionIfNeeded(func);
2131 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002132 << (mOutputLod0Function ? "Lod0(" : "(");
2133
Olli Etuahod4bd9632018-03-08 16:32:44 +02002134 size_t paramCount = func->getParamCount();
2135 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002136 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002137 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002138
Olli Etuahod4bd9632018-03-08 16:32:44 +02002139 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002140 {
2141 out << ", ";
2142 }
2143 }
2144
2145 out << ");\n";
2146
2147 // Also prototype the Lod0 variant if needed
2148 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2149 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2150 {
2151 mOutputLod0Function = true;
2152 node->traverse(this);
2153 mOutputLod0Function = false;
2154 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002155}
2156
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002157bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2158{
Jamie Madill32aab012015-01-27 14:12:26 -05002159 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002161 switch (node->getOp())
2162 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002163 case EOpCallBuiltInFunction:
2164 case EOpCallFunctionInAST:
2165 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002166 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002167 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002168
Corentin Wallez1239ee92015-03-19 14:38:02 -07002169 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002170 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002172 if (node->isArray())
2173 {
2174 UNIMPLEMENTED();
2175 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002176 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002177 ASSERT(index != CallDAG::InvalidIndex);
2178 lod0 &= mASTMetadataList[index].mNeedsLod0;
2179
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002180 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002181 out << DisambiguateFunctionName(node->getSequence());
2182 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002183 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002184 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002185 {
2186 // This path is used for internal functions that don't have their definitions in the
2187 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002188 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002189 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002190 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002191 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002192 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002193 TType type = (*arguments)[0]->getAsTyped()->getType();
2194 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002195 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002196 type.getMemoryQualifier().readonly);
2197 out << imageFunctionName << "(";
2198 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002199 else if (node->getFunction()->isAtomicCounterFunction())
2200 {
2201 const ImmutableString &name = node->getFunction()->name();
2202 ImmutableString atomicFunctionName =
2203 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2204 out << atomicFunctionName << "(";
2205 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002206 else
2207 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002208 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002209 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002210 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2211 if (arguments->size() > 1)
2212 {
2213 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2214 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002215 const ImmutableString &textureFunctionName =
2216 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2217 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002218 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002220
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002221 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002222 {
Olli Etuaho96963162016-03-21 11:54:33 +02002223 TIntermTyped *typedArg = (*arg)->getAsTyped();
2224 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002225 {
2226 out << "texture_";
2227 (*arg)->traverse(this);
2228 out << ", sampler_";
2229 }
2230
2231 (*arg)->traverse(this);
2232
Olli Etuaho96963162016-03-21 11:54:33 +02002233 if (typedArg->getType().isStructureContainingSamplers())
2234 {
2235 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002236 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002237 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2238 std::string namePrefix = "angle_";
2239 namePrefix += structName.data();
2240 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002241 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002242 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002243 {
2244 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2245 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002246 out << ", texture_" << sampler->name();
2247 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002248 }
2249 else
2250 {
2251 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2252 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002253 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002254 }
2255 }
2256 }
2257
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002258 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002259 {
2260 out << ", ";
2261 }
2262 }
2263
2264 out << ")";
2265
2266 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002268 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002269 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002270 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002271 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002272 outputTriplet(out, visit, "(", " == ", ")");
2273 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002274 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002275 outputTriplet(out, visit, "(", " != ", ")");
2276 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002277 case EOpLessThanComponentWise:
2278 outputTriplet(out, visit, "(", " < ", ")");
2279 break;
2280 case EOpGreaterThanComponentWise:
2281 outputTriplet(out, visit, "(", " > ", ")");
2282 break;
2283 case EOpLessThanEqualComponentWise:
2284 outputTriplet(out, visit, "(", " <= ", ")");
2285 break;
2286 case EOpGreaterThanEqualComponentWise:
2287 outputTriplet(out, visit, "(", " >= ", ")");
2288 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002289 case EOpMod:
2290 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002291 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002292 break;
2293 case EOpModf:
2294 outputTriplet(out, visit, "modf(", ", ", ")");
2295 break;
2296 case EOpPow:
2297 outputTriplet(out, visit, "pow(", ", ", ")");
2298 break;
2299 case EOpAtan:
2300 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2301 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002302 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002303 break;
2304 case EOpMin:
2305 outputTriplet(out, visit, "min(", ", ", ")");
2306 break;
2307 case EOpMax:
2308 outputTriplet(out, visit, "max(", ", ", ")");
2309 break;
2310 case EOpClamp:
2311 outputTriplet(out, visit, "clamp(", ", ", ")");
2312 break;
2313 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302314 {
2315 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2316 if (lastParamNode->getType().getBasicType() == EbtBool)
2317 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002318 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2319 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302320 // so use emulated version.
2321 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002322 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302323 }
2324 else
2325 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002326 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302327 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002328 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302329 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002330 case EOpStep:
2331 outputTriplet(out, visit, "step(", ", ", ")");
2332 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002333 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002334 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2335 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002336 case EOpFrexp:
2337 case EOpLdexp:
2338 ASSERT(node->getUseEmulatedFunction());
2339 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2340 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002341 case EOpDistance:
2342 outputTriplet(out, visit, "distance(", ", ", ")");
2343 break;
2344 case EOpDot:
2345 outputTriplet(out, visit, "dot(", ", ", ")");
2346 break;
2347 case EOpCross:
2348 outputTriplet(out, visit, "cross(", ", ", ")");
2349 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002350 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002351 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002352 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002353 break;
2354 case EOpReflect:
2355 outputTriplet(out, visit, "reflect(", ", ", ")");
2356 break;
2357 case EOpRefract:
2358 outputTriplet(out, visit, "refract(", ", ", ")");
2359 break;
2360 case EOpOuterProduct:
2361 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002362 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002363 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002364 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002365 outputTriplet(out, visit, "(", " * ", ")");
2366 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002367 case EOpBitfieldExtract:
2368 case EOpBitfieldInsert:
2369 case EOpUaddCarry:
2370 case EOpUsubBorrow:
2371 case EOpUmulExtended:
2372 case EOpImulExtended:
2373 ASSERT(node->getUseEmulatedFunction());
2374 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2375 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002376 case EOpBarrier:
2377 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2378 // cheapest *WithGroupSync() function, without any functionality loss, but
2379 // with the potential for severe performance loss.
2380 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2381 break;
2382 case EOpMemoryBarrierShared:
2383 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2384 break;
2385 case EOpMemoryBarrierAtomicCounter:
2386 case EOpMemoryBarrierBuffer:
2387 case EOpMemoryBarrierImage:
2388 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2389 break;
2390 case EOpGroupMemoryBarrier:
2391 case EOpMemoryBarrier:
2392 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2393 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002394
2395 // Single atomic function calls without return value.
2396 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2397 case EOpAtomicAdd:
2398 case EOpAtomicMin:
2399 case EOpAtomicMax:
2400 case EOpAtomicAnd:
2401 case EOpAtomicOr:
2402 case EOpAtomicXor:
2403 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2404 ",", ")");
2405 break;
2406
2407 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2408 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2409 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2410 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2411 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2412 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2413 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2414 // intermediate tree before traversing outputHLSL.
2415 case EOpAtomicExchange:
2416 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002417 default:
2418 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002419 }
2420
2421 return true;
2422}
2423
Olli Etuaho57961272016-09-14 13:57:46 +03002424void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002425{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002426 out << "if (";
2427
2428 node->getCondition()->traverse(this);
2429
2430 out << ")\n";
2431
Jamie Madill8c46ab12015-12-07 16:39:19 -05002432 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002433
2434 bool discard = false;
2435
2436 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002437 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002438 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002439 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002440
Olli Etuahoa6f22092015-05-08 18:31:10 +03002441 // Detect true discard
2442 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2443 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002444 else
2445 {
2446 // TODO(oetuaho): Check if the semicolon inside is necessary.
2447 // It's there as a result of conservative refactoring of the output.
2448 out << "{;}\n";
2449 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002450
Jamie Madill8c46ab12015-12-07 16:39:19 -05002451 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002452
Olli Etuahoa6f22092015-05-08 18:31:10 +03002453 if (node->getFalseBlock())
2454 {
2455 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002456
Jamie Madill8c46ab12015-12-07 16:39:19 -05002457 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002458
Olli Etuaho32db19b2016-10-04 14:43:16 +01002459 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002460 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002461
Jamie Madill8c46ab12015-12-07 16:39:19 -05002462 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002463
Olli Etuahoa6f22092015-05-08 18:31:10 +03002464 // Detect false discard
2465 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2466 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002467
Olli Etuahoa6f22092015-05-08 18:31:10 +03002468 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002469 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002470 {
2471 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002472 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002473}
2474
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002475bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2476{
2477 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2478 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2479 UNREACHABLE();
2480 return false;
2481}
2482
Olli Etuaho57961272016-09-14 13:57:46 +03002483bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002484{
2485 TInfoSinkBase &out = getInfoSink();
2486
Olli Etuaho3d932d82016-04-12 11:10:30 +03002487 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002488
2489 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002490 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002491 {
2492 out << "FLATTEN ";
2493 }
2494
Olli Etuaho57961272016-09-14 13:57:46 +03002495 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002496
2497 return false;
2498}
2499
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002500bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002501{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002502 TInfoSinkBase &out = getInfoSink();
2503
Olli Etuaho923ecef2017-10-11 12:01:38 +03002504 ASSERT(node->getStatementList());
2505 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002506 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002507 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002508 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002509 outputTriplet(out, visit, "switch (", ") ", "");
2510 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002511 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002512}
2513
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002514bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002515{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002516 TInfoSinkBase &out = getInfoSink();
2517
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002518 if (node->hasCondition())
2519 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002520 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002521 return true;
2522 }
2523 else
2524 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002525 out << "default:\n";
2526 return false;
2527 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002528}
2529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002530void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2531{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002532 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002533 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002534}
2535
2536bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2537{
Nicolas Capens655fe362014-04-11 13:12:34 -04002538 mNestedLoopDepth++;
2539
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002540 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002541 mInsideDiscontinuousLoop =
2542 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002543
Jamie Madill8c46ab12015-12-07 16:39:19 -05002544 TInfoSinkBase &out = getInfoSink();
2545
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002546 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002547 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002548 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002549 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002550 mInsideDiscontinuousLoop = wasDiscontinuous;
2551 mNestedLoopDepth--;
2552
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002553 return false;
2554 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002555 }
2556
Corentin Wallez1239ee92015-03-19 14:38:02 -07002557 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002558 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002559 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002560 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002561
Jamie Madill8c46ab12015-12-07 16:39:19 -05002562 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002563 }
2564 else
2565 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002566 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002567
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002568 if (node->getInit())
2569 {
2570 node->getInit()->traverse(this);
2571 }
2572
2573 out << "; ";
2574
alokp@chromium.org52813552010-11-16 18:36:09 +00002575 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002576 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002577 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002578 }
2579
2580 out << "; ";
2581
alokp@chromium.org52813552010-11-16 18:36:09 +00002582 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002583 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002584 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002585 }
2586
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002587 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002588
Jamie Madill8c46ab12015-12-07 16:39:19 -05002589 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002590 }
2591
2592 if (node->getBody())
2593 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002594 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002595 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002596 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002597 else
2598 {
2599 // TODO(oetuaho): Check if the semicolon inside is necessary.
2600 // It's there as a result of conservative refactoring of the output.
2601 out << "{;}\n";
2602 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002603
Jamie Madill8c46ab12015-12-07 16:39:19 -05002604 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002605
alokp@chromium.org52813552010-11-16 18:36:09 +00002606 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002607 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002608 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002609 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002610
alokp@chromium.org52813552010-11-16 18:36:09 +00002611 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002612
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002613 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002614 }
2615
daniel@transgaming.com73536982012-03-21 20:45:49 +00002616 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002617
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002618 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002619 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002620
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002621 return false;
2622}
2623
2624bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2625{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002626 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002627 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002628 TInfoSinkBase &out = getInfoSink();
2629
2630 switch (node->getFlowOp())
2631 {
2632 case EOpKill:
2633 out << "discard";
2634 break;
2635 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002636 if (mNestedLoopDepth > 1)
2637 {
2638 mUsesNestedBreak = true;
2639 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002640
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002641 if (mExcessiveLoopIndex)
2642 {
2643 out << "{Break";
2644 mExcessiveLoopIndex->traverse(this);
2645 out << " = true; break;}\n";
2646 }
2647 else
2648 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002649 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002650 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002651 break;
2652 case EOpContinue:
2653 out << "continue";
2654 break;
2655 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002656 if (node->getExpression())
2657 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002658 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002659 out << "return ";
2660 }
2661 else
2662 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002663 if (mInsideMain && shaderNeedsGenerateOutput())
2664 {
2665 out << "return " << generateOutputCall();
2666 }
2667 else
2668 {
2669 out << "return";
2670 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002671 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002672 break;
2673 default:
2674 UNREACHABLE();
2675 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002676 }
2677
2678 return true;
2679}
2680
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002681// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002682// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2683// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002684bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002685{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002686 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002687
2688 // Parse loops of the form:
2689 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002690 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002691 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002692 int initial = 0;
2693 int limit = 0;
2694 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002695
2696 // Parse index name and intial value
2697 if (node->getInit())
2698 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002699 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002700
2701 if (init)
2702 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002703 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002704 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002705
2706 if (variable && variable->getQualifier() == EvqTemporary)
2707 {
2708 TIntermBinary *assign = variable->getAsBinaryNode();
2709
2710 if (assign->getOp() == EOpInitialize)
2711 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002712 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002713 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2714
2715 if (symbol && constant)
2716 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002717 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002718 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002719 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002720 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002721 }
2722 }
2723 }
2724 }
2725 }
2726 }
2727
2728 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002729 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002730 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002731 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002732
Olli Etuahob6af22b2017-12-15 14:05:44 +02002733 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002734 {
2735 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2736
2737 if (constant)
2738 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002739 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002740 {
2741 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002742 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002743 }
2744 }
2745 }
2746 }
2747
2748 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002749 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002750 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002751 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002752 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002753
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002754 if (binaryTerminal)
2755 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002756 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002757 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2758
2759 if (constant)
2760 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002761 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002762 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002763 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002764
2765 switch (op)
2766 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002767 case EOpAddAssign:
2768 increment = value;
2769 break;
2770 case EOpSubAssign:
2771 increment = -value;
2772 break;
2773 default:
2774 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002775 }
2776 }
2777 }
2778 }
2779 else if (unaryTerminal)
2780 {
2781 TOperator op = unaryTerminal->getOp();
2782
2783 switch (op)
2784 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002785 case EOpPostIncrement:
2786 increment = 1;
2787 break;
2788 case EOpPostDecrement:
2789 increment = -1;
2790 break;
2791 case EOpPreIncrement:
2792 increment = 1;
2793 break;
2794 case EOpPreDecrement:
2795 increment = -1;
2796 break;
2797 default:
2798 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002799 }
2800 }
2801 }
2802
Yunchao He4f285442017-04-21 12:15:49 +08002803 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002804 {
2805 if (comparator == EOpLessThanEqual)
2806 {
2807 comparator = EOpLessThan;
2808 limit += 1;
2809 }
2810
2811 if (comparator == EOpLessThan)
2812 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002813 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002814
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002815 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002816 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002817 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002818 }
2819
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002820 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002821 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002822
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002823 out << "{int ";
2824 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002825 out << ";\n"
2826 "bool Break";
2827 index->traverse(this);
2828 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002829
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002830 bool firstLoopFragment = true;
2831
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002832 while (iterations > 0)
2833 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002834 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002835
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002836 if (!firstLoopFragment)
2837 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002838 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002839 index->traverse(this);
2840 out << ") {\n";
2841 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002842
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002843 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002844 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002845 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002846 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002847
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002848 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002849 const char *unroll =
2850 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002851
Corentin Wallez1239ee92015-03-19 14:38:02 -07002852 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002853 index->traverse(this);
2854 out << " = ";
2855 out << initial;
2856
2857 out << "; ";
2858 index->traverse(this);
2859 out << " < ";
2860 out << clampedLimit;
2861
2862 out << "; ";
2863 index->traverse(this);
2864 out << " += ";
2865 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002866 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002867
Jamie Madill8c46ab12015-12-07 16:39:19 -05002868 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002869 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002870
2871 if (node->getBody())
2872 {
2873 node->getBody()->traverse(this);
2874 }
2875
Jamie Madill8c46ab12015-12-07 16:39:19 -05002876 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002877 out << ";}\n";
2878
2879 if (!firstLoopFragment)
2880 {
2881 out << "}\n";
2882 }
2883
2884 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002885
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002886 initial += MAX_LOOP_ITERATIONS * increment;
2887 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002888 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002889
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002890 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002891
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002892 mExcessiveLoopIndex = restoreIndex;
2893
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002894 return true;
2895 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002896 else
2897 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002898 }
2899
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002900 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002901}
2902
Jamie Madill8c46ab12015-12-07 16:39:19 -05002903void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2904 Visit visit,
2905 const char *preString,
2906 const char *inString,
2907 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002908{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002909 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002910 {
2911 out << preString;
2912 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002913 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002914 {
2915 out << inString;
2916 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002917 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002918 {
2919 out << postString;
2920 }
2921}
2922
Jamie Madill8c46ab12015-12-07 16:39:19 -05002923void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002924{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002925 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002926 {
Jamie Madill32aab012015-01-27 14:12:26 -05002927 out << "\n";
2928 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002929
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002930 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002931 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002932 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002933 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002934
Jamie Madill32aab012015-01-27 14:12:26 -05002935 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002936 }
2937}
2938
Olli Etuahod4bd9632018-03-08 16:32:44 +02002939void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002940{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002941 const TType &type = param->getType();
2942 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002943
Olli Etuahod4bd9632018-03-08 16:32:44 +02002944 TString nameStr = DecorateVariableIfNeeded(*param);
2945 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002946
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002947 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002948 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002949 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2950 {
2951 // Samplers are passed as indices to the sampler array.
2952 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002953 out << "const uint " << nameStr << ArrayString(type);
2954 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002955 }
2956 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2957 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002958 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2959 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2960 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2961 << ArrayString(type);
2962 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002963 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002964 }
2965
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002966 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
2967 // buffer offset.
2968 if (IsAtomicCounter(type.getBasicType()))
2969 {
2970 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
2971 << nameStr << "_offset";
2972 }
2973 else
2974 {
2975 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2976 << ArrayString(type);
2977 }
Olli Etuaho96963162016-03-21 11:54:33 +02002978
2979 // If the structure parameter contains samplers, they need to be passed into the function as
2980 // separate parameters. HLSL doesn't natively support samplers in structs.
2981 if (type.isStructureContainingSamplers())
2982 {
2983 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002984 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002985 std::string namePrefix = "angle";
2986 namePrefix += nameStr.c_str();
2987 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2988 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002989 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002990 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002991 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002992 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2993 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002994 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002995 }
2996 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2997 {
Olli Etuaho96963162016-03-21 11:54:33 +02002998 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002999 out << ", " << QualifierString(qualifier) << " "
3000 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
3001 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
3002 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
3003 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003004 }
3005 else
3006 {
Olli Etuaho96963162016-03-21 11:54:33 +02003007 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003008 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3009 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003010 }
3011 }
3012 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003013}
3014
jchen10efe061b2018-11-13 16:44:40 +08003015TString OutputHLSL::zeroInitializer(const TType &type) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003016{
3017 TString string;
3018
Jamie Madill94bf7f22013-07-08 13:31:15 -04003019 size_t size = type.getObjectSize();
jchen10efe061b2018-11-13 16:44:40 +08003020 if (size >= kZeroCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003021 {
jchen10efe061b2018-11-13 16:44:40 +08003022 mUseZeroArray = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003023 }
jchen10efe061b2018-11-13 16:44:40 +08003024 string = GetZeroInitializer(size).c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003025
daniel@transgaming.comead23042010-04-29 03:35:36 +00003026 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003027}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003028
Olli Etuahobd3cd502017-11-03 15:48:52 +02003029void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003030{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003031 // Array constructors should have been already pruned from the code.
3032 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003033
3034 if (visit == PreVisit)
3035 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003036 TString constructorName;
3037 if (node->getBasicType() == EbtStruct)
3038 {
3039 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3040 }
3041 else
3042 {
3043 constructorName =
3044 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3045 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003046 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003047 }
3048 else if (visit == InVisit)
3049 {
3050 out << ", ";
3051 }
3052 else if (visit == PostVisit)
3053 {
3054 out << ")";
3055 }
3056}
3057
Jamie Madill8c46ab12015-12-07 16:39:19 -05003058const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3059 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003060 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003061{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003062 ASSERT(!type.isArray());
3063
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003064 const TConstantUnion *constUnionIterated = constUnion;
3065
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003066 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003067 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003068 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003069 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003070
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003071 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003072
Jamie Madill98493dd2013-07-08 14:39:03 -04003073 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003074 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003075 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003076 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003077
Jamie Madill98493dd2013-07-08 14:39:03 -04003078 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003079 {
3080 out << ", ";
3081 }
3082 }
3083
3084 out << ")";
3085 }
3086 else
3087 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003088 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003089 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003090
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003091 if (writeType)
3092 {
Jamie Madill033dae62014-06-18 12:56:28 -04003093 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003094 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003095 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003096 if (writeType)
3097 {
3098 out << ")";
3099 }
3100 }
3101
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003102 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003103}
3104
Olli Etuahod68924e2017-01-02 17:34:40 +00003105void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003106{
Olli Etuahod68924e2017-01-02 17:34:40 +00003107 if (visit == PreVisit)
3108 {
3109 const char *opStr = GetOperatorString(op);
3110 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3111 out << "(";
3112 }
3113 else
3114 {
3115 outputTriplet(out, visit, nullptr, ", ", ")");
3116 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003117}
3118
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003119bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3120 TIntermSymbol *symbolNode,
3121 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003122{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003123 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3124 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003125
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003126 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003127 {
3128 // Type already printed
3129 out << "t" + str(mUniqueIndex) + " = ";
3130 expression->traverse(this);
3131 out << ", ";
3132 symbolNode->traverse(this);
3133 out << " = t" + str(mUniqueIndex);
3134
3135 mUniqueIndex++;
3136 return true;
3137 }
3138
3139 return false;
3140}
3141
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003142bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3143 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003144 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003145{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003146 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003147 {
3148 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003149 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003150 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003151 writeConstantUnionArray(out, initializer->getConstantValue(),
3152 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003153 out << "}";
3154 return true;
3155 }
3156 return false;
3157}
3158
Jamie Madill55e79e02015-02-09 15:35:00 -05003159TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3160{
3161 const TFieldList &fields = structure.fields();
3162
3163 for (const auto &eqFunction : mStructEqualityFunctions)
3164 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003165 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003166 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003167 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003168 }
3169 }
3170
3171 const TString &structNameString = StructNameString(structure);
3172
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003173 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003174 function->structure = &structure;
3175 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003176
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003177 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003178
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003179 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3180 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003181 << "{\n"
3182 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003183
3184 for (size_t i = 0; i < fields.size(); i++)
3185 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003186 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003187 const TType *fieldType = field->type();
3188
3189 const TString &fieldNameA = "a." + Decorate(field->name());
3190 const TString &fieldNameB = "b." + Decorate(field->name());
3191
3192 if (i > 0)
3193 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003194 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003195 }
3196
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003197 fnOut << "(";
3198 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3199 fnOut << fieldNameA;
3200 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3201 fnOut << fieldNameB;
3202 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3203 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003204 }
3205
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003206 fnOut << ";\n"
3207 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003208
3209 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003210
3211 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003212 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003213
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003214 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003215}
3216
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003217TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003218{
3219 for (const auto &eqFunction : mArrayEqualityFunctions)
3220 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003221 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003222 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003223 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003224 }
3225 }
3226
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003227 TType elementType(type);
3228 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003229
Olli Etuaho12690762015-03-31 12:55:28 +03003230 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003231 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003232
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003233 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003234
3235 TInfoSinkBase fnOut;
3236
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003237 const TString &typeName = TypeString(type);
3238 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3239 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003240 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003241 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003242 << type.getOutermostArraySize()
3243 << "; ++i)\n"
3244 " {\n"
3245 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003246
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003247 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003248 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003249 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003250 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003251 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003252
3253 fnOut << ") { return false; }\n"
3254 " }\n"
3255 " return true;\n"
3256 "}\n";
3257
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003258 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003259
3260 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003261 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003262
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003263 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003264}
3265
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003266TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003267{
3268 for (const auto &assignFunction : mArrayAssignmentFunctions)
3269 {
3270 if (assignFunction.type == type)
3271 {
3272 return assignFunction.functionName;
3273 }
3274 }
3275
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003276 TType elementType(type);
3277 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003278
3279 ArrayHelperFunction function;
3280 function.type = type;
3281
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003282 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003283
3284 TInfoSinkBase fnOut;
3285
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003286 const TString &typeName = TypeString(type);
3287 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3288 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003289 << "{\n"
3290 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003291 << type.getOutermostArraySize()
3292 << "; ++i)\n"
3293 " {\n"
3294 " ";
3295
3296 outputAssign(PreVisit, elementType, fnOut);
3297 fnOut << "a[i]";
3298 outputAssign(InVisit, elementType, fnOut);
3299 fnOut << "b[i]";
3300 outputAssign(PostVisit, elementType, fnOut);
3301
3302 fnOut << ";\n"
3303 " }\n"
3304 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003305
3306 function.functionDefinition = fnOut.c_str();
3307
3308 mArrayAssignmentFunctions.push_back(function);
3309
3310 return function.functionName;
3311}
3312
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003313TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003314{
3315 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3316 {
3317 if (constructIntoFunction.type == type)
3318 {
3319 return constructIntoFunction.functionName;
3320 }
3321 }
3322
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003323 TType elementType(type);
3324 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003325
3326 ArrayHelperFunction function;
3327 function.type = type;
3328
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003329 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003330
3331 TInfoSinkBase fnOut;
3332
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003333 const TString &typeName = TypeString(type);
3334 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3335 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003336 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003337 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003338 }
3339 fnOut << ")\n"
3340 "{\n";
3341
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003342 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003343 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003344 fnOut << " ";
3345 outputAssign(PreVisit, elementType, fnOut);
3346 fnOut << "a[" << i << "]";
3347 outputAssign(InVisit, elementType, fnOut);
3348 fnOut << "b" << i;
3349 outputAssign(PostVisit, elementType, fnOut);
3350 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003351 }
3352 fnOut << "}\n";
3353
3354 function.functionDefinition = fnOut.c_str();
3355
3356 mArrayConstructIntoFunctions.push_back(function);
3357
3358 return function.functionName;
3359}
3360
Jamie Madill2e295e22015-04-29 10:41:33 -04003361void OutputHLSL::ensureStructDefined(const TType &type)
3362{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003363 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003364 if (structure)
3365 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003366 ASSERT(type.getBasicType() == EbtStruct);
3367 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003368 }
3369}
3370
Olli Etuaho06235df2018-07-20 14:26:07 +03003371bool OutputHLSL::shaderNeedsGenerateOutput() const
3372{
3373 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3374}
3375
3376const char *OutputHLSL::generateOutputCall() const
3377{
3378 if (mShaderType == GL_VERTEX_SHADER)
3379 {
3380 return "generateOutput(input)";
3381 }
3382 else
3383 {
3384 return "generateOutput()";
3385 }
3386}
3387
Jamie Madill45bcc782016-11-07 13:58:48 -05003388} // namespace sh