blob: fee56a4e16b388063f76859f6b9365149a492efd [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());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08002031 // We don't initialize shared variables because:
2032 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
2033 // code to initialize a groupshared array variable with a large array size.
2034 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
2035 // allow initializing shared variables at all.
2036 if (declarator->getQualifier() != EvqShared)
2037 {
2038 out << " = " + zeroInitializer(symbol->getType());
2039 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002040 }
2041 else
2042 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002043 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002044 }
2045 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002046 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002047 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002048 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002049 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002050 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002051
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002052 const TVariable &variable = symbol->variable();
2053
2054 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002055 {
2056 // Vertex outputs which are declared but not written to should still be declared to
2057 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002058 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002059 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002060 }
2061 }
2062 return false;
2063}
2064
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002065bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2066{
2067 // Do not do any translation
2068 return false;
2069}
2070
Olli Etuahod4bd9632018-03-08 16:32:44 +02002071void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002072{
2073 TInfoSinkBase &out = getInfoSink();
2074
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002075 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002076 // Skip the prototype if it is not implemented (and thus not used)
2077 if (index == CallDAG::InvalidIndex)
2078 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002079 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002080 }
2081
Olli Etuahod4bd9632018-03-08 16:32:44 +02002082 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002083
Olli Etuahod4bd9632018-03-08 16:32:44 +02002084 TString name = DecorateFunctionIfNeeded(func);
2085 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002086 << (mOutputLod0Function ? "Lod0(" : "(");
2087
Olli Etuahod4bd9632018-03-08 16:32:44 +02002088 size_t paramCount = func->getParamCount();
2089 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002090 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002091 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002092
Olli Etuahod4bd9632018-03-08 16:32:44 +02002093 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002094 {
2095 out << ", ";
2096 }
2097 }
2098
2099 out << ");\n";
2100
2101 // Also prototype the Lod0 variant if needed
2102 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2103 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2104 {
2105 mOutputLod0Function = true;
2106 node->traverse(this);
2107 mOutputLod0Function = false;
2108 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002109}
2110
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002111bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2112{
Jamie Madill32aab012015-01-27 14:12:26 -05002113 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002114
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002115 switch (node->getOp())
2116 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002117 case EOpCallBuiltInFunction:
2118 case EOpCallFunctionInAST:
2119 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002120 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002121 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002122
Corentin Wallez1239ee92015-03-19 14:38:02 -07002123 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002124 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002125 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002126 if (node->isArray())
2127 {
2128 UNIMPLEMENTED();
2129 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002130 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002131 ASSERT(index != CallDAG::InvalidIndex);
2132 lod0 &= mASTMetadataList[index].mNeedsLod0;
2133
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002134 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002135 out << DisambiguateFunctionName(node->getSequence());
2136 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002137 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002138 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002139 {
2140 // This path is used for internal functions that don't have their definitions in the
2141 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002142 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002143 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002144 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002145 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002146 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002147 TType type = (*arguments)[0]->getAsTyped()->getType();
2148 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002149 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002150 type.getMemoryQualifier().readonly);
2151 out << imageFunctionName << "(";
2152 }
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002153 else if (node->getFunction()->isAtomicCounterFunction())
2154 {
2155 const ImmutableString &name = node->getFunction()->name();
2156 ImmutableString atomicFunctionName =
2157 mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2158 out << atomicFunctionName << "(";
2159 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002160 else
2161 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002162 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002163 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002164 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2165 if (arguments->size() > 1)
2166 {
2167 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2168 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002169 const ImmutableString &textureFunctionName =
2170 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2171 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002172 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002173 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002174
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002175 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002176 {
Olli Etuaho96963162016-03-21 11:54:33 +02002177 TIntermTyped *typedArg = (*arg)->getAsTyped();
2178 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002179 {
2180 out << "texture_";
2181 (*arg)->traverse(this);
2182 out << ", sampler_";
2183 }
2184
2185 (*arg)->traverse(this);
2186
Olli Etuaho96963162016-03-21 11:54:33 +02002187 if (typedArg->getType().isStructureContainingSamplers())
2188 {
2189 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002190 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002191 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2192 std::string namePrefix = "angle_";
2193 namePrefix += structName.data();
2194 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002195 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002196 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002197 {
2198 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2199 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002200 out << ", texture_" << sampler->name();
2201 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002202 }
2203 else
2204 {
2205 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2206 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002207 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002208 }
2209 }
2210 }
2211
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002212 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002213 {
2214 out << ", ";
2215 }
2216 }
2217
2218 out << ")";
2219
2220 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002221 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002222 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002223 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002224 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002225 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002226 outputTriplet(out, visit, "(", " == ", ")");
2227 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002228 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002229 outputTriplet(out, visit, "(", " != ", ")");
2230 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002231 case EOpLessThanComponentWise:
2232 outputTriplet(out, visit, "(", " < ", ")");
2233 break;
2234 case EOpGreaterThanComponentWise:
2235 outputTriplet(out, visit, "(", " > ", ")");
2236 break;
2237 case EOpLessThanEqualComponentWise:
2238 outputTriplet(out, visit, "(", " <= ", ")");
2239 break;
2240 case EOpGreaterThanEqualComponentWise:
2241 outputTriplet(out, visit, "(", " >= ", ")");
2242 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002243 case EOpMod:
2244 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002245 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002246 break;
2247 case EOpModf:
2248 outputTriplet(out, visit, "modf(", ", ", ")");
2249 break;
2250 case EOpPow:
2251 outputTriplet(out, visit, "pow(", ", ", ")");
2252 break;
2253 case EOpAtan:
2254 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2255 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002256 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002257 break;
2258 case EOpMin:
2259 outputTriplet(out, visit, "min(", ", ", ")");
2260 break;
2261 case EOpMax:
2262 outputTriplet(out, visit, "max(", ", ", ")");
2263 break;
2264 case EOpClamp:
2265 outputTriplet(out, visit, "clamp(", ", ", ")");
2266 break;
2267 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302268 {
2269 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2270 if (lastParamNode->getType().getBasicType() == EbtBool)
2271 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002272 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2273 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302274 // so use emulated version.
2275 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002276 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302277 }
2278 else
2279 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002280 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302281 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002282 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302283 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002284 case EOpStep:
2285 outputTriplet(out, visit, "step(", ", ", ")");
2286 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002287 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002288 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2289 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002290 case EOpFrexp:
2291 case EOpLdexp:
2292 ASSERT(node->getUseEmulatedFunction());
2293 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2294 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002295 case EOpDistance:
2296 outputTriplet(out, visit, "distance(", ", ", ")");
2297 break;
2298 case EOpDot:
2299 outputTriplet(out, visit, "dot(", ", ", ")");
2300 break;
2301 case EOpCross:
2302 outputTriplet(out, visit, "cross(", ", ", ")");
2303 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002304 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002305 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002306 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002307 break;
2308 case EOpReflect:
2309 outputTriplet(out, visit, "reflect(", ", ", ")");
2310 break;
2311 case EOpRefract:
2312 outputTriplet(out, visit, "refract(", ", ", ")");
2313 break;
2314 case EOpOuterProduct:
2315 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002316 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002317 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002318 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002319 outputTriplet(out, visit, "(", " * ", ")");
2320 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002321 case EOpBitfieldExtract:
2322 case EOpBitfieldInsert:
2323 case EOpUaddCarry:
2324 case EOpUsubBorrow:
2325 case EOpUmulExtended:
2326 case EOpImulExtended:
2327 ASSERT(node->getUseEmulatedFunction());
2328 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2329 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002330 case EOpBarrier:
2331 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2332 // cheapest *WithGroupSync() function, without any functionality loss, but
2333 // with the potential for severe performance loss.
2334 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2335 break;
2336 case EOpMemoryBarrierShared:
2337 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2338 break;
2339 case EOpMemoryBarrierAtomicCounter:
2340 case EOpMemoryBarrierBuffer:
2341 case EOpMemoryBarrierImage:
2342 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2343 break;
2344 case EOpGroupMemoryBarrier:
2345 case EOpMemoryBarrier:
2346 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2347 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002348
2349 // Single atomic function calls without return value.
2350 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2351 case EOpAtomicAdd:
2352 case EOpAtomicMin:
2353 case EOpAtomicMax:
2354 case EOpAtomicAnd:
2355 case EOpAtomicOr:
2356 case EOpAtomicXor:
2357 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2358 ",", ")");
2359 break;
2360
2361 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2362 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2363 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2364 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2365 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2366 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2367 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2368 // intermediate tree before traversing outputHLSL.
2369 case EOpAtomicExchange:
2370 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002371 default:
2372 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002373 }
2374
2375 return true;
2376}
2377
Olli Etuaho57961272016-09-14 13:57:46 +03002378void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002379{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002380 out << "if (";
2381
2382 node->getCondition()->traverse(this);
2383
2384 out << ")\n";
2385
Jamie Madill8c46ab12015-12-07 16:39:19 -05002386 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002387
2388 bool discard = false;
2389
2390 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002391 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002392 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002393 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002394
Olli Etuahoa6f22092015-05-08 18:31:10 +03002395 // Detect true discard
2396 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2397 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002398 else
2399 {
2400 // TODO(oetuaho): Check if the semicolon inside is necessary.
2401 // It's there as a result of conservative refactoring of the output.
2402 out << "{;}\n";
2403 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002404
Jamie Madill8c46ab12015-12-07 16:39:19 -05002405 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002406
Olli Etuahoa6f22092015-05-08 18:31:10 +03002407 if (node->getFalseBlock())
2408 {
2409 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002410
Jamie Madill8c46ab12015-12-07 16:39:19 -05002411 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002412
Olli Etuaho32db19b2016-10-04 14:43:16 +01002413 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002414 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002415
Jamie Madill8c46ab12015-12-07 16:39:19 -05002416 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002417
Olli Etuahoa6f22092015-05-08 18:31:10 +03002418 // Detect false discard
2419 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2420 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002421
Olli Etuahoa6f22092015-05-08 18:31:10 +03002422 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002423 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002424 {
2425 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002426 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002427}
2428
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002429bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2430{
2431 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2432 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2433 UNREACHABLE();
2434 return false;
2435}
2436
Olli Etuaho57961272016-09-14 13:57:46 +03002437bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002438{
2439 TInfoSinkBase &out = getInfoSink();
2440
Olli Etuaho3d932d82016-04-12 11:10:30 +03002441 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002442
2443 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002444 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002445 {
2446 out << "FLATTEN ";
2447 }
2448
Olli Etuaho57961272016-09-14 13:57:46 +03002449 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002450
2451 return false;
2452}
2453
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002454bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002455{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002456 TInfoSinkBase &out = getInfoSink();
2457
Olli Etuaho923ecef2017-10-11 12:01:38 +03002458 ASSERT(node->getStatementList());
2459 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002460 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002461 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002462 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002463 outputTriplet(out, visit, "switch (", ") ", "");
2464 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002465 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002466}
2467
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002468bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002469{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002470 TInfoSinkBase &out = getInfoSink();
2471
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002472 if (node->hasCondition())
2473 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002474 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002475 return true;
2476 }
2477 else
2478 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002479 out << "default:\n";
2480 return false;
2481 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002482}
2483
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002484void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2485{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002486 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002487 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002488}
2489
2490bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2491{
Nicolas Capens655fe362014-04-11 13:12:34 -04002492 mNestedLoopDepth++;
2493
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002494 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002495 mInsideDiscontinuousLoop =
2496 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002497
Jamie Madill8c46ab12015-12-07 16:39:19 -05002498 TInfoSinkBase &out = getInfoSink();
2499
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002500 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002501 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002502 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002503 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002504 mInsideDiscontinuousLoop = wasDiscontinuous;
2505 mNestedLoopDepth--;
2506
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002507 return false;
2508 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002509 }
2510
Corentin Wallez1239ee92015-03-19 14:38:02 -07002511 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002512 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002513 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002514 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002515
Jamie Madill8c46ab12015-12-07 16:39:19 -05002516 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002517 }
2518 else
2519 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002520 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002521
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002522 if (node->getInit())
2523 {
2524 node->getInit()->traverse(this);
2525 }
2526
2527 out << "; ";
2528
alokp@chromium.org52813552010-11-16 18:36:09 +00002529 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002530 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002531 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002532 }
2533
2534 out << "; ";
2535
alokp@chromium.org52813552010-11-16 18:36:09 +00002536 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002537 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002538 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002539 }
2540
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002541 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002542
Jamie Madill8c46ab12015-12-07 16:39:19 -05002543 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002544 }
2545
2546 if (node->getBody())
2547 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002548 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002549 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002550 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002551 else
2552 {
2553 // TODO(oetuaho): Check if the semicolon inside is necessary.
2554 // It's there as a result of conservative refactoring of the output.
2555 out << "{;}\n";
2556 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002557
Jamie Madill8c46ab12015-12-07 16:39:19 -05002558 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002559
alokp@chromium.org52813552010-11-16 18:36:09 +00002560 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002561 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002562 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002563 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002564
alokp@chromium.org52813552010-11-16 18:36:09 +00002565 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002566
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002567 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002568 }
2569
daniel@transgaming.com73536982012-03-21 20:45:49 +00002570 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002571
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002572 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002573 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002574
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002575 return false;
2576}
2577
2578bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2579{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002580 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002581 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002582 TInfoSinkBase &out = getInfoSink();
2583
2584 switch (node->getFlowOp())
2585 {
2586 case EOpKill:
2587 out << "discard";
2588 break;
2589 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002590 if (mNestedLoopDepth > 1)
2591 {
2592 mUsesNestedBreak = true;
2593 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002594
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002595 if (mExcessiveLoopIndex)
2596 {
2597 out << "{Break";
2598 mExcessiveLoopIndex->traverse(this);
2599 out << " = true; break;}\n";
2600 }
2601 else
2602 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002603 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002604 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002605 break;
2606 case EOpContinue:
2607 out << "continue";
2608 break;
2609 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002610 if (node->getExpression())
2611 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002612 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002613 out << "return ";
2614 }
2615 else
2616 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002617 if (mInsideMain && shaderNeedsGenerateOutput())
2618 {
2619 out << "return " << generateOutputCall();
2620 }
2621 else
2622 {
2623 out << "return";
2624 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002625 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002626 break;
2627 default:
2628 UNREACHABLE();
2629 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002630 }
2631
2632 return true;
2633}
2634
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002635// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002636// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2637// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002638bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002639{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002640 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002641
2642 // Parse loops of the form:
2643 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002644 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002645 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002646 int initial = 0;
2647 int limit = 0;
2648 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002649
2650 // Parse index name and intial value
2651 if (node->getInit())
2652 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002653 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002654
2655 if (init)
2656 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002657 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002658 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002659
2660 if (variable && variable->getQualifier() == EvqTemporary)
2661 {
2662 TIntermBinary *assign = variable->getAsBinaryNode();
2663
2664 if (assign->getOp() == EOpInitialize)
2665 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002666 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002667 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2668
2669 if (symbol && constant)
2670 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002671 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002672 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002673 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002674 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002675 }
2676 }
2677 }
2678 }
2679 }
2680 }
2681
2682 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002683 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002684 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002685 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002686
Olli Etuahob6af22b2017-12-15 14:05:44 +02002687 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002688 {
2689 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2690
2691 if (constant)
2692 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002693 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002694 {
2695 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002696 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002697 }
2698 }
2699 }
2700 }
2701
2702 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002703 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002704 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002705 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002706 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002707
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002708 if (binaryTerminal)
2709 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002710 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002711 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2712
2713 if (constant)
2714 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002715 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002716 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002717 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002718
2719 switch (op)
2720 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002721 case EOpAddAssign:
2722 increment = value;
2723 break;
2724 case EOpSubAssign:
2725 increment = -value;
2726 break;
2727 default:
2728 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002729 }
2730 }
2731 }
2732 }
2733 else if (unaryTerminal)
2734 {
2735 TOperator op = unaryTerminal->getOp();
2736
2737 switch (op)
2738 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002739 case EOpPostIncrement:
2740 increment = 1;
2741 break;
2742 case EOpPostDecrement:
2743 increment = -1;
2744 break;
2745 case EOpPreIncrement:
2746 increment = 1;
2747 break;
2748 case EOpPreDecrement:
2749 increment = -1;
2750 break;
2751 default:
2752 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002753 }
2754 }
2755 }
2756
Yunchao He4f285442017-04-21 12:15:49 +08002757 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002758 {
2759 if (comparator == EOpLessThanEqual)
2760 {
2761 comparator = EOpLessThan;
2762 limit += 1;
2763 }
2764
2765 if (comparator == EOpLessThan)
2766 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002767 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002768
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002769 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002770 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002771 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002772 }
2773
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002774 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002775 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002776
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002777 out << "{int ";
2778 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002779 out << ";\n"
2780 "bool Break";
2781 index->traverse(this);
2782 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002783
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002784 bool firstLoopFragment = true;
2785
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002786 while (iterations > 0)
2787 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002788 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002789
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002790 if (!firstLoopFragment)
2791 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002792 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002793 index->traverse(this);
2794 out << ") {\n";
2795 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002796
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002797 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002798 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002799 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002800 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002801
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002802 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002803 const char *unroll =
2804 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002805
Corentin Wallez1239ee92015-03-19 14:38:02 -07002806 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002807 index->traverse(this);
2808 out << " = ";
2809 out << initial;
2810
2811 out << "; ";
2812 index->traverse(this);
2813 out << " < ";
2814 out << clampedLimit;
2815
2816 out << "; ";
2817 index->traverse(this);
2818 out << " += ";
2819 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002820 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002821
Jamie Madill8c46ab12015-12-07 16:39:19 -05002822 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002823 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002824
2825 if (node->getBody())
2826 {
2827 node->getBody()->traverse(this);
2828 }
2829
Jamie Madill8c46ab12015-12-07 16:39:19 -05002830 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002831 out << ";}\n";
2832
2833 if (!firstLoopFragment)
2834 {
2835 out << "}\n";
2836 }
2837
2838 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002839
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002840 initial += MAX_LOOP_ITERATIONS * increment;
2841 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002842 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002843
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002844 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002845
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002846 mExcessiveLoopIndex = restoreIndex;
2847
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002848 return true;
2849 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002850 else
2851 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002852 }
2853
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002854 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002855}
2856
Jamie Madill8c46ab12015-12-07 16:39:19 -05002857void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2858 Visit visit,
2859 const char *preString,
2860 const char *inString,
2861 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002862{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002863 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002864 {
2865 out << preString;
2866 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002867 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002868 {
2869 out << inString;
2870 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002871 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002872 {
2873 out << postString;
2874 }
2875}
2876
Jamie Madill8c46ab12015-12-07 16:39:19 -05002877void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002878{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002879 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002880 {
Jamie Madill32aab012015-01-27 14:12:26 -05002881 out << "\n";
2882 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002883
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002884 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002885 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002886 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002887 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002888
Jamie Madill32aab012015-01-27 14:12:26 -05002889 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002890 }
2891}
2892
Olli Etuahod4bd9632018-03-08 16:32:44 +02002893void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002894{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002895 const TType &type = param->getType();
2896 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002897
Olli Etuahod4bd9632018-03-08 16:32:44 +02002898 TString nameStr = DecorateVariableIfNeeded(*param);
2899 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002900
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002901 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002902 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002903 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2904 {
2905 // Samplers are passed as indices to the sampler array.
2906 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002907 out << "const uint " << nameStr << ArrayString(type);
2908 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002909 }
2910 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2911 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002912 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2913 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2914 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2915 << ArrayString(type);
2916 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002917 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002918 }
2919
Brandon Jones4a22f4b2018-10-23 14:36:47 -07002920 // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
2921 // buffer offset.
2922 if (IsAtomicCounter(type.getBasicType()))
2923 {
2924 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
2925 << nameStr << "_offset";
2926 }
2927 else
2928 {
2929 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2930 << ArrayString(type);
2931 }
Olli Etuaho96963162016-03-21 11:54:33 +02002932
2933 // If the structure parameter contains samplers, they need to be passed into the function as
2934 // separate parameters. HLSL doesn't natively support samplers in structs.
2935 if (type.isStructureContainingSamplers())
2936 {
2937 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002938 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002939 std::string namePrefix = "angle";
2940 namePrefix += nameStr.c_str();
2941 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2942 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002943 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002944 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002945 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002946 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2947 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002948 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002949 }
2950 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2951 {
Olli Etuaho96963162016-03-21 11:54:33 +02002952 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002953 out << ", " << QualifierString(qualifier) << " "
2954 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2955 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2956 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2957 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002958 }
2959 else
2960 {
Olli Etuaho96963162016-03-21 11:54:33 +02002961 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002962 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2963 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002964 }
2965 }
2966 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002967}
2968
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002969TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002970{
2971 TString string;
2972
Jamie Madill94bf7f22013-07-08 13:31:15 -04002973 size_t size = type.getObjectSize();
2974 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002975 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002976 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002977
Jamie Madill94bf7f22013-07-08 13:31:15 -04002978 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002979 {
2980 string += ", ";
2981 }
2982 }
2983
daniel@transgaming.comead23042010-04-29 03:35:36 +00002984 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002985}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002986
Olli Etuahobd3cd502017-11-03 15:48:52 +02002987void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002988{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002989 // Array constructors should have been already pruned from the code.
2990 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002991
2992 if (visit == PreVisit)
2993 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002994 TString constructorName;
2995 if (node->getBasicType() == EbtStruct)
2996 {
2997 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2998 }
2999 else
3000 {
3001 constructorName =
3002 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3003 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02003004 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003005 }
3006 else if (visit == InVisit)
3007 {
3008 out << ", ";
3009 }
3010 else if (visit == PostVisit)
3011 {
3012 out << ")";
3013 }
3014}
3015
Jamie Madill8c46ab12015-12-07 16:39:19 -05003016const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3017 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003018 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003019{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003020 ASSERT(!type.isArray());
3021
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003022 const TConstantUnion *constUnionIterated = constUnion;
3023
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003024 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04003025 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003026 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003027 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003028
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003029 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003030
Jamie Madill98493dd2013-07-08 14:39:03 -04003031 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003032 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003033 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003034 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003035
Jamie Madill98493dd2013-07-08 14:39:03 -04003036 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003037 {
3038 out << ", ";
3039 }
3040 }
3041
3042 out << ")";
3043 }
3044 else
3045 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003046 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003047 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003048
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003049 if (writeType)
3050 {
Jamie Madill033dae62014-06-18 12:56:28 -04003051 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003052 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00003053 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003054 if (writeType)
3055 {
3056 out << ")";
3057 }
3058 }
3059
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003060 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003061}
3062
Olli Etuahod68924e2017-01-02 17:34:40 +00003063void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003064{
Olli Etuahod68924e2017-01-02 17:34:40 +00003065 if (visit == PreVisit)
3066 {
3067 const char *opStr = GetOperatorString(op);
3068 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3069 out << "(";
3070 }
3071 else
3072 {
3073 outputTriplet(out, visit, nullptr, ", ", ")");
3074 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003075}
3076
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003077bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3078 TIntermSymbol *symbolNode,
3079 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003080{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003081 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3082 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003083
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003084 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003085 {
3086 // Type already printed
3087 out << "t" + str(mUniqueIndex) + " = ";
3088 expression->traverse(this);
3089 out << ", ";
3090 symbolNode->traverse(this);
3091 out << " = t" + str(mUniqueIndex);
3092
3093 mUniqueIndex++;
3094 return true;
3095 }
3096
3097 return false;
3098}
3099
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003100bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3101 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003102 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003103{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003104 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003105 {
3106 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003107 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003108 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003109 writeConstantUnionArray(out, initializer->getConstantValue(),
3110 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003111 out << "}";
3112 return true;
3113 }
3114 return false;
3115}
3116
Jamie Madill55e79e02015-02-09 15:35:00 -05003117TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3118{
3119 const TFieldList &fields = structure.fields();
3120
3121 for (const auto &eqFunction : mStructEqualityFunctions)
3122 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003123 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003124 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003125 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003126 }
3127 }
3128
3129 const TString &structNameString = StructNameString(structure);
3130
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003131 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003132 function->structure = &structure;
3133 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003134
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003135 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003136
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003137 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3138 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003139 << "{\n"
3140 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003141
3142 for (size_t i = 0; i < fields.size(); i++)
3143 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003144 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003145 const TType *fieldType = field->type();
3146
3147 const TString &fieldNameA = "a." + Decorate(field->name());
3148 const TString &fieldNameB = "b." + Decorate(field->name());
3149
3150 if (i > 0)
3151 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003152 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003153 }
3154
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003155 fnOut << "(";
3156 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3157 fnOut << fieldNameA;
3158 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3159 fnOut << fieldNameB;
3160 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3161 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003162 }
3163
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003164 fnOut << ";\n"
3165 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003166
3167 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003168
3169 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003170 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003171
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003172 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003173}
3174
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003175TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003176{
3177 for (const auto &eqFunction : mArrayEqualityFunctions)
3178 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003179 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003180 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003181 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003182 }
3183 }
3184
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003185 TType elementType(type);
3186 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003187
Olli Etuaho12690762015-03-31 12:55:28 +03003188 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003189 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003190
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003191 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003192
3193 TInfoSinkBase fnOut;
3194
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003195 const TString &typeName = TypeString(type);
3196 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3197 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003198 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003199 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003200 << type.getOutermostArraySize()
3201 << "; ++i)\n"
3202 " {\n"
3203 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003204
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003205 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003206 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003207 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003208 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003209 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003210
3211 fnOut << ") { return false; }\n"
3212 " }\n"
3213 " return true;\n"
3214 "}\n";
3215
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003216 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003217
3218 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003219 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003220
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003221 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003222}
3223
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003224TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003225{
3226 for (const auto &assignFunction : mArrayAssignmentFunctions)
3227 {
3228 if (assignFunction.type == type)
3229 {
3230 return assignFunction.functionName;
3231 }
3232 }
3233
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003234 TType elementType(type);
3235 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003236
3237 ArrayHelperFunction function;
3238 function.type = type;
3239
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003240 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003241
3242 TInfoSinkBase fnOut;
3243
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003244 const TString &typeName = TypeString(type);
3245 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3246 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003247 << "{\n"
3248 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003249 << type.getOutermostArraySize()
3250 << "; ++i)\n"
3251 " {\n"
3252 " ";
3253
3254 outputAssign(PreVisit, elementType, fnOut);
3255 fnOut << "a[i]";
3256 outputAssign(InVisit, elementType, fnOut);
3257 fnOut << "b[i]";
3258 outputAssign(PostVisit, elementType, fnOut);
3259
3260 fnOut << ";\n"
3261 " }\n"
3262 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003263
3264 function.functionDefinition = fnOut.c_str();
3265
3266 mArrayAssignmentFunctions.push_back(function);
3267
3268 return function.functionName;
3269}
3270
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003271TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003272{
3273 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3274 {
3275 if (constructIntoFunction.type == type)
3276 {
3277 return constructIntoFunction.functionName;
3278 }
3279 }
3280
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003281 TType elementType(type);
3282 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003283
3284 ArrayHelperFunction function;
3285 function.type = type;
3286
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003287 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003288
3289 TInfoSinkBase fnOut;
3290
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003291 const TString &typeName = TypeString(type);
3292 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3293 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003294 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003295 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003296 }
3297 fnOut << ")\n"
3298 "{\n";
3299
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003300 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003301 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003302 fnOut << " ";
3303 outputAssign(PreVisit, elementType, fnOut);
3304 fnOut << "a[" << i << "]";
3305 outputAssign(InVisit, elementType, fnOut);
3306 fnOut << "b" << i;
3307 outputAssign(PostVisit, elementType, fnOut);
3308 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003309 }
3310 fnOut << "}\n";
3311
3312 function.functionDefinition = fnOut.c_str();
3313
3314 mArrayConstructIntoFunctions.push_back(function);
3315
3316 return function.functionName;
3317}
3318
Jamie Madill2e295e22015-04-29 10:41:33 -04003319void OutputHLSL::ensureStructDefined(const TType &type)
3320{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003321 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003322 if (structure)
3323 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003324 ASSERT(type.getBasicType() == EbtStruct);
3325 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003326 }
3327}
3328
Olli Etuaho06235df2018-07-20 14:26:07 +03003329bool OutputHLSL::shaderNeedsGenerateOutput() const
3330{
3331 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3332}
3333
3334const char *OutputHLSL::generateOutputCall() const
3335{
3336 if (mShaderType == GL_VERTEX_SHADER)
3337 {
3338 return "generateOutput(input)";
3339 }
3340 else
3341 {
3342 return "generateOutput()";
3343 }
3344}
3345
Jamie Madill45bcc782016-11-07 13:58:48 -05003346} // namespace sh