blob: d660b9a5161246719ec4c90e6a28da4069f78099 [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
Qin Jiajia46229052018-12-10 13:31:00 +0800113bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800114{
Qin Jiajia46229052018-12-10 13:31:00 +0800115 TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
116 if (aggregateNode == nullptr)
117 {
118 return false;
119 }
120
121 if (node.getOp() == EOpAssign && IsAtomicFunction(aggregateNode->getOp()))
122 {
123 return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped());
124 }
125
126 return false;
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800127}
128
jchen10efe061b2018-11-13 16:44:40 +0800129const char *kZeros = "_ANGLE_ZEROS_";
130constexpr int kZeroCount = 256;
131std::string DefineZeroArray()
132{
133 std::stringstream ss;
134 // For 'static', if the declaration does not include an initializer, the value is set to zero.
135 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
136 ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
137 return ss.str();
138}
139
140std::string GetZeroInitializer(size_t size)
141{
142 std::stringstream ss;
143 size_t quotient = size / kZeroCount;
144 size_t reminder = size % kZeroCount;
145
146 for (size_t i = 0; i < quotient; ++i)
147 {
148 if (i != 0)
149 {
150 ss << ", ";
151 }
152 ss << kZeros;
153 }
154
155 for (size_t i = 0; i < reminder; ++i)
156 {
157 if (quotient != 0 || i != 0)
158 {
159 ss << ", ";
160 }
161 ss << "0";
162 }
163
164 return ss.str();
165}
166
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300167} // anonymous namespace
168
Olli Etuahoc71862a2017-12-21 12:58:29 +0200169TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
170 const TVariable *aInstanceVariable)
171 : block(aBlock), instanceVariable(aInstanceVariable)
Jamie Madillb980c562018-11-27 11:34:27 -0500172{}
Olli Etuahoc71862a2017-12-21 12:58:29 +0200173
Olli Etuaho56a2f952016-12-08 12:16:27 +0000174void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300175{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000176 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
177 // regardless.
178 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
179 mOutputType == SH_HLSL_4_1_OUTPUT)
180 {
181 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
182 }
183 else
184 {
185 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
186 }
187}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300188
Olli Etuaho56a2f952016-12-08 12:16:27 +0000189void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200190{
191 ASSERT(constUnion != nullptr);
192 switch (constUnion->getType())
193 {
194 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000195 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200196 break;
197 case EbtInt:
198 out << constUnion->getIConst();
199 break;
200 case EbtUInt:
201 out << constUnion->getUConst();
202 break;
203 case EbtBool:
204 out << constUnion->getBConst();
205 break;
206 default:
207 UNREACHABLE();
208 }
209}
210
Olli Etuaho56a2f952016-12-08 12:16:27 +0000211const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
212 const TConstantUnion *const constUnion,
213 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200214{
215 const TConstantUnion *constUnionIterated = constUnion;
216 for (size_t i = 0; i < size; i++, constUnionIterated++)
217 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000218 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200219
220 if (i != size - 1)
221 {
222 out << ", ";
223 }
224 }
225 return constUnionIterated;
226}
227
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800228OutputHLSL::OutputHLSL(sh::GLenum shaderType,
229 int shaderVersion,
230 const TExtensionBehavior &extensionBehavior,
231 const char *sourcePath,
232 ShShaderOutput outputType,
233 int numRenderTargets,
234 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300235 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300236 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300237 TSymbolTable *symbolTable,
238 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300239 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200240 mShaderType(shaderType),
241 mShaderVersion(shaderVersion),
242 mExtensionBehavior(extensionBehavior),
243 mSourcePath(sourcePath),
244 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700245 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300246 mInsideFunction(false),
247 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000248 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300249 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300250 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300251 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800253 mUsesFragColor = false;
254 mUsesFragData = false;
255 mUsesDepthRange = false;
256 mUsesFragCoord = false;
257 mUsesPointCoord = false;
258 mUsesFrontFacing = false;
259 mUsesPointSize = false;
260 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300261 mHasMultiviewExtensionEnabled =
262 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300263 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500264 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500265 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800266 mUsesNumWorkGroups = false;
267 mUsesWorkGroupID = false;
268 mUsesLocalInvocationID = false;
269 mUsesGlobalInvocationID = false;
270 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500271 mUsesXor = false;
272 mUsesDiscardRewriting = false;
273 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530274 mRequiresIEEEStrictCompiling = false;
jchen10efe061b2018-11-13 16:44:40 +0800275 mUseZeroArray = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000276
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000277 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000278
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500279 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000280 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500281 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000282
Yunchao Hed7297bf2017-04-19 15:27:10 +0800283 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000284
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700285 mStructureHLSL = new StructureHLSL;
286 mTextureFunctionHLSL = new TextureFunctionHLSL;
287 mImageFunctionHLSL = new ImageFunctionHLSL;
288 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400289
Olli Etuahod8724a92017-12-29 18:40:36 +0200290 unsigned int firstUniformRegister =
291 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800292 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200293
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200294 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000295 {
Arun Patole63419392015-03-13 11:51:07 +0530296 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500297 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
298 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530299 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800300 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000301 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000302
Geoff Lang00140f42016-02-03 18:47:33 +0000303 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800304 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800305
306 mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307}
308
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000309OutputHLSL::~OutputHLSL()
310{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800311 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400312 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800313 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300314 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800315 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700316 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200317 for (auto &eqFunction : mStructEqualityFunctions)
318 {
319 SafeDelete(eqFunction);
320 }
321 for (auto &eqFunction : mArrayEqualityFunctions)
322 {
323 SafeDelete(eqFunction);
324 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000325}
326
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200327void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000328{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200329 BuiltInFunctionEmulator builtInFunctionEmulator;
330 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800331 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
332 {
333 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
334 mShaderVersion);
335 }
336
Olli Etuahodfa75e82017-01-23 09:43:06 -0800337 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500338
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700339 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000340 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700341 ASSERT(success == CallDAG::INITDAG_SUCCESS);
342 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700343
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200344 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
345 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
346 // the shader code. When we add shader storage blocks we might also consider an alternative
347 // solution, since the struct mapping won't work very well for shader storage blocks.
348
Jamie Madill37997142015-01-28 10:06:34 -0500349 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500350 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200351 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500352 mInfoSinkStack.pop();
353
Jamie Madill37997142015-01-28 10:06:34 -0500354 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500355 mInfoSinkStack.pop();
356
Jamie Madill32aab012015-01-27 14:12:26 -0500357 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200358 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500359 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000360
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200361 objSink << mHeader.c_str();
362 objSink << mBody.c_str();
363 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200364
Olli Etuahodfa75e82017-01-23 09:43:06 -0800365 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000366}
367
Qin Jiajiaa602f902018-09-11 14:40:24 +0800368const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
369{
370 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
371}
372
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800373const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400374{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800375 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400376}
377
Jamie Madill9fe25e92014-07-18 10:33:08 -0400378const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
379{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800380 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400381}
382
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200383TString OutputHLSL::structInitializerString(int indent,
384 const TType &type,
385 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400386{
387 TString init;
388
Olli Etuahoed049ab2017-06-30 17:38:33 +0300389 TString indentString;
390 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400391 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300392 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400393 }
394
Olli Etuahoed049ab2017-06-30 17:38:33 +0300395 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400396 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300397 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300398 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400399 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300400 TStringStream indexedString;
401 indexedString << name << "[" << arrayIndex << "]";
402 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300403 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300404 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300405 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300406 {
407 init += ",";
408 }
409 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400410 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300411 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400412 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300413 else if (type.getBasicType() == EbtStruct)
414 {
415 init += indentString + "{\n";
416 const TStructure &structure = *type.getStruct();
417 const TFieldList &fields = structure.fields();
418 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
419 {
420 const TField &field = *fields[fieldIndex];
421 const TString &fieldName = name + "." + Decorate(field.name());
422 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400423
Olli Etuahoed049ab2017-06-30 17:38:33 +0300424 init += structInitializerString(indent + 1, fieldType, fieldName);
425 if (fieldIndex < fields.size() - 1)
426 {
427 init += ",";
428 }
429 init += "\n";
430 }
431 init += indentString + "}";
432 }
433 else
434 {
435 init += indentString + name;
436 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400437
438 return init;
439}
440
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200441TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
442{
443 TString mappedStructs;
444
445 for (auto &mappedStruct : std140Structs)
446 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200447 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200448 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800449 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
450 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200451 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800452 case EvqUniform:
453 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
454 {
455 continue;
456 }
457 break;
458 case EvqBuffer:
459 continue;
460 default:
461 UNREACHABLE();
462 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200463 }
464
465 unsigned int instanceCount = 1u;
466 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
467 if (isInstanceArray)
468 {
469 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
470 }
471
472 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
473 ++instanceArrayIndex)
474 {
475 TString originalName;
476 TString mappedName("map");
477
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200478 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200479 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200480 const ImmutableString &instanceName =
481 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200482 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
483 if (isInstanceArray)
484 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800485 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200486 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200487 originalName += instanceString;
488 mappedName += instanceString;
489 originalName += ".";
490 mappedName += "_";
491 }
492
493 TString fieldName = Decorate(mappedStruct.field->name());
494 originalName += fieldName;
495 mappedName += fieldName;
496
497 TType *structType = mappedStruct.field->type();
498 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200499 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200500
501 if (structType->isArray())
502 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300503 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200504 }
505
506 mappedStructs += " =\n";
507 mappedStructs += structInitializerString(0, *structType, originalName);
508 mappedStructs += ";\n";
509 }
510 }
511 return mappedStructs;
512}
513
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300514void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300516 for (const auto &attribute : mReferencedAttributes)
517 {
518 const TType &type = attribute.second->getType();
519 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400520
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300521 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
522 << zeroInitializer(type) << ";\n";
523 }
524}
525
526void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
527{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200528 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000529 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800530 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000531
532 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300533 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300534 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
535 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000536 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300537}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000538
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300539void OutputHLSL::header(TInfoSinkBase &out,
540 const std::vector<MappedStruct> &std140Structs,
541 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
542{
543 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000544
Jamie Madill8daaba12014-06-13 10:04:33 -0400545 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400546
Qin Jiajia3e217f62018-08-28 16:55:20 +0800547 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
548 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800549 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400550
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200551 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500552 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200553 out << "\n// Equality functions\n\n";
554 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500555 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200556 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200557 }
558 }
Olli Etuaho12690762015-03-31 12:55:28 +0300559 if (!mArrayAssignmentFunctions.empty())
560 {
561 out << "\n// Assignment functions\n\n";
562 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
563 {
564 out << assignmentFunction.functionDefinition << "\n";
565 }
566 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300567 if (!mArrayConstructIntoFunctions.empty())
568 {
569 out << "\n// Array constructor functions\n\n";
570 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
571 {
572 out << constructIntoFunction.functionDefinition << "\n";
573 }
574 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200575
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500576 if (mUsesDiscardRewriting)
577 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400578 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500579 }
580
Nicolas Capens655fe362014-04-11 13:12:34 -0400581 if (mUsesNestedBreak)
582 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400583 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400584 }
585
Arun Patole44efa0b2015-03-04 17:11:05 +0530586 if (mRequiresIEEEStrictCompiling)
587 {
588 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
589 }
590
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400591 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
592 "#define LOOP [loop]\n"
593 "#define FLATTEN [flatten]\n"
594 "#else\n"
595 "#define LOOP\n"
596 "#define FLATTEN\n"
597 "#endif\n";
598
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700599 // array stride for atomic counter buffers is always 4 per original extension
600 // ARB_shader_atomic_counters and discussion on
601 // https://github.com/KhronosGroup/OpenGL-API/issues/5
602 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
603
jchen10efe061b2018-11-13 16:44:40 +0800604 if (mUseZeroArray)
605 {
606 out << DefineZeroArray() << "\n";
607 }
608
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200609 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000610 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300611 const bool usingMRTExtension =
612 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000613
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000614 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300615 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400616 out << "\n";
617
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200618 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000619 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200620 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000621 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200622 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800623 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400624
Olli Etuahofbb1c792018-01-19 16:26:59 +0200625 out << "static " << TypeString(variableType) << " out_" << variableName
626 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000627 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000628 }
Jamie Madill46131a32013-06-20 11:55:50 -0400629 else
630 {
631 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
632
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800633 out << "static float4 gl_Color[" << numColorValues
634 << "] =\n"
635 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400636 for (unsigned int i = 0; i < numColorValues; i++)
637 {
638 out << " float4(0, 0, 0, 0)";
639 if (i + 1 != numColorValues)
640 {
641 out << ",";
642 }
643 out << "\n";
644 }
645
646 out << "};\n";
647 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000648
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400649 if (mUsesFragDepth)
650 {
651 out << "static float gl_Depth = 0.0;\n";
652 }
653
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000654 if (mUsesFragCoord)
655 {
656 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
657 }
658
659 if (mUsesPointCoord)
660 {
661 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
662 }
663
664 if (mUsesFrontFacing)
665 {
666 out << "static bool gl_FrontFacing = false;\n";
667 }
668
669 out << "\n";
670
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000671 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000672 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000673 out << "struct gl_DepthRangeParameters\n"
674 "{\n"
675 " float near;\n"
676 " float far;\n"
677 " float diff;\n"
678 "};\n"
679 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000680 }
681
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200682 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000683 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000684 out << "cbuffer DriverConstants : register(b1)\n"
685 "{\n";
686
687 if (mUsesDepthRange)
688 {
689 out << " float3 dx_DepthRange : packoffset(c0);\n";
690 }
691
692 if (mUsesFragCoord)
693 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000694 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000695 }
696
697 if (mUsesFragCoord || mUsesFrontFacing)
698 {
699 out << " float3 dx_DepthFront : packoffset(c2);\n";
700 }
701
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800702 if (mUsesFragCoord)
703 {
704 // dx_ViewScale is only used in the fragment shader to correct
705 // the value for glFragCoord if necessary
706 out << " float2 dx_ViewScale : packoffset(c3);\n";
707 }
708
Martin Radev72b4e1e2017-08-31 15:42:56 +0300709 if (mHasMultiviewExtensionEnabled)
710 {
711 // We have to add a value which we can use to keep track of which multi-view code
712 // path is to be selected in the GS.
713 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
714 }
715
Olli Etuaho618bebc2016-01-15 16:40:00 +0200716 if (mOutputType == SH_HLSL_4_1_OUTPUT)
717 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800718 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200719 }
720
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000721 out << "};\n";
722 }
723 else
724 {
725 if (mUsesDepthRange)
726 {
727 out << "uniform float3 dx_DepthRange : register(c0);";
728 }
729
730 if (mUsesFragCoord)
731 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000732 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000733 }
734
735 if (mUsesFragCoord || mUsesFrontFacing)
736 {
737 out << "uniform float3 dx_DepthFront : register(c2);\n";
738 }
739 }
740
741 out << "\n";
742
743 if (mUsesDepthRange)
744 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
746 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000747 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000748 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000749
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000750 if (usingMRTExtension && mNumRenderTargets > 1)
751 {
752 out << "#define GL_USES_MRT\n";
753 }
754
755 if (mUsesFragColor)
756 {
757 out << "#define GL_USES_FRAG_COLOR\n";
758 }
759
760 if (mUsesFragData)
761 {
762 out << "#define GL_USES_FRAG_DATA\n";
763 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764 }
Xinghua Caob1239382016-12-13 15:07:05 +0800765 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000767 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300768 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000769 out << "\n"
770 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400771
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000772 if (mUsesPointSize)
773 {
774 out << "static float gl_PointSize = float(1);\n";
775 }
776
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000777 if (mUsesInstanceID)
778 {
779 out << "static int gl_InstanceID;";
780 }
781
Corentin Wallezb076add2016-01-11 16:45:46 -0500782 if (mUsesVertexID)
783 {
784 out << "static int gl_VertexID;";
785 }
786
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000787 out << "\n"
788 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300789 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000790 out << "\n";
791
792 if (mUsesDepthRange)
793 {
794 out << "struct gl_DepthRangeParameters\n"
795 "{\n"
796 " float near;\n"
797 " float far;\n"
798 " float diff;\n"
799 "};\n"
800 "\n";
801 }
802
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200803 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000804 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800805 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500806 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800807
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000808 if (mUsesDepthRange)
809 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800810 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000811 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800812
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800813 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
814 // shaders. However, we declare it for all shaders (including Feature Level 10+).
815 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
816 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800817 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800818 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800819 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800820
Martin Radev72b4e1e2017-08-31 15:42:56 +0300821 if (mHasMultiviewExtensionEnabled)
822 {
823 // We have to add a value which we can use to keep track of which multi-view code
824 // path is to be selected in the GS.
825 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
826 }
827
Olli Etuaho618bebc2016-01-15 16:40:00 +0200828 if (mOutputType == SH_HLSL_4_1_OUTPUT)
829 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800830 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200831 }
832
Austin Kinross4fd18b12014-12-22 12:32:05 -0800833 out << "};\n"
834 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000835 }
836 else
837 {
838 if (mUsesDepthRange)
839 {
840 out << "uniform float3 dx_DepthRange : register(c0);\n";
841 }
842
Cooper Partine6664f02015-01-09 16:22:24 -0800843 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
844 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000845 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000846 }
847
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000848 if (mUsesDepthRange)
849 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500850 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
851 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000852 "\n";
853 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400854 }
Xinghua Caob1239382016-12-13 15:07:05 +0800855 else // Compute shader
856 {
857 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800858
859 out << "cbuffer DriverConstants : register(b1)\n"
860 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800861 if (mUsesNumWorkGroups)
862 {
Xinghua Caob1239382016-12-13 15:07:05 +0800863 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800864 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800865 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800866 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800867 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800868
Jiawei Shao203b26f2018-07-25 10:30:43 +0800869 std::ostringstream systemValueDeclaration;
870 std::ostringstream glBuiltinInitialization;
871
872 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
873 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
874 << "{\n";
875
Xinghua Caob1239382016-12-13 15:07:05 +0800876 if (mUsesWorkGroupID)
877 {
878 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800879 systemValueDeclaration << " uint3 dx_WorkGroupID : "
880 << "SV_GroupID;\n";
881 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800882 }
883
884 if (mUsesLocalInvocationID)
885 {
886 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800887 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
888 << "SV_GroupThreadID;\n";
889 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800890 }
891
892 if (mUsesGlobalInvocationID)
893 {
894 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800895 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
896 << "SV_DispatchThreadID;\n";
897 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800898 }
899
900 if (mUsesLocalInvocationIndex)
901 {
902 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800903 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
904 << "SV_GroupIndex;\n";
905 glBuiltinInitialization
906 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800907 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800908
909 systemValueDeclaration << "};\n\n";
910 glBuiltinInitialization << "};\n\n";
911
912 out << systemValueDeclaration.str();
913 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800914 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000915
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800916 if (!mappedStructs.empty())
917 {
918 out << "// Structures from std140 blocks with padding removed\n";
919 out << "\n";
920 out << mappedStructs;
921 out << "\n";
922 }
923
Geoff Lang1fe74c72016-08-25 13:23:01 -0400924 bool getDimensionsIgnoresBaseLevel =
925 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
926 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800927 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700928 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000930 if (mUsesFragCoord)
931 {
932 out << "#define GL_USES_FRAG_COORD\n";
933 }
934
935 if (mUsesPointCoord)
936 {
937 out << "#define GL_USES_POINT_COORD\n";
938 }
939
940 if (mUsesFrontFacing)
941 {
942 out << "#define GL_USES_FRONT_FACING\n";
943 }
944
945 if (mUsesPointSize)
946 {
947 out << "#define GL_USES_POINT_SIZE\n";
948 }
949
Martin Radev41ac68e2017-06-06 12:16:58 +0300950 if (mHasMultiviewExtensionEnabled)
951 {
952 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
953 }
954
955 if (mUsesViewID)
956 {
957 out << "#define GL_USES_VIEW_ID\n";
958 }
959
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400960 if (mUsesFragDepth)
961 {
962 out << "#define GL_USES_FRAG_DEPTH\n";
963 }
964
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000965 if (mUsesDepthRange)
966 {
967 out << "#define GL_USES_DEPTH_RANGE\n";
968 }
969
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000970 if (mUsesXor)
971 {
972 out << "bool xor(bool p, bool q)\n"
973 "{\n"
974 " return (p || q) && !(p && q);\n"
975 "}\n"
976 "\n";
977 }
978
Olli Etuahodfa75e82017-01-23 09:43:06 -0800979 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980}
981
982void OutputHLSL::visitSymbol(TIntermSymbol *node)
983{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200984 const TVariable &variable = node->variable();
985
986 // Empty symbols can only appear in declarations and function arguments, and in either of those
987 // cases the symbol nodes are not visited.
988 ASSERT(variable.symbolType() != SymbolType::Empty);
989
Jamie Madill32aab012015-01-27 14:12:26 -0500990 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000991
Jamie Madill570e04d2013-06-21 09:15:33 -0400992 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800993 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400994 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200995 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400996 }
997
Olli Etuahofbb1c792018-01-19 16:26:59 +0200998 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200999 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +02001000
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001001 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001002 {
1003 mUsesDepthRange = true;
1004 out << name;
1005 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001006 else if (IsAtomicCounter(variable.getType().getBasicType()))
1007 {
1008 const TType &variableType = variable.getType();
1009 if (variableType.getQualifier() == EvqUniform)
1010 {
1011 TLayoutQualifier layout = variableType.getLayoutQualifier();
1012 mReferencedUniforms[uniqueId.get()] = &variable;
1013 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1014 }
1015 else
1016 {
1017 TString varName = DecorateVariableIfNeeded(variable);
1018 out << varName << ", " << varName << "_offset";
1019 }
1020 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001021 else
1022 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001023 const TType &variableType = variable.getType();
1024 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001025
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001026 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +02001027
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001028 if (qualifier == EvqUniform)
1029 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001030 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001031
1032 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001033 {
Olli Etuahoc71862a2017-12-21 12:58:29 +02001034 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1035 {
1036 const TVariable *instanceVariable = nullptr;
1037 if (variableType.isInterfaceBlock())
1038 {
1039 instanceVariable = &variable;
1040 }
1041 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1042 new TReferencedBlock(interfaceBlock, instanceVariable);
1043 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001044 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001045 else
1046 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001047 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001048 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001049
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001050 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001051 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001052 else if (qualifier == EvqBuffer)
1053 {
1054 UNREACHABLE();
1055 }
Jamie Madill19571812013-08-12 15:26:34 -07001056 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001057 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001058 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001059 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001060 }
Jamie Madill033dae62014-06-18 12:56:28 -04001061 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001062 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001063 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001064 out << DecorateVariableIfNeeded(variable);
1065 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001066 {
1067 mUsesViewID = true;
1068 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001069 }
Jamie Madill19571812013-08-12 15:26:34 -07001070 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001071 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001072 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001073 out << "out_" << name;
1074 }
1075 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001076 {
1077 out << "gl_Color[0]";
1078 mUsesFragColor = true;
1079 }
1080 else if (qualifier == EvqFragData)
1081 {
1082 out << "gl_Color";
1083 mUsesFragData = true;
1084 }
1085 else if (qualifier == EvqFragCoord)
1086 {
1087 mUsesFragCoord = true;
1088 out << name;
1089 }
1090 else if (qualifier == EvqPointCoord)
1091 {
1092 mUsesPointCoord = true;
1093 out << name;
1094 }
1095 else if (qualifier == EvqFrontFacing)
1096 {
1097 mUsesFrontFacing = true;
1098 out << name;
1099 }
1100 else if (qualifier == EvqPointSize)
1101 {
1102 mUsesPointSize = true;
1103 out << name;
1104 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001105 else if (qualifier == EvqInstanceID)
1106 {
1107 mUsesInstanceID = true;
1108 out << name;
1109 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001110 else if (qualifier == EvqVertexID)
1111 {
1112 mUsesVertexID = true;
1113 out << name;
1114 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001115 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001116 {
1117 mUsesFragDepth = true;
1118 out << "gl_Depth";
1119 }
Xinghua Caob1239382016-12-13 15:07:05 +08001120 else if (qualifier == EvqNumWorkGroups)
1121 {
1122 mUsesNumWorkGroups = true;
1123 out << name;
1124 }
1125 else if (qualifier == EvqWorkGroupID)
1126 {
1127 mUsesWorkGroupID = true;
1128 out << name;
1129 }
1130 else if (qualifier == EvqLocalInvocationID)
1131 {
1132 mUsesLocalInvocationID = true;
1133 out << name;
1134 }
1135 else if (qualifier == EvqGlobalInvocationID)
1136 {
1137 mUsesGlobalInvocationID = true;
1138 out << name;
1139 }
1140 else if (qualifier == EvqLocalInvocationIndex)
1141 {
1142 mUsesLocalInvocationIndex = true;
1143 out << name;
1144 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001145 else
1146 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001147 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001148 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001149 }
1150}
1151
Olli Etuaho7fb49552015-03-18 17:27:44 +02001152void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1153{
1154 if (type.isScalar() && !type.isArray())
1155 {
1156 if (op == EOpEqual)
1157 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001158 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001159 }
1160 else
1161 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001162 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001163 }
1164 }
1165 else
1166 {
1167 if (visit == PreVisit && op == EOpNotEqual)
1168 {
1169 out << "!";
1170 }
1171
1172 if (type.isArray())
1173 {
1174 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001175 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001176 }
1177 else if (type.getBasicType() == EbtStruct)
1178 {
1179 const TStructure &structure = *type.getStruct();
1180 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001181 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001182 }
1183 else
1184 {
1185 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001186 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001187 }
1188 }
1189}
1190
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001191void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1192{
1193 if (type.isArray())
1194 {
1195 const TString &functionName = addArrayAssignmentFunction(type);
1196 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1197 }
1198 else
1199 {
1200 outputTriplet(out, visit, "(", " = ", ")");
1201 }
1202}
1203
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001204bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001205{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001206 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001207 {
1208 TIntermNode *ancestor = getAncestorNode(n);
1209 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1210 if (ancestorBinary == nullptr)
1211 {
1212 return false;
1213 }
1214 switch (ancestorBinary->getOp())
1215 {
1216 case EOpIndexDirectStruct:
1217 {
1218 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1219 const TIntermConstantUnion *index =
1220 ancestorBinary->getRight()->getAsConstantUnion();
1221 const TField *field = structure->fields()[index->getIConst(0)];
1222 if (IsSampler(field->type()->getBasicType()))
1223 {
1224 return true;
1225 }
1226 break;
1227 }
1228 case EOpIndexDirect:
1229 break;
1230 default:
1231 // Returning a sampler from indirect indexing is not supported.
1232 return false;
1233 }
1234 }
1235 return false;
1236}
1237
Olli Etuahob6fa0432016-09-28 16:28:05 +01001238bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1239{
1240 TInfoSinkBase &out = getInfoSink();
1241 if (visit == PostVisit)
1242 {
1243 out << ".";
1244 node->writeOffsetsAsXYZW(&out);
1245 }
1246 return true;
1247}
1248
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001249bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1250{
Jamie Madill32aab012015-01-27 14:12:26 -05001251 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001252
1253 switch (node->getOp())
1254 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001255 case EOpComma:
1256 outputTriplet(out, visit, "(", ", ", ")");
1257 break;
1258 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001259 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001260 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001261 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1262 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001263 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001264 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1265 out << functionName << "(";
1266 node->getLeft()->traverse(this);
1267 TIntermSequence *seq = rightAgg->getSequence();
1268 for (auto &arrayElement : *seq)
1269 {
1270 out << ", ";
1271 arrayElement->traverse(this);
1272 }
1273 out << ")";
1274 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001275 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001276 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1277 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001278 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001279 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001280 // Assignment expressions with atomic functions should be transformed into atomic
1281 // function calls in HLSL.
1282 // e.g. original_value = atomicAdd(dest, value) should be translated into
1283 // InterlockedAdd(dest, value, original_value);
Qin Jiajia46229052018-12-10 13:31:00 +08001284 else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001285 {
1286 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1287 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1288 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1289 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1290 ASSERT(argumentSeq->size() >= 2u);
1291 for (auto &argument : *argumentSeq)
1292 {
1293 argument->traverse(this);
1294 out << ", ";
1295 }
1296 node->getLeft()->traverse(this);
1297 out << ")";
1298 return false;
1299 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001300 else if (IsInShaderStorageBlock(node->getLeft()))
1301 {
1302 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1303 out << ", ";
1304 if (IsInShaderStorageBlock(node->getRight()))
1305 {
1306 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1307 }
1308 else
1309 {
1310 node->getRight()->traverse(this);
1311 }
1312
1313 out << ")";
1314 return false;
1315 }
1316 else if (IsInShaderStorageBlock(node->getRight()))
1317 {
1318 node->getLeft()->traverse(this);
1319 out << " = ";
1320 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1321 return false;
1322 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001323
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001324 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001325 break;
1326 case EOpInitialize:
1327 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001328 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001329 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1330 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001331 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001332
1333 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001334 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001335
1336 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1337 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1338 // new variable is created before the assignment is evaluated), so we need to
1339 // convert
1340 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001341 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001342 {
1343 // Skip initializing the rest of the expression
1344 return false;
1345 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001346 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001347 {
1348 return false;
1349 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001350 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001351 else if (visit == InVisit)
1352 {
1353 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001354 if (IsInShaderStorageBlock(node->getRight()))
1355 {
1356 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1357 return false;
1358 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001359 }
1360 break;
1361 case EOpAddAssign:
1362 outputTriplet(out, visit, "(", " += ", ")");
1363 break;
1364 case EOpSubAssign:
1365 outputTriplet(out, visit, "(", " -= ", ")");
1366 break;
1367 case EOpMulAssign:
1368 outputTriplet(out, visit, "(", " *= ", ")");
1369 break;
1370 case EOpVectorTimesScalarAssign:
1371 outputTriplet(out, visit, "(", " *= ", ")");
1372 break;
1373 case EOpMatrixTimesScalarAssign:
1374 outputTriplet(out, visit, "(", " *= ", ")");
1375 break;
1376 case EOpVectorTimesMatrixAssign:
1377 if (visit == PreVisit)
1378 {
1379 out << "(";
1380 }
1381 else if (visit == InVisit)
1382 {
1383 out << " = mul(";
1384 node->getLeft()->traverse(this);
1385 out << ", transpose(";
1386 }
1387 else
1388 {
1389 out << ")))";
1390 }
1391 break;
1392 case EOpMatrixTimesMatrixAssign:
1393 if (visit == PreVisit)
1394 {
1395 out << "(";
1396 }
1397 else if (visit == InVisit)
1398 {
1399 out << " = transpose(mul(transpose(";
1400 node->getLeft()->traverse(this);
1401 out << "), transpose(";
1402 }
1403 else
1404 {
1405 out << "))))";
1406 }
1407 break;
1408 case EOpDivAssign:
1409 outputTriplet(out, visit, "(", " /= ", ")");
1410 break;
1411 case EOpIModAssign:
1412 outputTriplet(out, visit, "(", " %= ", ")");
1413 break;
1414 case EOpBitShiftLeftAssign:
1415 outputTriplet(out, visit, "(", " <<= ", ")");
1416 break;
1417 case EOpBitShiftRightAssign:
1418 outputTriplet(out, visit, "(", " >>= ", ")");
1419 break;
1420 case EOpBitwiseAndAssign:
1421 outputTriplet(out, visit, "(", " &= ", ")");
1422 break;
1423 case EOpBitwiseXorAssign:
1424 outputTriplet(out, visit, "(", " ^= ", ")");
1425 break;
1426 case EOpBitwiseOrAssign:
1427 outputTriplet(out, visit, "(", " |= ", ")");
1428 break;
1429 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001430 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001431 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001432 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001433 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001434 if (visit == PreVisit)
1435 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001436 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001437 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001438
1439 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001440 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1441 {
1442 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1443 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1444 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001445 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001446 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001447 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001448 return false;
1449 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001450 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001451 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001452 {
1453 // All parts of an expression that access a sampler in a struct need to use _ as
1454 // separator to access the sampler variable that has been moved out of the struct.
1455 outputTriplet(out, visit, "", "_", "");
1456 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001457 else if (IsAtomicCounter(leftType.getBasicType()))
1458 {
1459 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1460 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001461 else
1462 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001463 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001464 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001465 }
1466 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001467 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001468 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001469 // We do not currently support indirect references to interface blocks
1470 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001471
1472 const TType &leftType = node->getLeft()->getType();
1473 if (IsAtomicCounter(leftType.getBasicType()))
1474 {
1475 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1476 }
1477 else
1478 {
1479 outputTriplet(out, visit, "", "[", "]");
1480 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001481 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001482 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001483 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001484 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001485 const TStructure *structure = node->getLeft()->getType().getStruct();
1486 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1487 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001488
Olli Etuaho96963162016-03-21 11:54:33 +02001489 // In cases where indexing returns a sampler, we need to access the sampler variable
1490 // that has been moved out of the struct.
1491 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1492 if (visit == PreVisit && indexingReturnsSampler)
1493 {
1494 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1495 // This prefix is only output at the beginning of the indexing expression, which
1496 // may have multiple parts.
1497 out << "angle";
1498 }
1499 if (!indexingReturnsSampler)
1500 {
1501 // All parts of an expression that access a sampler in a struct need to use _ as
1502 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001503 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001504 }
1505 if (visit == InVisit)
1506 {
1507 if (indexingReturnsSampler)
1508 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001509 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001510 }
1511 else
1512 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001513 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001514 }
1515
1516 return false;
1517 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001518 }
1519 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001520 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001521 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001522 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1523 bool structInStd140UniformBlock =
1524 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1525 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001526 {
1527 out << "map";
1528 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001529 if (visit == InVisit)
1530 {
1531 const TInterfaceBlock *interfaceBlock =
1532 node->getLeft()->getType().getInterfaceBlock();
1533 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1534 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001535 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001536 {
1537 out << "_";
1538 }
1539 else
1540 {
1541 out << ".";
1542 }
1543 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001544
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 return false;
1546 }
1547 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001548 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001549 case EOpAdd:
1550 outputTriplet(out, visit, "(", " + ", ")");
1551 break;
1552 case EOpSub:
1553 outputTriplet(out, visit, "(", " - ", ")");
1554 break;
1555 case EOpMul:
1556 outputTriplet(out, visit, "(", " * ", ")");
1557 break;
1558 case EOpDiv:
1559 outputTriplet(out, visit, "(", " / ", ")");
1560 break;
1561 case EOpIMod:
1562 outputTriplet(out, visit, "(", " % ", ")");
1563 break;
1564 case EOpBitShiftLeft:
1565 outputTriplet(out, visit, "(", " << ", ")");
1566 break;
1567 case EOpBitShiftRight:
1568 outputTriplet(out, visit, "(", " >> ", ")");
1569 break;
1570 case EOpBitwiseAnd:
1571 outputTriplet(out, visit, "(", " & ", ")");
1572 break;
1573 case EOpBitwiseXor:
1574 outputTriplet(out, visit, "(", " ^ ", ")");
1575 break;
1576 case EOpBitwiseOr:
1577 outputTriplet(out, visit, "(", " | ", ")");
1578 break;
1579 case EOpEqual:
1580 case EOpNotEqual:
1581 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1582 break;
1583 case EOpLessThan:
1584 outputTriplet(out, visit, "(", " < ", ")");
1585 break;
1586 case EOpGreaterThan:
1587 outputTriplet(out, visit, "(", " > ", ")");
1588 break;
1589 case EOpLessThanEqual:
1590 outputTriplet(out, visit, "(", " <= ", ")");
1591 break;
1592 case EOpGreaterThanEqual:
1593 outputTriplet(out, visit, "(", " >= ", ")");
1594 break;
1595 case EOpVectorTimesScalar:
1596 outputTriplet(out, visit, "(", " * ", ")");
1597 break;
1598 case EOpMatrixTimesScalar:
1599 outputTriplet(out, visit, "(", " * ", ")");
1600 break;
1601 case EOpVectorTimesMatrix:
1602 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1603 break;
1604 case EOpMatrixTimesVector:
1605 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1606 break;
1607 case EOpMatrixTimesMatrix:
1608 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1609 break;
1610 case EOpLogicalOr:
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 case EOpLogicalXor:
1617 mUsesXor = true;
1618 outputTriplet(out, visit, "xor(", ", ", ")");
1619 break;
1620 case EOpLogicalAnd:
1621 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1622 // been unfolded.
1623 ASSERT(!node->getRight()->hasSideEffects());
1624 outputTriplet(out, visit, "(", " && ", ")");
1625 return true;
1626 default:
1627 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001628 }
1629
1630 return true;
1631}
1632
1633bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1634{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001635 TInfoSinkBase &out = getInfoSink();
1636
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637 switch (node->getOp())
1638 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001639 case EOpNegative:
1640 outputTriplet(out, visit, "(-", "", ")");
1641 break;
1642 case EOpPositive:
1643 outputTriplet(out, visit, "(+", "", ")");
1644 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001645 case EOpLogicalNot:
1646 outputTriplet(out, visit, "(!", "", ")");
1647 break;
1648 case EOpBitwiseNot:
1649 outputTriplet(out, visit, "(~", "", ")");
1650 break;
1651 case EOpPostIncrement:
1652 outputTriplet(out, visit, "(", "", "++)");
1653 break;
1654 case EOpPostDecrement:
1655 outputTriplet(out, visit, "(", "", "--)");
1656 break;
1657 case EOpPreIncrement:
1658 outputTriplet(out, visit, "(++", "", ")");
1659 break;
1660 case EOpPreDecrement:
1661 outputTriplet(out, visit, "(--", "", ")");
1662 break;
1663 case EOpRadians:
1664 outputTriplet(out, visit, "radians(", "", ")");
1665 break;
1666 case EOpDegrees:
1667 outputTriplet(out, visit, "degrees(", "", ")");
1668 break;
1669 case EOpSin:
1670 outputTriplet(out, visit, "sin(", "", ")");
1671 break;
1672 case EOpCos:
1673 outputTriplet(out, visit, "cos(", "", ")");
1674 break;
1675 case EOpTan:
1676 outputTriplet(out, visit, "tan(", "", ")");
1677 break;
1678 case EOpAsin:
1679 outputTriplet(out, visit, "asin(", "", ")");
1680 break;
1681 case EOpAcos:
1682 outputTriplet(out, visit, "acos(", "", ")");
1683 break;
1684 case EOpAtan:
1685 outputTriplet(out, visit, "atan(", "", ")");
1686 break;
1687 case EOpSinh:
1688 outputTriplet(out, visit, "sinh(", "", ")");
1689 break;
1690 case EOpCosh:
1691 outputTriplet(out, visit, "cosh(", "", ")");
1692 break;
1693 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001694 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001695 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001696 case EOpAtanh:
1697 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001698 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001699 break;
1700 case EOpExp:
1701 outputTriplet(out, visit, "exp(", "", ")");
1702 break;
1703 case EOpLog:
1704 outputTriplet(out, visit, "log(", "", ")");
1705 break;
1706 case EOpExp2:
1707 outputTriplet(out, visit, "exp2(", "", ")");
1708 break;
1709 case EOpLog2:
1710 outputTriplet(out, visit, "log2(", "", ")");
1711 break;
1712 case EOpSqrt:
1713 outputTriplet(out, visit, "sqrt(", "", ")");
1714 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001715 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001716 outputTriplet(out, visit, "rsqrt(", "", ")");
1717 break;
1718 case EOpAbs:
1719 outputTriplet(out, visit, "abs(", "", ")");
1720 break;
1721 case EOpSign:
1722 outputTriplet(out, visit, "sign(", "", ")");
1723 break;
1724 case EOpFloor:
1725 outputTriplet(out, visit, "floor(", "", ")");
1726 break;
1727 case EOpTrunc:
1728 outputTriplet(out, visit, "trunc(", "", ")");
1729 break;
1730 case EOpRound:
1731 outputTriplet(out, visit, "round(", "", ")");
1732 break;
1733 case EOpRoundEven:
1734 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001735 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001736 break;
1737 case EOpCeil:
1738 outputTriplet(out, visit, "ceil(", "", ")");
1739 break;
1740 case EOpFract:
1741 outputTriplet(out, visit, "frac(", "", ")");
1742 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001743 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001744 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001745 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001746 else
1747 outputTriplet(out, visit, "isnan(", "", ")");
1748 mRequiresIEEEStrictCompiling = true;
1749 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001750 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001751 outputTriplet(out, visit, "isinf(", "", ")");
1752 break;
1753 case EOpFloatBitsToInt:
1754 outputTriplet(out, visit, "asint(", "", ")");
1755 break;
1756 case EOpFloatBitsToUint:
1757 outputTriplet(out, visit, "asuint(", "", ")");
1758 break;
1759 case EOpIntBitsToFloat:
1760 outputTriplet(out, visit, "asfloat(", "", ")");
1761 break;
1762 case EOpUintBitsToFloat:
1763 outputTriplet(out, visit, "asfloat(", "", ")");
1764 break;
1765 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001766 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001767 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001768 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001769 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001770 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001771 case EOpPackUnorm4x8:
1772 case EOpPackSnorm4x8:
1773 case EOpUnpackUnorm4x8:
1774 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001775 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001776 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001777 break;
1778 case EOpLength:
1779 outputTriplet(out, visit, "length(", "", ")");
1780 break;
1781 case EOpNormalize:
1782 outputTriplet(out, visit, "normalize(", "", ")");
1783 break;
1784 case EOpDFdx:
1785 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1786 {
1787 outputTriplet(out, visit, "(", "", ", 0.0)");
1788 }
1789 else
1790 {
1791 outputTriplet(out, visit, "ddx(", "", ")");
1792 }
1793 break;
1794 case EOpDFdy:
1795 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1796 {
1797 outputTriplet(out, visit, "(", "", ", 0.0)");
1798 }
1799 else
1800 {
1801 outputTriplet(out, visit, "ddy(", "", ")");
1802 }
1803 break;
1804 case EOpFwidth:
1805 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1806 {
1807 outputTriplet(out, visit, "(", "", ", 0.0)");
1808 }
1809 else
1810 {
1811 outputTriplet(out, visit, "fwidth(", "", ")");
1812 }
1813 break;
1814 case EOpTranspose:
1815 outputTriplet(out, visit, "transpose(", "", ")");
1816 break;
1817 case EOpDeterminant:
1818 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1819 break;
1820 case EOpInverse:
1821 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001822 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001823 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001824
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001825 case EOpAny:
1826 outputTriplet(out, visit, "any(", "", ")");
1827 break;
1828 case EOpAll:
1829 outputTriplet(out, visit, "all(", "", ")");
1830 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001831 case EOpLogicalNotComponentWise:
1832 outputTriplet(out, visit, "(!", "", ")");
1833 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001834 case EOpBitfieldReverse:
1835 outputTriplet(out, visit, "reversebits(", "", ")");
1836 break;
1837 case EOpBitCount:
1838 outputTriplet(out, visit, "countbits(", "", ")");
1839 break;
1840 case EOpFindLSB:
1841 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1842 // in GLSLTest and results are consistent with GL.
1843 outputTriplet(out, visit, "firstbitlow(", "", ")");
1844 break;
1845 case EOpFindMSB:
1846 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1847 // tested in GLSLTest and results are consistent with GL.
1848 outputTriplet(out, visit, "firstbithigh(", "", ")");
1849 break;
Qin Jiajia88faa692018-12-03 16:22:24 +08001850 case EOpArrayLength:
1851 {
1852 TIntermTyped *operand = node->getOperand();
1853 ASSERT(IsInShaderStorageBlock(operand));
1854 mSSBOOutputHLSL->outputLengthFunctionCall(operand);
1855 return false;
1856 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001857 default:
1858 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859 }
1860
1861 return true;
1862}
1863
Olli Etuahofbb1c792018-01-19 16:26:59 +02001864ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001865{
1866 if (node->getAsSymbolNode())
1867 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001868 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1869 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001870 }
1871 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1872 switch (nodeBinary->getOp())
1873 {
1874 case EOpIndexDirect:
1875 {
1876 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1877
Olli Etuahofbb1c792018-01-19 16:26:59 +02001878 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001879 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001880 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001881 }
1882 case EOpIndexDirectStruct:
1883 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001884 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001885 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1886 const TField *field = s->fields()[index];
1887
Olli Etuahofbb1c792018-01-19 16:26:59 +02001888 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001889 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1890 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001891 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001892 }
1893 default:
1894 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001895 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001896 }
1897}
1898
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001899bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1900{
1901 TInfoSinkBase &out = getInfoSink();
1902
Olli Etuaho06235df2018-07-20 14:26:07 +03001903 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1904
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001905 if (mInsideFunction)
1906 {
1907 outputLineDirective(out, node->getLine().first_line);
1908 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001909 if (isMainBlock)
1910 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001911 if (mShaderType == GL_COMPUTE_SHADER)
1912 {
1913 out << "initGLBuiltins(input);\n";
1914 }
1915 else
1916 {
1917 out << "@@ MAIN PROLOGUE @@\n";
1918 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001919 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001920 }
1921
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001922 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001923 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001924 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001925
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001926 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001927
1928 // Don't output ; after case labels, they're terminated by :
1929 // This is needed especially since outputting a ; after a case statement would turn empty
1930 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001931 // Also the output code is clearer if we don't output ; after statements where it is not
1932 // needed:
1933 // * if statements
1934 // * switch statements
1935 // * blocks
1936 // * function definitions
1937 // * loops (do-while loops output the semicolon in VisitLoop)
1938 // * declarations that don't generate output.
1939 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1940 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1941 statement->getAsSwitchNode() == nullptr &&
1942 statement->getAsFunctionDefinition() == nullptr &&
1943 (statement->getAsDeclarationNode() == nullptr ||
1944 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1945 statement->getAsInvariantDeclarationNode() == nullptr)
1946 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001947 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001948 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001949 }
1950
1951 if (mInsideFunction)
1952 {
1953 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001954 if (isMainBlock && shaderNeedsGenerateOutput())
1955 {
1956 // We could have an empty main, a main function without a branch at the end, or a main
1957 // function with a discard statement at the end. In these cases we need to add a return
1958 // statement.
1959 bool needReturnStatement =
1960 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1961 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1962 if (needReturnStatement)
1963 {
1964 out << "return " << generateOutputCall() << ";\n";
1965 }
1966 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001967 out << "}\n";
1968 }
1969
1970 return false;
1971}
1972
Olli Etuaho336b1472016-10-05 16:37:55 +01001973bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1974{
1975 TInfoSinkBase &out = getInfoSink();
1976
1977 ASSERT(mCurrentFunctionMetadata == nullptr);
1978
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001979 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001980 ASSERT(index != CallDAG::InvalidIndex);
1981 mCurrentFunctionMetadata = &mASTMetadataList[index];
1982
Olli Etuahod4bd9632018-03-08 16:32:44 +02001983 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001984
Olli Etuahod4bd9632018-03-08 16:32:44 +02001985 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001986 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001987 // The stub strings below are replaced when shader is dynamically defined by its layout:
1988 switch (mShaderType)
1989 {
1990 case GL_VERTEX_SHADER:
1991 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1992 << "@@ VERTEX OUTPUT @@\n\n"
1993 << "VS_OUTPUT main(VS_INPUT input)";
1994 break;
1995 case GL_FRAGMENT_SHADER:
1996 out << "@@ PIXEL OUTPUT @@\n\n"
1997 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1998 break;
1999 case GL_COMPUTE_SHADER:
2000 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
2001 << mWorkGroupSize[2] << ")]\n";
2002 out << "void main(CS_INPUT input)";
2003 break;
2004 default:
2005 UNREACHABLE();
2006 break;
2007 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002008 }
2009 else
2010 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002011 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02002012 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002013 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01002014
Olli Etuaho06235df2018-07-20 14:26:07 +03002015 size_t paramCount = func->getParamCount();
2016 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01002017 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002018 const TVariable *param = func->getParam(i);
2019 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01002020
Olli Etuaho06235df2018-07-20 14:26:07 +03002021 writeParameter(param, out);
2022
2023 if (i < paramCount - 1)
2024 {
2025 out << ", ";
2026 }
2027 }
2028
2029 out << ")\n";
2030 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002031
2032 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03002033 if (func->isMain())
2034 {
2035 mInsideMain = true;
2036 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002037 // The function body node will output braces.
2038 node->getBody()->traverse(this);
2039 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03002040 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01002041
2042 mCurrentFunctionMetadata = nullptr;
2043
2044 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2045 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2046 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002047 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01002048 mOutputLod0Function = true;
2049 node->traverse(this);
2050 mOutputLod0Function = false;
2051 }
2052
2053 return false;
2054}
2055
Olli Etuaho13389b62016-10-16 11:48:18 +01002056bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2057{
Olli Etuaho13389b62016-10-16 11:48:18 +01002058 if (visit == PreVisit)
2059 {
2060 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002061 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002062 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002063 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002064
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002065 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002066 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002067 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002068 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002069
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002070 if (!declarator->getAsSymbolNode() ||
2071 declarator->getAsSymbolNode()->variable().symbolType() !=
2072 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002073 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002074 if (declarator->getQualifier() == EvqShared)
2075 {
2076 out << "groupshared ";
2077 }
2078 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002079 {
2080 out << "static ";
2081 }
2082
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002083 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002084
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002085 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002086
2087 if (symbol)
2088 {
2089 symbol->traverse(this);
2090 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002091 if (declarator->getQualifier() != EvqShared ||
2092 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002093 {
2094 out << " = " + zeroInitializer(symbol->getType());
2095 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002096 }
2097 else
2098 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002099 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002100 }
2101 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002102 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002103 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002104 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002105 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002106 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002107
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002108 const TVariable &variable = symbol->variable();
2109
2110 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002111 {
2112 // Vertex outputs which are declared but not written to should still be declared to
2113 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002114 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002115 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002116 }
2117 }
2118 return false;
2119}
2120
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002121bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2122{
2123 // Do not do any translation
2124 return false;
2125}
2126
Olli Etuahod4bd9632018-03-08 16:32:44 +02002127void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002128{
2129 TInfoSinkBase &out = getInfoSink();
2130
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002131 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002132 // Skip the prototype if it is not implemented (and thus not used)
2133 if (index == CallDAG::InvalidIndex)
2134 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002135 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002136 }
2137
Olli Etuahod4bd9632018-03-08 16:32:44 +02002138 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002139
Olli Etuahod4bd9632018-03-08 16:32:44 +02002140 TString name = DecorateFunctionIfNeeded(func);
2141 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002142 << (mOutputLod0Function ? "Lod0(" : "(");
2143
Olli Etuahod4bd9632018-03-08 16:32:44 +02002144 size_t paramCount = func->getParamCount();
2145 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002146 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002147 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002148
Olli Etuahod4bd9632018-03-08 16:32:44 +02002149 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002150 {
2151 out << ", ";
2152 }
2153 }
2154
2155 out << ");\n";
2156
2157 // Also prototype the Lod0 variant if needed
2158 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2159 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2160 {
2161 mOutputLod0Function = true;
2162 node->traverse(this);
2163 mOutputLod0Function = false;
2164 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002165}
2166
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002167bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2168{
Jamie Madill32aab012015-01-27 14:12:26 -05002169 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002171 switch (node->getOp())
2172 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002173 case EOpCallBuiltInFunction:
2174 case EOpCallFunctionInAST:
2175 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002176 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002177 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002178
Corentin Wallez1239ee92015-03-19 14:38:02 -07002179 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002180 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002181 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002182 if (node->isArray())
2183 {
2184 UNIMPLEMENTED();
2185 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002186 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002187 ASSERT(index != CallDAG::InvalidIndex);
2188 lod0 &= mASTMetadataList[index].mNeedsLod0;
2189
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002190 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002191 out << DisambiguateFunctionName(node->getSequence());
2192 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002193 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002194 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002195 {
2196 // This path is used for internal functions that don't have their definitions in the
2197 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002198 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002199 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002200 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002201 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002202 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002203 TType type = (*arguments)[0]->getAsTyped()->getType();
2204 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002205 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002206 type.getMemoryQualifier().readonly);
2207 out << imageFunctionName << "(";
2208 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002209 else if (node->getFunction()->isAtomicCounterFunction())
2210 {
2211 const ImmutableString &name = node->getFunction()->name();
2212 ImmutableString atomicFunctionName =
2213 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2214 out << atomicFunctionName << "(";
2215 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002216 else
2217 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002218 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002219 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002220 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2221 if (arguments->size() > 1)
2222 {
2223 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2224 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002225 const ImmutableString &textureFunctionName =
2226 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2227 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002228 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002230
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002231 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002232 {
Olli Etuaho96963162016-03-21 11:54:33 +02002233 TIntermTyped *typedArg = (*arg)->getAsTyped();
2234 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002235 {
2236 out << "texture_";
2237 (*arg)->traverse(this);
2238 out << ", sampler_";
2239 }
2240
2241 (*arg)->traverse(this);
2242
Olli Etuaho96963162016-03-21 11:54:33 +02002243 if (typedArg->getType().isStructureContainingSamplers())
2244 {
2245 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002246 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002247 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2248 std::string namePrefix = "angle_";
2249 namePrefix += structName.data();
2250 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002251 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002252 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002253 {
2254 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2255 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002256 out << ", texture_" << sampler->name();
2257 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002258 }
2259 else
2260 {
2261 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2262 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002263 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002264 }
2265 }
2266 }
2267
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002268 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002269 {
2270 out << ", ";
2271 }
2272 }
2273
2274 out << ")";
2275
2276 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002277 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002278 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002279 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002280 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002281 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002282 outputTriplet(out, visit, "(", " == ", ")");
2283 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002284 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002285 outputTriplet(out, visit, "(", " != ", ")");
2286 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002287 case EOpLessThanComponentWise:
2288 outputTriplet(out, visit, "(", " < ", ")");
2289 break;
2290 case EOpGreaterThanComponentWise:
2291 outputTriplet(out, visit, "(", " > ", ")");
2292 break;
2293 case EOpLessThanEqualComponentWise:
2294 outputTriplet(out, visit, "(", " <= ", ")");
2295 break;
2296 case EOpGreaterThanEqualComponentWise:
2297 outputTriplet(out, visit, "(", " >= ", ")");
2298 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002299 case EOpMod:
2300 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002301 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002302 break;
2303 case EOpModf:
2304 outputTriplet(out, visit, "modf(", ", ", ")");
2305 break;
2306 case EOpPow:
2307 outputTriplet(out, visit, "pow(", ", ", ")");
2308 break;
2309 case EOpAtan:
2310 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2311 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002312 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002313 break;
2314 case EOpMin:
2315 outputTriplet(out, visit, "min(", ", ", ")");
2316 break;
2317 case EOpMax:
2318 outputTriplet(out, visit, "max(", ", ", ")");
2319 break;
2320 case EOpClamp:
2321 outputTriplet(out, visit, "clamp(", ", ", ")");
2322 break;
2323 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302324 {
2325 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2326 if (lastParamNode->getType().getBasicType() == EbtBool)
2327 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002328 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2329 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302330 // so use emulated version.
2331 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002332 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302333 }
2334 else
2335 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002336 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302337 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002338 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302339 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002340 case EOpStep:
2341 outputTriplet(out, visit, "step(", ", ", ")");
2342 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002343 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002344 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2345 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002346 case EOpFrexp:
2347 case EOpLdexp:
2348 ASSERT(node->getUseEmulatedFunction());
2349 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2350 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002351 case EOpDistance:
2352 outputTriplet(out, visit, "distance(", ", ", ")");
2353 break;
2354 case EOpDot:
2355 outputTriplet(out, visit, "dot(", ", ", ")");
2356 break;
2357 case EOpCross:
2358 outputTriplet(out, visit, "cross(", ", ", ")");
2359 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002360 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002361 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;
2364 case EOpReflect:
2365 outputTriplet(out, visit, "reflect(", ", ", ")");
2366 break;
2367 case EOpRefract:
2368 outputTriplet(out, visit, "refract(", ", ", ")");
2369 break;
2370 case EOpOuterProduct:
2371 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002372 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002373 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002374 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002375 outputTriplet(out, visit, "(", " * ", ")");
2376 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002377 case EOpBitfieldExtract:
2378 case EOpBitfieldInsert:
2379 case EOpUaddCarry:
2380 case EOpUsubBorrow:
2381 case EOpUmulExtended:
2382 case EOpImulExtended:
2383 ASSERT(node->getUseEmulatedFunction());
2384 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2385 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002386 case EOpBarrier:
2387 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2388 // cheapest *WithGroupSync() function, without any functionality loss, but
2389 // with the potential for severe performance loss.
2390 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2391 break;
2392 case EOpMemoryBarrierShared:
2393 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2394 break;
2395 case EOpMemoryBarrierAtomicCounter:
2396 case EOpMemoryBarrierBuffer:
2397 case EOpMemoryBarrierImage:
2398 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2399 break;
2400 case EOpGroupMemoryBarrier:
2401 case EOpMemoryBarrier:
2402 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2403 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002404
2405 // Single atomic function calls without return value.
2406 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2407 case EOpAtomicAdd:
2408 case EOpAtomicMin:
2409 case EOpAtomicMax:
2410 case EOpAtomicAnd:
2411 case EOpAtomicOr:
2412 case EOpAtomicXor:
Qin Jiajia46229052018-12-10 13:31:00 +08002413 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
2414 // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
2415 // optional.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002416 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2417 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
Qin Jiajia46229052018-12-10 13:31:00 +08002418 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
2419 // compare_value, value) should all be modified into the form of "int temp; temp =
2420 // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
2421 // compare_value, value);" in the intermediate tree before traversing outputHLSL.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002422 case EOpAtomicExchange:
2423 case EOpAtomicCompSwap:
Qin Jiajia46229052018-12-10 13:31:00 +08002424 {
2425 ASSERT(node->getChildCount() > 1);
2426 TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
2427 if (IsInShaderStorageBlock(memNode))
2428 {
2429 // Atomic memory functions for SSBO.
2430 // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
2431 mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
2432 // Write the rest argument list to |out|.
2433 for (size_t i = 1; i < node->getChildCount(); i++)
2434 {
2435 out << ", ";
2436 TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
2437 if (IsInShaderStorageBlock(argument))
2438 {
2439 mSSBOOutputHLSL->outputLoadFunctionCall(argument);
2440 }
2441 else
2442 {
2443 argument->traverse(this);
2444 }
2445 }
2446
2447 out << ")";
2448 return false;
2449 }
2450 else
2451 {
2452 // Atomic memory functions for shared variable.
2453 if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
2454 {
2455 outputTriplet(out, visit,
2456 GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
2457 ")");
2458 }
2459 else
2460 {
2461 UNREACHABLE();
2462 }
2463 }
2464
2465 break;
2466 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002467 default:
2468 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002469 }
2470
2471 return true;
2472}
2473
Olli Etuaho57961272016-09-14 13:57:46 +03002474void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002475{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002476 out << "if (";
2477
2478 node->getCondition()->traverse(this);
2479
2480 out << ")\n";
2481
Jamie Madill8c46ab12015-12-07 16:39:19 -05002482 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002483
2484 bool discard = false;
2485
2486 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002487 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002488 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002489 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002490
Olli Etuahoa6f22092015-05-08 18:31:10 +03002491 // Detect true discard
2492 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2493 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002494 else
2495 {
2496 // TODO(oetuaho): Check if the semicolon inside is necessary.
2497 // It's there as a result of conservative refactoring of the output.
2498 out << "{;}\n";
2499 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002500
Jamie Madill8c46ab12015-12-07 16:39:19 -05002501 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002502
Olli Etuahoa6f22092015-05-08 18:31:10 +03002503 if (node->getFalseBlock())
2504 {
2505 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002506
Jamie Madill8c46ab12015-12-07 16:39:19 -05002507 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002508
Olli Etuaho32db19b2016-10-04 14:43:16 +01002509 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002510 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002511
Jamie Madill8c46ab12015-12-07 16:39:19 -05002512 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002513
Olli Etuahoa6f22092015-05-08 18:31:10 +03002514 // Detect false discard
2515 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2516 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002517
Olli Etuahoa6f22092015-05-08 18:31:10 +03002518 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002519 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002520 {
2521 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002522 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002523}
2524
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002525bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2526{
2527 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2528 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2529 UNREACHABLE();
2530 return false;
2531}
2532
Olli Etuaho57961272016-09-14 13:57:46 +03002533bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002534{
2535 TInfoSinkBase &out = getInfoSink();
2536
Olli Etuaho3d932d82016-04-12 11:10:30 +03002537 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002538
2539 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002540 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002541 {
2542 out << "FLATTEN ";
2543 }
2544
Olli Etuaho57961272016-09-14 13:57:46 +03002545 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002546
2547 return false;
2548}
2549
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002550bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002551{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002552 TInfoSinkBase &out = getInfoSink();
2553
Olli Etuaho923ecef2017-10-11 12:01:38 +03002554 ASSERT(node->getStatementList());
2555 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002556 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002557 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002558 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002559 outputTriplet(out, visit, "switch (", ") ", "");
2560 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002561 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002562}
2563
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002564bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002565{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002566 TInfoSinkBase &out = getInfoSink();
2567
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002568 if (node->hasCondition())
2569 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002570 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002571 return true;
2572 }
2573 else
2574 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002575 out << "default:\n";
2576 return false;
2577 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002578}
2579
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002580void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2581{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002582 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002583 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002584}
2585
2586bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2587{
Nicolas Capens655fe362014-04-11 13:12:34 -04002588 mNestedLoopDepth++;
2589
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002590 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002591 mInsideDiscontinuousLoop =
2592 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002593
Jamie Madill8c46ab12015-12-07 16:39:19 -05002594 TInfoSinkBase &out = getInfoSink();
2595
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002596 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002597 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002598 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002599 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002600 mInsideDiscontinuousLoop = wasDiscontinuous;
2601 mNestedLoopDepth--;
2602
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002603 return false;
2604 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002605 }
2606
Corentin Wallez1239ee92015-03-19 14:38:02 -07002607 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002608 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002609 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002610 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002611
Jamie Madill8c46ab12015-12-07 16:39:19 -05002612 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002613 }
2614 else
2615 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002616 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002617
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002618 if (node->getInit())
2619 {
2620 node->getInit()->traverse(this);
2621 }
2622
2623 out << "; ";
2624
alokp@chromium.org52813552010-11-16 18:36:09 +00002625 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002626 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002627 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002628 }
2629
2630 out << "; ";
2631
alokp@chromium.org52813552010-11-16 18:36:09 +00002632 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002633 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002634 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002635 }
2636
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002637 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002638
Jamie Madill8c46ab12015-12-07 16:39:19 -05002639 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002640 }
2641
2642 if (node->getBody())
2643 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002644 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002645 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002646 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002647 else
2648 {
2649 // TODO(oetuaho): Check if the semicolon inside is necessary.
2650 // It's there as a result of conservative refactoring of the output.
2651 out << "{;}\n";
2652 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002653
Jamie Madill8c46ab12015-12-07 16:39:19 -05002654 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002655
alokp@chromium.org52813552010-11-16 18:36:09 +00002656 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002657 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002658 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002659 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002660
alokp@chromium.org52813552010-11-16 18:36:09 +00002661 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002662
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002663 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002664 }
2665
daniel@transgaming.com73536982012-03-21 20:45:49 +00002666 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002667
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002668 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002669 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002670
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002671 return false;
2672}
2673
2674bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2675{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002676 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002677 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002678 TInfoSinkBase &out = getInfoSink();
2679
2680 switch (node->getFlowOp())
2681 {
2682 case EOpKill:
2683 out << "discard";
2684 break;
2685 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002686 if (mNestedLoopDepth > 1)
2687 {
2688 mUsesNestedBreak = true;
2689 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002690
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002691 if (mExcessiveLoopIndex)
2692 {
2693 out << "{Break";
2694 mExcessiveLoopIndex->traverse(this);
2695 out << " = true; break;}\n";
2696 }
2697 else
2698 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002699 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002700 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002701 break;
2702 case EOpContinue:
2703 out << "continue";
2704 break;
2705 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002706 if (node->getExpression())
2707 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002708 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002709 out << "return ";
2710 }
2711 else
2712 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002713 if (mInsideMain && shaderNeedsGenerateOutput())
2714 {
2715 out << "return " << generateOutputCall();
2716 }
2717 else
2718 {
2719 out << "return";
2720 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002721 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002722 break;
2723 default:
2724 UNREACHABLE();
2725 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002726 }
2727
2728 return true;
2729}
2730
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002731// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002732// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2733// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002734bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002735{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002736 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002737
2738 // Parse loops of the form:
2739 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002740 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002741 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002742 int initial = 0;
2743 int limit = 0;
2744 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002745
2746 // Parse index name and intial value
2747 if (node->getInit())
2748 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002749 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002750
2751 if (init)
2752 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002753 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002754 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002755
2756 if (variable && variable->getQualifier() == EvqTemporary)
2757 {
2758 TIntermBinary *assign = variable->getAsBinaryNode();
2759
2760 if (assign->getOp() == EOpInitialize)
2761 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002762 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002763 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2764
2765 if (symbol && constant)
2766 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002767 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002768 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002769 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002770 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002771 }
2772 }
2773 }
2774 }
2775 }
2776 }
2777
2778 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002779 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002780 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002781 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002782
Olli Etuahob6af22b2017-12-15 14:05:44 +02002783 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002784 {
2785 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2786
2787 if (constant)
2788 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002789 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002790 {
2791 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002792 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002793 }
2794 }
2795 }
2796 }
2797
2798 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002799 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002800 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002801 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002802 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002803
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002804 if (binaryTerminal)
2805 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002806 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002807 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2808
2809 if (constant)
2810 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002811 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002812 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002813 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002814
2815 switch (op)
2816 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002817 case EOpAddAssign:
2818 increment = value;
2819 break;
2820 case EOpSubAssign:
2821 increment = -value;
2822 break;
2823 default:
2824 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002825 }
2826 }
2827 }
2828 }
2829 else if (unaryTerminal)
2830 {
2831 TOperator op = unaryTerminal->getOp();
2832
2833 switch (op)
2834 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002835 case EOpPostIncrement:
2836 increment = 1;
2837 break;
2838 case EOpPostDecrement:
2839 increment = -1;
2840 break;
2841 case EOpPreIncrement:
2842 increment = 1;
2843 break;
2844 case EOpPreDecrement:
2845 increment = -1;
2846 break;
2847 default:
2848 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002849 }
2850 }
2851 }
2852
Yunchao He4f285442017-04-21 12:15:49 +08002853 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002854 {
2855 if (comparator == EOpLessThanEqual)
2856 {
2857 comparator = EOpLessThan;
2858 limit += 1;
2859 }
2860
2861 if (comparator == EOpLessThan)
2862 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002863 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002864
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002865 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002866 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002867 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002868 }
2869
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002870 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002871 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002872
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002873 out << "{int ";
2874 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002875 out << ";\n"
2876 "bool Break";
2877 index->traverse(this);
2878 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002879
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002880 bool firstLoopFragment = true;
2881
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002882 while (iterations > 0)
2883 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002884 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002885
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002886 if (!firstLoopFragment)
2887 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002888 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002889 index->traverse(this);
2890 out << ") {\n";
2891 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002892
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002893 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002894 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002895 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002896 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002897
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002898 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002899 const char *unroll =
2900 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002901
Corentin Wallez1239ee92015-03-19 14:38:02 -07002902 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002903 index->traverse(this);
2904 out << " = ";
2905 out << initial;
2906
2907 out << "; ";
2908 index->traverse(this);
2909 out << " < ";
2910 out << clampedLimit;
2911
2912 out << "; ";
2913 index->traverse(this);
2914 out << " += ";
2915 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002916 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002917
Jamie Madill8c46ab12015-12-07 16:39:19 -05002918 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002919 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002920
2921 if (node->getBody())
2922 {
2923 node->getBody()->traverse(this);
2924 }
2925
Jamie Madill8c46ab12015-12-07 16:39:19 -05002926 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002927 out << ";}\n";
2928
2929 if (!firstLoopFragment)
2930 {
2931 out << "}\n";
2932 }
2933
2934 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002935
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002936 initial += MAX_LOOP_ITERATIONS * increment;
2937 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002938 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002939
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002940 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002941
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002942 mExcessiveLoopIndex = restoreIndex;
2943
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002944 return true;
2945 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002946 else
2947 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002948 }
2949
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002950 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002951}
2952
Jamie Madill8c46ab12015-12-07 16:39:19 -05002953void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2954 Visit visit,
2955 const char *preString,
2956 const char *inString,
2957 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002958{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002959 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002960 {
2961 out << preString;
2962 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002963 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002964 {
2965 out << inString;
2966 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002967 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002968 {
2969 out << postString;
2970 }
2971}
2972
Jamie Madill8c46ab12015-12-07 16:39:19 -05002973void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002974{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002975 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002976 {
Jamie Madill32aab012015-01-27 14:12:26 -05002977 out << "\n";
2978 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002979
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002980 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002981 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002982 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002983 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002984
Jamie Madill32aab012015-01-27 14:12:26 -05002985 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002986 }
2987}
2988
Olli Etuahod4bd9632018-03-08 16:32:44 +02002989void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002990{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002991 const TType &type = param->getType();
2992 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002993
Olli Etuahod4bd9632018-03-08 16:32:44 +02002994 TString nameStr = DecorateVariableIfNeeded(*param);
2995 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002996
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002997 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002998 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002999 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3000 {
3001 // Samplers are passed as indices to the sampler array.
3002 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003003 out << "const uint " << nameStr << ArrayString(type);
3004 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003005 }
3006 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3007 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003008 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
3009 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
3010 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
3011 << ArrayString(type);
3012 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003013 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003014 }
3015
Brandon Jones4a22f4b2018-10-23 14:36:47 -07003016 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
3017 // buffer offset.
3018 if (IsAtomicCounter(type.getBasicType()))
3019 {
3020 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
3021 << nameStr << "_offset";
3022 }
3023 else
3024 {
3025 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
3026 << ArrayString(type);
3027 }
Olli Etuaho96963162016-03-21 11:54:33 +02003028
3029 // If the structure parameter contains samplers, they need to be passed into the function as
3030 // separate parameters. HLSL doesn't natively support samplers in structs.
3031 if (type.isStructureContainingSamplers())
3032 {
3033 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003034 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02003035 std::string namePrefix = "angle";
3036 namePrefix += nameStr.c_str();
3037 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
3038 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003039 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02003040 {
Olli Etuaho28839f02017-08-15 11:38:16 +03003041 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02003042 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3043 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003044 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003045 }
3046 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3047 {
Olli Etuaho96963162016-03-21 11:54:33 +02003048 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003049 out << ", " << QualifierString(qualifier) << " "
3050 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
3051 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
3052 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
3053 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003054 }
3055 else
3056 {
Olli Etuaho96963162016-03-21 11:54:33 +02003057 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003058 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3059 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003060 }
3061 }
3062 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003063}
3064
jchen10efe061b2018-11-13 16:44:40 +08003065TString OutputHLSL::zeroInitializer(const TType &type) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003066{
3067 TString string;
3068
Jamie Madill94bf7f22013-07-08 13:31:15 -04003069 size_t size = type.getObjectSize();
jchen10efe061b2018-11-13 16:44:40 +08003070 if (size >= kZeroCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003071 {
jchen10efe061b2018-11-13 16:44:40 +08003072 mUseZeroArray = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003073 }
jchen10efe061b2018-11-13 16:44:40 +08003074 string = GetZeroInitializer(size).c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003075
daniel@transgaming.comead23042010-04-29 03:35:36 +00003076 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003077}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003078
Olli Etuahobd3cd502017-11-03 15:48:52 +02003079void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003080{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003081 // Array constructors should have been already pruned from the code.
3082 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003083
3084 if (visit == PreVisit)
3085 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003086 TString constructorName;
3087 if (node->getBasicType() == EbtStruct)
3088 {
3089 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3090 }
3091 else
3092 {
3093 constructorName =
3094 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3095 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003096 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003097 }
3098 else if (visit == InVisit)
3099 {
3100 out << ", ";
3101 }
3102 else if (visit == PostVisit)
3103 {
3104 out << ")";
3105 }
3106}
3107
Jamie Madill8c46ab12015-12-07 16:39:19 -05003108const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3109 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003110 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003111{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003112 ASSERT(!type.isArray());
3113
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003114 const TConstantUnion *constUnionIterated = constUnion;
3115
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003116 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003117 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003118 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003119 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003120
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003121 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003122
Jamie Madill98493dd2013-07-08 14:39:03 -04003123 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003124 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003125 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003126 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003127
Jamie Madill98493dd2013-07-08 14:39:03 -04003128 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003129 {
3130 out << ", ";
3131 }
3132 }
3133
3134 out << ")";
3135 }
3136 else
3137 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003138 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003139 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003140
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003141 if (writeType)
3142 {
Jamie Madill033dae62014-06-18 12:56:28 -04003143 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003144 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003145 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003146 if (writeType)
3147 {
3148 out << ")";
3149 }
3150 }
3151
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003152 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003153}
3154
Olli Etuahod68924e2017-01-02 17:34:40 +00003155void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003156{
Olli Etuahod68924e2017-01-02 17:34:40 +00003157 if (visit == PreVisit)
3158 {
3159 const char *opStr = GetOperatorString(op);
3160 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3161 out << "(";
3162 }
3163 else
3164 {
3165 outputTriplet(out, visit, nullptr, ", ", ")");
3166 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003167}
3168
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003169bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3170 TIntermSymbol *symbolNode,
3171 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003172{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003173 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3174 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003175
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003176 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003177 {
3178 // Type already printed
3179 out << "t" + str(mUniqueIndex) + " = ";
3180 expression->traverse(this);
3181 out << ", ";
3182 symbolNode->traverse(this);
3183 out << " = t" + str(mUniqueIndex);
3184
3185 mUniqueIndex++;
3186 return true;
3187 }
3188
3189 return false;
3190}
3191
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003192bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3193 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003194 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003195{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003196 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003197 {
3198 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003199 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003200 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003201 writeConstantUnionArray(out, initializer->getConstantValue(),
3202 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003203 out << "}";
3204 return true;
3205 }
3206 return false;
3207}
3208
Jamie Madill55e79e02015-02-09 15:35:00 -05003209TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3210{
3211 const TFieldList &fields = structure.fields();
3212
3213 for (const auto &eqFunction : mStructEqualityFunctions)
3214 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003215 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003216 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003217 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003218 }
3219 }
3220
3221 const TString &structNameString = StructNameString(structure);
3222
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003223 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003224 function->structure = &structure;
3225 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003226
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003227 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003228
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003229 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3230 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003231 << "{\n"
3232 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003233
3234 for (size_t i = 0; i < fields.size(); i++)
3235 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003236 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003237 const TType *fieldType = field->type();
3238
3239 const TString &fieldNameA = "a." + Decorate(field->name());
3240 const TString &fieldNameB = "b." + Decorate(field->name());
3241
3242 if (i > 0)
3243 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003244 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003245 }
3246
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003247 fnOut << "(";
3248 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3249 fnOut << fieldNameA;
3250 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3251 fnOut << fieldNameB;
3252 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3253 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003254 }
3255
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003256 fnOut << ";\n"
3257 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003258
3259 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003260
3261 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003262 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003263
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003264 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003265}
3266
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003267TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003268{
3269 for (const auto &eqFunction : mArrayEqualityFunctions)
3270 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003271 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003272 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003273 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003274 }
3275 }
3276
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003277 TType elementType(type);
3278 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003279
Olli Etuaho12690762015-03-31 12:55:28 +03003280 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003281 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003282
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003283 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003284
3285 TInfoSinkBase fnOut;
3286
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003287 const TString &typeName = TypeString(type);
3288 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3289 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003290 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003291 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003292 << type.getOutermostArraySize()
3293 << "; ++i)\n"
3294 " {\n"
3295 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003296
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003297 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003298 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003299 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003300 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003301 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003302
3303 fnOut << ") { return false; }\n"
3304 " }\n"
3305 " return true;\n"
3306 "}\n";
3307
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003308 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003309
3310 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003311 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003312
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003313 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003314}
3315
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003316TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003317{
3318 for (const auto &assignFunction : mArrayAssignmentFunctions)
3319 {
3320 if (assignFunction.type == type)
3321 {
3322 return assignFunction.functionName;
3323 }
3324 }
3325
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003326 TType elementType(type);
3327 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003328
3329 ArrayHelperFunction function;
3330 function.type = type;
3331
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003332 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003333
3334 TInfoSinkBase fnOut;
3335
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003336 const TString &typeName = TypeString(type);
3337 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3338 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003339 << "{\n"
3340 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003341 << type.getOutermostArraySize()
3342 << "; ++i)\n"
3343 " {\n"
3344 " ";
3345
3346 outputAssign(PreVisit, elementType, fnOut);
3347 fnOut << "a[i]";
3348 outputAssign(InVisit, elementType, fnOut);
3349 fnOut << "b[i]";
3350 outputAssign(PostVisit, elementType, fnOut);
3351
3352 fnOut << ";\n"
3353 " }\n"
3354 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003355
3356 function.functionDefinition = fnOut.c_str();
3357
3358 mArrayAssignmentFunctions.push_back(function);
3359
3360 return function.functionName;
3361}
3362
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003363TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003364{
3365 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3366 {
3367 if (constructIntoFunction.type == type)
3368 {
3369 return constructIntoFunction.functionName;
3370 }
3371 }
3372
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003373 TType elementType(type);
3374 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003375
3376 ArrayHelperFunction function;
3377 function.type = type;
3378
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003379 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003380
3381 TInfoSinkBase fnOut;
3382
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003383 const TString &typeName = TypeString(type);
3384 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3385 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003386 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003387 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003388 }
3389 fnOut << ")\n"
3390 "{\n";
3391
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003392 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003393 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003394 fnOut << " ";
3395 outputAssign(PreVisit, elementType, fnOut);
3396 fnOut << "a[" << i << "]";
3397 outputAssign(InVisit, elementType, fnOut);
3398 fnOut << "b" << i;
3399 outputAssign(PostVisit, elementType, fnOut);
3400 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003401 }
3402 fnOut << "}\n";
3403
3404 function.functionDefinition = fnOut.c_str();
3405
3406 mArrayConstructIntoFunctions.push_back(function);
3407
3408 return function.functionName;
3409}
3410
Jamie Madill2e295e22015-04-29 10:41:33 -04003411void OutputHLSL::ensureStructDefined(const TType &type)
3412{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003413 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003414 if (structure)
3415 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003416 ASSERT(type.getBasicType() == EbtStruct);
3417 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003418 }
3419}
3420
Olli Etuaho06235df2018-07-20 14:26:07 +03003421bool OutputHLSL::shaderNeedsGenerateOutput() const
3422{
3423 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3424}
3425
3426const char *OutputHLSL::generateOutputCall() const
3427{
3428 if (mShaderType == GL_VERTEX_SHADER)
3429 {
3430 return "generateOutput(input)";
3431 }
3432 else
3433 {
3434 return "generateOutput()";
3435 }
3436}
3437
Jamie Madill45bcc782016-11-07 13:58:48 -05003438} // namespace sh