blob: e0412cb3f660bdfa89bea015b47c7165253baeb7 [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
Xinghua Caof3179a62018-07-12 16:22:06 +080038constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
39
Olli Etuaho96f6adf2017-08-16 11:18:54 +030040TString ArrayHelperFunctionName(const char *prefix, const TType &type)
41{
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -050042 TStringStream fnName = sh::InitializeStream<TStringStream>();
Olli Etuaho96f6adf2017-08-16 11:18:54 +030043 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080044 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030045 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080046 for (unsigned int arraySize : *type.getArraySizes())
47 {
48 fnName << arraySize << "_";
49 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030050 }
51 fnName << TypeString(type);
52 return fnName.str();
53}
54
Olli Etuaho40dbdd62017-10-13 13:34:19 +030055bool IsDeclarationWrittenOut(TIntermDeclaration *node)
56{
57 TIntermSequence *sequence = node->getSequence();
58 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
59 ASSERT(sequence->size() == 1);
60 ASSERT(variable);
61 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080062 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030063}
64
Qin Jiajiaa735ee22018-05-18 13:29:09 +080065bool IsInStd140UniformBlock(TIntermTyped *node)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020066{
67 TIntermBinary *binaryNode = node->getAsBinaryNode();
68
69 if (binaryNode)
70 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080071 return IsInStd140UniformBlock(binaryNode->getLeft());
Olli Etuaho2ef23e22017-11-01 16:39:11 +020072 }
73
74 const TType &type = node->getType();
75
Qin Jiajiaa735ee22018-05-18 13:29:09 +080076 if (type.getQualifier() == EvqUniform)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020077 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080078 // determine if we are in the standard layout
79 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
80 if (interfaceBlock)
81 {
82 return (interfaceBlock->blockStorage() == EbsStd140);
83 }
Olli Etuaho2ef23e22017-11-01 16:39:11 +020084 }
85
86 return false;
87}
88
Jiawei Shaoa6a78422018-06-28 08:32:54 +080089const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
90{
91 switch (op)
92 {
93 case EOpAtomicAdd:
94 return "InterlockedAdd(";
95 case EOpAtomicMin:
96 return "InterlockedMin(";
97 case EOpAtomicMax:
98 return "InterlockedMax(";
99 case EOpAtomicAnd:
100 return "InterlockedAnd(";
101 case EOpAtomicOr:
102 return "InterlockedOr(";
103 case EOpAtomicXor:
104 return "InterlockedXor(";
105 case EOpAtomicExchange:
106 return "InterlockedExchange(";
107 case EOpAtomicCompSwap:
108 return "InterlockedCompareExchange(";
109 default:
110 UNREACHABLE();
111 return "";
112 }
113}
114
Qin Jiajia46229052018-12-10 13:31:00 +0800115bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800116{
Qin Jiajia46229052018-12-10 13:31:00 +0800117 TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
118 if (aggregateNode == nullptr)
119 {
120 return false;
121 }
122
123 if (node.getOp() == EOpAssign && IsAtomicFunction(aggregateNode->getOp()))
124 {
125 return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped());
126 }
127
128 return false;
Jiawei Shaoa6a78422018-06-28 08:32:54 +0800129}
130
jchen10efe061b2018-11-13 16:44:40 +0800131const char *kZeros = "_ANGLE_ZEROS_";
132constexpr int kZeroCount = 256;
133std::string DefineZeroArray()
134{
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -0500135 std::stringstream ss = sh::InitializeStream<std::stringstream>();
jchen10efe061b2018-11-13 16:44:40 +0800136 // For 'static', if the declaration does not include an initializer, the value is set to zero.
137 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
138 ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
139 return ss.str();
140}
141
142std::string GetZeroInitializer(size_t size)
143{
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -0500144 std::stringstream ss = sh::InitializeStream<std::stringstream>();
jchen10efe061b2018-11-13 16:44:40 +0800145 size_t quotient = size / kZeroCount;
146 size_t reminder = size % kZeroCount;
147
148 for (size_t i = 0; i < quotient; ++i)
149 {
150 if (i != 0)
151 {
152 ss << ", ";
153 }
154 ss << kZeros;
155 }
156
157 for (size_t i = 0; i < reminder; ++i)
158 {
159 if (quotient != 0 || i != 0)
160 {
161 ss << ", ";
162 }
163 ss << "0";
164 }
165
166 return ss.str();
167}
168
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300169} // anonymous namespace
170
Olli Etuahoc71862a2017-12-21 12:58:29 +0200171TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
172 const TVariable *aInstanceVariable)
173 : block(aBlock), instanceVariable(aInstanceVariable)
Jamie Madillb980c562018-11-27 11:34:27 -0500174{}
Olli Etuahoc71862a2017-12-21 12:58:29 +0200175
Olli Etuaho56a2f952016-12-08 12:16:27 +0000176void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300177{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000178 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
179 // regardless.
180 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
181 mOutputType == SH_HLSL_4_1_OUTPUT)
182 {
183 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
184 }
185 else
186 {
187 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
188 }
189}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300190
Olli Etuaho56a2f952016-12-08 12:16:27 +0000191void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200192{
193 ASSERT(constUnion != nullptr);
194 switch (constUnion->getType())
195 {
196 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000197 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200198 break;
199 case EbtInt:
200 out << constUnion->getIConst();
201 break;
202 case EbtUInt:
203 out << constUnion->getUConst();
204 break;
205 case EbtBool:
206 out << constUnion->getBConst();
207 break;
208 default:
209 UNREACHABLE();
210 }
211}
212
Olli Etuaho56a2f952016-12-08 12:16:27 +0000213const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
214 const TConstantUnion *const constUnion,
215 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200216{
217 const TConstantUnion *constUnionIterated = constUnion;
218 for (size_t i = 0; i < size; i++, constUnionIterated++)
219 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000220 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200221
222 if (i != size - 1)
223 {
224 out << ", ";
225 }
226 }
227 return constUnionIterated;
228}
229
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800230OutputHLSL::OutputHLSL(sh::GLenum shaderType,
231 int shaderVersion,
232 const TExtensionBehavior &extensionBehavior,
233 const char *sourcePath,
234 ShShaderOutput outputType,
235 int numRenderTargets,
236 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300237 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300238 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300239 TSymbolTable *symbolTable,
Jamie Madill4e712be2019-01-03 13:53:59 -0500240 PerformanceDiagnostics *perfDiagnostics,
241 const std::vector<InterfaceBlock> &shaderStorageBlocks)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300242 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200243 mShaderType(shaderType),
244 mShaderVersion(shaderVersion),
245 mExtensionBehavior(extensionBehavior),
246 mSourcePath(sourcePath),
247 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700248 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300249 mInsideFunction(false),
250 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000251 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300252 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300253 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300254 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800256 mUsesFragColor = false;
257 mUsesFragData = false;
258 mUsesDepthRange = false;
259 mUsesFragCoord = false;
260 mUsesPointCoord = false;
261 mUsesFrontFacing = false;
262 mUsesPointSize = false;
263 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300264 mHasMultiviewExtensionEnabled =
265 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300266 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500267 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500268 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800269 mUsesNumWorkGroups = false;
270 mUsesWorkGroupID = false;
271 mUsesLocalInvocationID = false;
272 mUsesGlobalInvocationID = false;
273 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500274 mUsesXor = false;
275 mUsesDiscardRewriting = false;
276 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530277 mRequiresIEEEStrictCompiling = false;
jchen10efe061b2018-11-13 16:44:40 +0800278 mUseZeroArray = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000279
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000280 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000281
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500282 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000283 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500284 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000285
Yunchao Hed7297bf2017-04-19 15:27:10 +0800286 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000287
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700288 mStructureHLSL = new StructureHLSL;
289 mTextureFunctionHLSL = new TextureFunctionHLSL;
290 mImageFunctionHLSL = new ImageFunctionHLSL;
291 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400292
Olli Etuahod8724a92017-12-29 18:40:36 +0200293 unsigned int firstUniformRegister =
294 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800295 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200296
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200297 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000298 {
Arun Patole63419392015-03-13 11:51:07 +0530299 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500300 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
301 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530302 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800303 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000304 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000305
Geoff Lang00140f42016-02-03 18:47:33 +0000306 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800307 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800308
Jamie Madill4e712be2019-01-03 13:53:59 -0500309 mSSBOOutputHLSL =
310 new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL, shaderStorageBlocks);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311}
312
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000313OutputHLSL::~OutputHLSL()
314{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800315 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400316 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800317 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300318 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800319 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700320 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200321 for (auto &eqFunction : mStructEqualityFunctions)
322 {
323 SafeDelete(eqFunction);
324 }
325 for (auto &eqFunction : mArrayEqualityFunctions)
326 {
327 SafeDelete(eqFunction);
328 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000329}
330
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200331void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000332{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200333 BuiltInFunctionEmulator builtInFunctionEmulator;
334 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800335 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
336 {
337 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
338 mShaderVersion);
339 }
340
Olli Etuahodfa75e82017-01-23 09:43:06 -0800341 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500342
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700343 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000344 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700345 ASSERT(success == CallDAG::INITDAG_SUCCESS);
346 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700347
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200348 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
349 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
350 // the shader code. When we add shader storage blocks we might also consider an alternative
351 // solution, since the struct mapping won't work very well for shader storage blocks.
352
Jamie Madill37997142015-01-28 10:06:34 -0500353 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500354 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200355 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500356 mInfoSinkStack.pop();
357
Jamie Madill37997142015-01-28 10:06:34 -0500358 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500359 mInfoSinkStack.pop();
360
Jamie Madill32aab012015-01-27 14:12:26 -0500361 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200362 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500363 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000364
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200365 objSink << mHeader.c_str();
366 objSink << mBody.c_str();
367 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200368
Olli Etuahodfa75e82017-01-23 09:43:06 -0800369 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000370}
371
Qin Jiajiaa602f902018-09-11 14:40:24 +0800372const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
373{
374 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
375}
376
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800377const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400378{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800379 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400380}
381
Jamie Madill9fe25e92014-07-18 10:33:08 -0400382const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
383{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800384 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400385}
386
Xinghua Caof3179a62018-07-12 16:22:06 +0800387unsigned int OutputHLSL::getReadonlyImage2DRegisterIndex() const
388{
389 return mResourcesHLSL->getReadonlyImage2DRegisterIndex();
390}
391
392unsigned int OutputHLSL::getImage2DRegisterIndex() const
393{
394 return mResourcesHLSL->getImage2DRegisterIndex();
395}
396
397const std::set<std::string> &OutputHLSL::getUsedImage2DFunctionNames() const
398{
399 return mImageFunctionHLSL->getUsedImage2DFunctionNames();
400}
401
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200402TString OutputHLSL::structInitializerString(int indent,
403 const TType &type,
404 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400405{
406 TString init;
407
Olli Etuahoed049ab2017-06-30 17:38:33 +0300408 TString indentString;
409 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400410 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300411 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400412 }
413
Olli Etuahoed049ab2017-06-30 17:38:33 +0300414 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400415 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300416 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300417 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400418 {
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -0500419 TStringStream indexedString = sh::InitializeStream<TStringStream>();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300420 indexedString << name << "[" << arrayIndex << "]";
421 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300422 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300423 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300424 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300425 {
426 init += ",";
427 }
428 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400429 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300430 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400431 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300432 else if (type.getBasicType() == EbtStruct)
433 {
434 init += indentString + "{\n";
435 const TStructure &structure = *type.getStruct();
436 const TFieldList &fields = structure.fields();
437 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
438 {
439 const TField &field = *fields[fieldIndex];
440 const TString &fieldName = name + "." + Decorate(field.name());
441 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400442
Olli Etuahoed049ab2017-06-30 17:38:33 +0300443 init += structInitializerString(indent + 1, fieldType, fieldName);
444 if (fieldIndex < fields.size() - 1)
445 {
446 init += ",";
447 }
448 init += "\n";
449 }
450 init += indentString + "}";
451 }
452 else
453 {
454 init += indentString + name;
455 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400456
457 return init;
458}
459
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200460TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
461{
462 TString mappedStructs;
463
464 for (auto &mappedStruct : std140Structs)
465 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200466 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200467 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800468 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
469 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200470 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800471 case EvqUniform:
472 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
473 {
474 continue;
475 }
476 break;
477 case EvqBuffer:
478 continue;
479 default:
480 UNREACHABLE();
481 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200482 }
483
484 unsigned int instanceCount = 1u;
485 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
486 if (isInstanceArray)
487 {
488 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
489 }
490
491 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
492 ++instanceArrayIndex)
493 {
494 TString originalName;
495 TString mappedName("map");
496
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200497 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200498 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200499 const ImmutableString &instanceName =
500 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200501 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
502 if (isInstanceArray)
503 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800504 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200505 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200506 originalName += instanceString;
507 mappedName += instanceString;
508 originalName += ".";
509 mappedName += "_";
510 }
511
512 TString fieldName = Decorate(mappedStruct.field->name());
513 originalName += fieldName;
514 mappedName += fieldName;
515
516 TType *structType = mappedStruct.field->type();
517 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200518 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200519
520 if (structType->isArray())
521 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300522 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200523 }
524
525 mappedStructs += " =\n";
526 mappedStructs += structInitializerString(0, *structType, originalName);
527 mappedStructs += ";\n";
528 }
529 }
530 return mappedStructs;
531}
532
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300533void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300535 for (const auto &attribute : mReferencedAttributes)
536 {
537 const TType &type = attribute.second->getType();
538 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400539
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300540 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
541 << zeroInitializer(type) << ";\n";
542 }
543}
544
545void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
546{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200547 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000548 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800549 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000550
551 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300552 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300553 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
554 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000555 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300556}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000557
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300558void OutputHLSL::header(TInfoSinkBase &out,
559 const std::vector<MappedStruct> &std140Structs,
560 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
561{
562 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000563
Jamie Madill8daaba12014-06-13 10:04:33 -0400564 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400565
Qin Jiajia3e217f62018-08-28 16:55:20 +0800566 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
567 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800568 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400569
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200570 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500571 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200572 out << "\n// Equality functions\n\n";
573 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500574 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200575 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200576 }
577 }
Olli Etuaho12690762015-03-31 12:55:28 +0300578 if (!mArrayAssignmentFunctions.empty())
579 {
580 out << "\n// Assignment functions\n\n";
581 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
582 {
583 out << assignmentFunction.functionDefinition << "\n";
584 }
585 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300586 if (!mArrayConstructIntoFunctions.empty())
587 {
588 out << "\n// Array constructor functions\n\n";
589 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
590 {
591 out << constructIntoFunction.functionDefinition << "\n";
592 }
593 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200594
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500595 if (mUsesDiscardRewriting)
596 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400597 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500598 }
599
Nicolas Capens655fe362014-04-11 13:12:34 -0400600 if (mUsesNestedBreak)
601 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400602 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400603 }
604
Arun Patole44efa0b2015-03-04 17:11:05 +0530605 if (mRequiresIEEEStrictCompiling)
606 {
607 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
608 }
609
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400610 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
611 "#define LOOP [loop]\n"
612 "#define FLATTEN [flatten]\n"
613 "#else\n"
614 "#define LOOP\n"
615 "#define FLATTEN\n"
616 "#endif\n";
617
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700618 // array stride for atomic counter buffers is always 4 per original extension
619 // ARB_shader_atomic_counters and discussion on
620 // https://github.com/KhronosGroup/OpenGL-API/issues/5
621 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
622
jchen10efe061b2018-11-13 16:44:40 +0800623 if (mUseZeroArray)
624 {
625 out << DefineZeroArray() << "\n";
626 }
627
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200628 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000629 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300630 const bool usingMRTExtension =
631 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000632
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000633 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300634 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400635 out << "\n";
636
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200637 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000638 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200639 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000640 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200641 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800642 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400643
Olli Etuahofbb1c792018-01-19 16:26:59 +0200644 out << "static " << TypeString(variableType) << " out_" << variableName
645 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000646 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000647 }
Jamie Madill46131a32013-06-20 11:55:50 -0400648 else
649 {
650 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
651
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800652 out << "static float4 gl_Color[" << numColorValues
653 << "] =\n"
654 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400655 for (unsigned int i = 0; i < numColorValues; i++)
656 {
657 out << " float4(0, 0, 0, 0)";
658 if (i + 1 != numColorValues)
659 {
660 out << ",";
661 }
662 out << "\n";
663 }
664
665 out << "};\n";
666 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000667
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400668 if (mUsesFragDepth)
669 {
670 out << "static float gl_Depth = 0.0;\n";
671 }
672
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000673 if (mUsesFragCoord)
674 {
675 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
676 }
677
678 if (mUsesPointCoord)
679 {
680 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
681 }
682
683 if (mUsesFrontFacing)
684 {
685 out << "static bool gl_FrontFacing = false;\n";
686 }
687
688 out << "\n";
689
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000690 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000691 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000692 out << "struct gl_DepthRangeParameters\n"
693 "{\n"
694 " float near;\n"
695 " float far;\n"
696 " float diff;\n"
697 "};\n"
698 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000699 }
700
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200701 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000702 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000703 out << "cbuffer DriverConstants : register(b1)\n"
704 "{\n";
705
706 if (mUsesDepthRange)
707 {
708 out << " float3 dx_DepthRange : packoffset(c0);\n";
709 }
710
711 if (mUsesFragCoord)
712 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000713 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000714 }
715
716 if (mUsesFragCoord || mUsesFrontFacing)
717 {
718 out << " float3 dx_DepthFront : packoffset(c2);\n";
719 }
720
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800721 if (mUsesFragCoord)
722 {
723 // dx_ViewScale is only used in the fragment shader to correct
724 // the value for glFragCoord if necessary
725 out << " float2 dx_ViewScale : packoffset(c3);\n";
726 }
727
Martin Radev72b4e1e2017-08-31 15:42:56 +0300728 if (mHasMultiviewExtensionEnabled)
729 {
730 // We have to add a value which we can use to keep track of which multi-view code
731 // path is to be selected in the GS.
732 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
733 }
734
Olli Etuaho618bebc2016-01-15 16:40:00 +0200735 if (mOutputType == SH_HLSL_4_1_OUTPUT)
736 {
Xinghua Caof3179a62018-07-12 16:22:06 +0800737 mResourcesHLSL->samplerMetadataUniforms(out, 4);
Olli Etuaho618bebc2016-01-15 16:40:00 +0200738 }
739
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000740 out << "};\n";
741 }
742 else
743 {
744 if (mUsesDepthRange)
745 {
746 out << "uniform float3 dx_DepthRange : register(c0);";
747 }
748
749 if (mUsesFragCoord)
750 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000751 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000752 }
753
754 if (mUsesFragCoord || mUsesFrontFacing)
755 {
756 out << "uniform float3 dx_DepthFront : register(c2);\n";
757 }
758 }
759
760 out << "\n";
761
762 if (mUsesDepthRange)
763 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
765 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000766 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000767 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000768
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000769 if (usingMRTExtension && mNumRenderTargets > 1)
770 {
771 out << "#define GL_USES_MRT\n";
772 }
773
774 if (mUsesFragColor)
775 {
776 out << "#define GL_USES_FRAG_COLOR\n";
777 }
778
779 if (mUsesFragData)
780 {
781 out << "#define GL_USES_FRAG_DATA\n";
782 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000783 }
Xinghua Caob1239382016-12-13 15:07:05 +0800784 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000786 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300787 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000788 out << "\n"
789 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400790
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000791 if (mUsesPointSize)
792 {
793 out << "static float gl_PointSize = float(1);\n";
794 }
795
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000796 if (mUsesInstanceID)
797 {
798 out << "static int gl_InstanceID;";
799 }
800
Corentin Wallezb076add2016-01-11 16:45:46 -0500801 if (mUsesVertexID)
802 {
803 out << "static int gl_VertexID;";
804 }
805
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000806 out << "\n"
807 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300808 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000809 out << "\n";
810
811 if (mUsesDepthRange)
812 {
813 out << "struct gl_DepthRangeParameters\n"
814 "{\n"
815 " float near;\n"
816 " float far;\n"
817 " float diff;\n"
818 "};\n"
819 "\n";
820 }
821
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200822 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000823 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800824 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500825 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800826
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000827 if (mUsesDepthRange)
828 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800829 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000830 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800831
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800832 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
833 // shaders. However, we declare it for all shaders (including Feature Level 10+).
834 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
835 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800836 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800837 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800838 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800839
Martin Radev72b4e1e2017-08-31 15:42:56 +0300840 if (mHasMultiviewExtensionEnabled)
841 {
842 // We have to add a value which we can use to keep track of which multi-view code
843 // path is to be selected in the GS.
844 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
845 }
846
Olli Etuaho618bebc2016-01-15 16:40:00 +0200847 if (mOutputType == SH_HLSL_4_1_OUTPUT)
848 {
Xinghua Caof3179a62018-07-12 16:22:06 +0800849 mResourcesHLSL->samplerMetadataUniforms(out, 4);
Olli Etuaho618bebc2016-01-15 16:40:00 +0200850 }
851
Austin Kinross4fd18b12014-12-22 12:32:05 -0800852 out << "};\n"
853 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000854 }
855 else
856 {
857 if (mUsesDepthRange)
858 {
859 out << "uniform float3 dx_DepthRange : register(c0);\n";
860 }
861
Cooper Partine6664f02015-01-09 16:22:24 -0800862 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
863 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000864 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000865 }
866
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000867 if (mUsesDepthRange)
868 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500869 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
870 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000871 "\n";
872 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400873 }
Xinghua Caob1239382016-12-13 15:07:05 +0800874 else // Compute shader
875 {
876 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800877
878 out << "cbuffer DriverConstants : register(b1)\n"
879 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800880 if (mUsesNumWorkGroups)
881 {
Xinghua Caob1239382016-12-13 15:07:05 +0800882 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800883 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800884 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Xinghua Caof3179a62018-07-12 16:22:06 +0800885 unsigned int registerIndex = 1;
886 mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
887 // Sampler metadata struct must be two 4-vec, 32 bytes.
888 registerIndex += mResourcesHLSL->getSamplerCount() * 2;
889 mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
Xinghua Cao73badc02017-03-29 19:14:53 +0800890 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800891
Xinghua Caof3179a62018-07-12 16:22:06 +0800892 out << kImage2DFunctionString << "\n";
893
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -0500894 std::ostringstream systemValueDeclaration = sh::InitializeStream<std::ostringstream>();
895 std::ostringstream glBuiltinInitialization = sh::InitializeStream<std::ostringstream>();
Jiawei Shao203b26f2018-07-25 10:30:43 +0800896
897 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
898 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
899 << "{\n";
900
Xinghua Caob1239382016-12-13 15:07:05 +0800901 if (mUsesWorkGroupID)
902 {
903 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800904 systemValueDeclaration << " uint3 dx_WorkGroupID : "
905 << "SV_GroupID;\n";
906 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800907 }
908
909 if (mUsesLocalInvocationID)
910 {
911 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800912 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
913 << "SV_GroupThreadID;\n";
914 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800915 }
916
917 if (mUsesGlobalInvocationID)
918 {
919 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800920 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
921 << "SV_DispatchThreadID;\n";
922 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800923 }
924
925 if (mUsesLocalInvocationIndex)
926 {
927 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800928 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
929 << "SV_GroupIndex;\n";
930 glBuiltinInitialization
931 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800932 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800933
934 systemValueDeclaration << "};\n\n";
935 glBuiltinInitialization << "};\n\n";
936
937 out << systemValueDeclaration.str();
938 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800939 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000940
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800941 if (!mappedStructs.empty())
942 {
943 out << "// Structures from std140 blocks with padding removed\n";
944 out << "\n";
945 out << mappedStructs;
946 out << "\n";
947 }
948
Geoff Lang1fe74c72016-08-25 13:23:01 -0400949 bool getDimensionsIgnoresBaseLevel =
950 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
951 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800952 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700953 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000955 if (mUsesFragCoord)
956 {
957 out << "#define GL_USES_FRAG_COORD\n";
958 }
959
960 if (mUsesPointCoord)
961 {
962 out << "#define GL_USES_POINT_COORD\n";
963 }
964
965 if (mUsesFrontFacing)
966 {
967 out << "#define GL_USES_FRONT_FACING\n";
968 }
969
970 if (mUsesPointSize)
971 {
972 out << "#define GL_USES_POINT_SIZE\n";
973 }
974
Martin Radev41ac68e2017-06-06 12:16:58 +0300975 if (mHasMultiviewExtensionEnabled)
976 {
977 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
978 }
979
980 if (mUsesViewID)
981 {
982 out << "#define GL_USES_VIEW_ID\n";
983 }
984
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400985 if (mUsesFragDepth)
986 {
987 out << "#define GL_USES_FRAG_DEPTH\n";
988 }
989
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000990 if (mUsesDepthRange)
991 {
992 out << "#define GL_USES_DEPTH_RANGE\n";
993 }
994
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000995 if (mUsesXor)
996 {
997 out << "bool xor(bool p, bool q)\n"
998 "{\n"
999 " return (p || q) && !(p && q);\n"
1000 "}\n"
1001 "\n";
1002 }
1003
Olli Etuahodfa75e82017-01-23 09:43:06 -08001004 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001005}
1006
1007void OutputHLSL::visitSymbol(TIntermSymbol *node)
1008{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001009 const TVariable &variable = node->variable();
1010
1011 // Empty symbols can only appear in declarations and function arguments, and in either of those
1012 // cases the symbol nodes are not visited.
1013 ASSERT(variable.symbolType() != SymbolType::Empty);
1014
Jamie Madill32aab012015-01-27 14:12:26 -05001015 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001016
Jamie Madill570e04d2013-06-21 09:15:33 -04001017 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001018 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -04001019 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001020 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -04001021 }
1022
Olli Etuahofbb1c792018-01-19 16:26:59 +02001023 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001024 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +02001025
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001026 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001027 {
1028 mUsesDepthRange = true;
1029 out << name;
1030 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001031 else if (IsAtomicCounter(variable.getType().getBasicType()))
1032 {
1033 const TType &variableType = variable.getType();
1034 if (variableType.getQualifier() == EvqUniform)
1035 {
1036 TLayoutQualifier layout = variableType.getLayoutQualifier();
1037 mReferencedUniforms[uniqueId.get()] = &variable;
1038 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1039 }
1040 else
1041 {
1042 TString varName = DecorateVariableIfNeeded(variable);
1043 out << varName << ", " << varName << "_offset";
1044 }
1045 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 else
1047 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001048 const TType &variableType = variable.getType();
1049 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001050
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001051 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +02001052
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001053 if (qualifier == EvqUniform)
1054 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001055 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001056
1057 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001058 {
Olli Etuahoc71862a2017-12-21 12:58:29 +02001059 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1060 {
1061 const TVariable *instanceVariable = nullptr;
1062 if (variableType.isInterfaceBlock())
1063 {
1064 instanceVariable = &variable;
1065 }
1066 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1067 new TReferencedBlock(interfaceBlock, instanceVariable);
1068 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001069 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001070 else
1071 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001072 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001073 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001074
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001075 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001076 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001077 else if (qualifier == EvqBuffer)
1078 {
1079 UNREACHABLE();
1080 }
Jamie Madill19571812013-08-12 15:26:34 -07001081 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001082 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001083 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001084 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001085 }
Jamie Madill033dae62014-06-18 12:56:28 -04001086 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001087 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001088 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001089 out << DecorateVariableIfNeeded(variable);
1090 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001091 {
1092 mUsesViewID = true;
1093 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001094 }
Jamie Madill19571812013-08-12 15:26:34 -07001095 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001096 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001097 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001098 out << "out_" << name;
1099 }
1100 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001101 {
1102 out << "gl_Color[0]";
1103 mUsesFragColor = true;
1104 }
1105 else if (qualifier == EvqFragData)
1106 {
1107 out << "gl_Color";
1108 mUsesFragData = true;
1109 }
1110 else if (qualifier == EvqFragCoord)
1111 {
1112 mUsesFragCoord = true;
1113 out << name;
1114 }
1115 else if (qualifier == EvqPointCoord)
1116 {
1117 mUsesPointCoord = true;
1118 out << name;
1119 }
1120 else if (qualifier == EvqFrontFacing)
1121 {
1122 mUsesFrontFacing = true;
1123 out << name;
1124 }
1125 else if (qualifier == EvqPointSize)
1126 {
1127 mUsesPointSize = true;
1128 out << name;
1129 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001130 else if (qualifier == EvqInstanceID)
1131 {
1132 mUsesInstanceID = true;
1133 out << name;
1134 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001135 else if (qualifier == EvqVertexID)
1136 {
1137 mUsesVertexID = true;
1138 out << name;
1139 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001140 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001141 {
1142 mUsesFragDepth = true;
1143 out << "gl_Depth";
1144 }
Xinghua Caob1239382016-12-13 15:07:05 +08001145 else if (qualifier == EvqNumWorkGroups)
1146 {
1147 mUsesNumWorkGroups = true;
1148 out << name;
1149 }
1150 else if (qualifier == EvqWorkGroupID)
1151 {
1152 mUsesWorkGroupID = true;
1153 out << name;
1154 }
1155 else if (qualifier == EvqLocalInvocationID)
1156 {
1157 mUsesLocalInvocationID = true;
1158 out << name;
1159 }
1160 else if (qualifier == EvqGlobalInvocationID)
1161 {
1162 mUsesGlobalInvocationID = true;
1163 out << name;
1164 }
1165 else if (qualifier == EvqLocalInvocationIndex)
1166 {
1167 mUsesLocalInvocationIndex = true;
1168 out << name;
1169 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001170 else
1171 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001172 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001173 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001174 }
1175}
1176
Olli Etuaho7fb49552015-03-18 17:27:44 +02001177void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1178{
1179 if (type.isScalar() && !type.isArray())
1180 {
1181 if (op == EOpEqual)
1182 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001183 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001184 }
1185 else
1186 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001187 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001188 }
1189 }
1190 else
1191 {
1192 if (visit == PreVisit && op == EOpNotEqual)
1193 {
1194 out << "!";
1195 }
1196
1197 if (type.isArray())
1198 {
1199 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001200 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001201 }
1202 else if (type.getBasicType() == EbtStruct)
1203 {
1204 const TStructure &structure = *type.getStruct();
1205 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001206 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001207 }
1208 else
1209 {
1210 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001211 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001212 }
1213 }
1214}
1215
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001216void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1217{
1218 if (type.isArray())
1219 {
1220 const TString &functionName = addArrayAssignmentFunction(type);
1221 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1222 }
1223 else
1224 {
1225 outputTriplet(out, visit, "(", " = ", ")");
1226 }
1227}
1228
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001229bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001230{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001231 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001232 {
1233 TIntermNode *ancestor = getAncestorNode(n);
1234 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1235 if (ancestorBinary == nullptr)
1236 {
1237 return false;
1238 }
1239 switch (ancestorBinary->getOp())
1240 {
1241 case EOpIndexDirectStruct:
1242 {
1243 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1244 const TIntermConstantUnion *index =
1245 ancestorBinary->getRight()->getAsConstantUnion();
1246 const TField *field = structure->fields()[index->getIConst(0)];
1247 if (IsSampler(field->type()->getBasicType()))
1248 {
1249 return true;
1250 }
1251 break;
1252 }
1253 case EOpIndexDirect:
1254 break;
1255 default:
1256 // Returning a sampler from indirect indexing is not supported.
1257 return false;
1258 }
1259 }
1260 return false;
1261}
1262
Olli Etuahob6fa0432016-09-28 16:28:05 +01001263bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1264{
1265 TInfoSinkBase &out = getInfoSink();
1266 if (visit == PostVisit)
1267 {
1268 out << ".";
1269 node->writeOffsetsAsXYZW(&out);
1270 }
1271 return true;
1272}
1273
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1275{
Jamie Madill32aab012015-01-27 14:12:26 -05001276 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277
1278 switch (node->getOp())
1279 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001280 case EOpComma:
1281 outputTriplet(out, visit, "(", ", ", ")");
1282 break;
1283 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001284 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001285 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001286 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1287 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001288 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001289 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1290 out << functionName << "(";
1291 node->getLeft()->traverse(this);
1292 TIntermSequence *seq = rightAgg->getSequence();
1293 for (auto &arrayElement : *seq)
1294 {
1295 out << ", ";
1296 arrayElement->traverse(this);
1297 }
1298 out << ")";
1299 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001300 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001301 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1302 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001303 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001304 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001305 // Assignment expressions with atomic functions should be transformed into atomic
1306 // function calls in HLSL.
1307 // e.g. original_value = atomicAdd(dest, value) should be translated into
1308 // InterlockedAdd(dest, value, original_value);
Qin Jiajia46229052018-12-10 13:31:00 +08001309 else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001310 {
1311 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1312 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1313 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1314 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1315 ASSERT(argumentSeq->size() >= 2u);
1316 for (auto &argument : *argumentSeq)
1317 {
1318 argument->traverse(this);
1319 out << ", ";
1320 }
1321 node->getLeft()->traverse(this);
1322 out << ")";
1323 return false;
1324 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001325 else if (IsInShaderStorageBlock(node->getLeft()))
1326 {
1327 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1328 out << ", ";
1329 if (IsInShaderStorageBlock(node->getRight()))
1330 {
1331 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1332 }
1333 else
1334 {
1335 node->getRight()->traverse(this);
1336 }
1337
1338 out << ")";
1339 return false;
1340 }
1341 else if (IsInShaderStorageBlock(node->getRight()))
1342 {
1343 node->getLeft()->traverse(this);
1344 out << " = ";
1345 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1346 return false;
1347 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001348
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001349 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001350 break;
1351 case EOpInitialize:
1352 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001353 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001354 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1355 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001356 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001357
1358 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001359 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001360
1361 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1362 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1363 // new variable is created before the assignment is evaluated), so we need to
1364 // convert
1365 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001366 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001367 {
1368 // Skip initializing the rest of the expression
1369 return false;
1370 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001371 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001372 {
1373 return false;
1374 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001375 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001376 else if (visit == InVisit)
1377 {
1378 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001379 if (IsInShaderStorageBlock(node->getRight()))
1380 {
1381 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1382 return false;
1383 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001384 }
1385 break;
1386 case EOpAddAssign:
1387 outputTriplet(out, visit, "(", " += ", ")");
1388 break;
1389 case EOpSubAssign:
1390 outputTriplet(out, visit, "(", " -= ", ")");
1391 break;
1392 case EOpMulAssign:
1393 outputTriplet(out, visit, "(", " *= ", ")");
1394 break;
1395 case EOpVectorTimesScalarAssign:
1396 outputTriplet(out, visit, "(", " *= ", ")");
1397 break;
1398 case EOpMatrixTimesScalarAssign:
1399 outputTriplet(out, visit, "(", " *= ", ")");
1400 break;
1401 case EOpVectorTimesMatrixAssign:
1402 if (visit == PreVisit)
1403 {
1404 out << "(";
1405 }
1406 else if (visit == InVisit)
1407 {
1408 out << " = mul(";
1409 node->getLeft()->traverse(this);
1410 out << ", transpose(";
1411 }
1412 else
1413 {
1414 out << ")))";
1415 }
1416 break;
1417 case EOpMatrixTimesMatrixAssign:
1418 if (visit == PreVisit)
1419 {
1420 out << "(";
1421 }
1422 else if (visit == InVisit)
1423 {
1424 out << " = transpose(mul(transpose(";
1425 node->getLeft()->traverse(this);
1426 out << "), transpose(";
1427 }
1428 else
1429 {
1430 out << "))))";
1431 }
1432 break;
1433 case EOpDivAssign:
1434 outputTriplet(out, visit, "(", " /= ", ")");
1435 break;
1436 case EOpIModAssign:
1437 outputTriplet(out, visit, "(", " %= ", ")");
1438 break;
1439 case EOpBitShiftLeftAssign:
1440 outputTriplet(out, visit, "(", " <<= ", ")");
1441 break;
1442 case EOpBitShiftRightAssign:
1443 outputTriplet(out, visit, "(", " >>= ", ")");
1444 break;
1445 case EOpBitwiseAndAssign:
1446 outputTriplet(out, visit, "(", " &= ", ")");
1447 break;
1448 case EOpBitwiseXorAssign:
1449 outputTriplet(out, visit, "(", " ^= ", ")");
1450 break;
1451 case EOpBitwiseOrAssign:
1452 outputTriplet(out, visit, "(", " |= ", ")");
1453 break;
1454 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001455 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001456 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001457 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001458 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001459 if (visit == PreVisit)
1460 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001461 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001462 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001463
1464 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001465 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1466 {
1467 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1468 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1469 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001470 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001471 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001472 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001473 return false;
1474 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001475 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001476 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001477 {
1478 // All parts of an expression that access a sampler in a struct need to use _ as
1479 // separator to access the sampler variable that has been moved out of the struct.
1480 outputTriplet(out, visit, "", "_", "");
1481 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001482 else if (IsAtomicCounter(leftType.getBasicType()))
1483 {
1484 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1485 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001486 else
1487 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001488 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001489 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001490 }
1491 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001493 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001494 // We do not currently support indirect references to interface blocks
1495 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001496
1497 const TType &leftType = node->getLeft()->getType();
1498 if (IsAtomicCounter(leftType.getBasicType()))
1499 {
1500 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1501 }
1502 else
1503 {
1504 outputTriplet(out, visit, "", "[", "]");
1505 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001506 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001507 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001508 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001509 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001510 const TStructure *structure = node->getLeft()->getType().getStruct();
1511 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1512 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001513
Olli Etuaho96963162016-03-21 11:54:33 +02001514 // In cases where indexing returns a sampler, we need to access the sampler variable
1515 // that has been moved out of the struct.
1516 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1517 if (visit == PreVisit && indexingReturnsSampler)
1518 {
1519 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1520 // This prefix is only output at the beginning of the indexing expression, which
1521 // may have multiple parts.
1522 out << "angle";
1523 }
1524 if (!indexingReturnsSampler)
1525 {
1526 // All parts of an expression that access a sampler in a struct need to use _ as
1527 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001528 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001529 }
1530 if (visit == InVisit)
1531 {
1532 if (indexingReturnsSampler)
1533 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001534 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001535 }
1536 else
1537 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001538 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001539 }
1540
1541 return false;
1542 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001543 }
1544 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001545 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001546 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001547 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1548 bool structInStd140UniformBlock =
1549 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1550 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001551 {
1552 out << "map";
1553 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001554 if (visit == InVisit)
1555 {
1556 const TInterfaceBlock *interfaceBlock =
1557 node->getLeft()->getType().getInterfaceBlock();
1558 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1559 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001560 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001561 {
1562 out << "_";
1563 }
1564 else
1565 {
1566 out << ".";
1567 }
1568 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001569
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001570 return false;
1571 }
1572 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001573 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001574 case EOpAdd:
1575 outputTriplet(out, visit, "(", " + ", ")");
1576 break;
1577 case EOpSub:
1578 outputTriplet(out, visit, "(", " - ", ")");
1579 break;
1580 case EOpMul:
1581 outputTriplet(out, visit, "(", " * ", ")");
1582 break;
1583 case EOpDiv:
1584 outputTriplet(out, visit, "(", " / ", ")");
1585 break;
1586 case EOpIMod:
1587 outputTriplet(out, visit, "(", " % ", ")");
1588 break;
1589 case EOpBitShiftLeft:
1590 outputTriplet(out, visit, "(", " << ", ")");
1591 break;
1592 case EOpBitShiftRight:
1593 outputTriplet(out, visit, "(", " >> ", ")");
1594 break;
1595 case EOpBitwiseAnd:
1596 outputTriplet(out, visit, "(", " & ", ")");
1597 break;
1598 case EOpBitwiseXor:
1599 outputTriplet(out, visit, "(", " ^ ", ")");
1600 break;
1601 case EOpBitwiseOr:
1602 outputTriplet(out, visit, "(", " | ", ")");
1603 break;
1604 case EOpEqual:
1605 case EOpNotEqual:
1606 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1607 break;
1608 case EOpLessThan:
1609 outputTriplet(out, visit, "(", " < ", ")");
1610 break;
1611 case EOpGreaterThan:
1612 outputTriplet(out, visit, "(", " > ", ")");
1613 break;
1614 case EOpLessThanEqual:
1615 outputTriplet(out, visit, "(", " <= ", ")");
1616 break;
1617 case EOpGreaterThanEqual:
1618 outputTriplet(out, visit, "(", " >= ", ")");
1619 break;
1620 case EOpVectorTimesScalar:
1621 outputTriplet(out, visit, "(", " * ", ")");
1622 break;
1623 case EOpMatrixTimesScalar:
1624 outputTriplet(out, visit, "(", " * ", ")");
1625 break;
1626 case EOpVectorTimesMatrix:
1627 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1628 break;
1629 case EOpMatrixTimesVector:
1630 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1631 break;
1632 case EOpMatrixTimesMatrix:
1633 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1634 break;
1635 case EOpLogicalOr:
1636 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1637 // been unfolded.
1638 ASSERT(!node->getRight()->hasSideEffects());
1639 outputTriplet(out, visit, "(", " || ", ")");
1640 return true;
1641 case EOpLogicalXor:
1642 mUsesXor = true;
1643 outputTriplet(out, visit, "xor(", ", ", ")");
1644 break;
1645 case EOpLogicalAnd:
1646 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1647 // been unfolded.
1648 ASSERT(!node->getRight()->hasSideEffects());
1649 outputTriplet(out, visit, "(", " && ", ")");
1650 return true;
1651 default:
1652 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001653 }
1654
1655 return true;
1656}
1657
1658bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1659{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001660 TInfoSinkBase &out = getInfoSink();
1661
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001662 switch (node->getOp())
1663 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001664 case EOpNegative:
1665 outputTriplet(out, visit, "(-", "", ")");
1666 break;
1667 case EOpPositive:
1668 outputTriplet(out, visit, "(+", "", ")");
1669 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001670 case EOpLogicalNot:
1671 outputTriplet(out, visit, "(!", "", ")");
1672 break;
1673 case EOpBitwiseNot:
1674 outputTriplet(out, visit, "(~", "", ")");
1675 break;
1676 case EOpPostIncrement:
1677 outputTriplet(out, visit, "(", "", "++)");
1678 break;
1679 case EOpPostDecrement:
1680 outputTriplet(out, visit, "(", "", "--)");
1681 break;
1682 case EOpPreIncrement:
1683 outputTriplet(out, visit, "(++", "", ")");
1684 break;
1685 case EOpPreDecrement:
1686 outputTriplet(out, visit, "(--", "", ")");
1687 break;
1688 case EOpRadians:
1689 outputTriplet(out, visit, "radians(", "", ")");
1690 break;
1691 case EOpDegrees:
1692 outputTriplet(out, visit, "degrees(", "", ")");
1693 break;
1694 case EOpSin:
1695 outputTriplet(out, visit, "sin(", "", ")");
1696 break;
1697 case EOpCos:
1698 outputTriplet(out, visit, "cos(", "", ")");
1699 break;
1700 case EOpTan:
1701 outputTriplet(out, visit, "tan(", "", ")");
1702 break;
1703 case EOpAsin:
1704 outputTriplet(out, visit, "asin(", "", ")");
1705 break;
1706 case EOpAcos:
1707 outputTriplet(out, visit, "acos(", "", ")");
1708 break;
1709 case EOpAtan:
1710 outputTriplet(out, visit, "atan(", "", ")");
1711 break;
1712 case EOpSinh:
1713 outputTriplet(out, visit, "sinh(", "", ")");
1714 break;
1715 case EOpCosh:
1716 outputTriplet(out, visit, "cosh(", "", ")");
1717 break;
1718 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001719 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001720 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001721 case EOpAtanh:
1722 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001723 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001724 break;
1725 case EOpExp:
1726 outputTriplet(out, visit, "exp(", "", ")");
1727 break;
1728 case EOpLog:
1729 outputTriplet(out, visit, "log(", "", ")");
1730 break;
1731 case EOpExp2:
1732 outputTriplet(out, visit, "exp2(", "", ")");
1733 break;
1734 case EOpLog2:
1735 outputTriplet(out, visit, "log2(", "", ")");
1736 break;
1737 case EOpSqrt:
1738 outputTriplet(out, visit, "sqrt(", "", ")");
1739 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001740 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001741 outputTriplet(out, visit, "rsqrt(", "", ")");
1742 break;
1743 case EOpAbs:
1744 outputTriplet(out, visit, "abs(", "", ")");
1745 break;
1746 case EOpSign:
1747 outputTriplet(out, visit, "sign(", "", ")");
1748 break;
1749 case EOpFloor:
1750 outputTriplet(out, visit, "floor(", "", ")");
1751 break;
1752 case EOpTrunc:
1753 outputTriplet(out, visit, "trunc(", "", ")");
1754 break;
1755 case EOpRound:
1756 outputTriplet(out, visit, "round(", "", ")");
1757 break;
1758 case EOpRoundEven:
1759 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001760 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 break;
1762 case EOpCeil:
1763 outputTriplet(out, visit, "ceil(", "", ")");
1764 break;
1765 case EOpFract:
1766 outputTriplet(out, visit, "frac(", "", ")");
1767 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001768 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001769 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001770 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001771 else
1772 outputTriplet(out, visit, "isnan(", "", ")");
1773 mRequiresIEEEStrictCompiling = true;
1774 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001775 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001776 outputTriplet(out, visit, "isinf(", "", ")");
1777 break;
1778 case EOpFloatBitsToInt:
1779 outputTriplet(out, visit, "asint(", "", ")");
1780 break;
1781 case EOpFloatBitsToUint:
1782 outputTriplet(out, visit, "asuint(", "", ")");
1783 break;
1784 case EOpIntBitsToFloat:
1785 outputTriplet(out, visit, "asfloat(", "", ")");
1786 break;
1787 case EOpUintBitsToFloat:
1788 outputTriplet(out, visit, "asfloat(", "", ")");
1789 break;
1790 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001791 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001792 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001793 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001794 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001795 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001796 case EOpPackUnorm4x8:
1797 case EOpPackSnorm4x8:
1798 case EOpUnpackUnorm4x8:
1799 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001800 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001801 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001802 break;
1803 case EOpLength:
1804 outputTriplet(out, visit, "length(", "", ")");
1805 break;
1806 case EOpNormalize:
1807 outputTriplet(out, visit, "normalize(", "", ")");
1808 break;
1809 case EOpDFdx:
1810 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1811 {
1812 outputTriplet(out, visit, "(", "", ", 0.0)");
1813 }
1814 else
1815 {
1816 outputTriplet(out, visit, "ddx(", "", ")");
1817 }
1818 break;
1819 case EOpDFdy:
1820 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1821 {
1822 outputTriplet(out, visit, "(", "", ", 0.0)");
1823 }
1824 else
1825 {
1826 outputTriplet(out, visit, "ddy(", "", ")");
1827 }
1828 break;
1829 case EOpFwidth:
1830 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1831 {
1832 outputTriplet(out, visit, "(", "", ", 0.0)");
1833 }
1834 else
1835 {
1836 outputTriplet(out, visit, "fwidth(", "", ")");
1837 }
1838 break;
1839 case EOpTranspose:
1840 outputTriplet(out, visit, "transpose(", "", ")");
1841 break;
1842 case EOpDeterminant:
1843 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1844 break;
1845 case EOpInverse:
1846 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001847 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001848 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001849
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001850 case EOpAny:
1851 outputTriplet(out, visit, "any(", "", ")");
1852 break;
1853 case EOpAll:
1854 outputTriplet(out, visit, "all(", "", ")");
1855 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001856 case EOpLogicalNotComponentWise:
1857 outputTriplet(out, visit, "(!", "", ")");
1858 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001859 case EOpBitfieldReverse:
1860 outputTriplet(out, visit, "reversebits(", "", ")");
1861 break;
1862 case EOpBitCount:
1863 outputTriplet(out, visit, "countbits(", "", ")");
1864 break;
1865 case EOpFindLSB:
1866 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1867 // in GLSLTest and results are consistent with GL.
1868 outputTriplet(out, visit, "firstbitlow(", "", ")");
1869 break;
1870 case EOpFindMSB:
1871 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1872 // tested in GLSLTest and results are consistent with GL.
1873 outputTriplet(out, visit, "firstbithigh(", "", ")");
1874 break;
Qin Jiajia88faa692018-12-03 16:22:24 +08001875 case EOpArrayLength:
1876 {
1877 TIntermTyped *operand = node->getOperand();
1878 ASSERT(IsInShaderStorageBlock(operand));
1879 mSSBOOutputHLSL->outputLengthFunctionCall(operand);
1880 return false;
1881 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001882 default:
1883 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001884 }
1885
1886 return true;
1887}
1888
Olli Etuahofbb1c792018-01-19 16:26:59 +02001889ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001890{
1891 if (node->getAsSymbolNode())
1892 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001893 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1894 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001895 }
1896 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1897 switch (nodeBinary->getOp())
1898 {
1899 case EOpIndexDirect:
1900 {
1901 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1902
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -05001903 std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
Olli Etuaho96963162016-03-21 11:54:33 +02001904 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001905 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001906 }
1907 case EOpIndexDirectStruct:
1908 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001909 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001910 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1911 const TField *field = s->fields()[index];
1912
Jonah Ryan-Davis5f662c02019-01-31 13:53:59 -05001913 std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
Olli Etuaho96963162016-03-21 11:54:33 +02001914 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1915 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001916 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001917 }
1918 default:
1919 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001920 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001921 }
1922}
1923
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001924bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1925{
1926 TInfoSinkBase &out = getInfoSink();
1927
Olli Etuaho06235df2018-07-20 14:26:07 +03001928 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1929
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001930 if (mInsideFunction)
1931 {
1932 outputLineDirective(out, node->getLine().first_line);
1933 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001934 if (isMainBlock)
1935 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001936 if (mShaderType == GL_COMPUTE_SHADER)
1937 {
1938 out << "initGLBuiltins(input);\n";
1939 }
1940 else
1941 {
1942 out << "@@ MAIN PROLOGUE @@\n";
1943 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001944 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001945 }
1946
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001947 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001948 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001949 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001950
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001951 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001952
1953 // Don't output ; after case labels, they're terminated by :
1954 // This is needed especially since outputting a ; after a case statement would turn empty
1955 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001956 // Also the output code is clearer if we don't output ; after statements where it is not
1957 // needed:
1958 // * if statements
1959 // * switch statements
1960 // * blocks
1961 // * function definitions
1962 // * loops (do-while loops output the semicolon in VisitLoop)
1963 // * declarations that don't generate output.
1964 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1965 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1966 statement->getAsSwitchNode() == nullptr &&
1967 statement->getAsFunctionDefinition() == nullptr &&
1968 (statement->getAsDeclarationNode() == nullptr ||
1969 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1970 statement->getAsInvariantDeclarationNode() == nullptr)
1971 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001972 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001973 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001974 }
1975
1976 if (mInsideFunction)
1977 {
1978 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001979 if (isMainBlock && shaderNeedsGenerateOutput())
1980 {
1981 // We could have an empty main, a main function without a branch at the end, or a main
1982 // function with a discard statement at the end. In these cases we need to add a return
1983 // statement.
1984 bool needReturnStatement =
1985 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1986 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1987 if (needReturnStatement)
1988 {
1989 out << "return " << generateOutputCall() << ";\n";
1990 }
1991 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001992 out << "}\n";
1993 }
1994
1995 return false;
1996}
1997
Olli Etuaho336b1472016-10-05 16:37:55 +01001998bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1999{
2000 TInfoSinkBase &out = getInfoSink();
2001
2002 ASSERT(mCurrentFunctionMetadata == nullptr);
2003
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002004 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01002005 ASSERT(index != CallDAG::InvalidIndex);
2006 mCurrentFunctionMetadata = &mASTMetadataList[index];
2007
Olli Etuahod4bd9632018-03-08 16:32:44 +02002008 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01002009
Olli Etuahod4bd9632018-03-08 16:32:44 +02002010 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01002011 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002012 // The stub strings below are replaced when shader is dynamically defined by its layout:
2013 switch (mShaderType)
2014 {
2015 case GL_VERTEX_SHADER:
2016 out << "@@ VERTEX ATTRIBUTES @@\n\n"
2017 << "@@ VERTEX OUTPUT @@\n\n"
2018 << "VS_OUTPUT main(VS_INPUT input)";
2019 break;
2020 case GL_FRAGMENT_SHADER:
2021 out << "@@ PIXEL OUTPUT @@\n\n"
2022 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
2023 break;
2024 case GL_COMPUTE_SHADER:
2025 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
2026 << mWorkGroupSize[2] << ")]\n";
2027 out << "void main(CS_INPUT input)";
2028 break;
2029 default:
2030 UNREACHABLE();
2031 break;
2032 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002033 }
2034 else
2035 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002036 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02002037 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002038 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01002039
Olli Etuaho06235df2018-07-20 14:26:07 +03002040 size_t paramCount = func->getParamCount();
2041 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01002042 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002043 const TVariable *param = func->getParam(i);
2044 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01002045
Olli Etuaho06235df2018-07-20 14:26:07 +03002046 writeParameter(param, out);
2047
2048 if (i < paramCount - 1)
2049 {
2050 out << ", ";
2051 }
2052 }
2053
2054 out << ")\n";
2055 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002056
2057 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03002058 if (func->isMain())
2059 {
2060 mInsideMain = true;
2061 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002062 // The function body node will output braces.
2063 node->getBody()->traverse(this);
2064 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03002065 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01002066
2067 mCurrentFunctionMetadata = nullptr;
2068
2069 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2070 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2071 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002072 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01002073 mOutputLod0Function = true;
2074 node->traverse(this);
2075 mOutputLod0Function = false;
2076 }
2077
2078 return false;
2079}
2080
Olli Etuaho13389b62016-10-16 11:48:18 +01002081bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2082{
Olli Etuaho13389b62016-10-16 11:48:18 +01002083 if (visit == PreVisit)
2084 {
2085 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002086 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002087 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002088 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002089
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002090 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002091 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002092 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002093 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002094
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002095 if (!declarator->getAsSymbolNode() ||
2096 declarator->getAsSymbolNode()->variable().symbolType() !=
2097 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002098 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002099 if (declarator->getQualifier() == EvqShared)
2100 {
2101 out << "groupshared ";
2102 }
2103 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002104 {
2105 out << "static ";
2106 }
2107
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002108 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002109
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002110 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002111
2112 if (symbol)
2113 {
2114 symbol->traverse(this);
2115 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002116 if (declarator->getQualifier() != EvqShared ||
2117 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002118 {
2119 out << " = " + zeroInitializer(symbol->getType());
2120 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002121 }
2122 else
2123 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002124 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002125 }
2126 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002127 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002128 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002129 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002130 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002131 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002132
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002133 const TVariable &variable = symbol->variable();
2134
2135 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002136 {
2137 // Vertex outputs which are declared but not written to should still be declared to
2138 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002139 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002140 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002141 }
2142 }
2143 return false;
2144}
2145
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002146bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2147{
2148 // Do not do any translation
2149 return false;
2150}
2151
Olli Etuahod4bd9632018-03-08 16:32:44 +02002152void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002153{
2154 TInfoSinkBase &out = getInfoSink();
2155
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002156 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002157 // Skip the prototype if it is not implemented (and thus not used)
2158 if (index == CallDAG::InvalidIndex)
2159 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002160 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002161 }
2162
Olli Etuahod4bd9632018-03-08 16:32:44 +02002163 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002164
Olli Etuahod4bd9632018-03-08 16:32:44 +02002165 TString name = DecorateFunctionIfNeeded(func);
2166 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002167 << (mOutputLod0Function ? "Lod0(" : "(");
2168
Olli Etuahod4bd9632018-03-08 16:32:44 +02002169 size_t paramCount = func->getParamCount();
2170 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002171 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002172 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002173
Olli Etuahod4bd9632018-03-08 16:32:44 +02002174 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002175 {
2176 out << ", ";
2177 }
2178 }
2179
2180 out << ");\n";
2181
2182 // Also prototype the Lod0 variant if needed
2183 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2184 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2185 {
2186 mOutputLod0Function = true;
2187 node->traverse(this);
2188 mOutputLod0Function = false;
2189 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002190}
2191
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002192bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2193{
Jamie Madill32aab012015-01-27 14:12:26 -05002194 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002195
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002196 switch (node->getOp())
2197 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002198 case EOpCallBuiltInFunction:
2199 case EOpCallFunctionInAST:
2200 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002201 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002202 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002203
Corentin Wallez1239ee92015-03-19 14:38:02 -07002204 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002205 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002206 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002207 if (node->isArray())
2208 {
2209 UNIMPLEMENTED();
2210 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002211 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002212 ASSERT(index != CallDAG::InvalidIndex);
2213 lod0 &= mASTMetadataList[index].mNeedsLod0;
2214
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002215 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002216 out << DisambiguateFunctionName(node->getSequence());
2217 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002219 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002220 {
2221 // This path is used for internal functions that don't have their definitions in the
2222 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002223 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002224 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002225 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002226 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002227 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002228 TType type = (*arguments)[0]->getAsTyped()->getType();
2229 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002230 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002231 type.getMemoryQualifier().readonly);
2232 out << imageFunctionName << "(";
2233 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002234 else if (node->getFunction()->isAtomicCounterFunction())
2235 {
2236 const ImmutableString &name = node->getFunction()->name();
2237 ImmutableString atomicFunctionName =
2238 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2239 out << atomicFunctionName << "(";
2240 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241 else
2242 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002243 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002244 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002245 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2246 if (arguments->size() > 1)
2247 {
2248 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2249 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002250 const ImmutableString &textureFunctionName =
2251 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2252 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002253 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002255
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002256 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002257 {
Olli Etuaho96963162016-03-21 11:54:33 +02002258 TIntermTyped *typedArg = (*arg)->getAsTyped();
2259 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002260 {
2261 out << "texture_";
2262 (*arg)->traverse(this);
2263 out << ", sampler_";
2264 }
2265
2266 (*arg)->traverse(this);
2267
Olli Etuaho96963162016-03-21 11:54:33 +02002268 if (typedArg->getType().isStructureContainingSamplers())
2269 {
2270 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002271 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002272 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2273 std::string namePrefix = "angle_";
2274 namePrefix += structName.data();
2275 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002276 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002277 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002278 {
2279 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2280 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002281 out << ", texture_" << sampler->name();
2282 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002283 }
2284 else
2285 {
2286 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2287 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002288 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002289 }
2290 }
2291 }
2292
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002293 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002294 {
2295 out << ", ";
2296 }
2297 }
2298
2299 out << ")";
2300
2301 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002303 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002304 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002305 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002306 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002307 outputTriplet(out, visit, "(", " == ", ")");
2308 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002309 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002310 outputTriplet(out, visit, "(", " != ", ")");
2311 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002312 case EOpLessThanComponentWise:
2313 outputTriplet(out, visit, "(", " < ", ")");
2314 break;
2315 case EOpGreaterThanComponentWise:
2316 outputTriplet(out, visit, "(", " > ", ")");
2317 break;
2318 case EOpLessThanEqualComponentWise:
2319 outputTriplet(out, visit, "(", " <= ", ")");
2320 break;
2321 case EOpGreaterThanEqualComponentWise:
2322 outputTriplet(out, visit, "(", " >= ", ")");
2323 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002324 case EOpMod:
2325 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002326 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002327 break;
2328 case EOpModf:
2329 outputTriplet(out, visit, "modf(", ", ", ")");
2330 break;
2331 case EOpPow:
2332 outputTriplet(out, visit, "pow(", ", ", ")");
2333 break;
2334 case EOpAtan:
2335 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2336 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002337 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002338 break;
2339 case EOpMin:
2340 outputTriplet(out, visit, "min(", ", ", ")");
2341 break;
2342 case EOpMax:
2343 outputTriplet(out, visit, "max(", ", ", ")");
2344 break;
2345 case EOpClamp:
2346 outputTriplet(out, visit, "clamp(", ", ", ")");
2347 break;
2348 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302349 {
2350 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2351 if (lastParamNode->getType().getBasicType() == EbtBool)
2352 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002353 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2354 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302355 // so use emulated version.
2356 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002357 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302358 }
2359 else
2360 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002361 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302362 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002363 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302364 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002365 case EOpStep:
2366 outputTriplet(out, visit, "step(", ", ", ")");
2367 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002368 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002369 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2370 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002371 case EOpFrexp:
2372 case EOpLdexp:
2373 ASSERT(node->getUseEmulatedFunction());
2374 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2375 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002376 case EOpDistance:
2377 outputTriplet(out, visit, "distance(", ", ", ")");
2378 break;
2379 case EOpDot:
2380 outputTriplet(out, visit, "dot(", ", ", ")");
2381 break;
2382 case EOpCross:
2383 outputTriplet(out, visit, "cross(", ", ", ")");
2384 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002385 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002386 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002387 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002388 break;
2389 case EOpReflect:
2390 outputTriplet(out, visit, "reflect(", ", ", ")");
2391 break;
2392 case EOpRefract:
2393 outputTriplet(out, visit, "refract(", ", ", ")");
2394 break;
2395 case EOpOuterProduct:
2396 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002397 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002398 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002399 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002400 outputTriplet(out, visit, "(", " * ", ")");
2401 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002402 case EOpBitfieldExtract:
2403 case EOpBitfieldInsert:
2404 case EOpUaddCarry:
2405 case EOpUsubBorrow:
2406 case EOpUmulExtended:
2407 case EOpImulExtended:
2408 ASSERT(node->getUseEmulatedFunction());
2409 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2410 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002411 case EOpBarrier:
2412 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2413 // cheapest *WithGroupSync() function, without any functionality loss, but
2414 // with the potential for severe performance loss.
2415 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2416 break;
2417 case EOpMemoryBarrierShared:
2418 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2419 break;
2420 case EOpMemoryBarrierAtomicCounter:
2421 case EOpMemoryBarrierBuffer:
2422 case EOpMemoryBarrierImage:
2423 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2424 break;
2425 case EOpGroupMemoryBarrier:
2426 case EOpMemoryBarrier:
2427 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2428 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002429
2430 // Single atomic function calls without return value.
2431 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2432 case EOpAtomicAdd:
2433 case EOpAtomicMin:
2434 case EOpAtomicMax:
2435 case EOpAtomicAnd:
2436 case EOpAtomicOr:
2437 case EOpAtomicXor:
Qin Jiajia46229052018-12-10 13:31:00 +08002438 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
2439 // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
2440 // optional.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002441 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2442 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
Qin Jiajia46229052018-12-10 13:31:00 +08002443 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
2444 // compare_value, value) should all be modified into the form of "int temp; temp =
2445 // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
2446 // compare_value, value);" in the intermediate tree before traversing outputHLSL.
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002447 case EOpAtomicExchange:
2448 case EOpAtomicCompSwap:
Qin Jiajia46229052018-12-10 13:31:00 +08002449 {
2450 ASSERT(node->getChildCount() > 1);
2451 TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
2452 if (IsInShaderStorageBlock(memNode))
2453 {
2454 // Atomic memory functions for SSBO.
2455 // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
2456 mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
2457 // Write the rest argument list to |out|.
2458 for (size_t i = 1; i < node->getChildCount(); i++)
2459 {
2460 out << ", ";
2461 TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
2462 if (IsInShaderStorageBlock(argument))
2463 {
2464 mSSBOOutputHLSL->outputLoadFunctionCall(argument);
2465 }
2466 else
2467 {
2468 argument->traverse(this);
2469 }
2470 }
2471
2472 out << ")";
2473 return false;
2474 }
2475 else
2476 {
2477 // Atomic memory functions for shared variable.
2478 if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
2479 {
2480 outputTriplet(out, visit,
2481 GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
2482 ")");
2483 }
2484 else
2485 {
2486 UNREACHABLE();
2487 }
2488 }
2489
2490 break;
2491 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002492 default:
2493 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002494 }
2495
2496 return true;
2497}
2498
Olli Etuaho57961272016-09-14 13:57:46 +03002499void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002500{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002501 out << "if (";
2502
2503 node->getCondition()->traverse(this);
2504
2505 out << ")\n";
2506
Jamie Madill8c46ab12015-12-07 16:39:19 -05002507 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002508
2509 bool discard = false;
2510
2511 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002512 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002513 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002514 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002515
Olli Etuahoa6f22092015-05-08 18:31:10 +03002516 // Detect true discard
2517 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2518 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002519 else
2520 {
2521 // TODO(oetuaho): Check if the semicolon inside is necessary.
2522 // It's there as a result of conservative refactoring of the output.
2523 out << "{;}\n";
2524 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002525
Jamie Madill8c46ab12015-12-07 16:39:19 -05002526 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002527
Olli Etuahoa6f22092015-05-08 18:31:10 +03002528 if (node->getFalseBlock())
2529 {
2530 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002531
Jamie Madill8c46ab12015-12-07 16:39:19 -05002532 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002533
Olli Etuaho32db19b2016-10-04 14:43:16 +01002534 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002535 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002536
Jamie Madill8c46ab12015-12-07 16:39:19 -05002537 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002538
Olli Etuahoa6f22092015-05-08 18:31:10 +03002539 // Detect false discard
2540 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2541 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002542
Olli Etuahoa6f22092015-05-08 18:31:10 +03002543 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002544 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002545 {
2546 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002547 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002548}
2549
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002550bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2551{
2552 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2553 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2554 UNREACHABLE();
2555 return false;
2556}
2557
Olli Etuaho57961272016-09-14 13:57:46 +03002558bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002559{
2560 TInfoSinkBase &out = getInfoSink();
2561
Olli Etuaho3d932d82016-04-12 11:10:30 +03002562 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002563
2564 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002565 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002566 {
2567 out << "FLATTEN ";
2568 }
2569
Olli Etuaho57961272016-09-14 13:57:46 +03002570 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002571
2572 return false;
2573}
2574
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002575bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002576{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002577 TInfoSinkBase &out = getInfoSink();
2578
Olli Etuaho923ecef2017-10-11 12:01:38 +03002579 ASSERT(node->getStatementList());
2580 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002581 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002582 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002583 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002584 outputTriplet(out, visit, "switch (", ") ", "");
2585 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002586 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002587}
2588
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002589bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002590{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002591 TInfoSinkBase &out = getInfoSink();
2592
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002593 if (node->hasCondition())
2594 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002595 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002596 return true;
2597 }
2598 else
2599 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002600 out << "default:\n";
2601 return false;
2602 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002603}
2604
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002605void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2606{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002607 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002608 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002609}
2610
2611bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2612{
Nicolas Capens655fe362014-04-11 13:12:34 -04002613 mNestedLoopDepth++;
2614
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002615 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002616 mInsideDiscontinuousLoop =
2617 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002618
Jamie Madill8c46ab12015-12-07 16:39:19 -05002619 TInfoSinkBase &out = getInfoSink();
2620
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002621 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002622 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002623 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002624 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002625 mInsideDiscontinuousLoop = wasDiscontinuous;
2626 mNestedLoopDepth--;
2627
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002628 return false;
2629 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002630 }
2631
Corentin Wallez1239ee92015-03-19 14:38:02 -07002632 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002633 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002634 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002635 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002636
Jamie Madill8c46ab12015-12-07 16:39:19 -05002637 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002638 }
2639 else
2640 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002641 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002642
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002643 if (node->getInit())
2644 {
2645 node->getInit()->traverse(this);
2646 }
2647
2648 out << "; ";
2649
alokp@chromium.org52813552010-11-16 18:36:09 +00002650 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002651 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002652 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002653 }
2654
2655 out << "; ";
2656
alokp@chromium.org52813552010-11-16 18:36:09 +00002657 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002658 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002659 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002660 }
2661
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002662 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002663
Jamie Madill8c46ab12015-12-07 16:39:19 -05002664 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002665 }
2666
2667 if (node->getBody())
2668 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002669 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002670 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002671 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002672 else
2673 {
2674 // TODO(oetuaho): Check if the semicolon inside is necessary.
2675 // It's there as a result of conservative refactoring of the output.
2676 out << "{;}\n";
2677 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002678
Jamie Madill8c46ab12015-12-07 16:39:19 -05002679 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002680
alokp@chromium.org52813552010-11-16 18:36:09 +00002681 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002682 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002683 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002684 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002685
alokp@chromium.org52813552010-11-16 18:36:09 +00002686 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002687
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002688 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002689 }
2690
daniel@transgaming.com73536982012-03-21 20:45:49 +00002691 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002692
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002693 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002694 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002695
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002696 return false;
2697}
2698
2699bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2700{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002701 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002702 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002703 TInfoSinkBase &out = getInfoSink();
2704
2705 switch (node->getFlowOp())
2706 {
2707 case EOpKill:
2708 out << "discard";
2709 break;
2710 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002711 if (mNestedLoopDepth > 1)
2712 {
2713 mUsesNestedBreak = true;
2714 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002715
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002716 if (mExcessiveLoopIndex)
2717 {
2718 out << "{Break";
2719 mExcessiveLoopIndex->traverse(this);
2720 out << " = true; break;}\n";
2721 }
2722 else
2723 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002724 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002725 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002726 break;
2727 case EOpContinue:
2728 out << "continue";
2729 break;
2730 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002731 if (node->getExpression())
2732 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002733 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002734 out << "return ";
2735 }
2736 else
2737 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002738 if (mInsideMain && shaderNeedsGenerateOutput())
2739 {
2740 out << "return " << generateOutputCall();
2741 }
2742 else
2743 {
2744 out << "return";
2745 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002747 break;
2748 default:
2749 UNREACHABLE();
2750 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002751 }
2752
2753 return true;
2754}
2755
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002756// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002757// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2758// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002759bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002760{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002761 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002762
2763 // Parse loops of the form:
2764 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002765 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002766 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002767 int initial = 0;
2768 int limit = 0;
2769 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002770
2771 // Parse index name and intial value
2772 if (node->getInit())
2773 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002774 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002775
2776 if (init)
2777 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002778 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002779 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002780
2781 if (variable && variable->getQualifier() == EvqTemporary)
2782 {
2783 TIntermBinary *assign = variable->getAsBinaryNode();
2784
2785 if (assign->getOp() == EOpInitialize)
2786 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002787 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002788 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2789
2790 if (symbol && constant)
2791 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002792 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002793 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002794 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002795 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002796 }
2797 }
2798 }
2799 }
2800 }
2801 }
2802
2803 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002804 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002805 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002806 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002807
Olli Etuahob6af22b2017-12-15 14:05:44 +02002808 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002809 {
2810 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2811
2812 if (constant)
2813 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002814 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002815 {
2816 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002817 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002818 }
2819 }
2820 }
2821 }
2822
2823 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002824 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002825 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002826 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002827 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002828
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002829 if (binaryTerminal)
2830 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002831 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002832 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2833
2834 if (constant)
2835 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002836 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002837 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002838 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002839
2840 switch (op)
2841 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002842 case EOpAddAssign:
2843 increment = value;
2844 break;
2845 case EOpSubAssign:
2846 increment = -value;
2847 break;
2848 default:
2849 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002850 }
2851 }
2852 }
2853 }
2854 else if (unaryTerminal)
2855 {
2856 TOperator op = unaryTerminal->getOp();
2857
2858 switch (op)
2859 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002860 case EOpPostIncrement:
2861 increment = 1;
2862 break;
2863 case EOpPostDecrement:
2864 increment = -1;
2865 break;
2866 case EOpPreIncrement:
2867 increment = 1;
2868 break;
2869 case EOpPreDecrement:
2870 increment = -1;
2871 break;
2872 default:
2873 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002874 }
2875 }
2876 }
2877
Yunchao He4f285442017-04-21 12:15:49 +08002878 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002879 {
2880 if (comparator == EOpLessThanEqual)
2881 {
2882 comparator = EOpLessThan;
2883 limit += 1;
2884 }
2885
2886 if (comparator == EOpLessThan)
2887 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002888 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002889
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002890 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002891 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002892 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002893 }
2894
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002895 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002896 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002897
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002898 out << "{int ";
2899 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002900 out << ";\n"
2901 "bool Break";
2902 index->traverse(this);
2903 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002904
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002905 bool firstLoopFragment = true;
2906
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002907 while (iterations > 0)
2908 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002909 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002910
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002911 if (!firstLoopFragment)
2912 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002913 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002914 index->traverse(this);
2915 out << ") {\n";
2916 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002917
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002918 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002919 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002920 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002921 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002922
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002923 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002924 const char *unroll =
2925 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002926
Corentin Wallez1239ee92015-03-19 14:38:02 -07002927 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002928 index->traverse(this);
2929 out << " = ";
2930 out << initial;
2931
2932 out << "; ";
2933 index->traverse(this);
2934 out << " < ";
2935 out << clampedLimit;
2936
2937 out << "; ";
2938 index->traverse(this);
2939 out << " += ";
2940 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002941 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002942
Jamie Madill8c46ab12015-12-07 16:39:19 -05002943 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002944 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002945
2946 if (node->getBody())
2947 {
2948 node->getBody()->traverse(this);
2949 }
2950
Jamie Madill8c46ab12015-12-07 16:39:19 -05002951 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002952 out << ";}\n";
2953
2954 if (!firstLoopFragment)
2955 {
2956 out << "}\n";
2957 }
2958
2959 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002960
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002961 initial += MAX_LOOP_ITERATIONS * increment;
2962 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002963 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002964
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002965 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002966
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002967 mExcessiveLoopIndex = restoreIndex;
2968
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002969 return true;
2970 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002971 else
2972 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002973 }
2974
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002975 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002976}
2977
Jamie Madill8c46ab12015-12-07 16:39:19 -05002978void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2979 Visit visit,
2980 const char *preString,
2981 const char *inString,
2982 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002983{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002984 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002985 {
2986 out << preString;
2987 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002988 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002989 {
2990 out << inString;
2991 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002992 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002993 {
2994 out << postString;
2995 }
2996}
2997
Jamie Madill8c46ab12015-12-07 16:39:19 -05002998void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002999{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003000 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003001 {
Jamie Madill32aab012015-01-27 14:12:26 -05003002 out << "\n";
3003 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003004
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003005 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003006 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003007 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003008 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003009
Jamie Madill32aab012015-01-27 14:12:26 -05003010 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003011 }
3012}
3013
Olli Etuahod4bd9632018-03-08 16:32:44 +02003014void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003015{
Olli Etuahod4bd9632018-03-08 16:32:44 +02003016 const TType &type = param->getType();
3017 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003018
Olli Etuahod4bd9632018-03-08 16:32:44 +02003019 TString nameStr = DecorateVariableIfNeeded(*param);
3020 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003021
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003022 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003023 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003024 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3025 {
3026 // Samplers are passed as indices to the sampler array.
3027 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003028 out << "const uint " << nameStr << ArrayString(type);
3029 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003030 }
3031 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3032 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003033 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
3034 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
3035 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
3036 << ArrayString(type);
3037 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02003038 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003039 }
3040
Brandon Jones4a22f4b2018-10-23 14:36:47 -07003041 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
3042 // buffer offset.
3043 if (IsAtomicCounter(type.getBasicType()))
3044 {
3045 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
3046 << nameStr << "_offset";
3047 }
3048 else
3049 {
3050 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
3051 << ArrayString(type);
3052 }
Olli Etuaho96963162016-03-21 11:54:33 +02003053
3054 // If the structure parameter contains samplers, they need to be passed into the function as
3055 // separate parameters. HLSL doesn't natively support samplers in structs.
3056 if (type.isStructureContainingSamplers())
3057 {
3058 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003059 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02003060 std::string namePrefix = "angle";
3061 namePrefix += nameStr.c_str();
3062 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
3063 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02003064 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02003065 {
Olli Etuaho28839f02017-08-15 11:38:16 +03003066 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02003067 if (mOutputType == SH_HLSL_4_1_OUTPUT)
3068 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003069 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003070 }
3071 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3072 {
Olli Etuaho96963162016-03-21 11:54:33 +02003073 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003074 out << ", " << QualifierString(qualifier) << " "
3075 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
3076 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
3077 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
3078 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003079 }
3080 else
3081 {
Olli Etuaho96963162016-03-21 11:54:33 +02003082 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003083 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3084 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003085 }
3086 }
3087 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003088}
3089
jchen10efe061b2018-11-13 16:44:40 +08003090TString OutputHLSL::zeroInitializer(const TType &type) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003091{
3092 TString string;
3093
Jamie Madill94bf7f22013-07-08 13:31:15 -04003094 size_t size = type.getObjectSize();
jchen10efe061b2018-11-13 16:44:40 +08003095 if (size >= kZeroCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003096 {
jchen10efe061b2018-11-13 16:44:40 +08003097 mUseZeroArray = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003098 }
jchen10efe061b2018-11-13 16:44:40 +08003099 string = GetZeroInitializer(size).c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003100
daniel@transgaming.comead23042010-04-29 03:35:36 +00003101 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003102}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003103
Olli Etuahobd3cd502017-11-03 15:48:52 +02003104void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003105{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003106 // Array constructors should have been already pruned from the code.
3107 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003108
3109 if (visit == PreVisit)
3110 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003111 TString constructorName;
3112 if (node->getBasicType() == EbtStruct)
3113 {
3114 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3115 }
3116 else
3117 {
3118 constructorName =
3119 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3120 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003121 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003122 }
3123 else if (visit == InVisit)
3124 {
3125 out << ", ";
3126 }
3127 else if (visit == PostVisit)
3128 {
3129 out << ")";
3130 }
3131}
3132
Jamie Madill8c46ab12015-12-07 16:39:19 -05003133const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3134 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003135 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003136{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003137 ASSERT(!type.isArray());
3138
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003139 const TConstantUnion *constUnionIterated = constUnion;
3140
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003141 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003142 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003143 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003144 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003145
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003146 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003147
Jamie Madill98493dd2013-07-08 14:39:03 -04003148 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003149 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003150 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003151 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003152
Jamie Madill98493dd2013-07-08 14:39:03 -04003153 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003154 {
3155 out << ", ";
3156 }
3157 }
3158
3159 out << ")";
3160 }
3161 else
3162 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003163 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003164 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003165
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003166 if (writeType)
3167 {
Jamie Madill033dae62014-06-18 12:56:28 -04003168 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003169 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003170 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003171 if (writeType)
3172 {
3173 out << ")";
3174 }
3175 }
3176
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003177 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003178}
3179
Olli Etuahod68924e2017-01-02 17:34:40 +00003180void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003181{
Olli Etuahod68924e2017-01-02 17:34:40 +00003182 if (visit == PreVisit)
3183 {
3184 const char *opStr = GetOperatorString(op);
3185 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3186 out << "(";
3187 }
3188 else
3189 {
3190 outputTriplet(out, visit, nullptr, ", ", ")");
3191 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003192}
3193
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003194bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3195 TIntermSymbol *symbolNode,
3196 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003197{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003198 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3199 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003200
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003201 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003202 {
3203 // Type already printed
3204 out << "t" + str(mUniqueIndex) + " = ";
3205 expression->traverse(this);
3206 out << ", ";
3207 symbolNode->traverse(this);
3208 out << " = t" + str(mUniqueIndex);
3209
3210 mUniqueIndex++;
3211 return true;
3212 }
3213
3214 return false;
3215}
3216
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003217bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3218 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003219 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003220{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003221 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003222 {
3223 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003224 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003225 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003226 writeConstantUnionArray(out, initializer->getConstantValue(),
3227 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003228 out << "}";
3229 return true;
3230 }
3231 return false;
3232}
3233
Jamie Madill55e79e02015-02-09 15:35:00 -05003234TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3235{
3236 const TFieldList &fields = structure.fields();
3237
3238 for (const auto &eqFunction : mStructEqualityFunctions)
3239 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003240 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003241 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003242 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003243 }
3244 }
3245
3246 const TString &structNameString = StructNameString(structure);
3247
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003248 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003249 function->structure = &structure;
3250 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003251
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003252 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003253
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003254 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3255 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003256 << "{\n"
3257 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003258
3259 for (size_t i = 0; i < fields.size(); i++)
3260 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003261 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003262 const TType *fieldType = field->type();
3263
3264 const TString &fieldNameA = "a." + Decorate(field->name());
3265 const TString &fieldNameB = "b." + Decorate(field->name());
3266
3267 if (i > 0)
3268 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003269 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003270 }
3271
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003272 fnOut << "(";
3273 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3274 fnOut << fieldNameA;
3275 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3276 fnOut << fieldNameB;
3277 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3278 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003279 }
3280
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003281 fnOut << ";\n"
3282 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003283
3284 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003285
3286 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003287 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003288
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003289 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003290}
3291
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003292TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003293{
3294 for (const auto &eqFunction : mArrayEqualityFunctions)
3295 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003296 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003297 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003298 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003299 }
3300 }
3301
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003302 TType elementType(type);
3303 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003304
Olli Etuaho12690762015-03-31 12:55:28 +03003305 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003306 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003307
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003308 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003309
3310 TInfoSinkBase fnOut;
3311
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003312 const TString &typeName = TypeString(type);
3313 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3314 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003315 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003316 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003317 << type.getOutermostArraySize()
3318 << "; ++i)\n"
3319 " {\n"
3320 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003321
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003322 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003323 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003324 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003325 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003326 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003327
3328 fnOut << ") { return false; }\n"
3329 " }\n"
3330 " return true;\n"
3331 "}\n";
3332
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003333 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003334
3335 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003336 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003337
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003338 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003339}
3340
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003341TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003342{
3343 for (const auto &assignFunction : mArrayAssignmentFunctions)
3344 {
3345 if (assignFunction.type == type)
3346 {
3347 return assignFunction.functionName;
3348 }
3349 }
3350
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003351 TType elementType(type);
3352 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003353
3354 ArrayHelperFunction function;
3355 function.type = type;
3356
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003357 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003358
3359 TInfoSinkBase fnOut;
3360
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003361 const TString &typeName = TypeString(type);
3362 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3363 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003364 << "{\n"
3365 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003366 << type.getOutermostArraySize()
3367 << "; ++i)\n"
3368 " {\n"
3369 " ";
3370
3371 outputAssign(PreVisit, elementType, fnOut);
3372 fnOut << "a[i]";
3373 outputAssign(InVisit, elementType, fnOut);
3374 fnOut << "b[i]";
3375 outputAssign(PostVisit, elementType, fnOut);
3376
3377 fnOut << ";\n"
3378 " }\n"
3379 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003380
3381 function.functionDefinition = fnOut.c_str();
3382
3383 mArrayAssignmentFunctions.push_back(function);
3384
3385 return function.functionName;
3386}
3387
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003388TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003389{
3390 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3391 {
3392 if (constructIntoFunction.type == type)
3393 {
3394 return constructIntoFunction.functionName;
3395 }
3396 }
3397
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003398 TType elementType(type);
3399 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003400
3401 ArrayHelperFunction function;
3402 function.type = type;
3403
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003404 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003405
3406 TInfoSinkBase fnOut;
3407
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003408 const TString &typeName = TypeString(type);
3409 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3410 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003411 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003412 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003413 }
3414 fnOut << ")\n"
3415 "{\n";
3416
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003417 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003418 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003419 fnOut << " ";
3420 outputAssign(PreVisit, elementType, fnOut);
3421 fnOut << "a[" << i << "]";
3422 outputAssign(InVisit, elementType, fnOut);
3423 fnOut << "b" << i;
3424 outputAssign(PostVisit, elementType, fnOut);
3425 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003426 }
3427 fnOut << "}\n";
3428
3429 function.functionDefinition = fnOut.c_str();
3430
3431 mArrayConstructIntoFunctions.push_back(function);
3432
3433 return function.functionName;
3434}
3435
Jamie Madill2e295e22015-04-29 10:41:33 -04003436void OutputHLSL::ensureStructDefined(const TType &type)
3437{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003438 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003439 if (structure)
3440 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003441 ASSERT(type.getBasicType() == EbtStruct);
3442 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003443 }
3444}
3445
Olli Etuaho06235df2018-07-20 14:26:07 +03003446bool OutputHLSL::shaderNeedsGenerateOutput() const
3447{
3448 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3449}
3450
3451const char *OutputHLSL::generateOutputCall() const
3452{
3453 if (mShaderType == GL_VERTEX_SHADER)
3454 {
3455 return "generateOutput(input)";
3456 }
3457 else
3458 {
3459 return "generateOutput()";
3460 }
3461}
3462
Jamie Madill45bcc782016-11-07 13:58:48 -05003463} // namespace sh