blob: 457f412c4034c3059a52237e6645222e847c9127 [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"
Olli Etuaho8efc5ad2015-03-03 17:21:10 +020016#include "compiler/translator/BuiltInFunctionEmulator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050017#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
Xinghua Cao711b7a12017-10-09 13:38:12 +080018#include "compiler/translator/ImageFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/InfoSink.h"
Qin Jiajia3e217f62018-08-28 16:55:20 +080020#include "compiler/translator/ResourcesHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050021#include "compiler/translator/StructureHLSL.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030022#include "compiler/translator/TextureFunctionHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050023#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050024#include "compiler/translator/UtilsHLSL.h"
25#include "compiler/translator/blocklayout.h"
Olli Etuahoa07b4212018-03-22 16:13:13 +020026#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +020027#include "compiler/translator/tree_util/FindSymbolNode.h"
28#include "compiler/translator/tree_util/NodeSearch.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050029#include "compiler/translator/util.h"
30
Jamie Madill45bcc782016-11-07 13:58:48 -050031namespace sh
32{
33
Olli Etuaho96f6adf2017-08-16 11:18:54 +030034namespace
35{
36
37TString ArrayHelperFunctionName(const char *prefix, const TType &type)
38{
39 TStringStream fnName;
40 fnName << prefix << "_";
Kai Ninomiya57ea5332017-11-22 14:04:48 -080041 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +030042 {
Kai Ninomiya57ea5332017-11-22 14:04:48 -080043 for (unsigned int arraySize : *type.getArraySizes())
44 {
45 fnName << arraySize << "_";
46 }
Olli Etuaho96f6adf2017-08-16 11:18:54 +030047 }
48 fnName << TypeString(type);
49 return fnName.str();
50}
51
Olli Etuaho40dbdd62017-10-13 13:34:19 +030052bool IsDeclarationWrittenOut(TIntermDeclaration *node)
53{
54 TIntermSequence *sequence = node->getSequence();
55 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
56 ASSERT(sequence->size() == 1);
57 ASSERT(variable);
58 return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080059 variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
Olli Etuaho40dbdd62017-10-13 13:34:19 +030060}
61
Qin Jiajiaa735ee22018-05-18 13:29:09 +080062bool IsInStd140UniformBlock(TIntermTyped *node)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020063{
64 TIntermBinary *binaryNode = node->getAsBinaryNode();
65
66 if (binaryNode)
67 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080068 return IsInStd140UniformBlock(binaryNode->getLeft());
Olli Etuaho2ef23e22017-11-01 16:39:11 +020069 }
70
71 const TType &type = node->getType();
72
Qin Jiajiaa735ee22018-05-18 13:29:09 +080073 if (type.getQualifier() == EvqUniform)
Olli Etuaho2ef23e22017-11-01 16:39:11 +020074 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +080075 // determine if we are in the standard layout
76 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
77 if (interfaceBlock)
78 {
79 return (interfaceBlock->blockStorage() == EbsStd140);
80 }
Olli Etuaho2ef23e22017-11-01 16:39:11 +020081 }
82
83 return false;
84}
85
Jiawei Shaoa6a78422018-06-28 08:32:54 +080086const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
87{
88 switch (op)
89 {
90 case EOpAtomicAdd:
91 return "InterlockedAdd(";
92 case EOpAtomicMin:
93 return "InterlockedMin(";
94 case EOpAtomicMax:
95 return "InterlockedMax(";
96 case EOpAtomicAnd:
97 return "InterlockedAnd(";
98 case EOpAtomicOr:
99 return "InterlockedOr(";
100 case EOpAtomicXor:
101 return "InterlockedXor(";
102 case EOpAtomicExchange:
103 return "InterlockedExchange(";
104 case EOpAtomicCompSwap:
105 return "InterlockedCompareExchange(";
106 default:
107 UNREACHABLE();
108 return "";
109 }
110}
111
112bool IsAtomicFunctionDirectAssign(const TIntermBinary &node)
113{
114 return node.getOp() == EOpAssign && node.getRight()->getAsAggregate() &&
115 IsAtomicFunction(node.getRight()->getAsAggregate()->getOp());
116}
117
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300118} // anonymous namespace
119
Olli Etuahoc71862a2017-12-21 12:58:29 +0200120TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
121 const TVariable *aInstanceVariable)
122 : block(aBlock), instanceVariable(aInstanceVariable)
123{
124}
125
Olli Etuaho56a2f952016-12-08 12:16:27 +0000126void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
Olli Etuaho4785fec2015-05-18 16:09:37 +0300127{
Olli Etuaho56a2f952016-12-08 12:16:27 +0000128 // This is known not to work for NaN on all drivers but make the best effort to output NaNs
129 // regardless.
130 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
131 mOutputType == SH_HLSL_4_1_OUTPUT)
132 {
133 out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
134 }
135 else
136 {
137 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
138 }
139}
Olli Etuaho4785fec2015-05-18 16:09:37 +0300140
Olli Etuaho56a2f952016-12-08 12:16:27 +0000141void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200142{
143 ASSERT(constUnion != nullptr);
144 switch (constUnion->getType())
145 {
146 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000147 writeFloat(out, constUnion->getFConst());
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200148 break;
149 case EbtInt:
150 out << constUnion->getIConst();
151 break;
152 case EbtUInt:
153 out << constUnion->getUConst();
154 break;
155 case EbtBool:
156 out << constUnion->getBConst();
157 break;
158 default:
159 UNREACHABLE();
160 }
161}
162
Olli Etuaho56a2f952016-12-08 12:16:27 +0000163const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
164 const TConstantUnion *const constUnion,
165 const size_t size)
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200166{
167 const TConstantUnion *constUnionIterated = constUnion;
168 for (size_t i = 0; i < size; i++, constUnionIterated++)
169 {
Olli Etuaho56a2f952016-12-08 12:16:27 +0000170 writeSingleConstant(out, constUnionIterated);
Olli Etuaho18b9deb2015-11-05 12:14:50 +0200171
172 if (i != size - 1)
173 {
174 out << ", ";
175 }
176 }
177 return constUnionIterated;
178}
179
Qiankun Miao7ebb97f2016-09-08 18:01:50 +0800180OutputHLSL::OutputHLSL(sh::GLenum shaderType,
181 int shaderVersion,
182 const TExtensionBehavior &extensionBehavior,
183 const char *sourcePath,
184 ShShaderOutput outputType,
185 int numRenderTargets,
186 const std::vector<Uniform> &uniforms,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300187 ShCompileOptions compileOptions,
Olli Etuaho06235df2018-07-20 14:26:07 +0300188 sh::WorkGroupSize workGroupSize,
Olli Etuaho89a69a02017-10-23 12:20:45 +0300189 TSymbolTable *symbolTable,
190 PerformanceDiagnostics *perfDiagnostics)
Olli Etuaho2d88e9b2017-07-21 16:52:03 +0300191 : TIntermTraverser(true, true, true, symbolTable),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200192 mShaderType(shaderType),
193 mShaderVersion(shaderVersion),
194 mExtensionBehavior(extensionBehavior),
195 mSourcePath(sourcePath),
196 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700197 mCompileOptions(compileOptions),
Olli Etuaho06235df2018-07-20 14:26:07 +0300198 mInsideFunction(false),
199 mInsideMain(false),
Sam McNally5a0edc62015-06-30 12:36:07 +1000200 mNumRenderTargets(numRenderTargets),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300201 mCurrentFunctionMetadata(nullptr),
Olli Etuaho06235df2018-07-20 14:26:07 +0300202 mWorkGroupSize(workGroupSize),
Olli Etuaho89a69a02017-10-23 12:20:45 +0300203 mPerfDiagnostics(perfDiagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204{
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800205 mUsesFragColor = false;
206 mUsesFragData = false;
207 mUsesDepthRange = false;
208 mUsesFragCoord = false;
209 mUsesPointCoord = false;
210 mUsesFrontFacing = false;
211 mUsesPointSize = false;
212 mUsesInstanceID = false;
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300213 mHasMultiviewExtensionEnabled =
214 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
Martin Radev41ac68e2017-06-06 12:16:58 +0300215 mUsesViewID = false;
Corentin Wallezb076add2016-01-11 16:45:46 -0500216 mUsesVertexID = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500217 mUsesFragDepth = false;
Xinghua Caob1239382016-12-13 15:07:05 +0800218 mUsesNumWorkGroups = false;
219 mUsesWorkGroupID = false;
220 mUsesLocalInvocationID = false;
221 mUsesGlobalInvocationID = false;
222 mUsesLocalInvocationIndex = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500223 mUsesXor = false;
224 mUsesDiscardRewriting = false;
225 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530226 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000227
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000228 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000229
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500230 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000231 mInsideDiscontinuousLoop = false;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500232 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000233
Yunchao Hed7297bf2017-04-19 15:27:10 +0800234 mExcessiveLoopIndex = nullptr;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000235
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500236 mStructureHLSL = new StructureHLSL;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300237 mTextureFunctionHLSL = new TextureFunctionHLSL;
Xinghua Cao711b7a12017-10-09 13:38:12 +0800238 mImageFunctionHLSL = new ImageFunctionHLSL;
Jamie Madill8daaba12014-06-13 10:04:33 -0400239
Olli Etuahod8724a92017-12-29 18:40:36 +0200240 unsigned int firstUniformRegister =
241 ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
Qin Jiajia3e217f62018-08-28 16:55:20 +0800242 mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
Olli Etuahod8724a92017-12-29 18:40:36 +0200243
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200244 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000245 {
Arun Patole63419392015-03-13 11:51:07 +0530246 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500247 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
248 // dx_ViewAdjust.
Arun Patole63419392015-03-13 11:51:07 +0530249 // In both cases total 3 uniform registers need to be reserved.
Qin Jiajia3e217f62018-08-28 16:55:20 +0800250 mResourcesHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000251 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000252
Geoff Lang00140f42016-02-03 18:47:33 +0000253 // Reserve registers for the default uniform block and driver constants
Qin Jiajia3e217f62018-08-28 16:55:20 +0800254 mResourcesHLSL->reserveUniformBlockRegisters(2);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800255
256 mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257}
258
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000259OutputHLSL::~OutputHLSL()
260{
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800261 SafeDelete(mSSBOOutputHLSL);
Jamie Madill8daaba12014-06-13 10:04:33 -0400262 SafeDelete(mStructureHLSL);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800263 SafeDelete(mResourcesHLSL);
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300264 SafeDelete(mTextureFunctionHLSL);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800265 SafeDelete(mImageFunctionHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200266 for (auto &eqFunction : mStructEqualityFunctions)
267 {
268 SafeDelete(eqFunction);
269 }
270 for (auto &eqFunction : mArrayEqualityFunctions)
271 {
272 SafeDelete(eqFunction);
273 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000274}
275
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200276void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000277{
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200278 BuiltInFunctionEmulator builtInFunctionEmulator;
279 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Shao6f0a0dc2016-09-27 13:51:29 +0800280 if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
281 {
282 InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
283 mShaderVersion);
284 }
285
Olli Etuahodfa75e82017-01-23 09:43:06 -0800286 builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500287
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700288 // Now that we are done changing the AST, do the analyses need for HLSL generation
Olli Etuaho77ba4082016-12-16 12:01:18 +0000289 CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700290 ASSERT(success == CallDAG::INITDAG_SUCCESS);
291 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700292
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200293 const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
294 // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
295 // the shader code. When we add shader storage blocks we might also consider an alternative
296 // solution, since the struct mapping won't work very well for shader storage blocks.
297
Jamie Madill37997142015-01-28 10:06:34 -0500298 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500299 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200300 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500301 mInfoSinkStack.pop();
302
Jamie Madill37997142015-01-28 10:06:34 -0500303 mInfoSinkStack.push(&mFooter);
Jamie Madill37997142015-01-28 10:06:34 -0500304 mInfoSinkStack.pop();
305
Jamie Madill32aab012015-01-27 14:12:26 -0500306 mInfoSinkStack.push(&mHeader);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200307 header(mHeader, std140Structs, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500308 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000309
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200310 objSink << mHeader.c_str();
311 objSink << mBody.c_str();
312 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200313
Olli Etuahodfa75e82017-01-23 09:43:06 -0800314 builtInFunctionEmulator.cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000315}
316
Qin Jiajiaa602f902018-09-11 14:40:24 +0800317const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
318{
319 return mResourcesHLSL->getShaderStorageBlockRegisterMap();
320}
321
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800322const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400323{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800324 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400325}
326
Jamie Madill9fe25e92014-07-18 10:33:08 -0400327const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
328{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800329 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400330}
331
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200332TString OutputHLSL::structInitializerString(int indent,
333 const TType &type,
334 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400335{
336 TString init;
337
Olli Etuahoed049ab2017-06-30 17:38:33 +0300338 TString indentString;
339 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400340 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300341 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400342 }
343
Olli Etuahoed049ab2017-06-30 17:38:33 +0300344 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400345 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300346 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300347 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300349 TStringStream indexedString;
350 indexedString << name << "[" << arrayIndex << "]";
351 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300352 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300353 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300354 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300355 {
356 init += ",";
357 }
358 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400359 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300360 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400361 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300362 else if (type.getBasicType() == EbtStruct)
363 {
364 init += indentString + "{\n";
365 const TStructure &structure = *type.getStruct();
366 const TFieldList &fields = structure.fields();
367 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
368 {
369 const TField &field = *fields[fieldIndex];
370 const TString &fieldName = name + "." + Decorate(field.name());
371 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400372
Olli Etuahoed049ab2017-06-30 17:38:33 +0300373 init += structInitializerString(indent + 1, fieldType, fieldName);
374 if (fieldIndex < fields.size() - 1)
375 {
376 init += ",";
377 }
378 init += "\n";
379 }
380 init += indentString + "}";
381 }
382 else
383 {
384 init += indentString + name;
385 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400386
387 return init;
388}
389
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200390TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
391{
392 TString mappedStructs;
393
394 for (auto &mappedStruct : std140Structs)
395 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200396 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200397 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800398 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
399 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200400 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800401 case EvqUniform:
402 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
403 {
404 continue;
405 }
406 break;
407 case EvqBuffer:
408 continue;
409 default:
410 UNREACHABLE();
411 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200412 }
413
414 unsigned int instanceCount = 1u;
415 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
416 if (isInstanceArray)
417 {
418 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
419 }
420
421 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
422 ++instanceArrayIndex)
423 {
424 TString originalName;
425 TString mappedName("map");
426
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200427 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200428 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200429 const ImmutableString &instanceName =
430 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
432 if (isInstanceArray)
433 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800434 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200435 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200436 originalName += instanceString;
437 mappedName += instanceString;
438 originalName += ".";
439 mappedName += "_";
440 }
441
442 TString fieldName = Decorate(mappedStruct.field->name());
443 originalName += fieldName;
444 mappedName += fieldName;
445
446 TType *structType = mappedStruct.field->type();
447 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200448 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200449
450 if (structType->isArray())
451 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300452 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200453 }
454
455 mappedStructs += " =\n";
456 mappedStructs += structInitializerString(0, *structType, originalName);
457 mappedStructs += ";\n";
458 }
459 }
460 return mappedStructs;
461}
462
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300463void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300465 for (const auto &attribute : mReferencedAttributes)
466 {
467 const TType &type = attribute.second->getType();
468 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400469
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300470 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
471 << zeroInitializer(type) << ";\n";
472 }
473}
474
475void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
476{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200477 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000478 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800479 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000480
481 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300482 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300483 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
484 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000485 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300486}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000487
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300488void OutputHLSL::header(TInfoSinkBase &out,
489 const std::vector<MappedStruct> &std140Structs,
490 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
491{
492 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000493
Jamie Madill8daaba12014-06-13 10:04:33 -0400494 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400495
Qin Jiajia3e217f62018-08-28 16:55:20 +0800496 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
497 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800498 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400499
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200500 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500501 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200502 out << "\n// Equality functions\n\n";
503 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500504 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200505 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200506 }
507 }
Olli Etuaho12690762015-03-31 12:55:28 +0300508 if (!mArrayAssignmentFunctions.empty())
509 {
510 out << "\n// Assignment functions\n\n";
511 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
512 {
513 out << assignmentFunction.functionDefinition << "\n";
514 }
515 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300516 if (!mArrayConstructIntoFunctions.empty())
517 {
518 out << "\n// Array constructor functions\n\n";
519 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
520 {
521 out << constructIntoFunction.functionDefinition << "\n";
522 }
523 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200524
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500525 if (mUsesDiscardRewriting)
526 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400527 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500528 }
529
Nicolas Capens655fe362014-04-11 13:12:34 -0400530 if (mUsesNestedBreak)
531 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400532 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400533 }
534
Arun Patole44efa0b2015-03-04 17:11:05 +0530535 if (mRequiresIEEEStrictCompiling)
536 {
537 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
538 }
539
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400540 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
541 "#define LOOP [loop]\n"
542 "#define FLATTEN [flatten]\n"
543 "#else\n"
544 "#define LOOP\n"
545 "#define FLATTEN\n"
546 "#endif\n";
547
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200548 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300550 const bool usingMRTExtension =
551 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000552
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000553 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300554 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400555 out << "\n";
556
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200557 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000558 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200559 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000560 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200561 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800562 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400563
Olli Etuahofbb1c792018-01-19 16:26:59 +0200564 out << "static " << TypeString(variableType) << " out_" << variableName
565 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000566 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000567 }
Jamie Madill46131a32013-06-20 11:55:50 -0400568 else
569 {
570 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
571
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800572 out << "static float4 gl_Color[" << numColorValues
573 << "] =\n"
574 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400575 for (unsigned int i = 0; i < numColorValues; i++)
576 {
577 out << " float4(0, 0, 0, 0)";
578 if (i + 1 != numColorValues)
579 {
580 out << ",";
581 }
582 out << "\n";
583 }
584
585 out << "};\n";
586 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000587
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400588 if (mUsesFragDepth)
589 {
590 out << "static float gl_Depth = 0.0;\n";
591 }
592
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000593 if (mUsesFragCoord)
594 {
595 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
596 }
597
598 if (mUsesPointCoord)
599 {
600 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
601 }
602
603 if (mUsesFrontFacing)
604 {
605 out << "static bool gl_FrontFacing = false;\n";
606 }
607
608 out << "\n";
609
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000610 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000611 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000612 out << "struct gl_DepthRangeParameters\n"
613 "{\n"
614 " float near;\n"
615 " float far;\n"
616 " float diff;\n"
617 "};\n"
618 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000619 }
620
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200621 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000622 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000623 out << "cbuffer DriverConstants : register(b1)\n"
624 "{\n";
625
626 if (mUsesDepthRange)
627 {
628 out << " float3 dx_DepthRange : packoffset(c0);\n";
629 }
630
631 if (mUsesFragCoord)
632 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000633 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000634 }
635
636 if (mUsesFragCoord || mUsesFrontFacing)
637 {
638 out << " float3 dx_DepthFront : packoffset(c2);\n";
639 }
640
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800641 if (mUsesFragCoord)
642 {
643 // dx_ViewScale is only used in the fragment shader to correct
644 // the value for glFragCoord if necessary
645 out << " float2 dx_ViewScale : packoffset(c3);\n";
646 }
647
Martin Radev72b4e1e2017-08-31 15:42:56 +0300648 if (mHasMultiviewExtensionEnabled)
649 {
650 // We have to add a value which we can use to keep track of which multi-view code
651 // path is to be selected in the GS.
652 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
653 }
654
Olli Etuaho618bebc2016-01-15 16:40:00 +0200655 if (mOutputType == SH_HLSL_4_1_OUTPUT)
656 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800657 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200658 }
659
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000660 out << "};\n";
661 }
662 else
663 {
664 if (mUsesDepthRange)
665 {
666 out << "uniform float3 dx_DepthRange : register(c0);";
667 }
668
669 if (mUsesFragCoord)
670 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000671 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000672 }
673
674 if (mUsesFragCoord || mUsesFrontFacing)
675 {
676 out << "uniform float3 dx_DepthFront : register(c2);\n";
677 }
678 }
679
680 out << "\n";
681
682 if (mUsesDepthRange)
683 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500684 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
685 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000686 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000687 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000688
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000689 if (usingMRTExtension && mNumRenderTargets > 1)
690 {
691 out << "#define GL_USES_MRT\n";
692 }
693
694 if (mUsesFragColor)
695 {
696 out << "#define GL_USES_FRAG_COLOR\n";
697 }
698
699 if (mUsesFragData)
700 {
701 out << "#define GL_USES_FRAG_DATA\n";
702 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703 }
Xinghua Caob1239382016-12-13 15:07:05 +0800704 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000705 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000706 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300707 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000708 out << "\n"
709 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400710
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000711 if (mUsesPointSize)
712 {
713 out << "static float gl_PointSize = float(1);\n";
714 }
715
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000716 if (mUsesInstanceID)
717 {
718 out << "static int gl_InstanceID;";
719 }
720
Corentin Wallezb076add2016-01-11 16:45:46 -0500721 if (mUsesVertexID)
722 {
723 out << "static int gl_VertexID;";
724 }
725
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000726 out << "\n"
727 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300728 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000729 out << "\n";
730
731 if (mUsesDepthRange)
732 {
733 out << "struct gl_DepthRangeParameters\n"
734 "{\n"
735 " float near;\n"
736 " float far;\n"
737 " float diff;\n"
738 "};\n"
739 "\n";
740 }
741
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200742 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000743 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800744 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800746
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000747 if (mUsesDepthRange)
748 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800749 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000750 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800751
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800752 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
753 // shaders. However, we declare it for all shaders (including Feature Level 10+).
754 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
755 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800756 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800757 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800758 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800759
Martin Radev72b4e1e2017-08-31 15:42:56 +0300760 if (mHasMultiviewExtensionEnabled)
761 {
762 // We have to add a value which we can use to keep track of which multi-view code
763 // path is to be selected in the GS.
764 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
765 }
766
Olli Etuaho618bebc2016-01-15 16:40:00 +0200767 if (mOutputType == SH_HLSL_4_1_OUTPUT)
768 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800769 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200770 }
771
Austin Kinross4fd18b12014-12-22 12:32:05 -0800772 out << "};\n"
773 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000774 }
775 else
776 {
777 if (mUsesDepthRange)
778 {
779 out << "uniform float3 dx_DepthRange : register(c0);\n";
780 }
781
Cooper Partine6664f02015-01-09 16:22:24 -0800782 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
783 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000784 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000785 }
786
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000787 if (mUsesDepthRange)
788 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
790 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000791 "\n";
792 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400793 }
Xinghua Caob1239382016-12-13 15:07:05 +0800794 else // Compute shader
795 {
796 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800797
798 out << "cbuffer DriverConstants : register(b1)\n"
799 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800800 if (mUsesNumWorkGroups)
801 {
Xinghua Caob1239382016-12-13 15:07:05 +0800802 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800803 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800804 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800805 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800806 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800807
Jiawei Shao203b26f2018-07-25 10:30:43 +0800808 std::ostringstream systemValueDeclaration;
809 std::ostringstream glBuiltinInitialization;
810
811 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
812 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
813 << "{\n";
814
Xinghua Caob1239382016-12-13 15:07:05 +0800815 if (mUsesWorkGroupID)
816 {
817 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800818 systemValueDeclaration << " uint3 dx_WorkGroupID : "
819 << "SV_GroupID;\n";
820 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800821 }
822
823 if (mUsesLocalInvocationID)
824 {
825 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800826 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
827 << "SV_GroupThreadID;\n";
828 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800829 }
830
831 if (mUsesGlobalInvocationID)
832 {
833 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800834 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
835 << "SV_DispatchThreadID;\n";
836 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800837 }
838
839 if (mUsesLocalInvocationIndex)
840 {
841 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800842 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
843 << "SV_GroupIndex;\n";
844 glBuiltinInitialization
845 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800846 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800847
848 systemValueDeclaration << "};\n\n";
849 glBuiltinInitialization << "};\n\n";
850
851 out << systemValueDeclaration.str();
852 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800853 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000854
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800855 if (!mappedStructs.empty())
856 {
857 out << "// Structures from std140 blocks with padding removed\n";
858 out << "\n";
859 out << mappedStructs;
860 out << "\n";
861 }
862
Geoff Lang1fe74c72016-08-25 13:23:01 -0400863 bool getDimensionsIgnoresBaseLevel =
864 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
865 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800866 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000867
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000868 if (mUsesFragCoord)
869 {
870 out << "#define GL_USES_FRAG_COORD\n";
871 }
872
873 if (mUsesPointCoord)
874 {
875 out << "#define GL_USES_POINT_COORD\n";
876 }
877
878 if (mUsesFrontFacing)
879 {
880 out << "#define GL_USES_FRONT_FACING\n";
881 }
882
883 if (mUsesPointSize)
884 {
885 out << "#define GL_USES_POINT_SIZE\n";
886 }
887
Martin Radev41ac68e2017-06-06 12:16:58 +0300888 if (mHasMultiviewExtensionEnabled)
889 {
890 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
891 }
892
893 if (mUsesViewID)
894 {
895 out << "#define GL_USES_VIEW_ID\n";
896 }
897
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400898 if (mUsesFragDepth)
899 {
900 out << "#define GL_USES_FRAG_DEPTH\n";
901 }
902
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000903 if (mUsesDepthRange)
904 {
905 out << "#define GL_USES_DEPTH_RANGE\n";
906 }
907
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000908 if (mUsesXor)
909 {
910 out << "bool xor(bool p, bool q)\n"
911 "{\n"
912 " return (p || q) && !(p && q);\n"
913 "}\n"
914 "\n";
915 }
916
Olli Etuahodfa75e82017-01-23 09:43:06 -0800917 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000918}
919
920void OutputHLSL::visitSymbol(TIntermSymbol *node)
921{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200922 const TVariable &variable = node->variable();
923
924 // Empty symbols can only appear in declarations and function arguments, and in either of those
925 // cases the symbol nodes are not visited.
926 ASSERT(variable.symbolType() != SymbolType::Empty);
927
Jamie Madill32aab012015-01-27 14:12:26 -0500928 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929
Jamie Madill570e04d2013-06-21 09:15:33 -0400930 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800931 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400932 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200933 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400934 }
935
Olli Etuahofbb1c792018-01-19 16:26:59 +0200936 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200937 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200938
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000939 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000940 {
941 mUsesDepthRange = true;
942 out << name;
943 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944 else
945 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200946 const TType &variableType = variable.getType();
947 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000948
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200949 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200950
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000951 if (qualifier == EvqUniform)
952 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200953 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400954
955 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000956 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200957 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
958 {
959 const TVariable *instanceVariable = nullptr;
960 if (variableType.isInterfaceBlock())
961 {
962 instanceVariable = &variable;
963 }
964 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
965 new TReferencedBlock(interfaceBlock, instanceVariable);
966 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000967 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000968 else
969 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200970 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000971 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400972
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200973 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000974 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800975 else if (qualifier == EvqBuffer)
976 {
977 UNREACHABLE();
978 }
Jamie Madill19571812013-08-12 15:26:34 -0700979 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000980 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200981 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400982 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000983 }
Jamie Madill033dae62014-06-18 12:56:28 -0400984 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000985 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200986 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +0300987 out << DecorateVariableIfNeeded(variable);
988 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +0300989 {
990 mUsesViewID = true;
991 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000992 }
Jamie Madill19571812013-08-12 15:26:34 -0700993 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400994 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200995 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400996 out << "out_" << name;
997 }
998 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000999 {
1000 out << "gl_Color[0]";
1001 mUsesFragColor = true;
1002 }
1003 else if (qualifier == EvqFragData)
1004 {
1005 out << "gl_Color";
1006 mUsesFragData = true;
1007 }
1008 else if (qualifier == EvqFragCoord)
1009 {
1010 mUsesFragCoord = true;
1011 out << name;
1012 }
1013 else if (qualifier == EvqPointCoord)
1014 {
1015 mUsesPointCoord = true;
1016 out << name;
1017 }
1018 else if (qualifier == EvqFrontFacing)
1019 {
1020 mUsesFrontFacing = true;
1021 out << name;
1022 }
1023 else if (qualifier == EvqPointSize)
1024 {
1025 mUsesPointSize = true;
1026 out << name;
1027 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001028 else if (qualifier == EvqInstanceID)
1029 {
1030 mUsesInstanceID = true;
1031 out << name;
1032 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001033 else if (qualifier == EvqVertexID)
1034 {
1035 mUsesVertexID = true;
1036 out << name;
1037 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001038 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001039 {
1040 mUsesFragDepth = true;
1041 out << "gl_Depth";
1042 }
Xinghua Caob1239382016-12-13 15:07:05 +08001043 else if (qualifier == EvqNumWorkGroups)
1044 {
1045 mUsesNumWorkGroups = true;
1046 out << name;
1047 }
1048 else if (qualifier == EvqWorkGroupID)
1049 {
1050 mUsesWorkGroupID = true;
1051 out << name;
1052 }
1053 else if (qualifier == EvqLocalInvocationID)
1054 {
1055 mUsesLocalInvocationID = true;
1056 out << name;
1057 }
1058 else if (qualifier == EvqGlobalInvocationID)
1059 {
1060 mUsesGlobalInvocationID = true;
1061 out << name;
1062 }
1063 else if (qualifier == EvqLocalInvocationIndex)
1064 {
1065 mUsesLocalInvocationIndex = true;
1066 out << name;
1067 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001068 else
1069 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001070 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001071 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 }
1073}
1074
Olli Etuaho7fb49552015-03-18 17:27:44 +02001075void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1076{
1077 if (type.isScalar() && !type.isArray())
1078 {
1079 if (op == EOpEqual)
1080 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001081 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001082 }
1083 else
1084 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001085 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001086 }
1087 }
1088 else
1089 {
1090 if (visit == PreVisit && op == EOpNotEqual)
1091 {
1092 out << "!";
1093 }
1094
1095 if (type.isArray())
1096 {
1097 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001098 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001099 }
1100 else if (type.getBasicType() == EbtStruct)
1101 {
1102 const TStructure &structure = *type.getStruct();
1103 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001104 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001105 }
1106 else
1107 {
1108 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001109 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001110 }
1111 }
1112}
1113
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001114void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1115{
1116 if (type.isArray())
1117 {
1118 const TString &functionName = addArrayAssignmentFunction(type);
1119 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1120 }
1121 else
1122 {
1123 outputTriplet(out, visit, "(", " = ", ")");
1124 }
1125}
1126
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001127bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001128{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001129 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001130 {
1131 TIntermNode *ancestor = getAncestorNode(n);
1132 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1133 if (ancestorBinary == nullptr)
1134 {
1135 return false;
1136 }
1137 switch (ancestorBinary->getOp())
1138 {
1139 case EOpIndexDirectStruct:
1140 {
1141 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1142 const TIntermConstantUnion *index =
1143 ancestorBinary->getRight()->getAsConstantUnion();
1144 const TField *field = structure->fields()[index->getIConst(0)];
1145 if (IsSampler(field->type()->getBasicType()))
1146 {
1147 return true;
1148 }
1149 break;
1150 }
1151 case EOpIndexDirect:
1152 break;
1153 default:
1154 // Returning a sampler from indirect indexing is not supported.
1155 return false;
1156 }
1157 }
1158 return false;
1159}
1160
Olli Etuahob6fa0432016-09-28 16:28:05 +01001161bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1162{
1163 TInfoSinkBase &out = getInfoSink();
1164 if (visit == PostVisit)
1165 {
1166 out << ".";
1167 node->writeOffsetsAsXYZW(&out);
1168 }
1169 return true;
1170}
1171
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001172bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1173{
Jamie Madill32aab012015-01-27 14:12:26 -05001174 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001175
1176 switch (node->getOp())
1177 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001178 case EOpComma:
1179 outputTriplet(out, visit, "(", ", ", ")");
1180 break;
1181 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001182 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001183 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001184 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1185 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001186 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001187 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1188 out << functionName << "(";
1189 node->getLeft()->traverse(this);
1190 TIntermSequence *seq = rightAgg->getSequence();
1191 for (auto &arrayElement : *seq)
1192 {
1193 out << ", ";
1194 arrayElement->traverse(this);
1195 }
1196 out << ")";
1197 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001198 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001199 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1200 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001201 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001202 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001203 // Assignment expressions with atomic functions should be transformed into atomic
1204 // function calls in HLSL.
1205 // e.g. original_value = atomicAdd(dest, value) should be translated into
1206 // InterlockedAdd(dest, value, original_value);
1207 else if (IsAtomicFunctionDirectAssign(*node))
1208 {
1209 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1210 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1211 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1212 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1213 ASSERT(argumentSeq->size() >= 2u);
1214 for (auto &argument : *argumentSeq)
1215 {
1216 argument->traverse(this);
1217 out << ", ";
1218 }
1219 node->getLeft()->traverse(this);
1220 out << ")";
1221 return false;
1222 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001223 else if (IsInShaderStorageBlock(node->getLeft()))
1224 {
1225 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1226 out << ", ";
1227 if (IsInShaderStorageBlock(node->getRight()))
1228 {
1229 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1230 }
1231 else
1232 {
1233 node->getRight()->traverse(this);
1234 }
1235
1236 out << ")";
1237 return false;
1238 }
1239 else if (IsInShaderStorageBlock(node->getRight()))
1240 {
1241 node->getLeft()->traverse(this);
1242 out << " = ";
1243 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1244 return false;
1245 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001246
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001247 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001248 break;
1249 case EOpInitialize:
1250 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001251 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001252 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1253 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001254 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001255
1256 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001257 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001258
1259 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1260 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1261 // new variable is created before the assignment is evaluated), so we need to
1262 // convert
1263 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001264 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001265 {
1266 // Skip initializing the rest of the expression
1267 return false;
1268 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001269 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001270 {
1271 return false;
1272 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001273 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001274 else if (visit == InVisit)
1275 {
1276 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001277 if (IsInShaderStorageBlock(node->getRight()))
1278 {
1279 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1280 return false;
1281 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001282 }
1283 break;
1284 case EOpAddAssign:
1285 outputTriplet(out, visit, "(", " += ", ")");
1286 break;
1287 case EOpSubAssign:
1288 outputTriplet(out, visit, "(", " -= ", ")");
1289 break;
1290 case EOpMulAssign:
1291 outputTriplet(out, visit, "(", " *= ", ")");
1292 break;
1293 case EOpVectorTimesScalarAssign:
1294 outputTriplet(out, visit, "(", " *= ", ")");
1295 break;
1296 case EOpMatrixTimesScalarAssign:
1297 outputTriplet(out, visit, "(", " *= ", ")");
1298 break;
1299 case EOpVectorTimesMatrixAssign:
1300 if (visit == PreVisit)
1301 {
1302 out << "(";
1303 }
1304 else if (visit == InVisit)
1305 {
1306 out << " = mul(";
1307 node->getLeft()->traverse(this);
1308 out << ", transpose(";
1309 }
1310 else
1311 {
1312 out << ")))";
1313 }
1314 break;
1315 case EOpMatrixTimesMatrixAssign:
1316 if (visit == PreVisit)
1317 {
1318 out << "(";
1319 }
1320 else if (visit == InVisit)
1321 {
1322 out << " = transpose(mul(transpose(";
1323 node->getLeft()->traverse(this);
1324 out << "), transpose(";
1325 }
1326 else
1327 {
1328 out << "))))";
1329 }
1330 break;
1331 case EOpDivAssign:
1332 outputTriplet(out, visit, "(", " /= ", ")");
1333 break;
1334 case EOpIModAssign:
1335 outputTriplet(out, visit, "(", " %= ", ")");
1336 break;
1337 case EOpBitShiftLeftAssign:
1338 outputTriplet(out, visit, "(", " <<= ", ")");
1339 break;
1340 case EOpBitShiftRightAssign:
1341 outputTriplet(out, visit, "(", " >>= ", ")");
1342 break;
1343 case EOpBitwiseAndAssign:
1344 outputTriplet(out, visit, "(", " &= ", ")");
1345 break;
1346 case EOpBitwiseXorAssign:
1347 outputTriplet(out, visit, "(", " ^= ", ")");
1348 break;
1349 case EOpBitwiseOrAssign:
1350 outputTriplet(out, visit, "(", " |= ", ")");
1351 break;
1352 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001353 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001354 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001355 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001356 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001357 if (visit == PreVisit)
1358 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001359 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001360 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001361
1362 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001363 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1364 {
1365 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1366 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1367 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001368 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001369 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001370 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001371 return false;
1372 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001373 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001374 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001375 {
1376 // All parts of an expression that access a sampler in a struct need to use _ as
1377 // separator to access the sampler variable that has been moved out of the struct.
1378 outputTriplet(out, visit, "", "_", "");
1379 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001380 else
1381 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001382 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001383 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001384 }
1385 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001386 case EOpIndexIndirect:
1387 // We do not currently support indirect references to interface blocks
1388 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1389 outputTriplet(out, visit, "", "[", "]");
1390 break;
1391 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001392 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001393 const TStructure *structure = node->getLeft()->getType().getStruct();
1394 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1395 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001396
Olli Etuaho96963162016-03-21 11:54:33 +02001397 // In cases where indexing returns a sampler, we need to access the sampler variable
1398 // that has been moved out of the struct.
1399 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1400 if (visit == PreVisit && indexingReturnsSampler)
1401 {
1402 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1403 // This prefix is only output at the beginning of the indexing expression, which
1404 // may have multiple parts.
1405 out << "angle";
1406 }
1407 if (!indexingReturnsSampler)
1408 {
1409 // All parts of an expression that access a sampler in a struct need to use _ as
1410 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001411 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001412 }
1413 if (visit == InVisit)
1414 {
1415 if (indexingReturnsSampler)
1416 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001417 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001418 }
1419 else
1420 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001421 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001422 }
1423
1424 return false;
1425 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001426 }
1427 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001428 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001429 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001430 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1431 bool structInStd140UniformBlock =
1432 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1433 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001434 {
1435 out << "map";
1436 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001437 if (visit == InVisit)
1438 {
1439 const TInterfaceBlock *interfaceBlock =
1440 node->getLeft()->getType().getInterfaceBlock();
1441 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1442 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001443 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001444 {
1445 out << "_";
1446 }
1447 else
1448 {
1449 out << ".";
1450 }
1451 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001452
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001453 return false;
1454 }
1455 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001456 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001457 case EOpAdd:
1458 outputTriplet(out, visit, "(", " + ", ")");
1459 break;
1460 case EOpSub:
1461 outputTriplet(out, visit, "(", " - ", ")");
1462 break;
1463 case EOpMul:
1464 outputTriplet(out, visit, "(", " * ", ")");
1465 break;
1466 case EOpDiv:
1467 outputTriplet(out, visit, "(", " / ", ")");
1468 break;
1469 case EOpIMod:
1470 outputTriplet(out, visit, "(", " % ", ")");
1471 break;
1472 case EOpBitShiftLeft:
1473 outputTriplet(out, visit, "(", " << ", ")");
1474 break;
1475 case EOpBitShiftRight:
1476 outputTriplet(out, visit, "(", " >> ", ")");
1477 break;
1478 case EOpBitwiseAnd:
1479 outputTriplet(out, visit, "(", " & ", ")");
1480 break;
1481 case EOpBitwiseXor:
1482 outputTriplet(out, visit, "(", " ^ ", ")");
1483 break;
1484 case EOpBitwiseOr:
1485 outputTriplet(out, visit, "(", " | ", ")");
1486 break;
1487 case EOpEqual:
1488 case EOpNotEqual:
1489 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1490 break;
1491 case EOpLessThan:
1492 outputTriplet(out, visit, "(", " < ", ")");
1493 break;
1494 case EOpGreaterThan:
1495 outputTriplet(out, visit, "(", " > ", ")");
1496 break;
1497 case EOpLessThanEqual:
1498 outputTriplet(out, visit, "(", " <= ", ")");
1499 break;
1500 case EOpGreaterThanEqual:
1501 outputTriplet(out, visit, "(", " >= ", ")");
1502 break;
1503 case EOpVectorTimesScalar:
1504 outputTriplet(out, visit, "(", " * ", ")");
1505 break;
1506 case EOpMatrixTimesScalar:
1507 outputTriplet(out, visit, "(", " * ", ")");
1508 break;
1509 case EOpVectorTimesMatrix:
1510 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1511 break;
1512 case EOpMatrixTimesVector:
1513 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1514 break;
1515 case EOpMatrixTimesMatrix:
1516 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1517 break;
1518 case EOpLogicalOr:
1519 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1520 // been unfolded.
1521 ASSERT(!node->getRight()->hasSideEffects());
1522 outputTriplet(out, visit, "(", " || ", ")");
1523 return true;
1524 case EOpLogicalXor:
1525 mUsesXor = true;
1526 outputTriplet(out, visit, "xor(", ", ", ")");
1527 break;
1528 case EOpLogicalAnd:
1529 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1530 // been unfolded.
1531 ASSERT(!node->getRight()->hasSideEffects());
1532 outputTriplet(out, visit, "(", " && ", ")");
1533 return true;
1534 default:
1535 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001536 }
1537
1538 return true;
1539}
1540
1541bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1542{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001543 TInfoSinkBase &out = getInfoSink();
1544
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001545 switch (node->getOp())
1546 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001547 case EOpNegative:
1548 outputTriplet(out, visit, "(-", "", ")");
1549 break;
1550 case EOpPositive:
1551 outputTriplet(out, visit, "(+", "", ")");
1552 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001553 case EOpLogicalNot:
1554 outputTriplet(out, visit, "(!", "", ")");
1555 break;
1556 case EOpBitwiseNot:
1557 outputTriplet(out, visit, "(~", "", ")");
1558 break;
1559 case EOpPostIncrement:
1560 outputTriplet(out, visit, "(", "", "++)");
1561 break;
1562 case EOpPostDecrement:
1563 outputTriplet(out, visit, "(", "", "--)");
1564 break;
1565 case EOpPreIncrement:
1566 outputTriplet(out, visit, "(++", "", ")");
1567 break;
1568 case EOpPreDecrement:
1569 outputTriplet(out, visit, "(--", "", ")");
1570 break;
1571 case EOpRadians:
1572 outputTriplet(out, visit, "radians(", "", ")");
1573 break;
1574 case EOpDegrees:
1575 outputTriplet(out, visit, "degrees(", "", ")");
1576 break;
1577 case EOpSin:
1578 outputTriplet(out, visit, "sin(", "", ")");
1579 break;
1580 case EOpCos:
1581 outputTriplet(out, visit, "cos(", "", ")");
1582 break;
1583 case EOpTan:
1584 outputTriplet(out, visit, "tan(", "", ")");
1585 break;
1586 case EOpAsin:
1587 outputTriplet(out, visit, "asin(", "", ")");
1588 break;
1589 case EOpAcos:
1590 outputTriplet(out, visit, "acos(", "", ")");
1591 break;
1592 case EOpAtan:
1593 outputTriplet(out, visit, "atan(", "", ")");
1594 break;
1595 case EOpSinh:
1596 outputTriplet(out, visit, "sinh(", "", ")");
1597 break;
1598 case EOpCosh:
1599 outputTriplet(out, visit, "cosh(", "", ")");
1600 break;
1601 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001603 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001604 case EOpAtanh:
1605 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001606 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001607 break;
1608 case EOpExp:
1609 outputTriplet(out, visit, "exp(", "", ")");
1610 break;
1611 case EOpLog:
1612 outputTriplet(out, visit, "log(", "", ")");
1613 break;
1614 case EOpExp2:
1615 outputTriplet(out, visit, "exp2(", "", ")");
1616 break;
1617 case EOpLog2:
1618 outputTriplet(out, visit, "log2(", "", ")");
1619 break;
1620 case EOpSqrt:
1621 outputTriplet(out, visit, "sqrt(", "", ")");
1622 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001623 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001624 outputTriplet(out, visit, "rsqrt(", "", ")");
1625 break;
1626 case EOpAbs:
1627 outputTriplet(out, visit, "abs(", "", ")");
1628 break;
1629 case EOpSign:
1630 outputTriplet(out, visit, "sign(", "", ")");
1631 break;
1632 case EOpFloor:
1633 outputTriplet(out, visit, "floor(", "", ")");
1634 break;
1635 case EOpTrunc:
1636 outputTriplet(out, visit, "trunc(", "", ")");
1637 break;
1638 case EOpRound:
1639 outputTriplet(out, visit, "round(", "", ")");
1640 break;
1641 case EOpRoundEven:
1642 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001643 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001644 break;
1645 case EOpCeil:
1646 outputTriplet(out, visit, "ceil(", "", ")");
1647 break;
1648 case EOpFract:
1649 outputTriplet(out, visit, "frac(", "", ")");
1650 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001651 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001652 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001653 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001654 else
1655 outputTriplet(out, visit, "isnan(", "", ")");
1656 mRequiresIEEEStrictCompiling = true;
1657 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001658 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001659 outputTriplet(out, visit, "isinf(", "", ")");
1660 break;
1661 case EOpFloatBitsToInt:
1662 outputTriplet(out, visit, "asint(", "", ")");
1663 break;
1664 case EOpFloatBitsToUint:
1665 outputTriplet(out, visit, "asuint(", "", ")");
1666 break;
1667 case EOpIntBitsToFloat:
1668 outputTriplet(out, visit, "asfloat(", "", ")");
1669 break;
1670 case EOpUintBitsToFloat:
1671 outputTriplet(out, visit, "asfloat(", "", ")");
1672 break;
1673 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001674 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001675 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001676 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001677 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001678 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001679 case EOpPackUnorm4x8:
1680 case EOpPackSnorm4x8:
1681 case EOpUnpackUnorm4x8:
1682 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001683 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001684 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001685 break;
1686 case EOpLength:
1687 outputTriplet(out, visit, "length(", "", ")");
1688 break;
1689 case EOpNormalize:
1690 outputTriplet(out, visit, "normalize(", "", ")");
1691 break;
1692 case EOpDFdx:
1693 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1694 {
1695 outputTriplet(out, visit, "(", "", ", 0.0)");
1696 }
1697 else
1698 {
1699 outputTriplet(out, visit, "ddx(", "", ")");
1700 }
1701 break;
1702 case EOpDFdy:
1703 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1704 {
1705 outputTriplet(out, visit, "(", "", ", 0.0)");
1706 }
1707 else
1708 {
1709 outputTriplet(out, visit, "ddy(", "", ")");
1710 }
1711 break;
1712 case EOpFwidth:
1713 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1714 {
1715 outputTriplet(out, visit, "(", "", ", 0.0)");
1716 }
1717 else
1718 {
1719 outputTriplet(out, visit, "fwidth(", "", ")");
1720 }
1721 break;
1722 case EOpTranspose:
1723 outputTriplet(out, visit, "transpose(", "", ")");
1724 break;
1725 case EOpDeterminant:
1726 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1727 break;
1728 case EOpInverse:
1729 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001730 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001731 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001732
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001733 case EOpAny:
1734 outputTriplet(out, visit, "any(", "", ")");
1735 break;
1736 case EOpAll:
1737 outputTriplet(out, visit, "all(", "", ")");
1738 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001739 case EOpLogicalNotComponentWise:
1740 outputTriplet(out, visit, "(!", "", ")");
1741 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001742 case EOpBitfieldReverse:
1743 outputTriplet(out, visit, "reversebits(", "", ")");
1744 break;
1745 case EOpBitCount:
1746 outputTriplet(out, visit, "countbits(", "", ")");
1747 break;
1748 case EOpFindLSB:
1749 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1750 // in GLSLTest and results are consistent with GL.
1751 outputTriplet(out, visit, "firstbitlow(", "", ")");
1752 break;
1753 case EOpFindMSB:
1754 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1755 // tested in GLSLTest and results are consistent with GL.
1756 outputTriplet(out, visit, "firstbithigh(", "", ")");
1757 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001758 default:
1759 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760 }
1761
1762 return true;
1763}
1764
Olli Etuahofbb1c792018-01-19 16:26:59 +02001765ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001766{
1767 if (node->getAsSymbolNode())
1768 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001769 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1770 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001771 }
1772 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1773 switch (nodeBinary->getOp())
1774 {
1775 case EOpIndexDirect:
1776 {
1777 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1778
Olli Etuahofbb1c792018-01-19 16:26:59 +02001779 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001780 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001781 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001782 }
1783 case EOpIndexDirectStruct:
1784 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001785 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001786 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1787 const TField *field = s->fields()[index];
1788
Olli Etuahofbb1c792018-01-19 16:26:59 +02001789 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001790 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1791 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001792 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001793 }
1794 default:
1795 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001796 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001797 }
1798}
1799
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001800bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1801{
1802 TInfoSinkBase &out = getInfoSink();
1803
Olli Etuaho06235df2018-07-20 14:26:07 +03001804 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1805
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001806 if (mInsideFunction)
1807 {
1808 outputLineDirective(out, node->getLine().first_line);
1809 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001810 if (isMainBlock)
1811 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001812 if (mShaderType == GL_COMPUTE_SHADER)
1813 {
1814 out << "initGLBuiltins(input);\n";
1815 }
1816 else
1817 {
1818 out << "@@ MAIN PROLOGUE @@\n";
1819 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001820 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001821 }
1822
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001823 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001824 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001825 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001826
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001827 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001828
1829 // Don't output ; after case labels, they're terminated by :
1830 // This is needed especially since outputting a ; after a case statement would turn empty
1831 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001832 // Also the output code is clearer if we don't output ; after statements where it is not
1833 // needed:
1834 // * if statements
1835 // * switch statements
1836 // * blocks
1837 // * function definitions
1838 // * loops (do-while loops output the semicolon in VisitLoop)
1839 // * declarations that don't generate output.
1840 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1841 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1842 statement->getAsSwitchNode() == nullptr &&
1843 statement->getAsFunctionDefinition() == nullptr &&
1844 (statement->getAsDeclarationNode() == nullptr ||
1845 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1846 statement->getAsInvariantDeclarationNode() == nullptr)
1847 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001848 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001849 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001850 }
1851
1852 if (mInsideFunction)
1853 {
1854 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001855 if (isMainBlock && shaderNeedsGenerateOutput())
1856 {
1857 // We could have an empty main, a main function without a branch at the end, or a main
1858 // function with a discard statement at the end. In these cases we need to add a return
1859 // statement.
1860 bool needReturnStatement =
1861 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1862 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1863 if (needReturnStatement)
1864 {
1865 out << "return " << generateOutputCall() << ";\n";
1866 }
1867 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001868 out << "}\n";
1869 }
1870
1871 return false;
1872}
1873
Olli Etuaho336b1472016-10-05 16:37:55 +01001874bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1875{
1876 TInfoSinkBase &out = getInfoSink();
1877
1878 ASSERT(mCurrentFunctionMetadata == nullptr);
1879
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001880 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001881 ASSERT(index != CallDAG::InvalidIndex);
1882 mCurrentFunctionMetadata = &mASTMetadataList[index];
1883
Olli Etuahod4bd9632018-03-08 16:32:44 +02001884 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001885
Olli Etuahod4bd9632018-03-08 16:32:44 +02001886 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001887 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001888 // The stub strings below are replaced when shader is dynamically defined by its layout:
1889 switch (mShaderType)
1890 {
1891 case GL_VERTEX_SHADER:
1892 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1893 << "@@ VERTEX OUTPUT @@\n\n"
1894 << "VS_OUTPUT main(VS_INPUT input)";
1895 break;
1896 case GL_FRAGMENT_SHADER:
1897 out << "@@ PIXEL OUTPUT @@\n\n"
1898 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1899 break;
1900 case GL_COMPUTE_SHADER:
1901 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1902 << mWorkGroupSize[2] << ")]\n";
1903 out << "void main(CS_INPUT input)";
1904 break;
1905 default:
1906 UNREACHABLE();
1907 break;
1908 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001909 }
1910 else
1911 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001912 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001913 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001914 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001915
Olli Etuaho06235df2018-07-20 14:26:07 +03001916 size_t paramCount = func->getParamCount();
1917 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001918 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001919 const TVariable *param = func->getParam(i);
1920 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001921
Olli Etuaho06235df2018-07-20 14:26:07 +03001922 writeParameter(param, out);
1923
1924 if (i < paramCount - 1)
1925 {
1926 out << ", ";
1927 }
1928 }
1929
1930 out << ")\n";
1931 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001932
1933 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03001934 if (func->isMain())
1935 {
1936 mInsideMain = true;
1937 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001938 // The function body node will output braces.
1939 node->getBody()->traverse(this);
1940 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03001941 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01001942
1943 mCurrentFunctionMetadata = nullptr;
1944
1945 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1946 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1947 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001948 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001949 mOutputLod0Function = true;
1950 node->traverse(this);
1951 mOutputLod0Function = false;
1952 }
1953
1954 return false;
1955}
1956
Olli Etuaho13389b62016-10-16 11:48:18 +01001957bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1958{
Olli Etuaho13389b62016-10-16 11:48:18 +01001959 if (visit == PreVisit)
1960 {
1961 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001962 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001963 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001964 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001965
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001966 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001967 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001968 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001969 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001970
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001971 if (!declarator->getAsSymbolNode() ||
1972 declarator->getAsSymbolNode()->variable().symbolType() !=
1973 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001974 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001975 if (declarator->getQualifier() == EvqShared)
1976 {
1977 out << "groupshared ";
1978 }
1979 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001980 {
1981 out << "static ";
1982 }
1983
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001984 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001985
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001986 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001987
1988 if (symbol)
1989 {
1990 symbol->traverse(this);
1991 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001992 // We don't initialize shared variables because:
1993 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1994 // code to initialize a groupshared array variable with a large array size.
1995 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1996 // allow initializing shared variables at all.
1997 if (declarator->getQualifier() != EvqShared)
1998 {
1999 out << " = " + zeroInitializer(symbol->getType());
2000 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002001 }
2002 else
2003 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002004 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002005 }
2006 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002007 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002008 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002009 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002010 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002011 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002012
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002013 const TVariable &variable = symbol->variable();
2014
2015 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002016 {
2017 // Vertex outputs which are declared but not written to should still be declared to
2018 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002019 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002020 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002021 }
2022 }
2023 return false;
2024}
2025
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002026bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2027{
2028 // Do not do any translation
2029 return false;
2030}
2031
Olli Etuahod4bd9632018-03-08 16:32:44 +02002032void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002033{
2034 TInfoSinkBase &out = getInfoSink();
2035
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002036 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002037 // Skip the prototype if it is not implemented (and thus not used)
2038 if (index == CallDAG::InvalidIndex)
2039 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002040 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002041 }
2042
Olli Etuahod4bd9632018-03-08 16:32:44 +02002043 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002044
Olli Etuahod4bd9632018-03-08 16:32:44 +02002045 TString name = DecorateFunctionIfNeeded(func);
2046 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002047 << (mOutputLod0Function ? "Lod0(" : "(");
2048
Olli Etuahod4bd9632018-03-08 16:32:44 +02002049 size_t paramCount = func->getParamCount();
2050 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002051 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002052 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002053
Olli Etuahod4bd9632018-03-08 16:32:44 +02002054 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002055 {
2056 out << ", ";
2057 }
2058 }
2059
2060 out << ");\n";
2061
2062 // Also prototype the Lod0 variant if needed
2063 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2064 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2065 {
2066 mOutputLod0Function = true;
2067 node->traverse(this);
2068 mOutputLod0Function = false;
2069 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002070}
2071
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002072bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2073{
Jamie Madill32aab012015-01-27 14:12:26 -05002074 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002075
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 switch (node->getOp())
2077 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002078 case EOpCallBuiltInFunction:
2079 case EOpCallFunctionInAST:
2080 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002082 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002083
Corentin Wallez1239ee92015-03-19 14:38:02 -07002084 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002085 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002086 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002087 if (node->isArray())
2088 {
2089 UNIMPLEMENTED();
2090 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002091 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002092 ASSERT(index != CallDAG::InvalidIndex);
2093 lod0 &= mASTMetadataList[index].mNeedsLod0;
2094
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002095 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002096 out << DisambiguateFunctionName(node->getSequence());
2097 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002098 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002099 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002100 {
2101 // This path is used for internal functions that don't have their definitions in the
2102 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002103 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002104 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002105 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002106 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002107 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002108 TType type = (*arguments)[0]->getAsTyped()->getType();
2109 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002110 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002111 type.getMemoryQualifier().readonly);
2112 out << imageFunctionName << "(";
2113 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002114 else
2115 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002116 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002117 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002118 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2119 if (arguments->size() > 1)
2120 {
2121 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2122 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002123 const ImmutableString &textureFunctionName =
2124 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2125 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002126 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002127 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002128
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002129 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002130 {
Olli Etuaho96963162016-03-21 11:54:33 +02002131 TIntermTyped *typedArg = (*arg)->getAsTyped();
2132 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002133 {
2134 out << "texture_";
2135 (*arg)->traverse(this);
2136 out << ", sampler_";
2137 }
2138
2139 (*arg)->traverse(this);
2140
Olli Etuaho96963162016-03-21 11:54:33 +02002141 if (typedArg->getType().isStructureContainingSamplers())
2142 {
2143 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002144 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002145 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2146 std::string namePrefix = "angle_";
2147 namePrefix += structName.data();
2148 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002149 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002150 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002151 {
2152 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2153 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002154 out << ", texture_" << sampler->name();
2155 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002156 }
2157 else
2158 {
2159 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2160 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002161 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002162 }
2163 }
2164 }
2165
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002166 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002167 {
2168 out << ", ";
2169 }
2170 }
2171
2172 out << ")";
2173
2174 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002175 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002176 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002177 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002178 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002179 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002180 outputTriplet(out, visit, "(", " == ", ")");
2181 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002182 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002183 outputTriplet(out, visit, "(", " != ", ")");
2184 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002185 case EOpLessThanComponentWise:
2186 outputTriplet(out, visit, "(", " < ", ")");
2187 break;
2188 case EOpGreaterThanComponentWise:
2189 outputTriplet(out, visit, "(", " > ", ")");
2190 break;
2191 case EOpLessThanEqualComponentWise:
2192 outputTriplet(out, visit, "(", " <= ", ")");
2193 break;
2194 case EOpGreaterThanEqualComponentWise:
2195 outputTriplet(out, visit, "(", " >= ", ")");
2196 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002197 case EOpMod:
2198 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002199 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002200 break;
2201 case EOpModf:
2202 outputTriplet(out, visit, "modf(", ", ", ")");
2203 break;
2204 case EOpPow:
2205 outputTriplet(out, visit, "pow(", ", ", ")");
2206 break;
2207 case EOpAtan:
2208 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2209 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002210 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002211 break;
2212 case EOpMin:
2213 outputTriplet(out, visit, "min(", ", ", ")");
2214 break;
2215 case EOpMax:
2216 outputTriplet(out, visit, "max(", ", ", ")");
2217 break;
2218 case EOpClamp:
2219 outputTriplet(out, visit, "clamp(", ", ", ")");
2220 break;
2221 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302222 {
2223 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2224 if (lastParamNode->getType().getBasicType() == EbtBool)
2225 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002226 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2227 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302228 // so use emulated version.
2229 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002230 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302231 }
2232 else
2233 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002234 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302235 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002236 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302237 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002238 case EOpStep:
2239 outputTriplet(out, visit, "step(", ", ", ")");
2240 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002241 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002242 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2243 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002244 case EOpFrexp:
2245 case EOpLdexp:
2246 ASSERT(node->getUseEmulatedFunction());
2247 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2248 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002249 case EOpDistance:
2250 outputTriplet(out, visit, "distance(", ", ", ")");
2251 break;
2252 case EOpDot:
2253 outputTriplet(out, visit, "dot(", ", ", ")");
2254 break;
2255 case EOpCross:
2256 outputTriplet(out, visit, "cross(", ", ", ")");
2257 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002258 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002259 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002260 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002261 break;
2262 case EOpReflect:
2263 outputTriplet(out, visit, "reflect(", ", ", ")");
2264 break;
2265 case EOpRefract:
2266 outputTriplet(out, visit, "refract(", ", ", ")");
2267 break;
2268 case EOpOuterProduct:
2269 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002270 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002271 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002272 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002273 outputTriplet(out, visit, "(", " * ", ")");
2274 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002275 case EOpBitfieldExtract:
2276 case EOpBitfieldInsert:
2277 case EOpUaddCarry:
2278 case EOpUsubBorrow:
2279 case EOpUmulExtended:
2280 case EOpImulExtended:
2281 ASSERT(node->getUseEmulatedFunction());
2282 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2283 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002284 case EOpBarrier:
2285 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2286 // cheapest *WithGroupSync() function, without any functionality loss, but
2287 // with the potential for severe performance loss.
2288 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2289 break;
2290 case EOpMemoryBarrierShared:
2291 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2292 break;
2293 case EOpMemoryBarrierAtomicCounter:
2294 case EOpMemoryBarrierBuffer:
2295 case EOpMemoryBarrierImage:
2296 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2297 break;
2298 case EOpGroupMemoryBarrier:
2299 case EOpMemoryBarrier:
2300 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2301 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002302
2303 // Single atomic function calls without return value.
2304 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2305 case EOpAtomicAdd:
2306 case EOpAtomicMin:
2307 case EOpAtomicMax:
2308 case EOpAtomicAnd:
2309 case EOpAtomicOr:
2310 case EOpAtomicXor:
2311 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2312 ",", ")");
2313 break;
2314
2315 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2316 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2317 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2318 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2319 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2320 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2321 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2322 // intermediate tree before traversing outputHLSL.
2323 case EOpAtomicExchange:
2324 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002325 default:
2326 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002327 }
2328
2329 return true;
2330}
2331
Olli Etuaho57961272016-09-14 13:57:46 +03002332void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002333{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002334 out << "if (";
2335
2336 node->getCondition()->traverse(this);
2337
2338 out << ")\n";
2339
Jamie Madill8c46ab12015-12-07 16:39:19 -05002340 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002341
2342 bool discard = false;
2343
2344 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002345 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002346 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002347 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002348
Olli Etuahoa6f22092015-05-08 18:31:10 +03002349 // Detect true discard
2350 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2351 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002352 else
2353 {
2354 // TODO(oetuaho): Check if the semicolon inside is necessary.
2355 // It's there as a result of conservative refactoring of the output.
2356 out << "{;}\n";
2357 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002358
Jamie Madill8c46ab12015-12-07 16:39:19 -05002359 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002360
Olli Etuahoa6f22092015-05-08 18:31:10 +03002361 if (node->getFalseBlock())
2362 {
2363 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002364
Jamie Madill8c46ab12015-12-07 16:39:19 -05002365 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002366
Olli Etuaho32db19b2016-10-04 14:43:16 +01002367 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002368 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002369
Jamie Madill8c46ab12015-12-07 16:39:19 -05002370 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002371
Olli Etuahoa6f22092015-05-08 18:31:10 +03002372 // Detect false discard
2373 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2374 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002375
Olli Etuahoa6f22092015-05-08 18:31:10 +03002376 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002377 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002378 {
2379 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002380 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002381}
2382
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002383bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2384{
2385 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2386 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2387 UNREACHABLE();
2388 return false;
2389}
2390
Olli Etuaho57961272016-09-14 13:57:46 +03002391bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002392{
2393 TInfoSinkBase &out = getInfoSink();
2394
Olli Etuaho3d932d82016-04-12 11:10:30 +03002395 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002396
2397 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002398 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002399 {
2400 out << "FLATTEN ";
2401 }
2402
Olli Etuaho57961272016-09-14 13:57:46 +03002403 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404
2405 return false;
2406}
2407
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002408bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002409{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002410 TInfoSinkBase &out = getInfoSink();
2411
Olli Etuaho923ecef2017-10-11 12:01:38 +03002412 ASSERT(node->getStatementList());
2413 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002414 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002415 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002416 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002417 outputTriplet(out, visit, "switch (", ") ", "");
2418 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002419 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002420}
2421
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002422bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002423{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002424 TInfoSinkBase &out = getInfoSink();
2425
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002426 if (node->hasCondition())
2427 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002428 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002429 return true;
2430 }
2431 else
2432 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002433 out << "default:\n";
2434 return false;
2435 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002436}
2437
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002438void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2439{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002440 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002441 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002442}
2443
2444bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2445{
Nicolas Capens655fe362014-04-11 13:12:34 -04002446 mNestedLoopDepth++;
2447
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002448 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002449 mInsideDiscontinuousLoop =
2450 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002451
Jamie Madill8c46ab12015-12-07 16:39:19 -05002452 TInfoSinkBase &out = getInfoSink();
2453
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002454 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002455 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002456 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002457 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002458 mInsideDiscontinuousLoop = wasDiscontinuous;
2459 mNestedLoopDepth--;
2460
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002461 return false;
2462 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002463 }
2464
Corentin Wallez1239ee92015-03-19 14:38:02 -07002465 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002466 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002467 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002468 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002469
Jamie Madill8c46ab12015-12-07 16:39:19 -05002470 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471 }
2472 else
2473 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002474 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002475
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002476 if (node->getInit())
2477 {
2478 node->getInit()->traverse(this);
2479 }
2480
2481 out << "; ";
2482
alokp@chromium.org52813552010-11-16 18:36:09 +00002483 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002484 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002485 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002486 }
2487
2488 out << "; ";
2489
alokp@chromium.org52813552010-11-16 18:36:09 +00002490 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002491 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002492 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002493 }
2494
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002495 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002496
Jamie Madill8c46ab12015-12-07 16:39:19 -05002497 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002498 }
2499
2500 if (node->getBody())
2501 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002502 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002503 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002504 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002505 else
2506 {
2507 // TODO(oetuaho): Check if the semicolon inside is necessary.
2508 // It's there as a result of conservative refactoring of the output.
2509 out << "{;}\n";
2510 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002511
Jamie Madill8c46ab12015-12-07 16:39:19 -05002512 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002513
alokp@chromium.org52813552010-11-16 18:36:09 +00002514 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002515 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002516 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002517 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002518
alokp@chromium.org52813552010-11-16 18:36:09 +00002519 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002520
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002521 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002522 }
2523
daniel@transgaming.com73536982012-03-21 20:45:49 +00002524 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002525
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002526 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002527 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002528
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002529 return false;
2530}
2531
2532bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2533{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002534 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002535 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002536 TInfoSinkBase &out = getInfoSink();
2537
2538 switch (node->getFlowOp())
2539 {
2540 case EOpKill:
2541 out << "discard";
2542 break;
2543 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002544 if (mNestedLoopDepth > 1)
2545 {
2546 mUsesNestedBreak = true;
2547 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002548
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002549 if (mExcessiveLoopIndex)
2550 {
2551 out << "{Break";
2552 mExcessiveLoopIndex->traverse(this);
2553 out << " = true; break;}\n";
2554 }
2555 else
2556 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002557 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002558 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002559 break;
2560 case EOpContinue:
2561 out << "continue";
2562 break;
2563 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002564 if (node->getExpression())
2565 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002566 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002567 out << "return ";
2568 }
2569 else
2570 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002571 if (mInsideMain && shaderNeedsGenerateOutput())
2572 {
2573 out << "return " << generateOutputCall();
2574 }
2575 else
2576 {
2577 out << "return";
2578 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002579 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002580 break;
2581 default:
2582 UNREACHABLE();
2583 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002584 }
2585
2586 return true;
2587}
2588
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002589// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002590// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2591// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002592bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002593{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002594 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002595
2596 // Parse loops of the form:
2597 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002598 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002599 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002600 int initial = 0;
2601 int limit = 0;
2602 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002603
2604 // Parse index name and intial value
2605 if (node->getInit())
2606 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002607 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002608
2609 if (init)
2610 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002611 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002612 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002613
2614 if (variable && variable->getQualifier() == EvqTemporary)
2615 {
2616 TIntermBinary *assign = variable->getAsBinaryNode();
2617
2618 if (assign->getOp() == EOpInitialize)
2619 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002620 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002621 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2622
2623 if (symbol && constant)
2624 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002625 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002626 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002627 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002628 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002629 }
2630 }
2631 }
2632 }
2633 }
2634 }
2635
2636 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002637 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002638 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002639 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002640
Olli Etuahob6af22b2017-12-15 14:05:44 +02002641 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002642 {
2643 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2644
2645 if (constant)
2646 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002647 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002648 {
2649 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002650 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002651 }
2652 }
2653 }
2654 }
2655
2656 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002657 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002658 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002659 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002660 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002661
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002662 if (binaryTerminal)
2663 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002664 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002665 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2666
2667 if (constant)
2668 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002669 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002670 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002671 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002672
2673 switch (op)
2674 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002675 case EOpAddAssign:
2676 increment = value;
2677 break;
2678 case EOpSubAssign:
2679 increment = -value;
2680 break;
2681 default:
2682 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002683 }
2684 }
2685 }
2686 }
2687 else if (unaryTerminal)
2688 {
2689 TOperator op = unaryTerminal->getOp();
2690
2691 switch (op)
2692 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002693 case EOpPostIncrement:
2694 increment = 1;
2695 break;
2696 case EOpPostDecrement:
2697 increment = -1;
2698 break;
2699 case EOpPreIncrement:
2700 increment = 1;
2701 break;
2702 case EOpPreDecrement:
2703 increment = -1;
2704 break;
2705 default:
2706 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002707 }
2708 }
2709 }
2710
Yunchao He4f285442017-04-21 12:15:49 +08002711 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002712 {
2713 if (comparator == EOpLessThanEqual)
2714 {
2715 comparator = EOpLessThan;
2716 limit += 1;
2717 }
2718
2719 if (comparator == EOpLessThan)
2720 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002721 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002722
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002723 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002724 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002725 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002726 }
2727
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002728 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002729 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002730
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002731 out << "{int ";
2732 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002733 out << ";\n"
2734 "bool Break";
2735 index->traverse(this);
2736 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002737
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002738 bool firstLoopFragment = true;
2739
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002740 while (iterations > 0)
2741 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002742 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002743
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002744 if (!firstLoopFragment)
2745 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002746 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002747 index->traverse(this);
2748 out << ") {\n";
2749 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002750
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002751 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002752 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002753 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002754 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002755
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002756 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002757 const char *unroll =
2758 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002759
Corentin Wallez1239ee92015-03-19 14:38:02 -07002760 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002761 index->traverse(this);
2762 out << " = ";
2763 out << initial;
2764
2765 out << "; ";
2766 index->traverse(this);
2767 out << " < ";
2768 out << clampedLimit;
2769
2770 out << "; ";
2771 index->traverse(this);
2772 out << " += ";
2773 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002774 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002775
Jamie Madill8c46ab12015-12-07 16:39:19 -05002776 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002777 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002778
2779 if (node->getBody())
2780 {
2781 node->getBody()->traverse(this);
2782 }
2783
Jamie Madill8c46ab12015-12-07 16:39:19 -05002784 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002785 out << ";}\n";
2786
2787 if (!firstLoopFragment)
2788 {
2789 out << "}\n";
2790 }
2791
2792 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002793
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002794 initial += MAX_LOOP_ITERATIONS * increment;
2795 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002796 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002797
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002798 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002799
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002800 mExcessiveLoopIndex = restoreIndex;
2801
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002802 return true;
2803 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002804 else
2805 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002806 }
2807
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002808 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002809}
2810
Jamie Madill8c46ab12015-12-07 16:39:19 -05002811void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2812 Visit visit,
2813 const char *preString,
2814 const char *inString,
2815 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002816{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002817 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002818 {
2819 out << preString;
2820 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002821 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002822 {
2823 out << inString;
2824 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002825 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002826 {
2827 out << postString;
2828 }
2829}
2830
Jamie Madill8c46ab12015-12-07 16:39:19 -05002831void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002832{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002833 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002834 {
Jamie Madill32aab012015-01-27 14:12:26 -05002835 out << "\n";
2836 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002837
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002838 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002839 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002840 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002841 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002842
Jamie Madill32aab012015-01-27 14:12:26 -05002843 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002844 }
2845}
2846
Olli Etuahod4bd9632018-03-08 16:32:44 +02002847void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002848{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002849 const TType &type = param->getType();
2850 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002851
Olli Etuahod4bd9632018-03-08 16:32:44 +02002852 TString nameStr = DecorateVariableIfNeeded(*param);
2853 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002854
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002855 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002856 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002857 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2858 {
2859 // Samplers are passed as indices to the sampler array.
2860 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002861 out << "const uint " << nameStr << ArrayString(type);
2862 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002863 }
2864 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2865 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002866 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2867 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2868 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2869 << ArrayString(type);
2870 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002871 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002872 }
2873
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002874 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2875 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002876
2877 // If the structure parameter contains samplers, they need to be passed into the function as
2878 // separate parameters. HLSL doesn't natively support samplers in structs.
2879 if (type.isStructureContainingSamplers())
2880 {
2881 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002882 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002883 std::string namePrefix = "angle";
2884 namePrefix += nameStr.c_str();
2885 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2886 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002887 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002888 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002889 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002890 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2891 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002892 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002893 }
2894 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2895 {
Olli Etuaho96963162016-03-21 11:54:33 +02002896 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002897 out << ", " << QualifierString(qualifier) << " "
2898 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2899 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2900 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2901 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002902 }
2903 else
2904 {
Olli Etuaho96963162016-03-21 11:54:33 +02002905 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002906 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2907 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002908 }
2909 }
2910 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002911}
2912
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002913TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002914{
2915 TString string;
2916
Jamie Madill94bf7f22013-07-08 13:31:15 -04002917 size_t size = type.getObjectSize();
2918 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002919 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002920 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002921
Jamie Madill94bf7f22013-07-08 13:31:15 -04002922 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002923 {
2924 string += ", ";
2925 }
2926 }
2927
daniel@transgaming.comead23042010-04-29 03:35:36 +00002928 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002929}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002930
Olli Etuahobd3cd502017-11-03 15:48:52 +02002931void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002932{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002933 // Array constructors should have been already pruned from the code.
2934 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002935
2936 if (visit == PreVisit)
2937 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002938 TString constructorName;
2939 if (node->getBasicType() == EbtStruct)
2940 {
2941 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2942 }
2943 else
2944 {
2945 constructorName =
2946 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2947 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002948 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002949 }
2950 else if (visit == InVisit)
2951 {
2952 out << ", ";
2953 }
2954 else if (visit == PostVisit)
2955 {
2956 out << ")";
2957 }
2958}
2959
Jamie Madill8c46ab12015-12-07 16:39:19 -05002960const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2961 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002962 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002963{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002964 ASSERT(!type.isArray());
2965
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002966 const TConstantUnion *constUnionIterated = constUnion;
2967
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002968 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002969 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002970 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002971 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002972
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002973 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002974
Jamie Madill98493dd2013-07-08 14:39:03 -04002975 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002976 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002977 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002978 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002979
Jamie Madill98493dd2013-07-08 14:39:03 -04002980 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002981 {
2982 out << ", ";
2983 }
2984 }
2985
2986 out << ")";
2987 }
2988 else
2989 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002990 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002991 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002992
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002993 if (writeType)
2994 {
Jamie Madill033dae62014-06-18 12:56:28 -04002995 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002996 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002997 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002998 if (writeType)
2999 {
3000 out << ")";
3001 }
3002 }
3003
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003004 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003005}
3006
Olli Etuahod68924e2017-01-02 17:34:40 +00003007void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003008{
Olli Etuahod68924e2017-01-02 17:34:40 +00003009 if (visit == PreVisit)
3010 {
3011 const char *opStr = GetOperatorString(op);
3012 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3013 out << "(";
3014 }
3015 else
3016 {
3017 outputTriplet(out, visit, nullptr, ", ", ")");
3018 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003019}
3020
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003021bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3022 TIntermSymbol *symbolNode,
3023 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003024{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003025 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3026 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003027
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003028 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003029 {
3030 // Type already printed
3031 out << "t" + str(mUniqueIndex) + " = ";
3032 expression->traverse(this);
3033 out << ", ";
3034 symbolNode->traverse(this);
3035 out << " = t" + str(mUniqueIndex);
3036
3037 mUniqueIndex++;
3038 return true;
3039 }
3040
3041 return false;
3042}
3043
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003044bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3045 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003046 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003047{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003048 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003049 {
3050 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003051 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003052 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003053 writeConstantUnionArray(out, initializer->getConstantValue(),
3054 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003055 out << "}";
3056 return true;
3057 }
3058 return false;
3059}
3060
Jamie Madill55e79e02015-02-09 15:35:00 -05003061TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3062{
3063 const TFieldList &fields = structure.fields();
3064
3065 for (const auto &eqFunction : mStructEqualityFunctions)
3066 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003067 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003068 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003069 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003070 }
3071 }
3072
3073 const TString &structNameString = StructNameString(structure);
3074
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003075 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003076 function->structure = &structure;
3077 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003078
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003079 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003080
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003081 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3082 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003083 << "{\n"
3084 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003085
3086 for (size_t i = 0; i < fields.size(); i++)
3087 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003088 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003089 const TType *fieldType = field->type();
3090
3091 const TString &fieldNameA = "a." + Decorate(field->name());
3092 const TString &fieldNameB = "b." + Decorate(field->name());
3093
3094 if (i > 0)
3095 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003096 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003097 }
3098
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003099 fnOut << "(";
3100 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3101 fnOut << fieldNameA;
3102 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3103 fnOut << fieldNameB;
3104 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3105 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003106 }
3107
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003108 fnOut << ";\n"
3109 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003110
3111 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003112
3113 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003114 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003115
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003116 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003117}
3118
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003119TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003120{
3121 for (const auto &eqFunction : mArrayEqualityFunctions)
3122 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003123 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003124 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003125 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003126 }
3127 }
3128
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003129 TType elementType(type);
3130 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003131
Olli Etuaho12690762015-03-31 12:55:28 +03003132 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003133 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003134
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003135 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003136
3137 TInfoSinkBase fnOut;
3138
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003139 const TString &typeName = TypeString(type);
3140 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3141 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003142 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003143 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003144 << type.getOutermostArraySize()
3145 << "; ++i)\n"
3146 " {\n"
3147 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003148
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003149 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003150 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003151 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003152 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003153 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003154
3155 fnOut << ") { return false; }\n"
3156 " }\n"
3157 " return true;\n"
3158 "}\n";
3159
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003160 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003161
3162 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003163 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003164
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003165 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003166}
3167
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003168TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003169{
3170 for (const auto &assignFunction : mArrayAssignmentFunctions)
3171 {
3172 if (assignFunction.type == type)
3173 {
3174 return assignFunction.functionName;
3175 }
3176 }
3177
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003178 TType elementType(type);
3179 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003180
3181 ArrayHelperFunction function;
3182 function.type = type;
3183
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003184 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003185
3186 TInfoSinkBase fnOut;
3187
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003188 const TString &typeName = TypeString(type);
3189 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3190 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003191 << "{\n"
3192 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003193 << type.getOutermostArraySize()
3194 << "; ++i)\n"
3195 " {\n"
3196 " ";
3197
3198 outputAssign(PreVisit, elementType, fnOut);
3199 fnOut << "a[i]";
3200 outputAssign(InVisit, elementType, fnOut);
3201 fnOut << "b[i]";
3202 outputAssign(PostVisit, elementType, fnOut);
3203
3204 fnOut << ";\n"
3205 " }\n"
3206 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003207
3208 function.functionDefinition = fnOut.c_str();
3209
3210 mArrayAssignmentFunctions.push_back(function);
3211
3212 return function.functionName;
3213}
3214
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003215TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003216{
3217 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3218 {
3219 if (constructIntoFunction.type == type)
3220 {
3221 return constructIntoFunction.functionName;
3222 }
3223 }
3224
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003225 TType elementType(type);
3226 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003227
3228 ArrayHelperFunction function;
3229 function.type = type;
3230
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003231 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003232
3233 TInfoSinkBase fnOut;
3234
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003235 const TString &typeName = TypeString(type);
3236 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3237 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003238 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003239 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003240 }
3241 fnOut << ")\n"
3242 "{\n";
3243
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003244 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003245 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003246 fnOut << " ";
3247 outputAssign(PreVisit, elementType, fnOut);
3248 fnOut << "a[" << i << "]";
3249 outputAssign(InVisit, elementType, fnOut);
3250 fnOut << "b" << i;
3251 outputAssign(PostVisit, elementType, fnOut);
3252 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003253 }
3254 fnOut << "}\n";
3255
3256 function.functionDefinition = fnOut.c_str();
3257
3258 mArrayConstructIntoFunctions.push_back(function);
3259
3260 return function.functionName;
3261}
3262
Jamie Madill2e295e22015-04-29 10:41:33 -04003263void OutputHLSL::ensureStructDefined(const TType &type)
3264{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003265 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003266 if (structure)
3267 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003268 ASSERT(type.getBasicType() == EbtStruct);
3269 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003270 }
3271}
3272
Olli Etuaho06235df2018-07-20 14:26:07 +03003273bool OutputHLSL::shaderNeedsGenerateOutput() const
3274{
3275 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3276}
3277
3278const char *OutputHLSL::generateOutputCall() const
3279{
3280 if (mShaderType == GL_VERTEX_SHADER)
3281 {
3282 return "generateOutput(input)";
3283 }
3284 else
3285 {
3286 return "generateOutput()";
3287 }
3288}
3289
Jamie Madill45bcc782016-11-07 13:58:48 -05003290} // namespace sh