blob: 05d892f5ff638892b1e9b85154c59e7c3e7e0ef1 [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
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300119} // anonymous namespace
120
Olli Etuahoc71862a2017-12-21 12:58:29 +0200121TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
122 const TVariable *aInstanceVariable)
123 : block(aBlock), instanceVariable(aInstanceVariable)
124{
125}
126
Olli Etuaho56a2f952016-12-08 12:16:27 +0000127void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300128{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000129 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
130 // regardless.
131 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
132 mOutputType == SH_HLSL_4_1_OUTPUT)
133 {
134 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
135 }
136 else
137 {
138 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
139 }
140}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300141
Olli Etuaho56a2f952016-12-08 12:16:27 +0000142void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200143{
144 ASSERT(constUnion != nullptr);
145 switch (constUnion->getType())
146 {
147 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000148 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200149 break;
150 case EbtInt:
151 out << constUnion->getIConst();
152 break;
153 case EbtUInt:
154 out << constUnion->getUConst();
155 break;
156 case EbtBool:
157 out << constUnion->getBConst();
158 break;
159 default:
160 UNREACHABLE();
161 }
162}
163
Olli Etuaho56a2f952016-12-08 12:16:27 +0000164const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
165 const TConstantUnion *const constUnion,
166 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200167{
168 const TConstantUnion *constUnionIterated = constUnion;
169 for (size_t i = 0; i < size; i++, constUnionIterated++)
170 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000171 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200172
173 if (i != size - 1)
174 {
175 out << ", ";
176 }
177 }
178 return constUnionIterated;
179}
180
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800181OutputHLSL::OutputHLSL(sh::GLenum shaderType,
182 int shaderVersion,
183 const TExtensionBehavior &extensionBehavior,
184 const char *sourcePath,
185 ShShaderOutput outputType,
186 int numRenderTargets,
187 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300188 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300189 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300190 TSymbolTable *symbolTable,
191 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300192 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200193 mShaderType(shaderType),
194 mShaderVersion(shaderVersion),
195 mExtensionBehavior(extensionBehavior),
196 mSourcePath(sourcePath),
197 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700198 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300199 mInsideFunction(false),
200 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000201 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300202 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300203 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300204 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800206 mUsesFragColor = false;
207 mUsesFragData = false;
208 mUsesDepthRange = false;
209 mUsesFragCoord = false;
210 mUsesPointCoord = false;
211 mUsesFrontFacing = false;
212 mUsesPointSize = false;
213 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300214 mHasMultiviewExtensionEnabled =
215 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300216 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500217 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500218 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800219 mUsesNumWorkGroups = false;
220 mUsesWorkGroupID = false;
221 mUsesLocalInvocationID = false;
222 mUsesGlobalInvocationID = false;
223 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500224 mUsesXor = false;
225 mUsesDiscardRewriting = false;
226 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530227 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000228
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000229 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000230
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500231 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000232 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500233 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000234
Yunchao Hed7297bf2017-04-19 15:27:10 +0800235 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000236
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700237 mStructureHLSL = new StructureHLSL;
238 mTextureFunctionHLSL = new TextureFunctionHLSL;
239 mImageFunctionHLSL = new ImageFunctionHLSL;
240 mAtomicCounterFunctionHLSL = new AtomicCounterFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400241
Olli Etuahod8724a92017-12-29 18:40:36 +0200242 unsigned int firstUniformRegister =
243 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800244 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200245
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200246 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000247 {
Arun Patole63419392015-03-13 11:51:07 +0530248 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500249 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
250 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530251 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800252 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000253 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000254
Geoff Lang00140f42016-02-03 18:47:33 +0000255 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800256 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800257
258 mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259}
260
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000261OutputHLSL::~OutputHLSL()
262{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800263 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400264 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800265 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300266 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800267 SafeDelete(mImageFunctionHLSL);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700268 SafeDelete(mAtomicCounterFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200269 for (auto &eqFunction : mStructEqualityFunctions)
270 {
271 SafeDelete(eqFunction);
272 }
273 for (auto &eqFunction : mArrayEqualityFunctions)
274 {
275 SafeDelete(eqFunction);
276 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000277}
278
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200279void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000280{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200281 BuiltInFunctionEmulator builtInFunctionEmulator;
282 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800283 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
284 {
285 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
286 mShaderVersion);
287 }
288
Olli Etuahodfa75e82017-01-23 09:43:06 -0800289 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500290
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700291 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000292 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700293 ASSERT(success == CallDAG::INITDAG_SUCCESS);
294 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700295
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200296 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
297 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
298 // the shader code. When we add shader storage blocks we might also consider an alternative
299 // solution, since the struct mapping won't work very well for shader storage blocks.
300
Jamie Madill37997142015-01-28 10:06:34 -0500301 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500302 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200303 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500304 mInfoSinkStack.pop();
305
Jamie Madill37997142015-01-28 10:06:34 -0500306 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500307 mInfoSinkStack.pop();
308
Jamie Madill32aab012015-01-27 14:12:26 -0500309 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200310 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500311 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000312
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200313 objSink << mHeader.c_str();
314 objSink << mBody.c_str();
315 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200316
Olli Etuahodfa75e82017-01-23 09:43:06 -0800317 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000318}
319
Qin Jiajiaa602f902018-09-11 14:40:24 +0800320const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
321{
322 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
323}
324
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800325const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400326{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800327 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400328}
329
Jamie Madill9fe25e92014-07-18 10:33:08 -0400330const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
331{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800332 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400333}
334
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200335TString OutputHLSL::structInitializerString(int indent,
336 const TType &type,
337 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400338{
339 TString init;
340
Olli Etuahoed049ab2017-06-30 17:38:33 +0300341 TString indentString;
342 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300344 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400345 }
346
Olli Etuahoed049ab2017-06-30 17:38:33 +0300347 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300350 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400351 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300352 TStringStream indexedString;
353 indexedString << name << "[" << arrayIndex << "]";
354 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300355 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300356 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300357 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300358 {
359 init += ",";
360 }
361 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400362 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300363 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400364 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300365 else if (type.getBasicType() == EbtStruct)
366 {
367 init += indentString + "{\n";
368 const TStructure &structure = *type.getStruct();
369 const TFieldList &fields = structure.fields();
370 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
371 {
372 const TField &field = *fields[fieldIndex];
373 const TString &fieldName = name + "." + Decorate(field.name());
374 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400375
Olli Etuahoed049ab2017-06-30 17:38:33 +0300376 init += structInitializerString(indent + 1, fieldType, fieldName);
377 if (fieldIndex < fields.size() - 1)
378 {
379 init += ",";
380 }
381 init += "\n";
382 }
383 init += indentString + "}";
384 }
385 else
386 {
387 init += indentString + name;
388 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400389
390 return init;
391}
392
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200393TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
394{
395 TString mappedStructs;
396
397 for (auto &mappedStruct : std140Structs)
398 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200399 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200400 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800401 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
402 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200403 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800404 case EvqUniform:
405 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
406 {
407 continue;
408 }
409 break;
410 case EvqBuffer:
411 continue;
412 default:
413 UNREACHABLE();
414 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200415 }
416
417 unsigned int instanceCount = 1u;
418 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
419 if (isInstanceArray)
420 {
421 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
422 }
423
424 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
425 ++instanceArrayIndex)
426 {
427 TString originalName;
428 TString mappedName("map");
429
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200430 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200432 const ImmutableString &instanceName =
433 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200434 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
435 if (isInstanceArray)
436 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800437 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200438 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200439 originalName += instanceString;
440 mappedName += instanceString;
441 originalName += ".";
442 mappedName += "_";
443 }
444
445 TString fieldName = Decorate(mappedStruct.field->name());
446 originalName += fieldName;
447 mappedName += fieldName;
448
449 TType *structType = mappedStruct.field->type();
450 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200451 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200452
453 if (structType->isArray())
454 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300455 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200456 }
457
458 mappedStructs += " =\n";
459 mappedStructs += structInitializerString(0, *structType, originalName);
460 mappedStructs += ";\n";
461 }
462 }
463 return mappedStructs;
464}
465
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300466void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300468 for (const auto &attribute : mReferencedAttributes)
469 {
470 const TType &type = attribute.second->getType();
471 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400472
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300473 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
474 << zeroInitializer(type) << ";\n";
475 }
476}
477
478void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
479{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200480 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000481 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800482 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000483
484 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300485 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300486 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
487 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000488 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300489}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000490
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300491void OutputHLSL::header(TInfoSinkBase &out,
492 const std::vector<MappedStruct> &std140Structs,
493 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
494{
495 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000496
Jamie Madill8daaba12014-06-13 10:04:33 -0400497 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400498
Qin Jiajia3e217f62018-08-28 16:55:20 +0800499 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
500 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800501 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400502
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200503 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500504 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200505 out << "\n// Equality functions\n\n";
506 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500507 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200508 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200509 }
510 }
Olli Etuaho12690762015-03-31 12:55:28 +0300511 if (!mArrayAssignmentFunctions.empty())
512 {
513 out << "\n// Assignment functions\n\n";
514 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
515 {
516 out << assignmentFunction.functionDefinition << "\n";
517 }
518 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300519 if (!mArrayConstructIntoFunctions.empty())
520 {
521 out << "\n// Array constructor functions\n\n";
522 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
523 {
524 out << constructIntoFunction.functionDefinition << "\n";
525 }
526 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200527
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500528 if (mUsesDiscardRewriting)
529 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400530 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500531 }
532
Nicolas Capens655fe362014-04-11 13:12:34 -0400533 if (mUsesNestedBreak)
534 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400535 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400536 }
537
Arun Patole44efa0b2015-03-04 17:11:05 +0530538 if (mRequiresIEEEStrictCompiling)
539 {
540 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
541 }
542
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400543 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
544 "#define LOOP [loop]\n"
545 "#define FLATTEN [flatten]\n"
546 "#else\n"
547 "#define LOOP\n"
548 "#define FLATTEN\n"
549 "#endif\n";
550
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700551 // array stride for atomic counter buffers is always 4 per original extension
552 // ARB_shader_atomic_counters and discussion on
553 // https://github.com/KhronosGroup/OpenGL-API/issues/5
554 out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
555
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200556 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300558 const bool usingMRTExtension =
559 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000560
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000561 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300562 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400563 out << "\n";
564
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200565 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000566 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200567 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000568 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200569 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800570 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400571
Olli Etuahofbb1c792018-01-19 16:26:59 +0200572 out << "static " << TypeString(variableType) << " out_" << variableName
573 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000574 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000575 }
Jamie Madill46131a32013-06-20 11:55:50 -0400576 else
577 {
578 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
579
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800580 out << "static float4 gl_Color[" << numColorValues
581 << "] =\n"
582 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400583 for (unsigned int i = 0; i < numColorValues; i++)
584 {
585 out << " float4(0, 0, 0, 0)";
586 if (i + 1 != numColorValues)
587 {
588 out << ",";
589 }
590 out << "\n";
591 }
592
593 out << "};\n";
594 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000595
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400596 if (mUsesFragDepth)
597 {
598 out << "static float gl_Depth = 0.0;\n";
599 }
600
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000601 if (mUsesFragCoord)
602 {
603 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
604 }
605
606 if (mUsesPointCoord)
607 {
608 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
609 }
610
611 if (mUsesFrontFacing)
612 {
613 out << "static bool gl_FrontFacing = false;\n";
614 }
615
616 out << "\n";
617
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000618 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000619 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000620 out << "struct gl_DepthRangeParameters\n"
621 "{\n"
622 " float near;\n"
623 " float far;\n"
624 " float diff;\n"
625 "};\n"
626 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000627 }
628
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200629 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000630 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000631 out << "cbuffer DriverConstants : register(b1)\n"
632 "{\n";
633
634 if (mUsesDepthRange)
635 {
636 out << " float3 dx_DepthRange : packoffset(c0);\n";
637 }
638
639 if (mUsesFragCoord)
640 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000641 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000642 }
643
644 if (mUsesFragCoord || mUsesFrontFacing)
645 {
646 out << " float3 dx_DepthFront : packoffset(c2);\n";
647 }
648
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800649 if (mUsesFragCoord)
650 {
651 // dx_ViewScale is only used in the fragment shader to correct
652 // the value for glFragCoord if necessary
653 out << " float2 dx_ViewScale : packoffset(c3);\n";
654 }
655
Martin Radev72b4e1e2017-08-31 15:42:56 +0300656 if (mHasMultiviewExtensionEnabled)
657 {
658 // We have to add a value which we can use to keep track of which multi-view code
659 // path is to be selected in the GS.
660 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
661 }
662
Olli Etuaho618bebc2016-01-15 16:40:00 +0200663 if (mOutputType == SH_HLSL_4_1_OUTPUT)
664 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800665 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200666 }
667
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000668 out << "};\n";
669 }
670 else
671 {
672 if (mUsesDepthRange)
673 {
674 out << "uniform float3 dx_DepthRange : register(c0);";
675 }
676
677 if (mUsesFragCoord)
678 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000679 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000680 }
681
682 if (mUsesFragCoord || mUsesFrontFacing)
683 {
684 out << "uniform float3 dx_DepthFront : register(c2);\n";
685 }
686 }
687
688 out << "\n";
689
690 if (mUsesDepthRange)
691 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500692 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
693 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000694 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000695 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000696
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000697 if (usingMRTExtension && mNumRenderTargets > 1)
698 {
699 out << "#define GL_USES_MRT\n";
700 }
701
702 if (mUsesFragColor)
703 {
704 out << "#define GL_USES_FRAG_COLOR\n";
705 }
706
707 if (mUsesFragData)
708 {
709 out << "#define GL_USES_FRAG_DATA\n";
710 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000711 }
Xinghua Caob1239382016-12-13 15:07:05 +0800712 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000713 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000714 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300715 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000716 out << "\n"
717 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400718
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000719 if (mUsesPointSize)
720 {
721 out << "static float gl_PointSize = float(1);\n";
722 }
723
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000724 if (mUsesInstanceID)
725 {
726 out << "static int gl_InstanceID;";
727 }
728
Corentin Wallezb076add2016-01-11 16:45:46 -0500729 if (mUsesVertexID)
730 {
731 out << "static int gl_VertexID;";
732 }
733
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000734 out << "\n"
735 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300736 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000737 out << "\n";
738
739 if (mUsesDepthRange)
740 {
741 out << "struct gl_DepthRangeParameters\n"
742 "{\n"
743 " float near;\n"
744 " float far;\n"
745 " float diff;\n"
746 "};\n"
747 "\n";
748 }
749
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200750 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000751 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800752 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800754
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000755 if (mUsesDepthRange)
756 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800757 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000758 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800759
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800760 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
761 // shaders. However, we declare it for all shaders (including Feature Level 10+).
762 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
763 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800764 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800765 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800766 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800767
Martin Radev72b4e1e2017-08-31 15:42:56 +0300768 if (mHasMultiviewExtensionEnabled)
769 {
770 // We have to add a value which we can use to keep track of which multi-view code
771 // path is to be selected in the GS.
772 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
773 }
774
Olli Etuaho618bebc2016-01-15 16:40:00 +0200775 if (mOutputType == SH_HLSL_4_1_OUTPUT)
776 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800777 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200778 }
779
Austin Kinross4fd18b12014-12-22 12:32:05 -0800780 out << "};\n"
781 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000782 }
783 else
784 {
785 if (mUsesDepthRange)
786 {
787 out << "uniform float3 dx_DepthRange : register(c0);\n";
788 }
789
Cooper Partine6664f02015-01-09 16:22:24 -0800790 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
791 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000792 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000793 }
794
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000795 if (mUsesDepthRange)
796 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500797 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
798 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000799 "\n";
800 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400801 }
Xinghua Caob1239382016-12-13 15:07:05 +0800802 else // Compute shader
803 {
804 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800805
806 out << "cbuffer DriverConstants : register(b1)\n"
807 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800808 if (mUsesNumWorkGroups)
809 {
Xinghua Caob1239382016-12-13 15:07:05 +0800810 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800811 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800812 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800813 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800814 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800815
Jiawei Shao203b26f2018-07-25 10:30:43 +0800816 std::ostringstream systemValueDeclaration;
817 std::ostringstream glBuiltinInitialization;
818
819 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
820 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
821 << "{\n";
822
Xinghua Caob1239382016-12-13 15:07:05 +0800823 if (mUsesWorkGroupID)
824 {
825 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800826 systemValueDeclaration << " uint3 dx_WorkGroupID : "
827 << "SV_GroupID;\n";
828 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800829 }
830
831 if (mUsesLocalInvocationID)
832 {
833 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800834 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
835 << "SV_GroupThreadID;\n";
836 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800837 }
838
839 if (mUsesGlobalInvocationID)
840 {
841 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800842 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
843 << "SV_DispatchThreadID;\n";
844 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800845 }
846
847 if (mUsesLocalInvocationIndex)
848 {
849 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800850 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
851 << "SV_GroupIndex;\n";
852 glBuiltinInitialization
853 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800854 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800855
856 systemValueDeclaration << "};\n\n";
857 glBuiltinInitialization << "};\n\n";
858
859 out << systemValueDeclaration.str();
860 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800861 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000862
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800863 if (!mappedStructs.empty())
864 {
865 out << "// Structures from std140 blocks with padding removed\n";
866 out << "\n";
867 out << mappedStructs;
868 out << "\n";
869 }
870
Geoff Lang1fe74c72016-08-25 13:23:01 -0400871 bool getDimensionsIgnoresBaseLevel =
872 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
873 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800874 mImageFunctionHLSL->imageFunctionHeader(out);
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700875 mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000876
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000877 if (mUsesFragCoord)
878 {
879 out << "#define GL_USES_FRAG_COORD\n";
880 }
881
882 if (mUsesPointCoord)
883 {
884 out << "#define GL_USES_POINT_COORD\n";
885 }
886
887 if (mUsesFrontFacing)
888 {
889 out << "#define GL_USES_FRONT_FACING\n";
890 }
891
892 if (mUsesPointSize)
893 {
894 out << "#define GL_USES_POINT_SIZE\n";
895 }
896
Martin Radev41ac68e2017-06-06 12:16:58 +0300897 if (mHasMultiviewExtensionEnabled)
898 {
899 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
900 }
901
902 if (mUsesViewID)
903 {
904 out << "#define GL_USES_VIEW_ID\n";
905 }
906
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400907 if (mUsesFragDepth)
908 {
909 out << "#define GL_USES_FRAG_DEPTH\n";
910 }
911
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000912 if (mUsesDepthRange)
913 {
914 out << "#define GL_USES_DEPTH_RANGE\n";
915 }
916
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000917 if (mUsesXor)
918 {
919 out << "bool xor(bool p, bool q)\n"
920 "{\n"
921 " return (p || q) && !(p && q);\n"
922 "}\n"
923 "\n";
924 }
925
Olli Etuahodfa75e82017-01-23 09:43:06 -0800926 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927}
928
929void OutputHLSL::visitSymbol(TIntermSymbol *node)
930{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200931 const TVariable &variable = node->variable();
932
933 // Empty symbols can only appear in declarations and function arguments, and in either of those
934 // cases the symbol nodes are not visited.
935 ASSERT(variable.symbolType() != SymbolType::Empty);
936
Jamie Madill32aab012015-01-27 14:12:26 -0500937 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938
Jamie Madill570e04d2013-06-21 09:15:33 -0400939 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800940 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400941 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200942 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400943 }
944
Olli Etuahofbb1c792018-01-19 16:26:59 +0200945 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200946 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200947
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000948 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000949 {
950 mUsesDepthRange = true;
951 out << name;
952 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -0700953 else if (IsAtomicCounter(variable.getType().getBasicType()))
954 {
955 const TType &variableType = variable.getType();
956 if (variableType.getQualifier() == EvqUniform)
957 {
958 TLayoutQualifier layout = variableType.getLayoutQualifier();
959 mReferencedUniforms[uniqueId.get()] = &variable;
960 out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
961 }
962 else
963 {
964 TString varName = DecorateVariableIfNeeded(variable);
965 out << varName << ", " << varName << "_offset";
966 }
967 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000968 else
969 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200970 const TType &variableType = variable.getType();
971 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000972
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200973 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200974
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000975 if (qualifier == EvqUniform)
976 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200977 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400978
979 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000980 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200981 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
982 {
983 const TVariable *instanceVariable = nullptr;
984 if (variableType.isInterfaceBlock())
985 {
986 instanceVariable = &variable;
987 }
988 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
989 new TReferencedBlock(interfaceBlock, instanceVariable);
990 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000991 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000992 else
993 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200994 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000995 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400996
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200997 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000998 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800999 else if (qualifier == EvqBuffer)
1000 {
1001 UNREACHABLE();
1002 }
Jamie Madill19571812013-08-12 15:26:34 -07001003 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001004 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001005 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -04001006 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001007 }
Jamie Madill033dae62014-06-18 12:56:28 -04001008 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001009 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001010 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +03001011 out << DecorateVariableIfNeeded(variable);
1012 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +03001013 {
1014 mUsesViewID = true;
1015 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001016 }
Jamie Madill19571812013-08-12 15:26:34 -07001017 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001018 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02001019 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -04001020 out << "out_" << name;
1021 }
1022 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001023 {
1024 out << "gl_Color[0]";
1025 mUsesFragColor = true;
1026 }
1027 else if (qualifier == EvqFragData)
1028 {
1029 out << "gl_Color";
1030 mUsesFragData = true;
1031 }
1032 else if (qualifier == EvqFragCoord)
1033 {
1034 mUsesFragCoord = true;
1035 out << name;
1036 }
1037 else if (qualifier == EvqPointCoord)
1038 {
1039 mUsesPointCoord = true;
1040 out << name;
1041 }
1042 else if (qualifier == EvqFrontFacing)
1043 {
1044 mUsesFrontFacing = true;
1045 out << name;
1046 }
1047 else if (qualifier == EvqPointSize)
1048 {
1049 mUsesPointSize = true;
1050 out << name;
1051 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001052 else if (qualifier == EvqInstanceID)
1053 {
1054 mUsesInstanceID = true;
1055 out << name;
1056 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001057 else if (qualifier == EvqVertexID)
1058 {
1059 mUsesVertexID = true;
1060 out << name;
1061 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001062 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001063 {
1064 mUsesFragDepth = true;
1065 out << "gl_Depth";
1066 }
Xinghua Caob1239382016-12-13 15:07:05 +08001067 else if (qualifier == EvqNumWorkGroups)
1068 {
1069 mUsesNumWorkGroups = true;
1070 out << name;
1071 }
1072 else if (qualifier == EvqWorkGroupID)
1073 {
1074 mUsesWorkGroupID = true;
1075 out << name;
1076 }
1077 else if (qualifier == EvqLocalInvocationID)
1078 {
1079 mUsesLocalInvocationID = true;
1080 out << name;
1081 }
1082 else if (qualifier == EvqGlobalInvocationID)
1083 {
1084 mUsesGlobalInvocationID = true;
1085 out << name;
1086 }
1087 else if (qualifier == EvqLocalInvocationIndex)
1088 {
1089 mUsesLocalInvocationIndex = true;
1090 out << name;
1091 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001092 else
1093 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001094 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001095 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 }
1097}
1098
Olli Etuaho7fb49552015-03-18 17:27:44 +02001099void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1100{
1101 if (type.isScalar() && !type.isArray())
1102 {
1103 if (op == EOpEqual)
1104 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001105 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001106 }
1107 else
1108 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001109 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001110 }
1111 }
1112 else
1113 {
1114 if (visit == PreVisit && op == EOpNotEqual)
1115 {
1116 out << "!";
1117 }
1118
1119 if (type.isArray())
1120 {
1121 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001122 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001123 }
1124 else if (type.getBasicType() == EbtStruct)
1125 {
1126 const TStructure &structure = *type.getStruct();
1127 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001128 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001129 }
1130 else
1131 {
1132 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001133 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001134 }
1135 }
1136}
1137
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001138void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1139{
1140 if (type.isArray())
1141 {
1142 const TString &functionName = addArrayAssignmentFunction(type);
1143 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1144 }
1145 else
1146 {
1147 outputTriplet(out, visit, "(", " = ", ")");
1148 }
1149}
1150
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001151bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001152{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001153 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001154 {
1155 TIntermNode *ancestor = getAncestorNode(n);
1156 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1157 if (ancestorBinary == nullptr)
1158 {
1159 return false;
1160 }
1161 switch (ancestorBinary->getOp())
1162 {
1163 case EOpIndexDirectStruct:
1164 {
1165 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1166 const TIntermConstantUnion *index =
1167 ancestorBinary->getRight()->getAsConstantUnion();
1168 const TField *field = structure->fields()[index->getIConst(0)];
1169 if (IsSampler(field->type()->getBasicType()))
1170 {
1171 return true;
1172 }
1173 break;
1174 }
1175 case EOpIndexDirect:
1176 break;
1177 default:
1178 // Returning a sampler from indirect indexing is not supported.
1179 return false;
1180 }
1181 }
1182 return false;
1183}
1184
Olli Etuahob6fa0432016-09-28 16:28:05 +01001185bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1186{
1187 TInfoSinkBase &out = getInfoSink();
1188 if (visit == PostVisit)
1189 {
1190 out << ".";
1191 node->writeOffsetsAsXYZW(&out);
1192 }
1193 return true;
1194}
1195
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001196bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1197{
Jamie Madill32aab012015-01-27 14:12:26 -05001198 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199
1200 switch (node->getOp())
1201 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001202 case EOpComma:
1203 outputTriplet(out, visit, "(", ", ", ")");
1204 break;
1205 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001206 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001207 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001208 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1209 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001210 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001211 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1212 out << functionName << "(";
1213 node->getLeft()->traverse(this);
1214 TIntermSequence *seq = rightAgg->getSequence();
1215 for (auto &arrayElement : *seq)
1216 {
1217 out << ", ";
1218 arrayElement->traverse(this);
1219 }
1220 out << ")";
1221 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001222 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001223 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1224 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001225 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001226 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001227 // Assignment expressions with atomic functions should be transformed into atomic
1228 // function calls in HLSL.
1229 // e.g. original_value = atomicAdd(dest, value) should be translated into
1230 // InterlockedAdd(dest, value, original_value);
1231 else if (IsAtomicFunctionDirectAssign(*node))
1232 {
1233 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1234 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1235 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1236 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1237 ASSERT(argumentSeq->size() >= 2u);
1238 for (auto &argument : *argumentSeq)
1239 {
1240 argument->traverse(this);
1241 out << ", ";
1242 }
1243 node->getLeft()->traverse(this);
1244 out << ")";
1245 return false;
1246 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001247 else if (IsInShaderStorageBlock(node->getLeft()))
1248 {
1249 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1250 out << ", ";
1251 if (IsInShaderStorageBlock(node->getRight()))
1252 {
1253 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1254 }
1255 else
1256 {
1257 node->getRight()->traverse(this);
1258 }
1259
1260 out << ")";
1261 return false;
1262 }
1263 else if (IsInShaderStorageBlock(node->getRight()))
1264 {
1265 node->getLeft()->traverse(this);
1266 out << " = ";
1267 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1268 return false;
1269 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001270
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001271 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001272 break;
1273 case EOpInitialize:
1274 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001275 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001276 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1277 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001278 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001279
1280 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001281 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001282
1283 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1284 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1285 // new variable is created before the assignment is evaluated), so we need to
1286 // convert
1287 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001288 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001289 {
1290 // Skip initializing the rest of the expression
1291 return false;
1292 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001293 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001294 {
1295 return false;
1296 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001297 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001298 else if (visit == InVisit)
1299 {
1300 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001301 if (IsInShaderStorageBlock(node->getRight()))
1302 {
1303 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1304 return false;
1305 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001306 }
1307 break;
1308 case EOpAddAssign:
1309 outputTriplet(out, visit, "(", " += ", ")");
1310 break;
1311 case EOpSubAssign:
1312 outputTriplet(out, visit, "(", " -= ", ")");
1313 break;
1314 case EOpMulAssign:
1315 outputTriplet(out, visit, "(", " *= ", ")");
1316 break;
1317 case EOpVectorTimesScalarAssign:
1318 outputTriplet(out, visit, "(", " *= ", ")");
1319 break;
1320 case EOpMatrixTimesScalarAssign:
1321 outputTriplet(out, visit, "(", " *= ", ")");
1322 break;
1323 case EOpVectorTimesMatrixAssign:
1324 if (visit == PreVisit)
1325 {
1326 out << "(";
1327 }
1328 else if (visit == InVisit)
1329 {
1330 out << " = mul(";
1331 node->getLeft()->traverse(this);
1332 out << ", transpose(";
1333 }
1334 else
1335 {
1336 out << ")))";
1337 }
1338 break;
1339 case EOpMatrixTimesMatrixAssign:
1340 if (visit == PreVisit)
1341 {
1342 out << "(";
1343 }
1344 else if (visit == InVisit)
1345 {
1346 out << " = transpose(mul(transpose(";
1347 node->getLeft()->traverse(this);
1348 out << "), transpose(";
1349 }
1350 else
1351 {
1352 out << "))))";
1353 }
1354 break;
1355 case EOpDivAssign:
1356 outputTriplet(out, visit, "(", " /= ", ")");
1357 break;
1358 case EOpIModAssign:
1359 outputTriplet(out, visit, "(", " %= ", ")");
1360 break;
1361 case EOpBitShiftLeftAssign:
1362 outputTriplet(out, visit, "(", " <<= ", ")");
1363 break;
1364 case EOpBitShiftRightAssign:
1365 outputTriplet(out, visit, "(", " >>= ", ")");
1366 break;
1367 case EOpBitwiseAndAssign:
1368 outputTriplet(out, visit, "(", " &= ", ")");
1369 break;
1370 case EOpBitwiseXorAssign:
1371 outputTriplet(out, visit, "(", " ^= ", ")");
1372 break;
1373 case EOpBitwiseOrAssign:
1374 outputTriplet(out, visit, "(", " |= ", ")");
1375 break;
1376 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001377 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001378 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001379 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001380 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001381 if (visit == PreVisit)
1382 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001383 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001384 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001385
1386 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001387 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1388 {
1389 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1390 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1391 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001392 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001393 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001394 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001395 return false;
1396 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001397 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001398 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001399 {
1400 // All parts of an expression that access a sampler in a struct need to use _ as
1401 // separator to access the sampler variable that has been moved out of the struct.
1402 outputTriplet(out, visit, "", "_", "");
1403 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001404 else if (IsAtomicCounter(leftType.getBasicType()))
1405 {
1406 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1407 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001408 else
1409 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001410 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001411 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001412 }
1413 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001414 case EOpIndexIndirect:
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001415 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001416 // We do not currently support indirect references to interface blocks
1417 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001418
1419 const TType &leftType = node->getLeft()->getType();
1420 if (IsAtomicCounter(leftType.getBasicType()))
1421 {
1422 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1423 }
1424 else
1425 {
1426 outputTriplet(out, visit, "", "[", "]");
1427 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 break;
Brandon Jones4a22f4b2018-10-23 14:36:47 -07001429 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001430 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001431 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001432 const TStructure *structure = node->getLeft()->getType().getStruct();
1433 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1434 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001435
Olli Etuaho96963162016-03-21 11:54:33 +02001436 // In cases where indexing returns a sampler, we need to access the sampler variable
1437 // that has been moved out of the struct.
1438 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1439 if (visit == PreVisit && indexingReturnsSampler)
1440 {
1441 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1442 // This prefix is only output at the beginning of the indexing expression, which
1443 // may have multiple parts.
1444 out << "angle";
1445 }
1446 if (!indexingReturnsSampler)
1447 {
1448 // All parts of an expression that access a sampler in a struct need to use _ as
1449 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001450 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001451 }
1452 if (visit == InVisit)
1453 {
1454 if (indexingReturnsSampler)
1455 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001456 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001457 }
1458 else
1459 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001460 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001461 }
1462
1463 return false;
1464 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001465 }
1466 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001467 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001468 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001469 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1470 bool structInStd140UniformBlock =
1471 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1472 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001473 {
1474 out << "map";
1475 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001476 if (visit == InVisit)
1477 {
1478 const TInterfaceBlock *interfaceBlock =
1479 node->getLeft()->getType().getInterfaceBlock();
1480 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1481 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001482 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001483 {
1484 out << "_";
1485 }
1486 else
1487 {
1488 out << ".";
1489 }
1490 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001491
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001492 return false;
1493 }
1494 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001495 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001496 case EOpAdd:
1497 outputTriplet(out, visit, "(", " + ", ")");
1498 break;
1499 case EOpSub:
1500 outputTriplet(out, visit, "(", " - ", ")");
1501 break;
1502 case EOpMul:
1503 outputTriplet(out, visit, "(", " * ", ")");
1504 break;
1505 case EOpDiv:
1506 outputTriplet(out, visit, "(", " / ", ")");
1507 break;
1508 case EOpIMod:
1509 outputTriplet(out, visit, "(", " % ", ")");
1510 break;
1511 case EOpBitShiftLeft:
1512 outputTriplet(out, visit, "(", " << ", ")");
1513 break;
1514 case EOpBitShiftRight:
1515 outputTriplet(out, visit, "(", " >> ", ")");
1516 break;
1517 case EOpBitwiseAnd:
1518 outputTriplet(out, visit, "(", " & ", ")");
1519 break;
1520 case EOpBitwiseXor:
1521 outputTriplet(out, visit, "(", " ^ ", ")");
1522 break;
1523 case EOpBitwiseOr:
1524 outputTriplet(out, visit, "(", " | ", ")");
1525 break;
1526 case EOpEqual:
1527 case EOpNotEqual:
1528 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1529 break;
1530 case EOpLessThan:
1531 outputTriplet(out, visit, "(", " < ", ")");
1532 break;
1533 case EOpGreaterThan:
1534 outputTriplet(out, visit, "(", " > ", ")");
1535 break;
1536 case EOpLessThanEqual:
1537 outputTriplet(out, visit, "(", " <= ", ")");
1538 break;
1539 case EOpGreaterThanEqual:
1540 outputTriplet(out, visit, "(", " >= ", ")");
1541 break;
1542 case EOpVectorTimesScalar:
1543 outputTriplet(out, visit, "(", " * ", ")");
1544 break;
1545 case EOpMatrixTimesScalar:
1546 outputTriplet(out, visit, "(", " * ", ")");
1547 break;
1548 case EOpVectorTimesMatrix:
1549 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1550 break;
1551 case EOpMatrixTimesVector:
1552 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1553 break;
1554 case EOpMatrixTimesMatrix:
1555 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1556 break;
1557 case EOpLogicalOr:
1558 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1559 // been unfolded.
1560 ASSERT(!node->getRight()->hasSideEffects());
1561 outputTriplet(out, visit, "(", " || ", ")");
1562 return true;
1563 case EOpLogicalXor:
1564 mUsesXor = true;
1565 outputTriplet(out, visit, "xor(", ", ", ")");
1566 break;
1567 case EOpLogicalAnd:
1568 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1569 // been unfolded.
1570 ASSERT(!node->getRight()->hasSideEffects());
1571 outputTriplet(out, visit, "(", " && ", ")");
1572 return true;
1573 default:
1574 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001575 }
1576
1577 return true;
1578}
1579
1580bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1581{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001582 TInfoSinkBase &out = getInfoSink();
1583
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001584 switch (node->getOp())
1585 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001586 case EOpNegative:
1587 outputTriplet(out, visit, "(-", "", ")");
1588 break;
1589 case EOpPositive:
1590 outputTriplet(out, visit, "(+", "", ")");
1591 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001592 case EOpLogicalNot:
1593 outputTriplet(out, visit, "(!", "", ")");
1594 break;
1595 case EOpBitwiseNot:
1596 outputTriplet(out, visit, "(~", "", ")");
1597 break;
1598 case EOpPostIncrement:
1599 outputTriplet(out, visit, "(", "", "++)");
1600 break;
1601 case EOpPostDecrement:
1602 outputTriplet(out, visit, "(", "", "--)");
1603 break;
1604 case EOpPreIncrement:
1605 outputTriplet(out, visit, "(++", "", ")");
1606 break;
1607 case EOpPreDecrement:
1608 outputTriplet(out, visit, "(--", "", ")");
1609 break;
1610 case EOpRadians:
1611 outputTriplet(out, visit, "radians(", "", ")");
1612 break;
1613 case EOpDegrees:
1614 outputTriplet(out, visit, "degrees(", "", ")");
1615 break;
1616 case EOpSin:
1617 outputTriplet(out, visit, "sin(", "", ")");
1618 break;
1619 case EOpCos:
1620 outputTriplet(out, visit, "cos(", "", ")");
1621 break;
1622 case EOpTan:
1623 outputTriplet(out, visit, "tan(", "", ")");
1624 break;
1625 case EOpAsin:
1626 outputTriplet(out, visit, "asin(", "", ")");
1627 break;
1628 case EOpAcos:
1629 outputTriplet(out, visit, "acos(", "", ")");
1630 break;
1631 case EOpAtan:
1632 outputTriplet(out, visit, "atan(", "", ")");
1633 break;
1634 case EOpSinh:
1635 outputTriplet(out, visit, "sinh(", "", ")");
1636 break;
1637 case EOpCosh:
1638 outputTriplet(out, visit, "cosh(", "", ")");
1639 break;
1640 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001641 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001642 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001643 case EOpAtanh:
1644 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001645 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001646 break;
1647 case EOpExp:
1648 outputTriplet(out, visit, "exp(", "", ")");
1649 break;
1650 case EOpLog:
1651 outputTriplet(out, visit, "log(", "", ")");
1652 break;
1653 case EOpExp2:
1654 outputTriplet(out, visit, "exp2(", "", ")");
1655 break;
1656 case EOpLog2:
1657 outputTriplet(out, visit, "log2(", "", ")");
1658 break;
1659 case EOpSqrt:
1660 outputTriplet(out, visit, "sqrt(", "", ")");
1661 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001662 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001663 outputTriplet(out, visit, "rsqrt(", "", ")");
1664 break;
1665 case EOpAbs:
1666 outputTriplet(out, visit, "abs(", "", ")");
1667 break;
1668 case EOpSign:
1669 outputTriplet(out, visit, "sign(", "", ")");
1670 break;
1671 case EOpFloor:
1672 outputTriplet(out, visit, "floor(", "", ")");
1673 break;
1674 case EOpTrunc:
1675 outputTriplet(out, visit, "trunc(", "", ")");
1676 break;
1677 case EOpRound:
1678 outputTriplet(out, visit, "round(", "", ")");
1679 break;
1680 case EOpRoundEven:
1681 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001682 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001683 break;
1684 case EOpCeil:
1685 outputTriplet(out, visit, "ceil(", "", ")");
1686 break;
1687 case EOpFract:
1688 outputTriplet(out, visit, "frac(", "", ")");
1689 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001690 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001691 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001692 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001693 else
1694 outputTriplet(out, visit, "isnan(", "", ")");
1695 mRequiresIEEEStrictCompiling = true;
1696 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001697 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001698 outputTriplet(out, visit, "isinf(", "", ")");
1699 break;
1700 case EOpFloatBitsToInt:
1701 outputTriplet(out, visit, "asint(", "", ")");
1702 break;
1703 case EOpFloatBitsToUint:
1704 outputTriplet(out, visit, "asuint(", "", ")");
1705 break;
1706 case EOpIntBitsToFloat:
1707 outputTriplet(out, visit, "asfloat(", "", ")");
1708 break;
1709 case EOpUintBitsToFloat:
1710 outputTriplet(out, visit, "asfloat(", "", ")");
1711 break;
1712 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001713 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001714 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001715 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001716 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001717 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001718 case EOpPackUnorm4x8:
1719 case EOpPackSnorm4x8:
1720 case EOpUnpackUnorm4x8:
1721 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001722 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001723 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001724 break;
1725 case EOpLength:
1726 outputTriplet(out, visit, "length(", "", ")");
1727 break;
1728 case EOpNormalize:
1729 outputTriplet(out, visit, "normalize(", "", ")");
1730 break;
1731 case EOpDFdx:
1732 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1733 {
1734 outputTriplet(out, visit, "(", "", ", 0.0)");
1735 }
1736 else
1737 {
1738 outputTriplet(out, visit, "ddx(", "", ")");
1739 }
1740 break;
1741 case EOpDFdy:
1742 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1743 {
1744 outputTriplet(out, visit, "(", "", ", 0.0)");
1745 }
1746 else
1747 {
1748 outputTriplet(out, visit, "ddy(", "", ")");
1749 }
1750 break;
1751 case EOpFwidth:
1752 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1753 {
1754 outputTriplet(out, visit, "(", "", ", 0.0)");
1755 }
1756 else
1757 {
1758 outputTriplet(out, visit, "fwidth(", "", ")");
1759 }
1760 break;
1761 case EOpTranspose:
1762 outputTriplet(out, visit, "transpose(", "", ")");
1763 break;
1764 case EOpDeterminant:
1765 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1766 break;
1767 case EOpInverse:
1768 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001769 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001770 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001771
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001772 case EOpAny:
1773 outputTriplet(out, visit, "any(", "", ")");
1774 break;
1775 case EOpAll:
1776 outputTriplet(out, visit, "all(", "", ")");
1777 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001778 case EOpLogicalNotComponentWise:
1779 outputTriplet(out, visit, "(!", "", ")");
1780 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001781 case EOpBitfieldReverse:
1782 outputTriplet(out, visit, "reversebits(", "", ")");
1783 break;
1784 case EOpBitCount:
1785 outputTriplet(out, visit, "countbits(", "", ")");
1786 break;
1787 case EOpFindLSB:
1788 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1789 // in GLSLTest and results are consistent with GL.
1790 outputTriplet(out, visit, "firstbitlow(", "", ")");
1791 break;
1792 case EOpFindMSB:
1793 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1794 // tested in GLSLTest and results are consistent with GL.
1795 outputTriplet(out, visit, "firstbithigh(", "", ")");
1796 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001797 default:
1798 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001799 }
1800
1801 return true;
1802}
1803
Olli Etuahofbb1c792018-01-19 16:26:59 +02001804ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001805{
1806 if (node->getAsSymbolNode())
1807 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001808 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1809 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001810 }
1811 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1812 switch (nodeBinary->getOp())
1813 {
1814 case EOpIndexDirect:
1815 {
1816 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1817
Olli Etuahofbb1c792018-01-19 16:26:59 +02001818 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001819 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001820 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001821 }
1822 case EOpIndexDirectStruct:
1823 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001824 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001825 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1826 const TField *field = s->fields()[index];
1827
Olli Etuahofbb1c792018-01-19 16:26:59 +02001828 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001829 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1830 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001831 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001832 }
1833 default:
1834 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001835 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001836 }
1837}
1838
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001839bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1840{
1841 TInfoSinkBase &out = getInfoSink();
1842
Olli Etuaho06235df2018-07-20 14:26:07 +03001843 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1844
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001845 if (mInsideFunction)
1846 {
1847 outputLineDirective(out, node->getLine().first_line);
1848 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001849 if (isMainBlock)
1850 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001851 if (mShaderType == GL_COMPUTE_SHADER)
1852 {
1853 out << "initGLBuiltins(input);\n";
1854 }
1855 else
1856 {
1857 out << "@@ MAIN PROLOGUE @@\n";
1858 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001859 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001860 }
1861
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001862 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001863 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001864 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001865
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001866 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001867
1868 // Don't output ; after case labels, they're terminated by :
1869 // This is needed especially since outputting a ; after a case statement would turn empty
1870 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001871 // Also the output code is clearer if we don't output ; after statements where it is not
1872 // needed:
1873 // * if statements
1874 // * switch statements
1875 // * blocks
1876 // * function definitions
1877 // * loops (do-while loops output the semicolon in VisitLoop)
1878 // * declarations that don't generate output.
1879 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1880 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1881 statement->getAsSwitchNode() == nullptr &&
1882 statement->getAsFunctionDefinition() == nullptr &&
1883 (statement->getAsDeclarationNode() == nullptr ||
1884 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1885 statement->getAsInvariantDeclarationNode() == nullptr)
1886 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001887 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001888 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001889 }
1890
1891 if (mInsideFunction)
1892 {
1893 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001894 if (isMainBlock && shaderNeedsGenerateOutput())
1895 {
1896 // We could have an empty main, a main function without a branch at the end, or a main
1897 // function with a discard statement at the end. In these cases we need to add a return
1898 // statement.
1899 bool needReturnStatement =
1900 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1901 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1902 if (needReturnStatement)
1903 {
1904 out << "return " << generateOutputCall() << ";\n";
1905 }
1906 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001907 out << "}\n";
1908 }
1909
1910 return false;
1911}
1912
Olli Etuaho336b1472016-10-05 16:37:55 +01001913bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1914{
1915 TInfoSinkBase &out = getInfoSink();
1916
1917 ASSERT(mCurrentFunctionMetadata == nullptr);
1918
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001919 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001920 ASSERT(index != CallDAG::InvalidIndex);
1921 mCurrentFunctionMetadata = &mASTMetadataList[index];
1922
Olli Etuahod4bd9632018-03-08 16:32:44 +02001923 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001924
Olli Etuahod4bd9632018-03-08 16:32:44 +02001925 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001926 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001927 // The stub strings below are replaced when shader is dynamically defined by its layout:
1928 switch (mShaderType)
1929 {
1930 case GL_VERTEX_SHADER:
1931 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1932 << "@@ VERTEX OUTPUT @@\n\n"
1933 << "VS_OUTPUT main(VS_INPUT input)";
1934 break;
1935 case GL_FRAGMENT_SHADER:
1936 out << "@@ PIXEL OUTPUT @@\n\n"
1937 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1938 break;
1939 case GL_COMPUTE_SHADER:
1940 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1941 << mWorkGroupSize[2] << ")]\n";
1942 out << "void main(CS_INPUT input)";
1943 break;
1944 default:
1945 UNREACHABLE();
1946 break;
1947 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001948 }
1949 else
1950 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001951 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001952 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001953 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001954
Olli Etuaho06235df2018-07-20 14:26:07 +03001955 size_t paramCount = func->getParamCount();
1956 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001957 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001958 const TVariable *param = func->getParam(i);
1959 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001960
Olli Etuaho06235df2018-07-20 14:26:07 +03001961 writeParameter(param, out);
1962
1963 if (i < paramCount - 1)
1964 {
1965 out << ", ";
1966 }
1967 }
1968
1969 out << ")\n";
1970 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001971
1972 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03001973 if (func->isMain())
1974 {
1975 mInsideMain = true;
1976 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001977 // The function body node will output braces.
1978 node->getBody()->traverse(this);
1979 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03001980 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01001981
1982 mCurrentFunctionMetadata = nullptr;
1983
1984 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1985 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1986 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001987 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001988 mOutputLod0Function = true;
1989 node->traverse(this);
1990 mOutputLod0Function = false;
1991 }
1992
1993 return false;
1994}
1995
Olli Etuaho13389b62016-10-16 11:48:18 +01001996bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1997{
Olli Etuaho13389b62016-10-16 11:48:18 +01001998 if (visit == PreVisit)
1999 {
2000 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002001 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01002002 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002003 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01002004
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002005 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01002006 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002007 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002008 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01002009
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002010 if (!declarator->getAsSymbolNode() ||
2011 declarator->getAsSymbolNode()->variable().symbolType() !=
2012 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01002013 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002014 if (declarator->getQualifier() == EvqShared)
2015 {
2016 out << "groupshared ";
2017 }
2018 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01002019 {
2020 out << "static ";
2021 }
2022
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002023 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01002024
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002025 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01002026
2027 if (symbol)
2028 {
2029 symbol->traverse(this);
2030 out << ArrayString(symbol->getType());
jchen10cd47a372018-11-11 11:08:16 +08002031 // Add initializer only when requested. It is very slow for D3D11 drivers to
2032 // compile a compute shader if we add code to initialize a groupshared array
2033 // variable with a large array size.
2034 if (declarator->getQualifier() != EvqShared ||
2035 mCompileOptions & SH_INIT_SHARED_VARIABLES)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002036 {
2037 out << " = " + zeroInitializer(symbol->getType());
2038 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002039 }
2040 else
2041 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002042 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002043 }
2044 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002045 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002046 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002047 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002048 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002049 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002050
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002051 const TVariable &variable = symbol->variable();
2052
2053 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002054 {
2055 // Vertex outputs which are declared but not written to should still be declared to
2056 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002057 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002058 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002059 }
2060 }
2061 return false;
2062}
2063
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002064bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2065{
2066 // Do not do any translation
2067 return false;
2068}
2069
Olli Etuahod4bd9632018-03-08 16:32:44 +02002070void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002071{
2072 TInfoSinkBase &out = getInfoSink();
2073
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002074 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002075 // Skip the prototype if it is not implemented (and thus not used)
2076 if (index == CallDAG::InvalidIndex)
2077 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002078 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002079 }
2080
Olli Etuahod4bd9632018-03-08 16:32:44 +02002081 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002082
Olli Etuahod4bd9632018-03-08 16:32:44 +02002083 TString name = DecorateFunctionIfNeeded(func);
2084 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002085 << (mOutputLod0Function ? "Lod0(" : "(");
2086
Olli Etuahod4bd9632018-03-08 16:32:44 +02002087 size_t paramCount = func->getParamCount();
2088 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002089 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002090 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002091
Olli Etuahod4bd9632018-03-08 16:32:44 +02002092 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002093 {
2094 out << ", ";
2095 }
2096 }
2097
2098 out << ");\n";
2099
2100 // Also prototype the Lod0 variant if needed
2101 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2102 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2103 {
2104 mOutputLod0Function = true;
2105 node->traverse(this);
2106 mOutputLod0Function = false;
2107 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002108}
2109
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002110bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2111{
Jamie Madill32aab012015-01-27 14:12:26 -05002112 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002113
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002114 switch (node->getOp())
2115 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002116 case EOpCallBuiltInFunction:
2117 case EOpCallFunctionInAST:
2118 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002119 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002120 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002121
Corentin Wallez1239ee92015-03-19 14:38:02 -07002122 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002123 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002124 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002125 if (node->isArray())
2126 {
2127 UNIMPLEMENTED();
2128 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002129 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002130 ASSERT(index != CallDAG::InvalidIndex);
2131 lod0 &= mASTMetadataList[index].mNeedsLod0;
2132
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002133 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002134 out << DisambiguateFunctionName(node->getSequence());
2135 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002136 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002137 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002138 {
2139 // This path is used for internal functions that don't have their definitions in the
2140 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002141 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002142 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002143 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002144 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002145 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002146 TType type = (*arguments)[0]->getAsTyped()->getType();
2147 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002148 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002149 type.getMemoryQualifier().readonly);
2150 out << imageFunctionName << "(";
2151 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002152 else if (node->getFunction()->isAtomicCounterFunction())
2153 {
2154 const ImmutableString &name = node->getFunction()->name();
2155 ImmutableString atomicFunctionName =
2156 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2157 out << atomicFunctionName << "(";
2158 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002159 else
2160 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002161 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002162 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002163 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2164 if (arguments->size() > 1)
2165 {
2166 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2167 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002168 const ImmutableString &textureFunctionName =
2169 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2170 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002171 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002173
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002174 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002175 {
Olli Etuaho96963162016-03-21 11:54:33 +02002176 TIntermTyped *typedArg = (*arg)->getAsTyped();
2177 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002178 {
2179 out << "texture_";
2180 (*arg)->traverse(this);
2181 out << ", sampler_";
2182 }
2183
2184 (*arg)->traverse(this);
2185
Olli Etuaho96963162016-03-21 11:54:33 +02002186 if (typedArg->getType().isStructureContainingSamplers())
2187 {
2188 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002189 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002190 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2191 std::string namePrefix = "angle_";
2192 namePrefix += structName.data();
2193 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002194 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002195 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002196 {
2197 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2198 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002199 out << ", texture_" << sampler->name();
2200 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002201 }
2202 else
2203 {
2204 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2205 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002206 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002207 }
2208 }
2209 }
2210
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002211 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002212 {
2213 out << ", ";
2214 }
2215 }
2216
2217 out << ")";
2218
2219 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002220 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002221 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002222 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002223 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002224 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002225 outputTriplet(out, visit, "(", " == ", ")");
2226 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002227 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002228 outputTriplet(out, visit, "(", " != ", ")");
2229 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002230 case EOpLessThanComponentWise:
2231 outputTriplet(out, visit, "(", " < ", ")");
2232 break;
2233 case EOpGreaterThanComponentWise:
2234 outputTriplet(out, visit, "(", " > ", ")");
2235 break;
2236 case EOpLessThanEqualComponentWise:
2237 outputTriplet(out, visit, "(", " <= ", ")");
2238 break;
2239 case EOpGreaterThanEqualComponentWise:
2240 outputTriplet(out, visit, "(", " >= ", ")");
2241 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002242 case EOpMod:
2243 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002244 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002245 break;
2246 case EOpModf:
2247 outputTriplet(out, visit, "modf(", ", ", ")");
2248 break;
2249 case EOpPow:
2250 outputTriplet(out, visit, "pow(", ", ", ")");
2251 break;
2252 case EOpAtan:
2253 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2254 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002255 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002256 break;
2257 case EOpMin:
2258 outputTriplet(out, visit, "min(", ", ", ")");
2259 break;
2260 case EOpMax:
2261 outputTriplet(out, visit, "max(", ", ", ")");
2262 break;
2263 case EOpClamp:
2264 outputTriplet(out, visit, "clamp(", ", ", ")");
2265 break;
2266 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302267 {
2268 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2269 if (lastParamNode->getType().getBasicType() == EbtBool)
2270 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002271 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2272 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302273 // so use emulated version.
2274 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002275 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302276 }
2277 else
2278 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002279 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302280 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002281 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302282 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002283 case EOpStep:
2284 outputTriplet(out, visit, "step(", ", ", ")");
2285 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002286 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002287 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2288 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002289 case EOpFrexp:
2290 case EOpLdexp:
2291 ASSERT(node->getUseEmulatedFunction());
2292 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2293 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002294 case EOpDistance:
2295 outputTriplet(out, visit, "distance(", ", ", ")");
2296 break;
2297 case EOpDot:
2298 outputTriplet(out, visit, "dot(", ", ", ")");
2299 break;
2300 case EOpCross:
2301 outputTriplet(out, visit, "cross(", ", ", ")");
2302 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002303 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002304 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002305 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002306 break;
2307 case EOpReflect:
2308 outputTriplet(out, visit, "reflect(", ", ", ")");
2309 break;
2310 case EOpRefract:
2311 outputTriplet(out, visit, "refract(", ", ", ")");
2312 break;
2313 case EOpOuterProduct:
2314 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002315 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002316 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002317 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002318 outputTriplet(out, visit, "(", " * ", ")");
2319 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002320 case EOpBitfieldExtract:
2321 case EOpBitfieldInsert:
2322 case EOpUaddCarry:
2323 case EOpUsubBorrow:
2324 case EOpUmulExtended:
2325 case EOpImulExtended:
2326 ASSERT(node->getUseEmulatedFunction());
2327 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2328 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002329 case EOpBarrier:
2330 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2331 // cheapest *WithGroupSync() function, without any functionality loss, but
2332 // with the potential for severe performance loss.
2333 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2334 break;
2335 case EOpMemoryBarrierShared:
2336 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2337 break;
2338 case EOpMemoryBarrierAtomicCounter:
2339 case EOpMemoryBarrierBuffer:
2340 case EOpMemoryBarrierImage:
2341 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2342 break;
2343 case EOpGroupMemoryBarrier:
2344 case EOpMemoryBarrier:
2345 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2346 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002347
2348 // Single atomic function calls without return value.
2349 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2350 case EOpAtomicAdd:
2351 case EOpAtomicMin:
2352 case EOpAtomicMax:
2353 case EOpAtomicAnd:
2354 case EOpAtomicOr:
2355 case EOpAtomicXor:
2356 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2357 ",", ")");
2358 break;
2359
2360 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2361 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2362 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2363 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2364 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2365 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2366 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2367 // intermediate tree before traversing outputHLSL.
2368 case EOpAtomicExchange:
2369 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002370 default:
2371 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002372 }
2373
2374 return true;
2375}
2376
Olli Etuaho57961272016-09-14 13:57:46 +03002377void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002378{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002379 out << "if (";
2380
2381 node->getCondition()->traverse(this);
2382
2383 out << ")\n";
2384
Jamie Madill8c46ab12015-12-07 16:39:19 -05002385 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002386
2387 bool discard = false;
2388
2389 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002390 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002391 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002392 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002393
Olli Etuahoa6f22092015-05-08 18:31:10 +03002394 // Detect true discard
2395 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2396 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002397 else
2398 {
2399 // TODO(oetuaho): Check if the semicolon inside is necessary.
2400 // It's there as a result of conservative refactoring of the output.
2401 out << "{;}\n";
2402 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002403
Jamie Madill8c46ab12015-12-07 16:39:19 -05002404 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002405
Olli Etuahoa6f22092015-05-08 18:31:10 +03002406 if (node->getFalseBlock())
2407 {
2408 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002409
Jamie Madill8c46ab12015-12-07 16:39:19 -05002410 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002411
Olli Etuaho32db19b2016-10-04 14:43:16 +01002412 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002413 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002414
Jamie Madill8c46ab12015-12-07 16:39:19 -05002415 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002416
Olli Etuahoa6f22092015-05-08 18:31:10 +03002417 // Detect false discard
2418 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2419 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002420
Olli Etuahoa6f22092015-05-08 18:31:10 +03002421 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002422 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002423 {
2424 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002425 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002426}
2427
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002428bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2429{
2430 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2431 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2432 UNREACHABLE();
2433 return false;
2434}
2435
Olli Etuaho57961272016-09-14 13:57:46 +03002436bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002437{
2438 TInfoSinkBase &out = getInfoSink();
2439
Olli Etuaho3d932d82016-04-12 11:10:30 +03002440 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002441
2442 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002443 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002444 {
2445 out << "FLATTEN ";
2446 }
2447
Olli Etuaho57961272016-09-14 13:57:46 +03002448 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002449
2450 return false;
2451}
2452
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002453bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002454{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002455 TInfoSinkBase &out = getInfoSink();
2456
Olli Etuaho923ecef2017-10-11 12:01:38 +03002457 ASSERT(node->getStatementList());
2458 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002459 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002460 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002461 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002462 outputTriplet(out, visit, "switch (", ") ", "");
2463 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002464 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002465}
2466
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002467bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002468{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002469 TInfoSinkBase &out = getInfoSink();
2470
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002471 if (node->hasCondition())
2472 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002473 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002474 return true;
2475 }
2476 else
2477 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002478 out << "default:\n";
2479 return false;
2480 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002481}
2482
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002483void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2484{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002485 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002486 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002487}
2488
2489bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2490{
Nicolas Capens655fe362014-04-11 13:12:34 -04002491 mNestedLoopDepth++;
2492
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002493 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002494 mInsideDiscontinuousLoop =
2495 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002496
Jamie Madill8c46ab12015-12-07 16:39:19 -05002497 TInfoSinkBase &out = getInfoSink();
2498
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002499 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002500 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002501 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002502 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002503 mInsideDiscontinuousLoop = wasDiscontinuous;
2504 mNestedLoopDepth--;
2505
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002506 return false;
2507 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002508 }
2509
Corentin Wallez1239ee92015-03-19 14:38:02 -07002510 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002511 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002512 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002513 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002514
Jamie Madill8c46ab12015-12-07 16:39:19 -05002515 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002516 }
2517 else
2518 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002519 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002520
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002521 if (node->getInit())
2522 {
2523 node->getInit()->traverse(this);
2524 }
2525
2526 out << "; ";
2527
alokp@chromium.org52813552010-11-16 18:36:09 +00002528 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002529 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002530 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002531 }
2532
2533 out << "; ";
2534
alokp@chromium.org52813552010-11-16 18:36:09 +00002535 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002536 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002537 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002538 }
2539
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002540 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002541
Jamie Madill8c46ab12015-12-07 16:39:19 -05002542 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002543 }
2544
2545 if (node->getBody())
2546 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002547 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002548 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002549 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002550 else
2551 {
2552 // TODO(oetuaho): Check if the semicolon inside is necessary.
2553 // It's there as a result of conservative refactoring of the output.
2554 out << "{;}\n";
2555 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002556
Jamie Madill8c46ab12015-12-07 16:39:19 -05002557 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002558
alokp@chromium.org52813552010-11-16 18:36:09 +00002559 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002560 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002561 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002562 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002563
alokp@chromium.org52813552010-11-16 18:36:09 +00002564 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002565
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002566 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002567 }
2568
daniel@transgaming.com73536982012-03-21 20:45:49 +00002569 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002570
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002571 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002572 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002573
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002574 return false;
2575}
2576
2577bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2578{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002579 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002580 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002581 TInfoSinkBase &out = getInfoSink();
2582
2583 switch (node->getFlowOp())
2584 {
2585 case EOpKill:
2586 out << "discard";
2587 break;
2588 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002589 if (mNestedLoopDepth > 1)
2590 {
2591 mUsesNestedBreak = true;
2592 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002593
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002594 if (mExcessiveLoopIndex)
2595 {
2596 out << "{Break";
2597 mExcessiveLoopIndex->traverse(this);
2598 out << " = true; break;}\n";
2599 }
2600 else
2601 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002602 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002603 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002604 break;
2605 case EOpContinue:
2606 out << "continue";
2607 break;
2608 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002609 if (node->getExpression())
2610 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002611 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002612 out << "return ";
2613 }
2614 else
2615 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002616 if (mInsideMain && shaderNeedsGenerateOutput())
2617 {
2618 out << "return " << generateOutputCall();
2619 }
2620 else
2621 {
2622 out << "return";
2623 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002624 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002625 break;
2626 default:
2627 UNREACHABLE();
2628 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002629 }
2630
2631 return true;
2632}
2633
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002634// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002635// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2636// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002637bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002638{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002639 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002640
2641 // Parse loops of the form:
2642 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002643 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002644 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002645 int initial = 0;
2646 int limit = 0;
2647 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002648
2649 // Parse index name and intial value
2650 if (node->getInit())
2651 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002652 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002653
2654 if (init)
2655 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002656 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002657 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002658
2659 if (variable && variable->getQualifier() == EvqTemporary)
2660 {
2661 TIntermBinary *assign = variable->getAsBinaryNode();
2662
2663 if (assign->getOp() == EOpInitialize)
2664 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002665 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002666 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2667
2668 if (symbol && constant)
2669 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002670 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002671 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002672 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002673 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002674 }
2675 }
2676 }
2677 }
2678 }
2679 }
2680
2681 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002682 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002683 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002684 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002685
Olli Etuahob6af22b2017-12-15 14:05:44 +02002686 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002687 {
2688 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2689
2690 if (constant)
2691 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002692 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002693 {
2694 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002695 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002696 }
2697 }
2698 }
2699 }
2700
2701 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002702 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002703 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002704 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002705 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002706
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002707 if (binaryTerminal)
2708 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002709 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002710 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2711
2712 if (constant)
2713 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002714 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002715 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002716 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002717
2718 switch (op)
2719 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002720 case EOpAddAssign:
2721 increment = value;
2722 break;
2723 case EOpSubAssign:
2724 increment = -value;
2725 break;
2726 default:
2727 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002728 }
2729 }
2730 }
2731 }
2732 else if (unaryTerminal)
2733 {
2734 TOperator op = unaryTerminal->getOp();
2735
2736 switch (op)
2737 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002738 case EOpPostIncrement:
2739 increment = 1;
2740 break;
2741 case EOpPostDecrement:
2742 increment = -1;
2743 break;
2744 case EOpPreIncrement:
2745 increment = 1;
2746 break;
2747 case EOpPreDecrement:
2748 increment = -1;
2749 break;
2750 default:
2751 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002752 }
2753 }
2754 }
2755
Yunchao He4f285442017-04-21 12:15:49 +08002756 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002757 {
2758 if (comparator == EOpLessThanEqual)
2759 {
2760 comparator = EOpLessThan;
2761 limit += 1;
2762 }
2763
2764 if (comparator == EOpLessThan)
2765 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002766 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002767
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002768 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002769 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002770 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002771 }
2772
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002773 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002774 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002775
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002776 out << "{int ";
2777 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002778 out << ";\n"
2779 "bool Break";
2780 index->traverse(this);
2781 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002782
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002783 bool firstLoopFragment = true;
2784
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002785 while (iterations > 0)
2786 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002787 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002788
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002789 if (!firstLoopFragment)
2790 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002791 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002792 index->traverse(this);
2793 out << ") {\n";
2794 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002795
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002796 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002797 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002798 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002799 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002800
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002801 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002802 const char *unroll =
2803 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002804
Corentin Wallez1239ee92015-03-19 14:38:02 -07002805 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002806 index->traverse(this);
2807 out << " = ";
2808 out << initial;
2809
2810 out << "; ";
2811 index->traverse(this);
2812 out << " < ";
2813 out << clampedLimit;
2814
2815 out << "; ";
2816 index->traverse(this);
2817 out << " += ";
2818 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002819 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002820
Jamie Madill8c46ab12015-12-07 16:39:19 -05002821 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002822 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002823
2824 if (node->getBody())
2825 {
2826 node->getBody()->traverse(this);
2827 }
2828
Jamie Madill8c46ab12015-12-07 16:39:19 -05002829 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002830 out << ";}\n";
2831
2832 if (!firstLoopFragment)
2833 {
2834 out << "}\n";
2835 }
2836
2837 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002838
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002839 initial += MAX_LOOP_ITERATIONS * increment;
2840 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002841 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002842
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002843 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002844
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002845 mExcessiveLoopIndex = restoreIndex;
2846
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002847 return true;
2848 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002849 else
2850 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002851 }
2852
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002853 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002854}
2855
Jamie Madill8c46ab12015-12-07 16:39:19 -05002856void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2857 Visit visit,
2858 const char *preString,
2859 const char *inString,
2860 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002861{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002862 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002863 {
2864 out << preString;
2865 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002866 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002867 {
2868 out << inString;
2869 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002870 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002871 {
2872 out << postString;
2873 }
2874}
2875
Jamie Madill8c46ab12015-12-07 16:39:19 -05002876void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002877{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002878 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002879 {
Jamie Madill32aab012015-01-27 14:12:26 -05002880 out << "\n";
2881 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002882
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002883 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002884 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002885 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002886 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002887
Jamie Madill32aab012015-01-27 14:12:26 -05002888 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002889 }
2890}
2891
Olli Etuahod4bd9632018-03-08 16:32:44 +02002892void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002893{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002894 const TType &type = param->getType();
2895 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002896
Olli Etuahod4bd9632018-03-08 16:32:44 +02002897 TString nameStr = DecorateVariableIfNeeded(*param);
2898 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002899
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002900 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002901 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002902 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2903 {
2904 // Samplers are passed as indices to the sampler array.
2905 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002906 out << "const uint " << nameStr << ArrayString(type);
2907 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002908 }
2909 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2910 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002911 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2912 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2913 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2914 << ArrayString(type);
2915 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002916 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002917 }
2918
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002919 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
2920 // buffer offset.
2921 if (IsAtomicCounter(type.getBasicType()))
2922 {
2923 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
2924 << nameStr << "_offset";
2925 }
2926 else
2927 {
2928 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2929 << ArrayString(type);
2930 }
Olli Etuaho96963162016-03-21 11:54:33 +02002931
2932 // If the structure parameter contains samplers, they need to be passed into the function as
2933 // separate parameters. HLSL doesn't natively support samplers in structs.
2934 if (type.isStructureContainingSamplers())
2935 {
2936 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002937 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002938 std::string namePrefix = "angle";
2939 namePrefix += nameStr.c_str();
2940 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2941 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002942 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002943 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002944 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002945 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2946 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002947 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002948 }
2949 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2950 {
Olli Etuaho96963162016-03-21 11:54:33 +02002951 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002952 out << ", " << QualifierString(qualifier) << " "
2953 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2954 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2955 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2956 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002957 }
2958 else
2959 {
Olli Etuaho96963162016-03-21 11:54:33 +02002960 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002961 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2962 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002963 }
2964 }
2965 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002966}
2967
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002968TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002969{
2970 TString string;
2971
Jamie Madill94bf7f22013-07-08 13:31:15 -04002972 size_t size = type.getObjectSize();
2973 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002974 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002975 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002976
Jamie Madill94bf7f22013-07-08 13:31:15 -04002977 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002978 {
2979 string += ", ";
2980 }
2981 }
2982
daniel@transgaming.comead23042010-04-29 03:35:36 +00002983 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002984}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002985
Olli Etuahobd3cd502017-11-03 15:48:52 +02002986void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002987{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002988 // Array constructors should have been already pruned from the code.
2989 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002990
2991 if (visit == PreVisit)
2992 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002993 TString constructorName;
2994 if (node->getBasicType() == EbtStruct)
2995 {
2996 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2997 }
2998 else
2999 {
3000 constructorName =
3001 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3002 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003003 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003004 }
3005 else if (visit == InVisit)
3006 {
3007 out << ", ";
3008 }
3009 else if (visit == PostVisit)
3010 {
3011 out << ")";
3012 }
3013}
3014
Jamie Madill8c46ab12015-12-07 16:39:19 -05003015const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3016 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003017 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003018{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003019 ASSERT(!type.isArray());
3020
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003021 const TConstantUnion *constUnionIterated = constUnion;
3022
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003023 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003024 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003025 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003026 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003027
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003028 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003029
Jamie Madill98493dd2013-07-08 14:39:03 -04003030 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003031 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003032 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003033 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003034
Jamie Madill98493dd2013-07-08 14:39:03 -04003035 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003036 {
3037 out << ", ";
3038 }
3039 }
3040
3041 out << ")";
3042 }
3043 else
3044 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003045 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003046 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003047
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003048 if (writeType)
3049 {
Jamie Madill033dae62014-06-18 12:56:28 -04003050 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003051 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003052 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003053 if (writeType)
3054 {
3055 out << ")";
3056 }
3057 }
3058
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003059 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003060}
3061
Olli Etuahod68924e2017-01-02 17:34:40 +00003062void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003063{
Olli Etuahod68924e2017-01-02 17:34:40 +00003064 if (visit == PreVisit)
3065 {
3066 const char *opStr = GetOperatorString(op);
3067 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3068 out << "(";
3069 }
3070 else
3071 {
3072 outputTriplet(out, visit, nullptr, ", ", ")");
3073 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003074}
3075
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003076bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3077 TIntermSymbol *symbolNode,
3078 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003079{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003080 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3081 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003082
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003083 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003084 {
3085 // Type already printed
3086 out << "t" + str(mUniqueIndex) + " = ";
3087 expression->traverse(this);
3088 out << ", ";
3089 symbolNode->traverse(this);
3090 out << " = t" + str(mUniqueIndex);
3091
3092 mUniqueIndex++;
3093 return true;
3094 }
3095
3096 return false;
3097}
3098
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003099bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3100 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003101 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003102{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003103 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003104 {
3105 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003106 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003107 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003108 writeConstantUnionArray(out, initializer->getConstantValue(),
3109 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003110 out << "}";
3111 return true;
3112 }
3113 return false;
3114}
3115
Jamie Madill55e79e02015-02-09 15:35:00 -05003116TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3117{
3118 const TFieldList &fields = structure.fields();
3119
3120 for (const auto &eqFunction : mStructEqualityFunctions)
3121 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003122 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003123 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003124 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003125 }
3126 }
3127
3128 const TString &structNameString = StructNameString(structure);
3129
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003130 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003131 function->structure = &structure;
3132 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003133
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003134 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003135
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003136 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3137 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003138 << "{\n"
3139 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003140
3141 for (size_t i = 0; i < fields.size(); i++)
3142 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003143 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003144 const TType *fieldType = field->type();
3145
3146 const TString &fieldNameA = "a." + Decorate(field->name());
3147 const TString &fieldNameB = "b." + Decorate(field->name());
3148
3149 if (i > 0)
3150 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003151 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003152 }
3153
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003154 fnOut << "(";
3155 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3156 fnOut << fieldNameA;
3157 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3158 fnOut << fieldNameB;
3159 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3160 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003161 }
3162
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003163 fnOut << ";\n"
3164 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003165
3166 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003167
3168 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003169 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003170
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003171 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003172}
3173
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003174TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003175{
3176 for (const auto &eqFunction : mArrayEqualityFunctions)
3177 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003178 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003179 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003180 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003181 }
3182 }
3183
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003184 TType elementType(type);
3185 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003186
Olli Etuaho12690762015-03-31 12:55:28 +03003187 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003188 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003189
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003190 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003191
3192 TInfoSinkBase fnOut;
3193
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003194 const TString &typeName = TypeString(type);
3195 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3196 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003197 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003198 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003199 << type.getOutermostArraySize()
3200 << "; ++i)\n"
3201 " {\n"
3202 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003203
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003204 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003205 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003206 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003207 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003208 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003209
3210 fnOut << ") { return false; }\n"
3211 " }\n"
3212 " return true;\n"
3213 "}\n";
3214
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003215 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003216
3217 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003218 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003219
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003220 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003221}
3222
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003223TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003224{
3225 for (const auto &assignFunction : mArrayAssignmentFunctions)
3226 {
3227 if (assignFunction.type == type)
3228 {
3229 return assignFunction.functionName;
3230 }
3231 }
3232
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003233 TType elementType(type);
3234 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003235
3236 ArrayHelperFunction function;
3237 function.type = type;
3238
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003239 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003240
3241 TInfoSinkBase fnOut;
3242
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003243 const TString &typeName = TypeString(type);
3244 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3245 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003246 << "{\n"
3247 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003248 << type.getOutermostArraySize()
3249 << "; ++i)\n"
3250 " {\n"
3251 " ";
3252
3253 outputAssign(PreVisit, elementType, fnOut);
3254 fnOut << "a[i]";
3255 outputAssign(InVisit, elementType, fnOut);
3256 fnOut << "b[i]";
3257 outputAssign(PostVisit, elementType, fnOut);
3258
3259 fnOut << ";\n"
3260 " }\n"
3261 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003262
3263 function.functionDefinition = fnOut.c_str();
3264
3265 mArrayAssignmentFunctions.push_back(function);
3266
3267 return function.functionName;
3268}
3269
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003270TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003271{
3272 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3273 {
3274 if (constructIntoFunction.type == type)
3275 {
3276 return constructIntoFunction.functionName;
3277 }
3278 }
3279
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003280 TType elementType(type);
3281 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003282
3283 ArrayHelperFunction function;
3284 function.type = type;
3285
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003286 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003287
3288 TInfoSinkBase fnOut;
3289
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003290 const TString &typeName = TypeString(type);
3291 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3292 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003293 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003294 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003295 }
3296 fnOut << ")\n"
3297 "{\n";
3298
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003299 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003300 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003301 fnOut << " ";
3302 outputAssign(PreVisit, elementType, fnOut);
3303 fnOut << "a[" << i << "]";
3304 outputAssign(InVisit, elementType, fnOut);
3305 fnOut << "b" << i;
3306 outputAssign(PostVisit, elementType, fnOut);
3307 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003308 }
3309 fnOut << "}\n";
3310
3311 function.functionDefinition = fnOut.c_str();
3312
3313 mArrayConstructIntoFunctions.push_back(function);
3314
3315 return function.functionName;
3316}
3317
Jamie Madill2e295e22015-04-29 10:41:33 -04003318void OutputHLSL::ensureStructDefined(const TType &type)
3319{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003320 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003321 if (structure)
3322 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003323 ASSERT(type.getBasicType() == EbtStruct);
3324 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003325 }
3326}
3327
Olli Etuaho06235df2018-07-20 14:26:07 +03003328bool OutputHLSL::shaderNeedsGenerateOutput() const
3329{
3330 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3331}
3332
3333const char *OutputHLSL::generateOutputCall() const
3334{
3335 if (mShaderType == GL_VERTEX_SHADER)
3336 {
3337 return "generateOutput(input)";
3338 }
3339 else
3340 {
3341 return "generateOutput()";
3342 }
3343}
3344
Jamie Madill45bcc782016-11-07 13:58:48 -05003345} // namespace sh