blob: 9bae425d728dfbb70fdf252b10c8e3c8d60e201d [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08009#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000010#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000011#include <cfloat>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000012
Jamie Madill9e0478f2015-01-13 11:13:54 -050013#include "common/angleutils.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030014#include "common/debug.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/utilities.h"
Brandon Jones4a22f4b2018-10-23 14:36:47 -070016#include "compiler/translator/AtomicCounterFunctionHLSL.h"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020017#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080019#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050020#include "compiler/translator/InfoSink.h"
Qin Jiajia3e217f62018-08-28 16:55:20 +080021#include "compiler/translator/ResourcesHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030023#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050024#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/UtilsHLSL.h"
26#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020027#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020028#include "compiler/translator/tree_util/FindSymbolNode.h"
29#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050030#include "compiler/translator/util.h"
31
Jamie Madill45bcc782016-11-07 13:58:48 -050032namespace sh
33{
34
Olli Etuaho96f6adf2017-08-16 11:18:54 +030035namespace
36{
37
38TString ArrayHelperFunctionName(const char *prefix, const TType &type)
39{
40 TStringStream fnName;
41 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080042 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030043 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080044 for (unsigned int arraySize : *type.getArraySizes())
45 {
46 fnName << arraySize << "_";
47 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030048 }
49 fnName << TypeString(type);
50 return fnName.str();
51}
52
Olli Etuaho40dbdd62017-10-13 13:34:19 +030053bool IsDeclarationWrittenOut(TIntermDeclaration *node)
54{
55 TIntermSequence *sequence = node->getSequence();
56 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
57 ASSERT(sequence->size() == 1);
58 ASSERT(variable);
59 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080060 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030061}
62
Qin Jiajiaa735ee22018-05-18 13:29:09 +080063bool IsInStd140UniformBlock(TIntermTyped *node)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020064{
65 TIntermBinary *binaryNode = node->getAsBinaryNode();
66
67 if (binaryNode)
68 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080069 return IsInStd140UniformBlock(binaryNode->getLeft());
Olli Etuaho2ef23e22017-11-01 16:39:11 +020070 }
71
72 const TType &type = node->getType();
73
Qin Jiajiaa735ee22018-05-18 13:29:09 +080074 if (type.getQualifier() == EvqUniform)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020075 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080076 // determine if we are in the standard layout
77 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
78 if (interfaceBlock)
79 {
80 return (interfaceBlock->blockStorage() == EbsStd140);
81 }
Olli Etuaho2ef23e22017-11-01 16:39:11 +020082 }
83
84 return false;
85}
86
Jiawei Shaoa6a78422018-06-28 08:32:54 +080087const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
88{
89 switch (op)
90 {
91 case EOpAtomicAdd:
92 return "InterlockedAdd(";
93 case EOpAtomicMin:
94 return "InterlockedMin(";
95 case EOpAtomicMax:
96 return "InterlockedMax(";
97 case EOpAtomicAnd:
98 return "InterlockedAnd(";
99 case EOpAtomicOr:
100 return "InterlockedOr(";
101 case EOpAtomicXor:
102 return "InterlockedXor(";
103 case EOpAtomicExchange:
104 return "InterlockedExchange(";
105 case EOpAtomicCompSwap:
106 return "InterlockedCompareExchange(";
107 default:
108 UNREACHABLE();
109 return "";
110 }
111}
112
113bool IsAtomicFunctionDirectAssign(const TIntermBinary &node)
114{
115 return node.getOp() == EOpAssign && node.getRight()->getAsAggregate() &&
116 IsAtomicFunction(node.getRight()->getAsAggregate()->getOp());
117}
118
jchen10efe061b2018-11-13 16:44:40 +0800119const char *kZeros = "_ANGLE_ZEROS_";
120constexpr int kZeroCount = 256;
121std::string DefineZeroArray()
122{
123 std::stringstream ss;
124 // For 'static', if the declaration does not include an initializer, the value is set to zero.
125 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
126 ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
127 return ss.str();
128}
129
130std::string GetZeroInitializer(size_t size)
131{
132 std::stringstream ss;
133 size_t quotient = size / kZeroCount;
134 size_t reminder = size % kZeroCount;
135
136 for (size_t i = 0; i < quotient; ++i)
137 {
138 if (i != 0)
139 {
140 ss << ", ";
141 }
142 ss << kZeros;
143 }
144
145 for (size_t i = 0; i < reminder; ++i)
146 {
147 if (quotient != 0 || i != 0)
148 {
149 ss << ", ";
150 }
151 ss << "0";
152 }
153
154 return ss.str();
155}
156
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300157} // anonymous namespace
158
Olli Etuahoc71862a2017-12-21 12:58:29 +0200159TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
160 const TVariable *aInstanceVariable)
161 : block(aBlock), instanceVariable(aInstanceVariable)
162{
163}
164
Olli Etuaho56a2f952016-12-08 12:16:27 +0000165void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300166{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000167 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
168 // regardless.
169 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
170 mOutputType == SH_HLSL_4_1_OUTPUT)
171 {
172 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
173 }
174 else
175 {
176 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
177 }
178}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300179
Olli Etuaho56a2f952016-12-08 12:16:27 +0000180void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200181{
182 ASSERT(constUnion != nullptr);
183 switch (constUnion->getType())
184 {
185 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000186 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200187 break;
188 case EbtInt:
189 out << constUnion->getIConst();
190 break;
191 case EbtUInt:
192 out << constUnion->getUConst();
193 break;
194 case EbtBool:
195 out << constUnion->getBConst();
196 break;
197 default:
198 UNREACHABLE();
199 }
200}
201
Olli Etuaho56a2f952016-12-08 12:16:27 +0000202const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
203 const TConstantUnion *const constUnion,
204 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200205{
206 const TConstantUnion *constUnionIterated = constUnion;
207 for (size_t i = 0; i < size; i++, constUnionIterated++)
208 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000209 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200210
211 if (i != size - 1)
212 {
213 out << ", ";
214 }
215 }
216 return constUnionIterated;
217}
218
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800219OutputHLSL::OutputHLSL(sh::GLenum shaderType,
220 int shaderVersion,
221 const TExtensionBehavior &extensionBehavior,
222 const char *sourcePath,
223 ShShaderOutput outputType,
224 int numRenderTargets,
225 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300226 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300227 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300228 TSymbolTable *symbolTable,
229 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300230 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200231 mShaderType(shaderType),
232 mShaderVersion(shaderVersion),
233 mExtensionBehavior(extensionBehavior),
234 mSourcePath(sourcePath),
235 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700236 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300237 mInsideFunction(false),
238 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000239 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300240 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300241 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300242 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800244 mUsesFragColor = false;
245 mUsesFragData = false;
246 mUsesDepthRange = false;
247 mUsesFragCoord = false;
248 mUsesPointCoord = false;
249 mUsesFrontFacing = false;
250 mUsesPointSize = false;
251 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300252 mHasMultiviewExtensionEnabled =
253 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300254 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500255 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500256 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800257 mUsesNumWorkGroups = false;
258 mUsesWorkGroupID = false;
259 mUsesLocalInvocationID = false;
260 mUsesGlobalInvocationID = false;
261 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500262 mUsesXor = false;
263 mUsesDiscardRewriting = false;
264 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530265 mRequiresIEEEStrictCompiling = false;
jchen10efe061b2018-11-13 16:44:40 +0800266 mUseZeroArray = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000267
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000268 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000269
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500270 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000271 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500272 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000273
Yunchao Hed7297bf2017-04-19 15:27:10 +0800274 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000275
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700276 mStructureHLSL = new StructureHLSL;
277 mTextureFunctionHLSL = new TextureFunctionHLSL;
278 mImageFunctionHLSL = new ImageFunctionHLSL;
279 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400280
Olli Etuahod8724a92017-12-29 18:40:36 +0200281 unsigned int firstUniformRegister =
282 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800283 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200284
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200285 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000286 {
Arun Patole63419392015-03-13 11:51:07 +0530287 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500288 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
289 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530290 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800291 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000292 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000293
Geoff Lang00140f42016-02-03 18:47:33 +0000294 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800295 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800296
297 mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298}
299
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000300OutputHLSL::~OutputHLSL()
301{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800302 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400303 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800304 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300305 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800306 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700307 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200308 for (auto &eqFunction : mStructEqualityFunctions)
309 {
310 SafeDelete(eqFunction);
311 }
312 for (auto &eqFunction : mArrayEqualityFunctions)
313 {
314 SafeDelete(eqFunction);
315 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000316}
317
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200318void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000319{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200320 BuiltInFunctionEmulator builtInFunctionEmulator;
321 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800322 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
323 {
324 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
325 mShaderVersion);
326 }
327
Olli Etuahodfa75e82017-01-23 09:43:06 -0800328 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500329
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700330 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000331 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700332 ASSERT(success == CallDAG::INITDAG_SUCCESS);
333 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700334
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200335 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
336 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
337 // the shader code. When we add shader storage blocks we might also consider an alternative
338 // solution, since the struct mapping won't work very well for shader storage blocks.
339
Jamie Madill37997142015-01-28 10:06:34 -0500340 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500341 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200342 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500343 mInfoSinkStack.pop();
344
Jamie Madill37997142015-01-28 10:06:34 -0500345 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500346 mInfoSinkStack.pop();
347
Jamie Madill32aab012015-01-27 14:12:26 -0500348 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200349 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500350 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000351
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200352 objSink << mHeader.c_str();
353 objSink << mBody.c_str();
354 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200355
Olli Etuahodfa75e82017-01-23 09:43:06 -0800356 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000357}
358
Qin Jiajiaa602f902018-09-11 14:40:24 +0800359const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
360{
361 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
362}
363
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800364const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400365{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800366 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400367}
368
Jamie Madill9fe25e92014-07-18 10:33:08 -0400369const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
370{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800371 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400372}
373
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200374TString OutputHLSL::structInitializerString(int indent,
375 const TType &type,
376 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400377{
378 TString init;
379
Olli Etuahoed049ab2017-06-30 17:38:33 +0300380 TString indentString;
381 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400382 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300383 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400384 }
385
Olli Etuahoed049ab2017-06-30 17:38:33 +0300386 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400387 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300388 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300389 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400390 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300391 TStringStream indexedString;
392 indexedString << name << "[" << arrayIndex << "]";
393 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300394 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300395 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300396 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300397 {
398 init += ",";
399 }
400 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400401 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300402 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400403 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300404 else if (type.getBasicType() == EbtStruct)
405 {
406 init += indentString + "{\n";
407 const TStructure &structure = *type.getStruct();
408 const TFieldList &fields = structure.fields();
409 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
410 {
411 const TField &field = *fields[fieldIndex];
412 const TString &fieldName = name + "." + Decorate(field.name());
413 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400414
Olli Etuahoed049ab2017-06-30 17:38:33 +0300415 init += structInitializerString(indent + 1, fieldType, fieldName);
416 if (fieldIndex < fields.size() - 1)
417 {
418 init += ",";
419 }
420 init += "\n";
421 }
422 init += indentString + "}";
423 }
424 else
425 {
426 init += indentString + name;
427 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400428
429 return init;
430}
431
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200432TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
433{
434 TString mappedStructs;
435
436 for (auto &mappedStruct : std140Structs)
437 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200438 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200439 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800440 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
441 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200442 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800443 case EvqUniform:
444 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
445 {
446 continue;
447 }
448 break;
449 case EvqBuffer:
450 continue;
451 default:
452 UNREACHABLE();
453 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200454 }
455
456 unsigned int instanceCount = 1u;
457 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
458 if (isInstanceArray)
459 {
460 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
461 }
462
463 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
464 ++instanceArrayIndex)
465 {
466 TString originalName;
467 TString mappedName("map");
468
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200469 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200470 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200471 const ImmutableString &instanceName =
472 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200473 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
474 if (isInstanceArray)
475 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800476 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200477 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200478 originalName += instanceString;
479 mappedName += instanceString;
480 originalName += ".";
481 mappedName += "_";
482 }
483
484 TString fieldName = Decorate(mappedStruct.field->name());
485 originalName += fieldName;
486 mappedName += fieldName;
487
488 TType *structType = mappedStruct.field->type();
489 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200490 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200491
492 if (structType->isArray())
493 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300494 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200495 }
496
497 mappedStructs += " =\n";
498 mappedStructs += structInitializerString(0, *structType, originalName);
499 mappedStructs += ";\n";
500 }
501 }
502 return mappedStructs;
503}
504
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300505void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000506{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300507 for (const auto &attribute : mReferencedAttributes)
508 {
509 const TType &type = attribute.second->getType();
510 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400511
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300512 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
513 << zeroInitializer(type) << ";\n";
514 }
515}
516
517void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
518{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200519 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000520 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800521 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000522
523 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300524 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300525 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
526 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000527 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300528}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000529
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300530void OutputHLSL::header(TInfoSinkBase &out,
531 const std::vector<MappedStruct> &std140Structs,
532 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
533{
534 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000535
Jamie Madill8daaba12014-06-13 10:04:33 -0400536 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400537
Qin Jiajia3e217f62018-08-28 16:55:20 +0800538 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
539 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800540 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400541
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200542 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500543 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200544 out << "\n// Equality functions\n\n";
545 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500546 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200547 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200548 }
549 }
Olli Etuaho12690762015-03-31 12:55:28 +0300550 if (!mArrayAssignmentFunctions.empty())
551 {
552 out << "\n// Assignment functions\n\n";
553 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
554 {
555 out << assignmentFunction.functionDefinition << "\n";
556 }
557 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300558 if (!mArrayConstructIntoFunctions.empty())
559 {
560 out << "\n// Array constructor functions\n\n";
561 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
562 {
563 out << constructIntoFunction.functionDefinition << "\n";
564 }
565 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200566
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500567 if (mUsesDiscardRewriting)
568 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400569 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500570 }
571
Nicolas Capens655fe362014-04-11 13:12:34 -0400572 if (mUsesNestedBreak)
573 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400574 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400575 }
576
Arun Patole44efa0b2015-03-04 17:11:05 +0530577 if (mRequiresIEEEStrictCompiling)
578 {
579 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
580 }
581
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400582 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
583 "#define LOOP [loop]\n"
584 "#define FLATTEN [flatten]\n"
585 "#else\n"
586 "#define LOOP\n"
587 "#define FLATTEN\n"
588 "#endif\n";
589
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700590 // array stride for atomic counter buffers is always 4 per original extension
591 // ARB_shader_atomic_counters and discussion on
592 // https://github.com/KhronosGroup/OpenGL-API/issues/5
593 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
594
jchen10efe061b2018-11-13 16:44:40 +0800595 if (mUseZeroArray)
596 {
597 out << DefineZeroArray() << "\n";
598 }
599
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200600 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300602 const bool usingMRTExtension =
603 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000604
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000605 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300606 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400607 out << "\n";
608
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200609 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000610 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200611 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000612 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200613 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800614 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400615
Olli Etuahofbb1c792018-01-19 16:26:59 +0200616 out << "static " << TypeString(variableType) << " out_" << variableName
617 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000618 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000619 }
Jamie Madill46131a32013-06-20 11:55:50 -0400620 else
621 {
622 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
623
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800624 out << "static float4 gl_Color[" << numColorValues
625 << "] =\n"
626 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400627 for (unsigned int i = 0; i < numColorValues; i++)
628 {
629 out << " float4(0, 0, 0, 0)";
630 if (i + 1 != numColorValues)
631 {
632 out << ",";
633 }
634 out << "\n";
635 }
636
637 out << "};\n";
638 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000639
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400640 if (mUsesFragDepth)
641 {
642 out << "static float gl_Depth = 0.0;\n";
643 }
644
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000645 if (mUsesFragCoord)
646 {
647 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
648 }
649
650 if (mUsesPointCoord)
651 {
652 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
653 }
654
655 if (mUsesFrontFacing)
656 {
657 out << "static bool gl_FrontFacing = false;\n";
658 }
659
660 out << "\n";
661
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000662 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000663 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000664 out << "struct gl_DepthRangeParameters\n"
665 "{\n"
666 " float near;\n"
667 " float far;\n"
668 " float diff;\n"
669 "};\n"
670 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000671 }
672
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200673 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000674 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000675 out << "cbuffer DriverConstants : register(b1)\n"
676 "{\n";
677
678 if (mUsesDepthRange)
679 {
680 out << " float3 dx_DepthRange : packoffset(c0);\n";
681 }
682
683 if (mUsesFragCoord)
684 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000685 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000686 }
687
688 if (mUsesFragCoord || mUsesFrontFacing)
689 {
690 out << " float3 dx_DepthFront : packoffset(c2);\n";
691 }
692
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800693 if (mUsesFragCoord)
694 {
695 // dx_ViewScale is only used in the fragment shader to correct
696 // the value for glFragCoord if necessary
697 out << " float2 dx_ViewScale : packoffset(c3);\n";
698 }
699
Martin Radev72b4e1e2017-08-31 15:42:56 +0300700 if (mHasMultiviewExtensionEnabled)
701 {
702 // We have to add a value which we can use to keep track of which multi-view code
703 // path is to be selected in the GS.
704 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
705 }
706
Olli Etuaho618bebc2016-01-15 16:40:00 +0200707 if (mOutputType == SH_HLSL_4_1_OUTPUT)
708 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800709 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200710 }
711
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000712 out << "};\n";
713 }
714 else
715 {
716 if (mUsesDepthRange)
717 {
718 out << "uniform float3 dx_DepthRange : register(c0);";
719 }
720
721 if (mUsesFragCoord)
722 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000723 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000724 }
725
726 if (mUsesFragCoord || mUsesFrontFacing)
727 {
728 out << "uniform float3 dx_DepthFront : register(c2);\n";
729 }
730 }
731
732 out << "\n";
733
734 if (mUsesDepthRange)
735 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500736 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
737 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000738 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000739 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000740
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000741 if (usingMRTExtension && mNumRenderTargets > 1)
742 {
743 out << "#define GL_USES_MRT\n";
744 }
745
746 if (mUsesFragColor)
747 {
748 out << "#define GL_USES_FRAG_COLOR\n";
749 }
750
751 if (mUsesFragData)
752 {
753 out << "#define GL_USES_FRAG_DATA\n";
754 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000755 }
Xinghua Caob1239382016-12-13 15:07:05 +0800756 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000757 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000758 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300759 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000760 out << "\n"
761 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400762
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000763 if (mUsesPointSize)
764 {
765 out << "static float gl_PointSize = float(1);\n";
766 }
767
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000768 if (mUsesInstanceID)
769 {
770 out << "static int gl_InstanceID;";
771 }
772
Corentin Wallezb076add2016-01-11 16:45:46 -0500773 if (mUsesVertexID)
774 {
775 out << "static int gl_VertexID;";
776 }
777
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000778 out << "\n"
779 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300780 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000781 out << "\n";
782
783 if (mUsesDepthRange)
784 {
785 out << "struct gl_DepthRangeParameters\n"
786 "{\n"
787 " float near;\n"
788 " float far;\n"
789 " float diff;\n"
790 "};\n"
791 "\n";
792 }
793
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200794 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000795 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800796 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500797 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800798
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000799 if (mUsesDepthRange)
800 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800801 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000802 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800803
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800804 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
805 // shaders. However, we declare it for all shaders (including Feature Level 10+).
806 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
807 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800808 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800809 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800810 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800811
Martin Radev72b4e1e2017-08-31 15:42:56 +0300812 if (mHasMultiviewExtensionEnabled)
813 {
814 // We have to add a value which we can use to keep track of which multi-view code
815 // path is to be selected in the GS.
816 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
817 }
818
Olli Etuaho618bebc2016-01-15 16:40:00 +0200819 if (mOutputType == SH_HLSL_4_1_OUTPUT)
820 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800821 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200822 }
823
Austin Kinross4fd18b12014-12-22 12:32:05 -0800824 out << "};\n"
825 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000826 }
827 else
828 {
829 if (mUsesDepthRange)
830 {
831 out << "uniform float3 dx_DepthRange : register(c0);\n";
832 }
833
Cooper Partine6664f02015-01-09 16:22:24 -0800834 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
835 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000836 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000837 }
838
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000839 if (mUsesDepthRange)
840 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500841 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
842 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000843 "\n";
844 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400845 }
Xinghua Caob1239382016-12-13 15:07:05 +0800846 else // Compute shader
847 {
848 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800849
850 out << "cbuffer DriverConstants : register(b1)\n"
851 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800852 if (mUsesNumWorkGroups)
853 {
Xinghua Caob1239382016-12-13 15:07:05 +0800854 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800855 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800856 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800857 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800858 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800859
Jiawei Shao203b26f2018-07-25 10:30:43 +0800860 std::ostringstream systemValueDeclaration;
861 std::ostringstream glBuiltinInitialization;
862
863 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
864 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
865 << "{\n";
866
Xinghua Caob1239382016-12-13 15:07:05 +0800867 if (mUsesWorkGroupID)
868 {
869 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800870 systemValueDeclaration << " uint3 dx_WorkGroupID : "
871 << "SV_GroupID;\n";
872 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800873 }
874
875 if (mUsesLocalInvocationID)
876 {
877 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800878 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
879 << "SV_GroupThreadID;\n";
880 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800881 }
882
883 if (mUsesGlobalInvocationID)
884 {
885 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800886 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
887 << "SV_DispatchThreadID;\n";
888 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800889 }
890
891 if (mUsesLocalInvocationIndex)
892 {
893 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800894 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
895 << "SV_GroupIndex;\n";
896 glBuiltinInitialization
897 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800898 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800899
900 systemValueDeclaration << "};\n\n";
901 glBuiltinInitialization << "};\n\n";
902
903 out << systemValueDeclaration.str();
904 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800905 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000906
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800907 if (!mappedStructs.empty())
908 {
909 out << "// Structures from std140 blocks with padding removed\n";
910 out << "\n";
911 out << mappedStructs;
912 out << "\n";
913 }
914
Geoff Lang1fe74c72016-08-25 13:23:01 -0400915 bool getDimensionsIgnoresBaseLevel =
916 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
917 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800918 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700919 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000921 if (mUsesFragCoord)
922 {
923 out << "#define GL_USES_FRAG_COORD\n";
924 }
925
926 if (mUsesPointCoord)
927 {
928 out << "#define GL_USES_POINT_COORD\n";
929 }
930
931 if (mUsesFrontFacing)
932 {
933 out << "#define GL_USES_FRONT_FACING\n";
934 }
935
936 if (mUsesPointSize)
937 {
938 out << "#define GL_USES_POINT_SIZE\n";
939 }
940
Martin Radev41ac68e2017-06-06 12:16:58 +0300941 if (mHasMultiviewExtensionEnabled)
942 {
943 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
944 }
945
946 if (mUsesViewID)
947 {
948 out << "#define GL_USES_VIEW_ID\n";
949 }
950
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400951 if (mUsesFragDepth)
952 {
953 out << "#define GL_USES_FRAG_DEPTH\n";
954 }
955
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000956 if (mUsesDepthRange)
957 {
958 out << "#define GL_USES_DEPTH_RANGE\n";
959 }
960
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000961 if (mUsesXor)
962 {
963 out << "bool xor(bool p, bool q)\n"
964 "{\n"
965 " return (p || q) && !(p && q);\n"
966 "}\n"
967 "\n";
968 }
969
Olli Etuahodfa75e82017-01-23 09:43:06 -0800970 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000971}
972
973void OutputHLSL::visitSymbol(TIntermSymbol *node)
974{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200975 const TVariable &variable = node->variable();
976
977 // Empty symbols can only appear in declarations and function arguments, and in either of those
978 // cases the symbol nodes are not visited.
979 ASSERT(variable.symbolType() != SymbolType::Empty);
980
Jamie Madill32aab012015-01-27 14:12:26 -0500981 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982
Jamie Madill570e04d2013-06-21 09:15:33 -0400983 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800984 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400985 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200986 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400987 }
988
Olli Etuahofbb1c792018-01-19 16:26:59 +0200989 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200990 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200991
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000992 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000993 {
994 mUsesDepthRange = true;
995 out << name;
996 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700997 else if (IsAtomicCounter(variable.getType().getBasicType()))
998 {
999 const TType &variableType = variable.getType();
1000 if (variableType.getQualifier() == EvqUniform)
1001 {
1002 TLayoutQualifier layout = variableType.getLayoutQualifier();
1003 mReferencedUniforms[uniqueId.get()] = &variable;
1004 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1005 }
1006 else
1007 {
1008 TString varName = DecorateVariableIfNeeded(variable);
1009 out << varName << ", " << varName << "_offset";
1010 }
1011 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001012 else
1013 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001014 const TType &variableType = variable.getType();
1015 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001016
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001017 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +02001018
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001019 if (qualifier == EvqUniform)
1020 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001021 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001022
1023 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001024 {
Olli Etuahoc71862a2017-12-21 12:58:29 +02001025 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1026 {
1027 const TVariable *instanceVariable = nullptr;
1028 if (variableType.isInterfaceBlock())
1029 {
1030 instanceVariable = &variable;
1031 }
1032 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1033 new TReferencedBlock(interfaceBlock, instanceVariable);
1034 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001035 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001036 else
1037 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001038 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001039 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001040
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001041 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001042 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001043 else if (qualifier == EvqBuffer)
1044 {
1045 UNREACHABLE();
1046 }
Jamie Madill19571812013-08-12 15:26:34 -07001047 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001048 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001049 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001050 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001051 }
Jamie Madill033dae62014-06-18 12:56:28 -04001052 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001053 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001054 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001055 out << DecorateVariableIfNeeded(variable);
1056 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001057 {
1058 mUsesViewID = true;
1059 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001060 }
Jamie Madill19571812013-08-12 15:26:34 -07001061 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001062 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001063 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001064 out << "out_" << name;
1065 }
1066 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001067 {
1068 out << "gl_Color[0]";
1069 mUsesFragColor = true;
1070 }
1071 else if (qualifier == EvqFragData)
1072 {
1073 out << "gl_Color";
1074 mUsesFragData = true;
1075 }
1076 else if (qualifier == EvqFragCoord)
1077 {
1078 mUsesFragCoord = true;
1079 out << name;
1080 }
1081 else if (qualifier == EvqPointCoord)
1082 {
1083 mUsesPointCoord = true;
1084 out << name;
1085 }
1086 else if (qualifier == EvqFrontFacing)
1087 {
1088 mUsesFrontFacing = true;
1089 out << name;
1090 }
1091 else if (qualifier == EvqPointSize)
1092 {
1093 mUsesPointSize = true;
1094 out << name;
1095 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001096 else if (qualifier == EvqInstanceID)
1097 {
1098 mUsesInstanceID = true;
1099 out << name;
1100 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001101 else if (qualifier == EvqVertexID)
1102 {
1103 mUsesVertexID = true;
1104 out << name;
1105 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001106 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001107 {
1108 mUsesFragDepth = true;
1109 out << "gl_Depth";
1110 }
Xinghua Caob1239382016-12-13 15:07:05 +08001111 else if (qualifier == EvqNumWorkGroups)
1112 {
1113 mUsesNumWorkGroups = true;
1114 out << name;
1115 }
1116 else if (qualifier == EvqWorkGroupID)
1117 {
1118 mUsesWorkGroupID = true;
1119 out << name;
1120 }
1121 else if (qualifier == EvqLocalInvocationID)
1122 {
1123 mUsesLocalInvocationID = true;
1124 out << name;
1125 }
1126 else if (qualifier == EvqGlobalInvocationID)
1127 {
1128 mUsesGlobalInvocationID = true;
1129 out << name;
1130 }
1131 else if (qualifier == EvqLocalInvocationIndex)
1132 {
1133 mUsesLocalInvocationIndex = true;
1134 out << name;
1135 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001136 else
1137 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001138 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001139 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140 }
1141}
1142
Olli Etuaho7fb49552015-03-18 17:27:44 +02001143void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1144{
1145 if (type.isScalar() && !type.isArray())
1146 {
1147 if (op == EOpEqual)
1148 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001149 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001150 }
1151 else
1152 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001153 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001154 }
1155 }
1156 else
1157 {
1158 if (visit == PreVisit && op == EOpNotEqual)
1159 {
1160 out << "!";
1161 }
1162
1163 if (type.isArray())
1164 {
1165 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001166 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001167 }
1168 else if (type.getBasicType() == EbtStruct)
1169 {
1170 const TStructure &structure = *type.getStruct();
1171 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001172 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001173 }
1174 else
1175 {
1176 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001177 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001178 }
1179 }
1180}
1181
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001182void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1183{
1184 if (type.isArray())
1185 {
1186 const TString &functionName = addArrayAssignmentFunction(type);
1187 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1188 }
1189 else
1190 {
1191 outputTriplet(out, visit, "(", " = ", ")");
1192 }
1193}
1194
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001195bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001196{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001197 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001198 {
1199 TIntermNode *ancestor = getAncestorNode(n);
1200 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1201 if (ancestorBinary == nullptr)
1202 {
1203 return false;
1204 }
1205 switch (ancestorBinary->getOp())
1206 {
1207 case EOpIndexDirectStruct:
1208 {
1209 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1210 const TIntermConstantUnion *index =
1211 ancestorBinary->getRight()->getAsConstantUnion();
1212 const TField *field = structure->fields()[index->getIConst(0)];
1213 if (IsSampler(field->type()->getBasicType()))
1214 {
1215 return true;
1216 }
1217 break;
1218 }
1219 case EOpIndexDirect:
1220 break;
1221 default:
1222 // Returning a sampler from indirect indexing is not supported.
1223 return false;
1224 }
1225 }
1226 return false;
1227}
1228
Olli Etuahob6fa0432016-09-28 16:28:05 +01001229bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1230{
1231 TInfoSinkBase &out = getInfoSink();
1232 if (visit == PostVisit)
1233 {
1234 out << ".";
1235 node->writeOffsetsAsXYZW(&out);
1236 }
1237 return true;
1238}
1239
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001240bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1241{
Jamie Madill32aab012015-01-27 14:12:26 -05001242 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001243
1244 switch (node->getOp())
1245 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001246 case EOpComma:
1247 outputTriplet(out, visit, "(", ", ", ")");
1248 break;
1249 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001250 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001251 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001252 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1253 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001254 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001255 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1256 out << functionName << "(";
1257 node->getLeft()->traverse(this);
1258 TIntermSequence *seq = rightAgg->getSequence();
1259 for (auto &arrayElement : *seq)
1260 {
1261 out << ", ";
1262 arrayElement->traverse(this);
1263 }
1264 out << ")";
1265 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001266 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001267 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1268 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001269 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001270 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001271 // Assignment expressions with atomic functions should be transformed into atomic
1272 // function calls in HLSL.
1273 // e.g. original_value = atomicAdd(dest, value) should be translated into
1274 // InterlockedAdd(dest, value, original_value);
1275 else if (IsAtomicFunctionDirectAssign(*node))
1276 {
1277 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1278 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1279 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1280 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1281 ASSERT(argumentSeq->size() >= 2u);
1282 for (auto &argument : *argumentSeq)
1283 {
1284 argument->traverse(this);
1285 out << ", ";
1286 }
1287 node->getLeft()->traverse(this);
1288 out << ")";
1289 return false;
1290 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001291 else if (IsInShaderStorageBlock(node->getLeft()))
1292 {
1293 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1294 out << ", ";
1295 if (IsInShaderStorageBlock(node->getRight()))
1296 {
1297 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1298 }
1299 else
1300 {
1301 node->getRight()->traverse(this);
1302 }
1303
1304 out << ")";
1305 return false;
1306 }
1307 else if (IsInShaderStorageBlock(node->getRight()))
1308 {
1309 node->getLeft()->traverse(this);
1310 out << " = ";
1311 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1312 return false;
1313 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001314
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001315 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001316 break;
1317 case EOpInitialize:
1318 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001319 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001320 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1321 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001322 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001323
1324 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001325 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001326
1327 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1328 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1329 // new variable is created before the assignment is evaluated), so we need to
1330 // convert
1331 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001332 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001333 {
1334 // Skip initializing the rest of the expression
1335 return false;
1336 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001337 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001338 {
1339 return false;
1340 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001341 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001342 else if (visit == InVisit)
1343 {
1344 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001345 if (IsInShaderStorageBlock(node->getRight()))
1346 {
1347 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1348 return false;
1349 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001350 }
1351 break;
1352 case EOpAddAssign:
1353 outputTriplet(out, visit, "(", " += ", ")");
1354 break;
1355 case EOpSubAssign:
1356 outputTriplet(out, visit, "(", " -= ", ")");
1357 break;
1358 case EOpMulAssign:
1359 outputTriplet(out, visit, "(", " *= ", ")");
1360 break;
1361 case EOpVectorTimesScalarAssign:
1362 outputTriplet(out, visit, "(", " *= ", ")");
1363 break;
1364 case EOpMatrixTimesScalarAssign:
1365 outputTriplet(out, visit, "(", " *= ", ")");
1366 break;
1367 case EOpVectorTimesMatrixAssign:
1368 if (visit == PreVisit)
1369 {
1370 out << "(";
1371 }
1372 else if (visit == InVisit)
1373 {
1374 out << " = mul(";
1375 node->getLeft()->traverse(this);
1376 out << ", transpose(";
1377 }
1378 else
1379 {
1380 out << ")))";
1381 }
1382 break;
1383 case EOpMatrixTimesMatrixAssign:
1384 if (visit == PreVisit)
1385 {
1386 out << "(";
1387 }
1388 else if (visit == InVisit)
1389 {
1390 out << " = transpose(mul(transpose(";
1391 node->getLeft()->traverse(this);
1392 out << "), transpose(";
1393 }
1394 else
1395 {
1396 out << "))))";
1397 }
1398 break;
1399 case EOpDivAssign:
1400 outputTriplet(out, visit, "(", " /= ", ")");
1401 break;
1402 case EOpIModAssign:
1403 outputTriplet(out, visit, "(", " %= ", ")");
1404 break;
1405 case EOpBitShiftLeftAssign:
1406 outputTriplet(out, visit, "(", " <<= ", ")");
1407 break;
1408 case EOpBitShiftRightAssign:
1409 outputTriplet(out, visit, "(", " >>= ", ")");
1410 break;
1411 case EOpBitwiseAndAssign:
1412 outputTriplet(out, visit, "(", " &= ", ")");
1413 break;
1414 case EOpBitwiseXorAssign:
1415 outputTriplet(out, visit, "(", " ^= ", ")");
1416 break;
1417 case EOpBitwiseOrAssign:
1418 outputTriplet(out, visit, "(", " |= ", ")");
1419 break;
1420 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001421 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001422 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001423 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001424 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001425 if (visit == PreVisit)
1426 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001427 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001428 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001429
1430 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001431 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1432 {
1433 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1434 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1435 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001436 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001437 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001438 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001439 return false;
1440 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001441 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001442 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001443 {
1444 // All parts of an expression that access a sampler in a struct need to use _ as
1445 // separator to access the sampler variable that has been moved out of the struct.
1446 outputTriplet(out, visit, "", "_", "");
1447 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001448 else if (IsAtomicCounter(leftType.getBasicType()))
1449 {
1450 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1451 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001452 else
1453 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001454 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001455 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001456 }
1457 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001458 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001459 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001460 // We do not currently support indirect references to interface blocks
1461 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001462
1463 const TType &leftType = node->getLeft()->getType();
1464 if (IsAtomicCounter(leftType.getBasicType()))
1465 {
1466 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1467 }
1468 else
1469 {
1470 outputTriplet(out, visit, "", "[", "]");
1471 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001472 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001473 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001474 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001475 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001476 const TStructure *structure = node->getLeft()->getType().getStruct();
1477 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1478 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001479
Olli Etuaho96963162016-03-21 11:54:33 +02001480 // In cases where indexing returns a sampler, we need to access the sampler variable
1481 // that has been moved out of the struct.
1482 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1483 if (visit == PreVisit && indexingReturnsSampler)
1484 {
1485 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1486 // This prefix is only output at the beginning of the indexing expression, which
1487 // may have multiple parts.
1488 out << "angle";
1489 }
1490 if (!indexingReturnsSampler)
1491 {
1492 // All parts of an expression that access a sampler in a struct need to use _ as
1493 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001494 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001495 }
1496 if (visit == InVisit)
1497 {
1498 if (indexingReturnsSampler)
1499 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001500 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001501 }
1502 else
1503 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001504 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001505 }
1506
1507 return false;
1508 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001509 }
1510 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001511 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001512 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001513 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1514 bool structInStd140UniformBlock =
1515 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1516 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001517 {
1518 out << "map";
1519 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001520 if (visit == InVisit)
1521 {
1522 const TInterfaceBlock *interfaceBlock =
1523 node->getLeft()->getType().getInterfaceBlock();
1524 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1525 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001526 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001527 {
1528 out << "_";
1529 }
1530 else
1531 {
1532 out << ".";
1533 }
1534 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001535
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001536 return false;
1537 }
1538 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001539 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001540 case EOpAdd:
1541 outputTriplet(out, visit, "(", " + ", ")");
1542 break;
1543 case EOpSub:
1544 outputTriplet(out, visit, "(", " - ", ")");
1545 break;
1546 case EOpMul:
1547 outputTriplet(out, visit, "(", " * ", ")");
1548 break;
1549 case EOpDiv:
1550 outputTriplet(out, visit, "(", " / ", ")");
1551 break;
1552 case EOpIMod:
1553 outputTriplet(out, visit, "(", " % ", ")");
1554 break;
1555 case EOpBitShiftLeft:
1556 outputTriplet(out, visit, "(", " << ", ")");
1557 break;
1558 case EOpBitShiftRight:
1559 outputTriplet(out, visit, "(", " >> ", ")");
1560 break;
1561 case EOpBitwiseAnd:
1562 outputTriplet(out, visit, "(", " & ", ")");
1563 break;
1564 case EOpBitwiseXor:
1565 outputTriplet(out, visit, "(", " ^ ", ")");
1566 break;
1567 case EOpBitwiseOr:
1568 outputTriplet(out, visit, "(", " | ", ")");
1569 break;
1570 case EOpEqual:
1571 case EOpNotEqual:
1572 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1573 break;
1574 case EOpLessThan:
1575 outputTriplet(out, visit, "(", " < ", ")");
1576 break;
1577 case EOpGreaterThan:
1578 outputTriplet(out, visit, "(", " > ", ")");
1579 break;
1580 case EOpLessThanEqual:
1581 outputTriplet(out, visit, "(", " <= ", ")");
1582 break;
1583 case EOpGreaterThanEqual:
1584 outputTriplet(out, visit, "(", " >= ", ")");
1585 break;
1586 case EOpVectorTimesScalar:
1587 outputTriplet(out, visit, "(", " * ", ")");
1588 break;
1589 case EOpMatrixTimesScalar:
1590 outputTriplet(out, visit, "(", " * ", ")");
1591 break;
1592 case EOpVectorTimesMatrix:
1593 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1594 break;
1595 case EOpMatrixTimesVector:
1596 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1597 break;
1598 case EOpMatrixTimesMatrix:
1599 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1600 break;
1601 case EOpLogicalOr:
1602 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1603 // been unfolded.
1604 ASSERT(!node->getRight()->hasSideEffects());
1605 outputTriplet(out, visit, "(", " || ", ")");
1606 return true;
1607 case EOpLogicalXor:
1608 mUsesXor = true;
1609 outputTriplet(out, visit, "xor(", ", ", ")");
1610 break;
1611 case EOpLogicalAnd:
1612 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1613 // been unfolded.
1614 ASSERT(!node->getRight()->hasSideEffects());
1615 outputTriplet(out, visit, "(", " && ", ")");
1616 return true;
1617 default:
1618 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619 }
1620
1621 return true;
1622}
1623
1624bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1625{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001626 TInfoSinkBase &out = getInfoSink();
1627
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001628 switch (node->getOp())
1629 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001630 case EOpNegative:
1631 outputTriplet(out, visit, "(-", "", ")");
1632 break;
1633 case EOpPositive:
1634 outputTriplet(out, visit, "(+", "", ")");
1635 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001636 case EOpLogicalNot:
1637 outputTriplet(out, visit, "(!", "", ")");
1638 break;
1639 case EOpBitwiseNot:
1640 outputTriplet(out, visit, "(~", "", ")");
1641 break;
1642 case EOpPostIncrement:
1643 outputTriplet(out, visit, "(", "", "++)");
1644 break;
1645 case EOpPostDecrement:
1646 outputTriplet(out, visit, "(", "", "--)");
1647 break;
1648 case EOpPreIncrement:
1649 outputTriplet(out, visit, "(++", "", ")");
1650 break;
1651 case EOpPreDecrement:
1652 outputTriplet(out, visit, "(--", "", ")");
1653 break;
1654 case EOpRadians:
1655 outputTriplet(out, visit, "radians(", "", ")");
1656 break;
1657 case EOpDegrees:
1658 outputTriplet(out, visit, "degrees(", "", ")");
1659 break;
1660 case EOpSin:
1661 outputTriplet(out, visit, "sin(", "", ")");
1662 break;
1663 case EOpCos:
1664 outputTriplet(out, visit, "cos(", "", ")");
1665 break;
1666 case EOpTan:
1667 outputTriplet(out, visit, "tan(", "", ")");
1668 break;
1669 case EOpAsin:
1670 outputTriplet(out, visit, "asin(", "", ")");
1671 break;
1672 case EOpAcos:
1673 outputTriplet(out, visit, "acos(", "", ")");
1674 break;
1675 case EOpAtan:
1676 outputTriplet(out, visit, "atan(", "", ")");
1677 break;
1678 case EOpSinh:
1679 outputTriplet(out, visit, "sinh(", "", ")");
1680 break;
1681 case EOpCosh:
1682 outputTriplet(out, visit, "cosh(", "", ")");
1683 break;
1684 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001685 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001686 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001687 case EOpAtanh:
1688 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001689 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001690 break;
1691 case EOpExp:
1692 outputTriplet(out, visit, "exp(", "", ")");
1693 break;
1694 case EOpLog:
1695 outputTriplet(out, visit, "log(", "", ")");
1696 break;
1697 case EOpExp2:
1698 outputTriplet(out, visit, "exp2(", "", ")");
1699 break;
1700 case EOpLog2:
1701 outputTriplet(out, visit, "log2(", "", ")");
1702 break;
1703 case EOpSqrt:
1704 outputTriplet(out, visit, "sqrt(", "", ")");
1705 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001706 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001707 outputTriplet(out, visit, "rsqrt(", "", ")");
1708 break;
1709 case EOpAbs:
1710 outputTriplet(out, visit, "abs(", "", ")");
1711 break;
1712 case EOpSign:
1713 outputTriplet(out, visit, "sign(", "", ")");
1714 break;
1715 case EOpFloor:
1716 outputTriplet(out, visit, "floor(", "", ")");
1717 break;
1718 case EOpTrunc:
1719 outputTriplet(out, visit, "trunc(", "", ")");
1720 break;
1721 case EOpRound:
1722 outputTriplet(out, visit, "round(", "", ")");
1723 break;
1724 case EOpRoundEven:
1725 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001726 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001727 break;
1728 case EOpCeil:
1729 outputTriplet(out, visit, "ceil(", "", ")");
1730 break;
1731 case EOpFract:
1732 outputTriplet(out, visit, "frac(", "", ")");
1733 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001734 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001735 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001736 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001737 else
1738 outputTriplet(out, visit, "isnan(", "", ")");
1739 mRequiresIEEEStrictCompiling = true;
1740 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001741 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001742 outputTriplet(out, visit, "isinf(", "", ")");
1743 break;
1744 case EOpFloatBitsToInt:
1745 outputTriplet(out, visit, "asint(", "", ")");
1746 break;
1747 case EOpFloatBitsToUint:
1748 outputTriplet(out, visit, "asuint(", "", ")");
1749 break;
1750 case EOpIntBitsToFloat:
1751 outputTriplet(out, visit, "asfloat(", "", ")");
1752 break;
1753 case EOpUintBitsToFloat:
1754 outputTriplet(out, visit, "asfloat(", "", ")");
1755 break;
1756 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001757 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001759 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001760 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001761 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001762 case EOpPackUnorm4x8:
1763 case EOpPackSnorm4x8:
1764 case EOpUnpackUnorm4x8:
1765 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001766 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001767 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001768 break;
1769 case EOpLength:
1770 outputTriplet(out, visit, "length(", "", ")");
1771 break;
1772 case EOpNormalize:
1773 outputTriplet(out, visit, "normalize(", "", ")");
1774 break;
1775 case EOpDFdx:
1776 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1777 {
1778 outputTriplet(out, visit, "(", "", ", 0.0)");
1779 }
1780 else
1781 {
1782 outputTriplet(out, visit, "ddx(", "", ")");
1783 }
1784 break;
1785 case EOpDFdy:
1786 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1787 {
1788 outputTriplet(out, visit, "(", "", ", 0.0)");
1789 }
1790 else
1791 {
1792 outputTriplet(out, visit, "ddy(", "", ")");
1793 }
1794 break;
1795 case EOpFwidth:
1796 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1797 {
1798 outputTriplet(out, visit, "(", "", ", 0.0)");
1799 }
1800 else
1801 {
1802 outputTriplet(out, visit, "fwidth(", "", ")");
1803 }
1804 break;
1805 case EOpTranspose:
1806 outputTriplet(out, visit, "transpose(", "", ")");
1807 break;
1808 case EOpDeterminant:
1809 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1810 break;
1811 case EOpInverse:
1812 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001813 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001814 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001815
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001816 case EOpAny:
1817 outputTriplet(out, visit, "any(", "", ")");
1818 break;
1819 case EOpAll:
1820 outputTriplet(out, visit, "all(", "", ")");
1821 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001822 case EOpLogicalNotComponentWise:
1823 outputTriplet(out, visit, "(!", "", ")");
1824 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001825 case EOpBitfieldReverse:
1826 outputTriplet(out, visit, "reversebits(", "", ")");
1827 break;
1828 case EOpBitCount:
1829 outputTriplet(out, visit, "countbits(", "", ")");
1830 break;
1831 case EOpFindLSB:
1832 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1833 // in GLSLTest and results are consistent with GL.
1834 outputTriplet(out, visit, "firstbitlow(", "", ")");
1835 break;
1836 case EOpFindMSB:
1837 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1838 // tested in GLSLTest and results are consistent with GL.
1839 outputTriplet(out, visit, "firstbithigh(", "", ")");
1840 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001841 default:
1842 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001843 }
1844
1845 return true;
1846}
1847
Olli Etuahofbb1c792018-01-19 16:26:59 +02001848ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001849{
1850 if (node->getAsSymbolNode())
1851 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001852 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1853 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001854 }
1855 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1856 switch (nodeBinary->getOp())
1857 {
1858 case EOpIndexDirect:
1859 {
1860 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1861
Olli Etuahofbb1c792018-01-19 16:26:59 +02001862 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001863 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001864 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001865 }
1866 case EOpIndexDirectStruct:
1867 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001868 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001869 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1870 const TField *field = s->fields()[index];
1871
Olli Etuahofbb1c792018-01-19 16:26:59 +02001872 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001873 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1874 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001875 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001876 }
1877 default:
1878 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001879 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001880 }
1881}
1882
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001883bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1884{
1885 TInfoSinkBase &out = getInfoSink();
1886
Olli Etuaho06235df2018-07-20 14:26:07 +03001887 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1888
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001889 if (mInsideFunction)
1890 {
1891 outputLineDirective(out, node->getLine().first_line);
1892 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001893 if (isMainBlock)
1894 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001895 if (mShaderType == GL_COMPUTE_SHADER)
1896 {
1897 out << "initGLBuiltins(input);\n";
1898 }
1899 else
1900 {
1901 out << "@@ MAIN PROLOGUE @@\n";
1902 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001903 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001904 }
1905
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001906 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001907 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001908 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001909
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001910 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001911
1912 // Don't output ; after case labels, they're terminated by :
1913 // This is needed especially since outputting a ; after a case statement would turn empty
1914 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001915 // Also the output code is clearer if we don't output ; after statements where it is not
1916 // needed:
1917 // * if statements
1918 // * switch statements
1919 // * blocks
1920 // * function definitions
1921 // * loops (do-while loops output the semicolon in VisitLoop)
1922 // * declarations that don't generate output.
1923 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1924 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1925 statement->getAsSwitchNode() == nullptr &&
1926 statement->getAsFunctionDefinition() == nullptr &&
1927 (statement->getAsDeclarationNode() == nullptr ||
1928 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1929 statement->getAsInvariantDeclarationNode() == nullptr)
1930 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001931 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001932 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001933 }
1934
1935 if (mInsideFunction)
1936 {
1937 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001938 if (isMainBlock && shaderNeedsGenerateOutput())
1939 {
1940 // We could have an empty main, a main function without a branch at the end, or a main
1941 // function with a discard statement at the end. In these cases we need to add a return
1942 // statement.
1943 bool needReturnStatement =
1944 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1945 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1946 if (needReturnStatement)
1947 {
1948 out << "return " << generateOutputCall() << ";\n";
1949 }
1950 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001951 out << "}\n";
1952 }
1953
1954 return false;
1955}
1956
Olli Etuaho336b1472016-10-05 16:37:55 +01001957bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1958{
1959 TInfoSinkBase &out = getInfoSink();
1960
1961 ASSERT(mCurrentFunctionMetadata == nullptr);
1962
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001963 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001964 ASSERT(index != CallDAG::InvalidIndex);
1965 mCurrentFunctionMetadata = &mASTMetadataList[index];
1966
Olli Etuahod4bd9632018-03-08 16:32:44 +02001967 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001968
Olli Etuahod4bd9632018-03-08 16:32:44 +02001969 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001970 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001971 // The stub strings below are replaced when shader is dynamically defined by its layout:
1972 switch (mShaderType)
1973 {
1974 case GL_VERTEX_SHADER:
1975 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1976 << "@@ VERTEX OUTPUT @@\n\n"
1977 << "VS_OUTPUT main(VS_INPUT input)";
1978 break;
1979 case GL_FRAGMENT_SHADER:
1980 out << "@@ PIXEL OUTPUT @@\n\n"
1981 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1982 break;
1983 case GL_COMPUTE_SHADER:
1984 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1985 << mWorkGroupSize[2] << ")]\n";
1986 out << "void main(CS_INPUT input)";
1987 break;
1988 default:
1989 UNREACHABLE();
1990 break;
1991 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001992 }
1993 else
1994 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001995 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001996 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001997 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001998
Olli Etuaho06235df2018-07-20 14:26:07 +03001999 size_t paramCount = func->getParamCount();
2000 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01002001 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002002 const TVariable *param = func->getParam(i);
2003 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01002004
Olli Etuaho06235df2018-07-20 14:26:07 +03002005 writeParameter(param, out);
2006
2007 if (i < paramCount - 1)
2008 {
2009 out << ", ";
2010 }
2011 }
2012
2013 out << ")\n";
2014 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002015
2016 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03002017 if (func->isMain())
2018 {
2019 mInsideMain = true;
2020 }
Olli Etuaho336b1472016-10-05 16:37:55 +01002021 // The function body node will output braces.
2022 node->getBody()->traverse(this);
2023 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03002024 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01002025
2026 mCurrentFunctionMetadata = nullptr;
2027
2028 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2029 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2030 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002031 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01002032 mOutputLod0Function = true;
2033 node->traverse(this);
2034 mOutputLod0Function = false;
2035 }
2036
2037 return false;
2038}
2039
Olli Etuaho13389b62016-10-16 11:48:18 +01002040bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2041{
Olli Etuaho13389b62016-10-16 11:48:18 +01002042 if (visit == PreVisit)
2043 {
2044 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002045 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002046 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002047 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002048
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002049 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002050 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002051 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002052 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002053
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002054 if (!declarator->getAsSymbolNode() ||
2055 declarator->getAsSymbolNode()->variable().symbolType() !=
2056 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002057 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002058 if (declarator->getQualifier() == EvqShared)
2059 {
2060 out << "groupshared ";
2061 }
2062 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002063 {
2064 out << "static ";
2065 }
2066
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002067 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002068
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002069 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002070
2071 if (symbol)
2072 {
2073 symbol->traverse(this);
2074 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002075 if (declarator->getQualifier() != EvqShared ||
2076 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002077 {
2078 out << " = " + zeroInitializer(symbol->getType());
2079 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002080 }
2081 else
2082 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002083 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002084 }
2085 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002086 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002087 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002088 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002089 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002090 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002091
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002092 const TVariable &variable = symbol->variable();
2093
2094 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002095 {
2096 // Vertex outputs which are declared but not written to should still be declared to
2097 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002098 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002099 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002100 }
2101 }
2102 return false;
2103}
2104
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002105bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2106{
2107 // Do not do any translation
2108 return false;
2109}
2110
Olli Etuahod4bd9632018-03-08 16:32:44 +02002111void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002112{
2113 TInfoSinkBase &out = getInfoSink();
2114
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002115 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002116 // Skip the prototype if it is not implemented (and thus not used)
2117 if (index == CallDAG::InvalidIndex)
2118 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002119 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002120 }
2121
Olli Etuahod4bd9632018-03-08 16:32:44 +02002122 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002123
Olli Etuahod4bd9632018-03-08 16:32:44 +02002124 TString name = DecorateFunctionIfNeeded(func);
2125 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002126 << (mOutputLod0Function ? "Lod0(" : "(");
2127
Olli Etuahod4bd9632018-03-08 16:32:44 +02002128 size_t paramCount = func->getParamCount();
2129 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002130 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002131 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002132
Olli Etuahod4bd9632018-03-08 16:32:44 +02002133 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002134 {
2135 out << ", ";
2136 }
2137 }
2138
2139 out << ");\n";
2140
2141 // Also prototype the Lod0 variant if needed
2142 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2143 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2144 {
2145 mOutputLod0Function = true;
2146 node->traverse(this);
2147 mOutputLod0Function = false;
2148 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002149}
2150
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002151bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2152{
Jamie Madill32aab012015-01-27 14:12:26 -05002153 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002154
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002155 switch (node->getOp())
2156 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002157 case EOpCallBuiltInFunction:
2158 case EOpCallFunctionInAST:
2159 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002161 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002162
Corentin Wallez1239ee92015-03-19 14:38:02 -07002163 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002164 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002165 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002166 if (node->isArray())
2167 {
2168 UNIMPLEMENTED();
2169 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002170 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002171 ASSERT(index != CallDAG::InvalidIndex);
2172 lod0 &= mASTMetadataList[index].mNeedsLod0;
2173
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002174 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002175 out << DisambiguateFunctionName(node->getSequence());
2176 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002177 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002178 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002179 {
2180 // This path is used for internal functions that don't have their definitions in the
2181 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002182 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002183 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002184 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002185 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002186 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002187 TType type = (*arguments)[0]->getAsTyped()->getType();
2188 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002189 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002190 type.getMemoryQualifier().readonly);
2191 out << imageFunctionName << "(";
2192 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002193 else if (node->getFunction()->isAtomicCounterFunction())
2194 {
2195 const ImmutableString &name = node->getFunction()->name();
2196 ImmutableString atomicFunctionName =
2197 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2198 out << atomicFunctionName << "(";
2199 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 else
2201 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002202 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002203 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002204 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2205 if (arguments->size() > 1)
2206 {
2207 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2208 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002209 const ImmutableString &textureFunctionName =
2210 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2211 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002212 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002213 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002214
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002215 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002216 {
Olli Etuaho96963162016-03-21 11:54:33 +02002217 TIntermTyped *typedArg = (*arg)->getAsTyped();
2218 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002219 {
2220 out << "texture_";
2221 (*arg)->traverse(this);
2222 out << ", sampler_";
2223 }
2224
2225 (*arg)->traverse(this);
2226
Olli Etuaho96963162016-03-21 11:54:33 +02002227 if (typedArg->getType().isStructureContainingSamplers())
2228 {
2229 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002230 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002231 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2232 std::string namePrefix = "angle_";
2233 namePrefix += structName.data();
2234 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002235 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002236 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002237 {
2238 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2239 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002240 out << ", texture_" << sampler->name();
2241 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002242 }
2243 else
2244 {
2245 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2246 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002247 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002248 }
2249 }
2250 }
2251
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002252 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002253 {
2254 out << ", ";
2255 }
2256 }
2257
2258 out << ")";
2259
2260 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002261 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002262 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002263 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002264 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002265 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002266 outputTriplet(out, visit, "(", " == ", ")");
2267 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002268 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002269 outputTriplet(out, visit, "(", " != ", ")");
2270 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002271 case EOpLessThanComponentWise:
2272 outputTriplet(out, visit, "(", " < ", ")");
2273 break;
2274 case EOpGreaterThanComponentWise:
2275 outputTriplet(out, visit, "(", " > ", ")");
2276 break;
2277 case EOpLessThanEqualComponentWise:
2278 outputTriplet(out, visit, "(", " <= ", ")");
2279 break;
2280 case EOpGreaterThanEqualComponentWise:
2281 outputTriplet(out, visit, "(", " >= ", ")");
2282 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002283 case EOpMod:
2284 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002285 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002286 break;
2287 case EOpModf:
2288 outputTriplet(out, visit, "modf(", ", ", ")");
2289 break;
2290 case EOpPow:
2291 outputTriplet(out, visit, "pow(", ", ", ")");
2292 break;
2293 case EOpAtan:
2294 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2295 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002296 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002297 break;
2298 case EOpMin:
2299 outputTriplet(out, visit, "min(", ", ", ")");
2300 break;
2301 case EOpMax:
2302 outputTriplet(out, visit, "max(", ", ", ")");
2303 break;
2304 case EOpClamp:
2305 outputTriplet(out, visit, "clamp(", ", ", ")");
2306 break;
2307 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302308 {
2309 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2310 if (lastParamNode->getType().getBasicType() == EbtBool)
2311 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002312 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2313 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302314 // so use emulated version.
2315 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002316 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302317 }
2318 else
2319 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002320 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302321 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002322 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302323 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002324 case EOpStep:
2325 outputTriplet(out, visit, "step(", ", ", ")");
2326 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002327 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002328 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2329 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002330 case EOpFrexp:
2331 case EOpLdexp:
2332 ASSERT(node->getUseEmulatedFunction());
2333 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2334 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002335 case EOpDistance:
2336 outputTriplet(out, visit, "distance(", ", ", ")");
2337 break;
2338 case EOpDot:
2339 outputTriplet(out, visit, "dot(", ", ", ")");
2340 break;
2341 case EOpCross:
2342 outputTriplet(out, visit, "cross(", ", ", ")");
2343 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002344 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002345 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002346 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002347 break;
2348 case EOpReflect:
2349 outputTriplet(out, visit, "reflect(", ", ", ")");
2350 break;
2351 case EOpRefract:
2352 outputTriplet(out, visit, "refract(", ", ", ")");
2353 break;
2354 case EOpOuterProduct:
2355 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002356 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002357 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002358 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002359 outputTriplet(out, visit, "(", " * ", ")");
2360 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002361 case EOpBitfieldExtract:
2362 case EOpBitfieldInsert:
2363 case EOpUaddCarry:
2364 case EOpUsubBorrow:
2365 case EOpUmulExtended:
2366 case EOpImulExtended:
2367 ASSERT(node->getUseEmulatedFunction());
2368 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2369 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002370 case EOpBarrier:
2371 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2372 // cheapest *WithGroupSync() function, without any functionality loss, but
2373 // with the potential for severe performance loss.
2374 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2375 break;
2376 case EOpMemoryBarrierShared:
2377 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2378 break;
2379 case EOpMemoryBarrierAtomicCounter:
2380 case EOpMemoryBarrierBuffer:
2381 case EOpMemoryBarrierImage:
2382 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2383 break;
2384 case EOpGroupMemoryBarrier:
2385 case EOpMemoryBarrier:
2386 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2387 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002388
2389 // Single atomic function calls without return value.
2390 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2391 case EOpAtomicAdd:
2392 case EOpAtomicMin:
2393 case EOpAtomicMax:
2394 case EOpAtomicAnd:
2395 case EOpAtomicOr:
2396 case EOpAtomicXor:
2397 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2398 ",", ")");
2399 break;
2400
2401 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2402 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2403 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2404 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2405 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2406 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2407 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2408 // intermediate tree before traversing outputHLSL.
2409 case EOpAtomicExchange:
2410 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002411 default:
2412 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002413 }
2414
2415 return true;
2416}
2417
Olli Etuaho57961272016-09-14 13:57:46 +03002418void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002419{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002420 out << "if (";
2421
2422 node->getCondition()->traverse(this);
2423
2424 out << ")\n";
2425
Jamie Madill8c46ab12015-12-07 16:39:19 -05002426 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002427
2428 bool discard = false;
2429
2430 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002431 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002432 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002433 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002434
Olli Etuahoa6f22092015-05-08 18:31:10 +03002435 // Detect true discard
2436 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2437 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002438 else
2439 {
2440 // TODO(oetuaho): Check if the semicolon inside is necessary.
2441 // It's there as a result of conservative refactoring of the output.
2442 out << "{;}\n";
2443 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002444
Jamie Madill8c46ab12015-12-07 16:39:19 -05002445 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002446
Olli Etuahoa6f22092015-05-08 18:31:10 +03002447 if (node->getFalseBlock())
2448 {
2449 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002450
Jamie Madill8c46ab12015-12-07 16:39:19 -05002451 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002452
Olli Etuaho32db19b2016-10-04 14:43:16 +01002453 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002454 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002455
Jamie Madill8c46ab12015-12-07 16:39:19 -05002456 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002457
Olli Etuahoa6f22092015-05-08 18:31:10 +03002458 // Detect false discard
2459 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2460 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002461
Olli Etuahoa6f22092015-05-08 18:31:10 +03002462 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002463 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002464 {
2465 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002466 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002467}
2468
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002469bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2470{
2471 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2472 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2473 UNREACHABLE();
2474 return false;
2475}
2476
Olli Etuaho57961272016-09-14 13:57:46 +03002477bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002478{
2479 TInfoSinkBase &out = getInfoSink();
2480
Olli Etuaho3d932d82016-04-12 11:10:30 +03002481 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002482
2483 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002484 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002485 {
2486 out << "FLATTEN ";
2487 }
2488
Olli Etuaho57961272016-09-14 13:57:46 +03002489 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002490
2491 return false;
2492}
2493
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002494bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002495{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002496 TInfoSinkBase &out = getInfoSink();
2497
Olli Etuaho923ecef2017-10-11 12:01:38 +03002498 ASSERT(node->getStatementList());
2499 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002500 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002501 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002502 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002503 outputTriplet(out, visit, "switch (", ") ", "");
2504 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002505 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002506}
2507
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002508bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002509{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002510 TInfoSinkBase &out = getInfoSink();
2511
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002512 if (node->hasCondition())
2513 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002514 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002515 return true;
2516 }
2517 else
2518 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002519 out << "default:\n";
2520 return false;
2521 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002522}
2523
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002524void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2525{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002526 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002527 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002528}
2529
2530bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2531{
Nicolas Capens655fe362014-04-11 13:12:34 -04002532 mNestedLoopDepth++;
2533
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002534 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002535 mInsideDiscontinuousLoop =
2536 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002537
Jamie Madill8c46ab12015-12-07 16:39:19 -05002538 TInfoSinkBase &out = getInfoSink();
2539
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002540 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002541 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002542 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002543 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002544 mInsideDiscontinuousLoop = wasDiscontinuous;
2545 mNestedLoopDepth--;
2546
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002547 return false;
2548 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002549 }
2550
Corentin Wallez1239ee92015-03-19 14:38:02 -07002551 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002552 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002553 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002554 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002555
Jamie Madill8c46ab12015-12-07 16:39:19 -05002556 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002557 }
2558 else
2559 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002560 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002561
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002562 if (node->getInit())
2563 {
2564 node->getInit()->traverse(this);
2565 }
2566
2567 out << "; ";
2568
alokp@chromium.org52813552010-11-16 18:36:09 +00002569 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002570 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002571 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002572 }
2573
2574 out << "; ";
2575
alokp@chromium.org52813552010-11-16 18:36:09 +00002576 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002577 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002578 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002579 }
2580
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002581 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002582
Jamie Madill8c46ab12015-12-07 16:39:19 -05002583 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002584 }
2585
2586 if (node->getBody())
2587 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002588 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002589 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002590 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002591 else
2592 {
2593 // TODO(oetuaho): Check if the semicolon inside is necessary.
2594 // It's there as a result of conservative refactoring of the output.
2595 out << "{;}\n";
2596 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002597
Jamie Madill8c46ab12015-12-07 16:39:19 -05002598 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002599
alokp@chromium.org52813552010-11-16 18:36:09 +00002600 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002601 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002602 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002603 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002604
alokp@chromium.org52813552010-11-16 18:36:09 +00002605 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002606
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002607 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002608 }
2609
daniel@transgaming.com73536982012-03-21 20:45:49 +00002610 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002611
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002612 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002613 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002614
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002615 return false;
2616}
2617
2618bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2619{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002620 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002621 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002622 TInfoSinkBase &out = getInfoSink();
2623
2624 switch (node->getFlowOp())
2625 {
2626 case EOpKill:
2627 out << "discard";
2628 break;
2629 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002630 if (mNestedLoopDepth > 1)
2631 {
2632 mUsesNestedBreak = true;
2633 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002634
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002635 if (mExcessiveLoopIndex)
2636 {
2637 out << "{Break";
2638 mExcessiveLoopIndex->traverse(this);
2639 out << " = true; break;}\n";
2640 }
2641 else
2642 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002643 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002644 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002645 break;
2646 case EOpContinue:
2647 out << "continue";
2648 break;
2649 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002650 if (node->getExpression())
2651 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002652 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002653 out << "return ";
2654 }
2655 else
2656 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002657 if (mInsideMain && shaderNeedsGenerateOutput())
2658 {
2659 out << "return " << generateOutputCall();
2660 }
2661 else
2662 {
2663 out << "return";
2664 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002665 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002666 break;
2667 default:
2668 UNREACHABLE();
2669 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002670 }
2671
2672 return true;
2673}
2674
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002675// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002676// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2677// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002678bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002679{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002680 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002681
2682 // Parse loops of the form:
2683 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002684 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002685 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002686 int initial = 0;
2687 int limit = 0;
2688 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002689
2690 // Parse index name and intial value
2691 if (node->getInit())
2692 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002693 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002694
2695 if (init)
2696 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002697 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002698 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002699
2700 if (variable && variable->getQualifier() == EvqTemporary)
2701 {
2702 TIntermBinary *assign = variable->getAsBinaryNode();
2703
2704 if (assign->getOp() == EOpInitialize)
2705 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002706 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002707 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2708
2709 if (symbol && constant)
2710 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002711 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002712 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002713 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002714 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002715 }
2716 }
2717 }
2718 }
2719 }
2720 }
2721
2722 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002723 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002724 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002725 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002726
Olli Etuahob6af22b2017-12-15 14:05:44 +02002727 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002728 {
2729 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2730
2731 if (constant)
2732 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002733 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002734 {
2735 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002736 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002737 }
2738 }
2739 }
2740 }
2741
2742 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002743 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002744 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002745 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002747
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002748 if (binaryTerminal)
2749 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002750 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002751 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2752
2753 if (constant)
2754 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002755 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002756 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002757 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002758
2759 switch (op)
2760 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002761 case EOpAddAssign:
2762 increment = value;
2763 break;
2764 case EOpSubAssign:
2765 increment = -value;
2766 break;
2767 default:
2768 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002769 }
2770 }
2771 }
2772 }
2773 else if (unaryTerminal)
2774 {
2775 TOperator op = unaryTerminal->getOp();
2776
2777 switch (op)
2778 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002779 case EOpPostIncrement:
2780 increment = 1;
2781 break;
2782 case EOpPostDecrement:
2783 increment = -1;
2784 break;
2785 case EOpPreIncrement:
2786 increment = 1;
2787 break;
2788 case EOpPreDecrement:
2789 increment = -1;
2790 break;
2791 default:
2792 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002793 }
2794 }
2795 }
2796
Yunchao He4f285442017-04-21 12:15:49 +08002797 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002798 {
2799 if (comparator == EOpLessThanEqual)
2800 {
2801 comparator = EOpLessThan;
2802 limit += 1;
2803 }
2804
2805 if (comparator == EOpLessThan)
2806 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002807 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002808
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002809 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002810 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002811 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002812 }
2813
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002814 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002815 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002816
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002817 out << "{int ";
2818 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002819 out << ";\n"
2820 "bool Break";
2821 index->traverse(this);
2822 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002823
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002824 bool firstLoopFragment = true;
2825
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002826 while (iterations > 0)
2827 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002828 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002829
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002830 if (!firstLoopFragment)
2831 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002832 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002833 index->traverse(this);
2834 out << ") {\n";
2835 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002836
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002837 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002838 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002839 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002840 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002841
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002842 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002843 const char *unroll =
2844 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002845
Corentin Wallez1239ee92015-03-19 14:38:02 -07002846 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002847 index->traverse(this);
2848 out << " = ";
2849 out << initial;
2850
2851 out << "; ";
2852 index->traverse(this);
2853 out << " < ";
2854 out << clampedLimit;
2855
2856 out << "; ";
2857 index->traverse(this);
2858 out << " += ";
2859 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002860 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002861
Jamie Madill8c46ab12015-12-07 16:39:19 -05002862 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002863 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002864
2865 if (node->getBody())
2866 {
2867 node->getBody()->traverse(this);
2868 }
2869
Jamie Madill8c46ab12015-12-07 16:39:19 -05002870 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002871 out << ";}\n";
2872
2873 if (!firstLoopFragment)
2874 {
2875 out << "}\n";
2876 }
2877
2878 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002879
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002880 initial += MAX_LOOP_ITERATIONS * increment;
2881 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002882 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002883
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002884 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002885
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002886 mExcessiveLoopIndex = restoreIndex;
2887
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002888 return true;
2889 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002890 else
2891 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002892 }
2893
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002894 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002895}
2896
Jamie Madill8c46ab12015-12-07 16:39:19 -05002897void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2898 Visit visit,
2899 const char *preString,
2900 const char *inString,
2901 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002902{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002903 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002904 {
2905 out << preString;
2906 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002907 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002908 {
2909 out << inString;
2910 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002911 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002912 {
2913 out << postString;
2914 }
2915}
2916
Jamie Madill8c46ab12015-12-07 16:39:19 -05002917void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002918{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002919 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002920 {
Jamie Madill32aab012015-01-27 14:12:26 -05002921 out << "\n";
2922 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002923
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002924 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002925 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002926 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002927 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002928
Jamie Madill32aab012015-01-27 14:12:26 -05002929 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002930 }
2931}
2932
Olli Etuahod4bd9632018-03-08 16:32:44 +02002933void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002934{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002935 const TType &type = param->getType();
2936 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002937
Olli Etuahod4bd9632018-03-08 16:32:44 +02002938 TString nameStr = DecorateVariableIfNeeded(*param);
2939 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002940
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002941 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002942 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002943 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2944 {
2945 // Samplers are passed as indices to the sampler array.
2946 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002947 out << "const uint " << nameStr << ArrayString(type);
2948 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002949 }
2950 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2951 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002952 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2953 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2954 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2955 << ArrayString(type);
2956 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002957 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002958 }
2959
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002960 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
2961 // buffer offset.
2962 if (IsAtomicCounter(type.getBasicType()))
2963 {
2964 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
2965 << nameStr << "_offset";
2966 }
2967 else
2968 {
2969 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2970 << ArrayString(type);
2971 }
Olli Etuaho96963162016-03-21 11:54:33 +02002972
2973 // If the structure parameter contains samplers, they need to be passed into the function as
2974 // separate parameters. HLSL doesn't natively support samplers in structs.
2975 if (type.isStructureContainingSamplers())
2976 {
2977 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002978 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002979 std::string namePrefix = "angle";
2980 namePrefix += nameStr.c_str();
2981 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2982 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002983 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002984 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002985 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002986 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2987 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002988 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002989 }
2990 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2991 {
Olli Etuaho96963162016-03-21 11:54:33 +02002992 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002993 out << ", " << QualifierString(qualifier) << " "
2994 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2995 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2996 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2997 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002998 }
2999 else
3000 {
Olli Etuaho96963162016-03-21 11:54:33 +02003001 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02003002 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3003 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02003004 }
3005 }
3006 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003007}
3008
jchen10efe061b2018-11-13 16:44:40 +08003009TString OutputHLSL::zeroInitializer(const TType &type) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003010{
3011 TString string;
3012
Jamie Madill94bf7f22013-07-08 13:31:15 -04003013 size_t size = type.getObjectSize();
jchen10efe061b2018-11-13 16:44:40 +08003014 if (size >= kZeroCount)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003015 {
jchen10efe061b2018-11-13 16:44:40 +08003016 mUseZeroArray = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003017 }
jchen10efe061b2018-11-13 16:44:40 +08003018 string = GetZeroInitializer(size).c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003019
daniel@transgaming.comead23042010-04-29 03:35:36 +00003020 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003021}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003022
Olli Etuahobd3cd502017-11-03 15:48:52 +02003023void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003024{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003025 // Array constructors should have been already pruned from the code.
3026 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003027
3028 if (visit == PreVisit)
3029 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003030 TString constructorName;
3031 if (node->getBasicType() == EbtStruct)
3032 {
3033 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3034 }
3035 else
3036 {
3037 constructorName =
3038 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3039 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003040 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003041 }
3042 else if (visit == InVisit)
3043 {
3044 out << ", ";
3045 }
3046 else if (visit == PostVisit)
3047 {
3048 out << ")";
3049 }
3050}
3051
Jamie Madill8c46ab12015-12-07 16:39:19 -05003052const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3053 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003054 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003055{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003056 ASSERT(!type.isArray());
3057
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003058 const TConstantUnion *constUnionIterated = constUnion;
3059
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003060 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003061 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003062 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003063 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003064
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003065 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003066
Jamie Madill98493dd2013-07-08 14:39:03 -04003067 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003068 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003069 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003070 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003071
Jamie Madill98493dd2013-07-08 14:39:03 -04003072 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003073 {
3074 out << ", ";
3075 }
3076 }
3077
3078 out << ")";
3079 }
3080 else
3081 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003082 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003083 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003084
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003085 if (writeType)
3086 {
Jamie Madill033dae62014-06-18 12:56:28 -04003087 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003088 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003089 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003090 if (writeType)
3091 {
3092 out << ")";
3093 }
3094 }
3095
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003096 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003097}
3098
Olli Etuahod68924e2017-01-02 17:34:40 +00003099void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003100{
Olli Etuahod68924e2017-01-02 17:34:40 +00003101 if (visit == PreVisit)
3102 {
3103 const char *opStr = GetOperatorString(op);
3104 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3105 out << "(";
3106 }
3107 else
3108 {
3109 outputTriplet(out, visit, nullptr, ", ", ")");
3110 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003111}
3112
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003113bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3114 TIntermSymbol *symbolNode,
3115 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003116{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003117 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3118 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003119
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003120 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003121 {
3122 // Type already printed
3123 out << "t" + str(mUniqueIndex) + " = ";
3124 expression->traverse(this);
3125 out << ", ";
3126 symbolNode->traverse(this);
3127 out << " = t" + str(mUniqueIndex);
3128
3129 mUniqueIndex++;
3130 return true;
3131 }
3132
3133 return false;
3134}
3135
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003136bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3137 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003138 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003139{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003140 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003141 {
3142 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003143 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003144 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003145 writeConstantUnionArray(out, initializer->getConstantValue(),
3146 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003147 out << "}";
3148 return true;
3149 }
3150 return false;
3151}
3152
Jamie Madill55e79e02015-02-09 15:35:00 -05003153TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3154{
3155 const TFieldList &fields = structure.fields();
3156
3157 for (const auto &eqFunction : mStructEqualityFunctions)
3158 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003159 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003160 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003161 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003162 }
3163 }
3164
3165 const TString &structNameString = StructNameString(structure);
3166
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003167 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003168 function->structure = &structure;
3169 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003170
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003171 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003172
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003173 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3174 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003175 << "{\n"
3176 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003177
3178 for (size_t i = 0; i < fields.size(); i++)
3179 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003180 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003181 const TType *fieldType = field->type();
3182
3183 const TString &fieldNameA = "a." + Decorate(field->name());
3184 const TString &fieldNameB = "b." + Decorate(field->name());
3185
3186 if (i > 0)
3187 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003188 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003189 }
3190
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003191 fnOut << "(";
3192 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3193 fnOut << fieldNameA;
3194 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3195 fnOut << fieldNameB;
3196 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3197 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003198 }
3199
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003200 fnOut << ";\n"
3201 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003202
3203 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003204
3205 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003206 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003207
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003208 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003209}
3210
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003211TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003212{
3213 for (const auto &eqFunction : mArrayEqualityFunctions)
3214 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003215 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003216 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003217 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003218 }
3219 }
3220
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003221 TType elementType(type);
3222 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003223
Olli Etuaho12690762015-03-31 12:55:28 +03003224 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003225 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003226
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003227 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003228
3229 TInfoSinkBase fnOut;
3230
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003231 const TString &typeName = TypeString(type);
3232 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3233 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003234 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003235 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003236 << type.getOutermostArraySize()
3237 << "; ++i)\n"
3238 " {\n"
3239 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003240
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003241 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003242 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003243 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003244 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003245 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003246
3247 fnOut << ") { return false; }\n"
3248 " }\n"
3249 " return true;\n"
3250 "}\n";
3251
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003252 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003253
3254 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003255 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003256
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003257 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003258}
3259
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003260TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003261{
3262 for (const auto &assignFunction : mArrayAssignmentFunctions)
3263 {
3264 if (assignFunction.type == type)
3265 {
3266 return assignFunction.functionName;
3267 }
3268 }
3269
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003270 TType elementType(type);
3271 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003272
3273 ArrayHelperFunction function;
3274 function.type = type;
3275
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003276 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003277
3278 TInfoSinkBase fnOut;
3279
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003280 const TString &typeName = TypeString(type);
3281 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3282 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003283 << "{\n"
3284 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003285 << type.getOutermostArraySize()
3286 << "; ++i)\n"
3287 " {\n"
3288 " ";
3289
3290 outputAssign(PreVisit, elementType, fnOut);
3291 fnOut << "a[i]";
3292 outputAssign(InVisit, elementType, fnOut);
3293 fnOut << "b[i]";
3294 outputAssign(PostVisit, elementType, fnOut);
3295
3296 fnOut << ";\n"
3297 " }\n"
3298 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003299
3300 function.functionDefinition = fnOut.c_str();
3301
3302 mArrayAssignmentFunctions.push_back(function);
3303
3304 return function.functionName;
3305}
3306
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003307TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003308{
3309 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3310 {
3311 if (constructIntoFunction.type == type)
3312 {
3313 return constructIntoFunction.functionName;
3314 }
3315 }
3316
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003317 TType elementType(type);
3318 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003319
3320 ArrayHelperFunction function;
3321 function.type = type;
3322
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003323 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003324
3325 TInfoSinkBase fnOut;
3326
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003327 const TString &typeName = TypeString(type);
3328 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3329 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003330 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003331 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003332 }
3333 fnOut << ")\n"
3334 "{\n";
3335
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003336 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003337 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003338 fnOut << " ";
3339 outputAssign(PreVisit, elementType, fnOut);
3340 fnOut << "a[" << i << "]";
3341 outputAssign(InVisit, elementType, fnOut);
3342 fnOut << "b" << i;
3343 outputAssign(PostVisit, elementType, fnOut);
3344 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003345 }
3346 fnOut << "}\n";
3347
3348 function.functionDefinition = fnOut.c_str();
3349
3350 mArrayConstructIntoFunctions.push_back(function);
3351
3352 return function.functionName;
3353}
3354
Jamie Madill2e295e22015-04-29 10:41:33 -04003355void OutputHLSL::ensureStructDefined(const TType &type)
3356{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003357 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003358 if (structure)
3359 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003360 ASSERT(type.getBasicType() == EbtStruct);
3361 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003362 }
3363}
3364
Olli Etuaho06235df2018-07-20 14:26:07 +03003365bool OutputHLSL::shaderNeedsGenerateOutput() const
3366{
3367 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3368}
3369
3370const char *OutputHLSL::generateOutputCall() const
3371{
3372 if (mShaderType == GL_VERTEX_SHADER)
3373 {
3374 return "generateOutput(input)";
3375 }
3376 else
3377 {
3378 return "generateOutput()";
3379 }
3380}
3381
Jamie Madill45bcc782016-11-07 13:58:48 -05003382} // namespace sh