blob: 65925f72dcf14ff7176c29e6b371b386133810b1 [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
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800317const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
Jamie Madill4e1fd412014-07-10 17:50:10 -0400318{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800319 return mResourcesHLSL->getUniformBlockRegisterMap();
Jamie Madill4e1fd412014-07-10 17:50:10 -0400320}
321
Jamie Madill9fe25e92014-07-18 10:33:08 -0400322const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
323{
Qin Jiajia3e217f62018-08-28 16:55:20 +0800324 return mResourcesHLSL->getUniformRegisterMap();
Jamie Madill9fe25e92014-07-18 10:33:08 -0400325}
326
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200327TString OutputHLSL::structInitializerString(int indent,
328 const TType &type,
329 const TString &name) const
Jamie Madill570e04d2013-06-21 09:15:33 -0400330{
331 TString init;
332
Olli Etuahoed049ab2017-06-30 17:38:33 +0300333 TString indentString;
334 for (int spaces = 0; spaces < indent; spaces++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400335 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300336 indentString += " ";
Jamie Madill570e04d2013-06-21 09:15:33 -0400337 }
338
Olli Etuahoed049ab2017-06-30 17:38:33 +0300339 if (type.isArray())
Jamie Madill570e04d2013-06-21 09:15:33 -0400340 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300341 init += indentString + "{\n";
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300342 for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 {
Olli Etuahoed049ab2017-06-30 17:38:33 +0300344 TStringStream indexedString;
345 indexedString << name << "[" << arrayIndex << "]";
346 TType elementType = type;
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300347 elementType.toArrayElementType();
Olli Etuahoed049ab2017-06-30 17:38:33 +0300348 init += structInitializerString(indent + 1, elementType, indexedString.str());
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300349 if (arrayIndex < type.getOutermostArraySize() - 1)
Olli Etuahoed049ab2017-06-30 17:38:33 +0300350 {
351 init += ",";
352 }
353 init += "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400354 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300355 init += indentString + "}";
Jamie Madill570e04d2013-06-21 09:15:33 -0400356 }
Olli Etuahoed049ab2017-06-30 17:38:33 +0300357 else if (type.getBasicType() == EbtStruct)
358 {
359 init += indentString + "{\n";
360 const TStructure &structure = *type.getStruct();
361 const TFieldList &fields = structure.fields();
362 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
363 {
364 const TField &field = *fields[fieldIndex];
365 const TString &fieldName = name + "." + Decorate(field.name());
366 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400367
Olli Etuahoed049ab2017-06-30 17:38:33 +0300368 init += structInitializerString(indent + 1, fieldType, fieldName);
369 if (fieldIndex < fields.size() - 1)
370 {
371 init += ",";
372 }
373 init += "\n";
374 }
375 init += indentString + "}";
376 }
377 else
378 {
379 init += indentString + name;
380 }
Jamie Madill570e04d2013-06-21 09:15:33 -0400381
382 return init;
383}
384
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200385TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
386{
387 TString mappedStructs;
388
389 for (auto &mappedStruct : std140Structs)
390 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200391 const TInterfaceBlock *interfaceBlock =
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200392 mappedStruct.blockDeclarator->getType().getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800393 TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
394 switch (qualifier)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200395 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800396 case EvqUniform:
397 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
398 {
399 continue;
400 }
401 break;
402 case EvqBuffer:
403 continue;
404 default:
405 UNREACHABLE();
406 return mappedStructs;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200407 }
408
409 unsigned int instanceCount = 1u;
410 bool isInstanceArray = mappedStruct.blockDeclarator->isArray();
411 if (isInstanceArray)
412 {
413 instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
414 }
415
416 for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
417 ++instanceArrayIndex)
418 {
419 TString originalName;
420 TString mappedName("map");
421
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200422 if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200423 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200424 const ImmutableString &instanceName =
425 mappedStruct.blockDeclarator->variable().name();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200426 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
427 if (isInstanceArray)
428 instanceStringArrayIndex = instanceArrayIndex;
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800429 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200430 instanceName, instanceStringArrayIndex);
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200431 originalName += instanceString;
432 mappedName += instanceString;
433 originalName += ".";
434 mappedName += "_";
435 }
436
437 TString fieldName = Decorate(mappedStruct.field->name());
438 originalName += fieldName;
439 mappedName += fieldName;
440
441 TType *structType = mappedStruct.field->type();
442 mappedStructs +=
Olli Etuahobed35d72017-12-20 16:36:26 +0200443 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200444
445 if (structType->isArray())
446 {
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300447 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200448 }
449
450 mappedStructs += " =\n";
451 mappedStructs += structInitializerString(0, *structType, originalName);
452 mappedStructs += ";\n";
453 }
454 }
455 return mappedStructs;
456}
457
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300458void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459{
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300460 for (const auto &attribute : mReferencedAttributes)
461 {
462 const TType &type = attribute.second->getType();
463 const ImmutableString &name = attribute.second->name();
Jamie Madill570e04d2013-06-21 09:15:33 -0400464
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300465 out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
466 << zeroInitializer(type) << ";\n";
467 }
468}
469
470void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
471{
Olli Etuahob8cb9392017-12-20 14:23:19 +0200472 for (const auto &varying : mReferencedVaryings)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000473 {
Jiawei Shao203b26f2018-07-25 10:30:43 +0800474 const TType &type = varying.second->getType();
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000475
476 // Program linking depends on this exact format
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300477 out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
Olli Etuahoda41ac62018-07-19 16:45:32 +0300478 << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
479 << zeroInitializer(type) << ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000480 }
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300481}
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000482
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300483void OutputHLSL::header(TInfoSinkBase &out,
484 const std::vector<MappedStruct> &std140Structs,
485 const BuiltInFunctionEmulator *builtInFunctionEmulator) const
486{
487 TString mappedStructs = generateStructMapping(std140Structs);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000488
Jamie Madill8daaba12014-06-13 10:04:33 -0400489 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400490
Qin Jiajia3e217f62018-08-28 16:55:20 +0800491 mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
492 out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks);
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800493 mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
Jamie Madillf91ce812014-06-13 10:04:34 -0400494
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200495 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500496 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200497 out << "\n// Equality functions\n\n";
498 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500499 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200500 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200501 }
502 }
Olli Etuaho12690762015-03-31 12:55:28 +0300503 if (!mArrayAssignmentFunctions.empty())
504 {
505 out << "\n// Assignment functions\n\n";
506 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
507 {
508 out << assignmentFunction.functionDefinition << "\n";
509 }
510 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300511 if (!mArrayConstructIntoFunctions.empty())
512 {
513 out << "\n// Array constructor functions\n\n";
514 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
515 {
516 out << constructIntoFunction.functionDefinition << "\n";
517 }
518 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200519
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500520 if (mUsesDiscardRewriting)
521 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400522 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500523 }
524
Nicolas Capens655fe362014-04-11 13:12:34 -0400525 if (mUsesNestedBreak)
526 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400527 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400528 }
529
Arun Patole44efa0b2015-03-04 17:11:05 +0530530 if (mRequiresIEEEStrictCompiling)
531 {
532 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
533 }
534
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400535 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
536 "#define LOOP [loop]\n"
537 "#define FLATTEN [flatten]\n"
538 "#else\n"
539 "#define LOOP\n"
540 "#define FLATTEN\n"
541 "#endif\n";
542
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200543 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544 {
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300545 const bool usingMRTExtension =
546 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000547
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000548 out << "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300549 writeReferencedVaryings(out);
Jamie Madill46131a32013-06-20 11:55:50 -0400550 out << "\n";
551
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200552 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000553 {
Olli Etuaho93b059d2017-12-20 12:46:58 +0200554 for (const auto &outputVariable : mReferencedOutputVariables)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000555 {
Olli Etuahofbb1c792018-01-19 16:26:59 +0200556 const ImmutableString &variableName = outputVariable.second->name();
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800557 const TType &variableType = outputVariable.second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400558
Olli Etuahofbb1c792018-01-19 16:26:59 +0200559 out << "static " << TypeString(variableType) << " out_" << variableName
560 << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000561 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000562 }
Jamie Madill46131a32013-06-20 11:55:50 -0400563 else
564 {
565 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
566
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +0800567 out << "static float4 gl_Color[" << numColorValues
568 << "] =\n"
569 "{\n";
Jamie Madill46131a32013-06-20 11:55:50 -0400570 for (unsigned int i = 0; i < numColorValues; i++)
571 {
572 out << " float4(0, 0, 0, 0)";
573 if (i + 1 != numColorValues)
574 {
575 out << ",";
576 }
577 out << "\n";
578 }
579
580 out << "};\n";
581 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000582
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400583 if (mUsesFragDepth)
584 {
585 out << "static float gl_Depth = 0.0;\n";
586 }
587
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 if (mUsesFragCoord)
589 {
590 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
591 }
592
593 if (mUsesPointCoord)
594 {
595 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
596 }
597
598 if (mUsesFrontFacing)
599 {
600 out << "static bool gl_FrontFacing = false;\n";
601 }
602
603 out << "\n";
604
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000605 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000606 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000607 out << "struct gl_DepthRangeParameters\n"
608 "{\n"
609 " float near;\n"
610 " float far;\n"
611 " float diff;\n"
612 "};\n"
613 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000614 }
615
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200616 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000617 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000618 out << "cbuffer DriverConstants : register(b1)\n"
619 "{\n";
620
621 if (mUsesDepthRange)
622 {
623 out << " float3 dx_DepthRange : packoffset(c0);\n";
624 }
625
626 if (mUsesFragCoord)
627 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000628 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000629 }
630
631 if (mUsesFragCoord || mUsesFrontFacing)
632 {
633 out << " float3 dx_DepthFront : packoffset(c2);\n";
634 }
635
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800636 if (mUsesFragCoord)
637 {
638 // dx_ViewScale is only used in the fragment shader to correct
639 // the value for glFragCoord if necessary
640 out << " float2 dx_ViewScale : packoffset(c3);\n";
641 }
642
Martin Radev72b4e1e2017-08-31 15:42:56 +0300643 if (mHasMultiviewExtensionEnabled)
644 {
645 // We have to add a value which we can use to keep track of which multi-view code
646 // path is to be selected in the GS.
647 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
648 }
649
Olli Etuaho618bebc2016-01-15 16:40:00 +0200650 if (mOutputType == SH_HLSL_4_1_OUTPUT)
651 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800652 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200653 }
654
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000655 out << "};\n";
656 }
657 else
658 {
659 if (mUsesDepthRange)
660 {
661 out << "uniform float3 dx_DepthRange : register(c0);";
662 }
663
664 if (mUsesFragCoord)
665 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000666 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000667 }
668
669 if (mUsesFragCoord || mUsesFrontFacing)
670 {
671 out << "uniform float3 dx_DepthFront : register(c2);\n";
672 }
673 }
674
675 out << "\n";
676
677 if (mUsesDepthRange)
678 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500679 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
680 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000681 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000682 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000683
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000684 if (usingMRTExtension && mNumRenderTargets > 1)
685 {
686 out << "#define GL_USES_MRT\n";
687 }
688
689 if (mUsesFragColor)
690 {
691 out << "#define GL_USES_FRAG_COLOR\n";
692 }
693
694 if (mUsesFragData)
695 {
696 out << "#define GL_USES_FRAG_DATA\n";
697 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698 }
Xinghua Caob1239382016-12-13 15:07:05 +0800699 else if (mShaderType == GL_VERTEX_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000700 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000701 out << "// Attributes\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300702 writeReferencedAttributes(out);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000703 out << "\n"
704 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400705
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000706 if (mUsesPointSize)
707 {
708 out << "static float gl_PointSize = float(1);\n";
709 }
710
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000711 if (mUsesInstanceID)
712 {
713 out << "static int gl_InstanceID;";
714 }
715
Corentin Wallezb076add2016-01-11 16:45:46 -0500716 if (mUsesVertexID)
717 {
718 out << "static int gl_VertexID;";
719 }
720
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000721 out << "\n"
722 "// Varyings\n";
Olli Etuahod8b1c5c2018-06-20 12:08:46 +0300723 writeReferencedVaryings(out);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000724 out << "\n";
725
726 if (mUsesDepthRange)
727 {
728 out << "struct gl_DepthRangeParameters\n"
729 "{\n"
730 " float near;\n"
731 " float far;\n"
732 " float diff;\n"
733 "};\n"
734 "\n";
735 }
736
Olli Etuaho9b4e8622015-12-22 15:53:22 +0200737 if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000738 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800739 out << "cbuffer DriverConstants : register(b1)\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 "{\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800741
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000742 if (mUsesDepthRange)
743 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800744 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000745 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800746
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800747 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
748 // shaders. However, we declare it for all shaders (including Feature Level 10+).
749 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
750 // if it's unused.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800751 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800752 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800753 out << " float2 dx_ViewScale : packoffset(c3);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800754
Martin Radev72b4e1e2017-08-31 15:42:56 +0300755 if (mHasMultiviewExtensionEnabled)
756 {
757 // We have to add a value which we can use to keep track of which multi-view code
758 // path is to be selected in the GS.
759 out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
760 }
761
Olli Etuaho618bebc2016-01-15 16:40:00 +0200762 if (mOutputType == SH_HLSL_4_1_OUTPUT)
763 {
Qin Jiajia3e217f62018-08-28 16:55:20 +0800764 mResourcesHLSL->samplerMetadataUniforms(out, "c4");
Olli Etuaho618bebc2016-01-15 16:40:00 +0200765 }
766
Austin Kinross4fd18b12014-12-22 12:32:05 -0800767 out << "};\n"
768 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000769 }
770 else
771 {
772 if (mUsesDepthRange)
773 {
774 out << "uniform float3 dx_DepthRange : register(c0);\n";
775 }
776
Cooper Partine6664f02015-01-09 16:22:24 -0800777 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
778 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000779 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000780 }
781
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000782 if (mUsesDepthRange)
783 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500784 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
785 "dx_DepthRange.y, dx_DepthRange.z};\n"
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000786 "\n";
787 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400788 }
Xinghua Caob1239382016-12-13 15:07:05 +0800789 else // Compute shader
790 {
791 ASSERT(mShaderType == GL_COMPUTE_SHADER);
Xinghua Cao73badc02017-03-29 19:14:53 +0800792
793 out << "cbuffer DriverConstants : register(b1)\n"
794 "{\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800795 if (mUsesNumWorkGroups)
796 {
Xinghua Caob1239382016-12-13 15:07:05 +0800797 out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800798 }
Xinghua Cao73badc02017-03-29 19:14:53 +0800799 ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
Qin Jiajia3e217f62018-08-28 16:55:20 +0800800 mResourcesHLSL->samplerMetadataUniforms(out, "c1");
Xinghua Cao73badc02017-03-29 19:14:53 +0800801 out << "};\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800802
Jiawei Shao203b26f2018-07-25 10:30:43 +0800803 std::ostringstream systemValueDeclaration;
804 std::ostringstream glBuiltinInitialization;
805
806 systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
807 glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
808 << "{\n";
809
Xinghua Caob1239382016-12-13 15:07:05 +0800810 if (mUsesWorkGroupID)
811 {
812 out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800813 systemValueDeclaration << " uint3 dx_WorkGroupID : "
814 << "SV_GroupID;\n";
815 glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800816 }
817
818 if (mUsesLocalInvocationID)
819 {
820 out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800821 systemValueDeclaration << " uint3 dx_LocalInvocationID : "
822 << "SV_GroupThreadID;\n";
823 glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800824 }
825
826 if (mUsesGlobalInvocationID)
827 {
828 out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800829 systemValueDeclaration << " uint3 dx_GlobalInvocationID : "
830 << "SV_DispatchThreadID;\n";
831 glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800832 }
833
834 if (mUsesLocalInvocationIndex)
835 {
836 out << "static uint gl_LocalInvocationIndex = uint(0);\n";
Jiawei Shao203b26f2018-07-25 10:30:43 +0800837 systemValueDeclaration << " uint dx_LocalInvocationIndex : "
838 << "SV_GroupIndex;\n";
839 glBuiltinInitialization
840 << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
Xinghua Caob1239382016-12-13 15:07:05 +0800841 }
Jiawei Shao203b26f2018-07-25 10:30:43 +0800842
843 systemValueDeclaration << "};\n\n";
844 glBuiltinInitialization << "};\n\n";
845
846 out << systemValueDeclaration.str();
847 out << glBuiltinInitialization.str();
Xinghua Caob1239382016-12-13 15:07:05 +0800848 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000849
Qin Jiajia2a12b3d2018-05-23 13:42:13 +0800850 if (!mappedStructs.empty())
851 {
852 out << "// Structures from std140 blocks with padding removed\n";
853 out << "\n";
854 out << mappedStructs;
855 out << "\n";
856 }
857
Geoff Lang1fe74c72016-08-25 13:23:01 -0400858 bool getDimensionsIgnoresBaseLevel =
859 (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
860 mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
Xinghua Cao711b7a12017-10-09 13:38:12 +0800861 mImageFunctionHLSL->imageFunctionHeader(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000862
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000863 if (mUsesFragCoord)
864 {
865 out << "#define GL_USES_FRAG_COORD\n";
866 }
867
868 if (mUsesPointCoord)
869 {
870 out << "#define GL_USES_POINT_COORD\n";
871 }
872
873 if (mUsesFrontFacing)
874 {
875 out << "#define GL_USES_FRONT_FACING\n";
876 }
877
878 if (mUsesPointSize)
879 {
880 out << "#define GL_USES_POINT_SIZE\n";
881 }
882
Martin Radev41ac68e2017-06-06 12:16:58 +0300883 if (mHasMultiviewExtensionEnabled)
884 {
885 out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
886 }
887
888 if (mUsesViewID)
889 {
890 out << "#define GL_USES_VIEW_ID\n";
891 }
892
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400893 if (mUsesFragDepth)
894 {
895 out << "#define GL_USES_FRAG_DEPTH\n";
896 }
897
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000898 if (mUsesDepthRange)
899 {
900 out << "#define GL_USES_DEPTH_RANGE\n";
901 }
902
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000903 if (mUsesXor)
904 {
905 out << "bool xor(bool p, bool q)\n"
906 "{\n"
907 " return (p || q) && !(p && q);\n"
908 "}\n"
909 "\n";
910 }
911
Olli Etuahodfa75e82017-01-23 09:43:06 -0800912 builtInFunctionEmulator->outputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000913}
914
915void OutputHLSL::visitSymbol(TIntermSymbol *node)
916{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200917 const TVariable &variable = node->variable();
918
919 // Empty symbols can only appear in declarations and function arguments, and in either of those
920 // cases the symbol nodes are not visited.
921 ASSERT(variable.symbolType() != SymbolType::Empty);
922
Jamie Madill32aab012015-01-27 14:12:26 -0500923 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924
Jamie Madill570e04d2013-06-21 09:15:33 -0400925 // Handle accessing std140 structs by value
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800926 if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct)
Jamie Madill570e04d2013-06-21 09:15:33 -0400927 {
Olli Etuaho2ef23e22017-11-01 16:39:11 +0200928 out << "map";
Jamie Madill570e04d2013-06-21 09:15:33 -0400929 }
930
Olli Etuahofbb1c792018-01-19 16:26:59 +0200931 const ImmutableString &name = variable.name();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200932 const TSymbolUniqueId &uniqueId = variable.uniqueId();
Olli Etuaho93b059d2017-12-20 12:46:58 +0200933
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000934 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000935 {
936 mUsesDepthRange = true;
937 out << name;
938 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000939 else
940 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200941 const TType &variableType = variable.getType();
942 TQualifier qualifier = variable.getType().getQualifier();
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000943
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200944 ensureStructDefined(variableType);
Olli Etuahobd3cd502017-11-03 15:48:52 +0200945
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000946 if (qualifier == EvqUniform)
947 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200948 const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -0400949
950 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000951 {
Olli Etuahoc71862a2017-12-21 12:58:29 +0200952 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
953 {
954 const TVariable *instanceVariable = nullptr;
955 if (variableType.isInterfaceBlock())
956 {
957 instanceVariable = &variable;
958 }
959 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
960 new TReferencedBlock(interfaceBlock, instanceVariable);
961 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000962 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000963 else
964 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200965 mReferencedUniforms[uniqueId.get()] = &variable;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000966 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400967
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200968 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000969 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +0800970 else if (qualifier == EvqBuffer)
971 {
972 UNREACHABLE();
973 }
Jamie Madill19571812013-08-12 15:26:34 -0700974 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000975 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200976 mReferencedAttributes[uniqueId.get()] = &variable;
Jamie Madill033dae62014-06-18 12:56:28 -0400977 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000978 }
Jamie Madill033dae62014-06-18 12:56:28 -0400979 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000980 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200981 mReferencedVaryings[uniqueId.get()] = &variable;
Olli Etuahoda41ac62018-07-19 16:45:32 +0300982 out << DecorateVariableIfNeeded(variable);
983 if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
Martin Radev41ac68e2017-06-06 12:16:58 +0300984 {
985 mUsesViewID = true;
986 }
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000987 }
Jamie Madill19571812013-08-12 15:26:34 -0700988 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -0400989 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +0200990 mReferencedOutputVariables[uniqueId.get()] = &variable;
Jamie Madill46131a32013-06-20 11:55:50 -0400991 out << "out_" << name;
992 }
993 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +0000994 {
995 out << "gl_Color[0]";
996 mUsesFragColor = true;
997 }
998 else if (qualifier == EvqFragData)
999 {
1000 out << "gl_Color";
1001 mUsesFragData = true;
1002 }
1003 else if (qualifier == EvqFragCoord)
1004 {
1005 mUsesFragCoord = true;
1006 out << name;
1007 }
1008 else if (qualifier == EvqPointCoord)
1009 {
1010 mUsesPointCoord = true;
1011 out << name;
1012 }
1013 else if (qualifier == EvqFrontFacing)
1014 {
1015 mUsesFrontFacing = true;
1016 out << name;
1017 }
1018 else if (qualifier == EvqPointSize)
1019 {
1020 mUsesPointSize = true;
1021 out << name;
1022 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001023 else if (qualifier == EvqInstanceID)
1024 {
1025 mUsesInstanceID = true;
1026 out << name;
1027 }
Corentin Wallezb076add2016-01-11 16:45:46 -05001028 else if (qualifier == EvqVertexID)
1029 {
1030 mUsesVertexID = true;
1031 out << name;
1032 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001033 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001034 {
1035 mUsesFragDepth = true;
1036 out << "gl_Depth";
1037 }
Xinghua Caob1239382016-12-13 15:07:05 +08001038 else if (qualifier == EvqNumWorkGroups)
1039 {
1040 mUsesNumWorkGroups = true;
1041 out << name;
1042 }
1043 else if (qualifier == EvqWorkGroupID)
1044 {
1045 mUsesWorkGroupID = true;
1046 out << name;
1047 }
1048 else if (qualifier == EvqLocalInvocationID)
1049 {
1050 mUsesLocalInvocationID = true;
1051 out << name;
1052 }
1053 else if (qualifier == EvqGlobalInvocationID)
1054 {
1055 mUsesGlobalInvocationID = true;
1056 out << name;
1057 }
1058 else if (qualifier == EvqLocalInvocationIndex)
1059 {
1060 mUsesLocalInvocationIndex = true;
1061 out << name;
1062 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001063 else
1064 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001065 out << DecorateVariableIfNeeded(variable);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001066 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 }
1068}
1069
Olli Etuaho7fb49552015-03-18 17:27:44 +02001070void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1071{
1072 if (type.isScalar() && !type.isArray())
1073 {
1074 if (op == EOpEqual)
1075 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001076 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001077 }
1078 else
1079 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001080 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001081 }
1082 }
1083 else
1084 {
1085 if (visit == PreVisit && op == EOpNotEqual)
1086 {
1087 out << "!";
1088 }
1089
1090 if (type.isArray())
1091 {
1092 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001093 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001094 }
1095 else if (type.getBasicType() == EbtStruct)
1096 {
1097 const TStructure &structure = *type.getStruct();
1098 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001099 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001100 }
1101 else
1102 {
1103 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001104 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001105 }
1106 }
1107}
1108
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001109void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1110{
1111 if (type.isArray())
1112 {
1113 const TString &functionName = addArrayAssignmentFunction(type);
1114 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1115 }
1116 else
1117 {
1118 outputTriplet(out, visit, "(", " = ", ")");
1119 }
1120}
1121
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001122bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
Olli Etuaho96963162016-03-21 11:54:33 +02001123{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001124 for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
Olli Etuaho96963162016-03-21 11:54:33 +02001125 {
1126 TIntermNode *ancestor = getAncestorNode(n);
1127 const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1128 if (ancestorBinary == nullptr)
1129 {
1130 return false;
1131 }
1132 switch (ancestorBinary->getOp())
1133 {
1134 case EOpIndexDirectStruct:
1135 {
1136 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1137 const TIntermConstantUnion *index =
1138 ancestorBinary->getRight()->getAsConstantUnion();
1139 const TField *field = structure->fields()[index->getIConst(0)];
1140 if (IsSampler(field->type()->getBasicType()))
1141 {
1142 return true;
1143 }
1144 break;
1145 }
1146 case EOpIndexDirect:
1147 break;
1148 default:
1149 // Returning a sampler from indirect indexing is not supported.
1150 return false;
1151 }
1152 }
1153 return false;
1154}
1155
Olli Etuahob6fa0432016-09-28 16:28:05 +01001156bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1157{
1158 TInfoSinkBase &out = getInfoSink();
1159 if (visit == PostVisit)
1160 {
1161 out << ".";
1162 node->writeOffsetsAsXYZW(&out);
1163 }
1164 return true;
1165}
1166
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001167bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1168{
Jamie Madill32aab012015-01-27 14:12:26 -05001169 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001170
1171 switch (node->getOp())
1172 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001173 case EOpComma:
1174 outputTriplet(out, visit, "(", ", ", ")");
1175 break;
1176 case EOpAssign:
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001177 if (node->isArray())
Olli Etuaho9638c352015-04-01 14:34:52 +03001178 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001179 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1180 if (rightAgg != nullptr && rightAgg->isConstructor())
Olli Etuaho9638c352015-04-01 14:34:52 +03001181 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001182 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1183 out << functionName << "(";
1184 node->getLeft()->traverse(this);
1185 TIntermSequence *seq = rightAgg->getSequence();
1186 for (auto &arrayElement : *seq)
1187 {
1188 out << ", ";
1189 arrayElement->traverse(this);
1190 }
1191 out << ")";
1192 return false;
Olli Etuaho9638c352015-04-01 14:34:52 +03001193 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001194 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1195 // function call is assigned.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08001196 ASSERT(rightAgg == nullptr);
Olli Etuaho9638c352015-04-01 14:34:52 +03001197 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001198 // Assignment expressions with atomic functions should be transformed into atomic
1199 // function calls in HLSL.
1200 // e.g. original_value = atomicAdd(dest, value) should be translated into
1201 // InterlockedAdd(dest, value, original_value);
1202 else if (IsAtomicFunctionDirectAssign(*node))
1203 {
1204 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1205 TOperator atomicFunctionOp = atomicFunctionNode->getOp();
1206 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1207 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1208 ASSERT(argumentSeq->size() >= 2u);
1209 for (auto &argument : *argumentSeq)
1210 {
1211 argument->traverse(this);
1212 out << ", ";
1213 }
1214 node->getLeft()->traverse(this);
1215 out << ")";
1216 return false;
1217 }
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001218 else if (IsInShaderStorageBlock(node->getLeft()))
1219 {
1220 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1221 out << ", ";
1222 if (IsInShaderStorageBlock(node->getRight()))
1223 {
1224 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1225 }
1226 else
1227 {
1228 node->getRight()->traverse(this);
1229 }
1230
1231 out << ")";
1232 return false;
1233 }
1234 else if (IsInShaderStorageBlock(node->getRight()))
1235 {
1236 node->getLeft()->traverse(this);
1237 out << " = ";
1238 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1239 return false;
1240 }
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001241
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001242 outputAssign(visit, node->getType(), out);
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001243 break;
1244 case EOpInitialize:
1245 if (visit == PreVisit)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001246 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001247 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1248 ASSERT(symbolNode);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001249 TIntermTyped *initializer = node->getRight();
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001250
1251 // Global initializers must be constant at this point.
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001252 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001253
1254 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1255 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1256 // new variable is created before the assignment is evaluated), so we need to
1257 // convert
1258 // this to "float t = x, x = t;".
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001259 if (writeSameSymbolInitializer(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001260 {
1261 // Skip initializing the rest of the expression
1262 return false;
1263 }
Olli Etuahoea22b7a2018-01-04 17:09:11 +02001264 else if (writeConstantInitialization(out, symbolNode, initializer))
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001265 {
1266 return false;
1267 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001268 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001269 else if (visit == InVisit)
1270 {
1271 out << " = ";
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001272 if (IsInShaderStorageBlock(node->getRight()))
1273 {
1274 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1275 return false;
1276 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +01001277 }
1278 break;
1279 case EOpAddAssign:
1280 outputTriplet(out, visit, "(", " += ", ")");
1281 break;
1282 case EOpSubAssign:
1283 outputTriplet(out, visit, "(", " -= ", ")");
1284 break;
1285 case EOpMulAssign:
1286 outputTriplet(out, visit, "(", " *= ", ")");
1287 break;
1288 case EOpVectorTimesScalarAssign:
1289 outputTriplet(out, visit, "(", " *= ", ")");
1290 break;
1291 case EOpMatrixTimesScalarAssign:
1292 outputTriplet(out, visit, "(", " *= ", ")");
1293 break;
1294 case EOpVectorTimesMatrixAssign:
1295 if (visit == PreVisit)
1296 {
1297 out << "(";
1298 }
1299 else if (visit == InVisit)
1300 {
1301 out << " = mul(";
1302 node->getLeft()->traverse(this);
1303 out << ", transpose(";
1304 }
1305 else
1306 {
1307 out << ")))";
1308 }
1309 break;
1310 case EOpMatrixTimesMatrixAssign:
1311 if (visit == PreVisit)
1312 {
1313 out << "(";
1314 }
1315 else if (visit == InVisit)
1316 {
1317 out << " = transpose(mul(transpose(";
1318 node->getLeft()->traverse(this);
1319 out << "), transpose(";
1320 }
1321 else
1322 {
1323 out << "))))";
1324 }
1325 break;
1326 case EOpDivAssign:
1327 outputTriplet(out, visit, "(", " /= ", ")");
1328 break;
1329 case EOpIModAssign:
1330 outputTriplet(out, visit, "(", " %= ", ")");
1331 break;
1332 case EOpBitShiftLeftAssign:
1333 outputTriplet(out, visit, "(", " <<= ", ")");
1334 break;
1335 case EOpBitShiftRightAssign:
1336 outputTriplet(out, visit, "(", " >>= ", ")");
1337 break;
1338 case EOpBitwiseAndAssign:
1339 outputTriplet(out, visit, "(", " &= ", ")");
1340 break;
1341 case EOpBitwiseXorAssign:
1342 outputTriplet(out, visit, "(", " ^= ", ")");
1343 break;
1344 case EOpBitwiseOrAssign:
1345 outputTriplet(out, visit, "(", " |= ", ")");
1346 break;
1347 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001348 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001349 const TType &leftType = node->getLeft()->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -04001350 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001351 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001352 if (visit == PreVisit)
1353 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001354 TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
Olli Etuahodd21ecf2018-01-10 12:42:09 +02001355 const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001356
1357 ASSERT(leftType.getQualifier() == EvqUniform);
Olli Etuahoc71862a2017-12-21 12:58:29 +02001358 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1359 {
1360 mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1361 new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1362 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001363 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001364 out << mResourcesHLSL->InterfaceBlockInstanceString(
Qin Jiajia3e217f62018-08-28 16:55:20 +08001365 instanceArraySymbol->getName(), arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001366 return false;
1367 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001368 }
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001369 else if (ancestorEvaluatesToSamplerInStruct())
Olli Etuaho96963162016-03-21 11:54:33 +02001370 {
1371 // All parts of an expression that access a sampler in a struct need to use _ as
1372 // separator to access the sampler variable that has been moved out of the struct.
1373 outputTriplet(out, visit, "", "_", "");
1374 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001375 else
1376 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001377 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001378 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001379 }
1380 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001381 case EOpIndexIndirect:
1382 // We do not currently support indirect references to interface blocks
1383 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1384 outputTriplet(out, visit, "", "[", "]");
1385 break;
1386 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001387 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001388 const TStructure *structure = node->getLeft()->getType().getStruct();
1389 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1390 const TField *field = structure->fields()[index->getIConst(0)];
Jamie Madill98493dd2013-07-08 14:39:03 -04001391
Olli Etuaho96963162016-03-21 11:54:33 +02001392 // In cases where indexing returns a sampler, we need to access the sampler variable
1393 // that has been moved out of the struct.
1394 bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1395 if (visit == PreVisit && indexingReturnsSampler)
1396 {
1397 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1398 // This prefix is only output at the beginning of the indexing expression, which
1399 // may have multiple parts.
1400 out << "angle";
1401 }
1402 if (!indexingReturnsSampler)
1403 {
1404 // All parts of an expression that access a sampler in a struct need to use _ as
1405 // separator to access the sampler variable that has been moved out of the struct.
Olli Etuaho1d9dcc22017-01-19 11:25:32 +00001406 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001407 }
1408 if (visit == InVisit)
1409 {
1410 if (indexingReturnsSampler)
1411 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001412 out << "_" << field->name();
Olli Etuaho96963162016-03-21 11:54:33 +02001413 }
1414 else
1415 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02001416 out << "." << DecorateField(field->name(), *structure);
Olli Etuaho96963162016-03-21 11:54:33 +02001417 }
1418
1419 return false;
1420 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001421 }
1422 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001423 case EOpIndexDirectInterfaceBlock:
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001424 {
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001425 ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1426 bool structInStd140UniformBlock =
1427 node->getBasicType() == EbtStruct && IsInStd140UniformBlock(node->getLeft());
1428 if (visit == PreVisit && structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001429 {
1430 out << "map";
1431 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001432 if (visit == InVisit)
1433 {
1434 const TInterfaceBlock *interfaceBlock =
1435 node->getLeft()->getType().getInterfaceBlock();
1436 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1437 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Qin Jiajiaa735ee22018-05-18 13:29:09 +08001438 if (structInStd140UniformBlock)
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001439 {
1440 out << "_";
1441 }
1442 else
1443 {
1444 out << ".";
1445 }
1446 out << Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001447
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001448 return false;
1449 }
1450 break;
Olli Etuaho2ef23e22017-11-01 16:39:11 +02001451 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001452 case EOpAdd:
1453 outputTriplet(out, visit, "(", " + ", ")");
1454 break;
1455 case EOpSub:
1456 outputTriplet(out, visit, "(", " - ", ")");
1457 break;
1458 case EOpMul:
1459 outputTriplet(out, visit, "(", " * ", ")");
1460 break;
1461 case EOpDiv:
1462 outputTriplet(out, visit, "(", " / ", ")");
1463 break;
1464 case EOpIMod:
1465 outputTriplet(out, visit, "(", " % ", ")");
1466 break;
1467 case EOpBitShiftLeft:
1468 outputTriplet(out, visit, "(", " << ", ")");
1469 break;
1470 case EOpBitShiftRight:
1471 outputTriplet(out, visit, "(", " >> ", ")");
1472 break;
1473 case EOpBitwiseAnd:
1474 outputTriplet(out, visit, "(", " & ", ")");
1475 break;
1476 case EOpBitwiseXor:
1477 outputTriplet(out, visit, "(", " ^ ", ")");
1478 break;
1479 case EOpBitwiseOr:
1480 outputTriplet(out, visit, "(", " | ", ")");
1481 break;
1482 case EOpEqual:
1483 case EOpNotEqual:
1484 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1485 break;
1486 case EOpLessThan:
1487 outputTriplet(out, visit, "(", " < ", ")");
1488 break;
1489 case EOpGreaterThan:
1490 outputTriplet(out, visit, "(", " > ", ")");
1491 break;
1492 case EOpLessThanEqual:
1493 outputTriplet(out, visit, "(", " <= ", ")");
1494 break;
1495 case EOpGreaterThanEqual:
1496 outputTriplet(out, visit, "(", " >= ", ")");
1497 break;
1498 case EOpVectorTimesScalar:
1499 outputTriplet(out, visit, "(", " * ", ")");
1500 break;
1501 case EOpMatrixTimesScalar:
1502 outputTriplet(out, visit, "(", " * ", ")");
1503 break;
1504 case EOpVectorTimesMatrix:
1505 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1506 break;
1507 case EOpMatrixTimesVector:
1508 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1509 break;
1510 case EOpMatrixTimesMatrix:
1511 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1512 break;
1513 case EOpLogicalOr:
1514 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
1515 // been unfolded.
1516 ASSERT(!node->getRight()->hasSideEffects());
1517 outputTriplet(out, visit, "(", " || ", ")");
1518 return true;
1519 case EOpLogicalXor:
1520 mUsesXor = true;
1521 outputTriplet(out, visit, "xor(", ", ", ")");
1522 break;
1523 case EOpLogicalAnd:
1524 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
1525 // been unfolded.
1526 ASSERT(!node->getRight()->hasSideEffects());
1527 outputTriplet(out, visit, "(", " && ", ")");
1528 return true;
1529 default:
1530 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001531 }
1532
1533 return true;
1534}
1535
1536bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1537{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001538 TInfoSinkBase &out = getInfoSink();
1539
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001540 switch (node->getOp())
1541 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001542 case EOpNegative:
1543 outputTriplet(out, visit, "(-", "", ")");
1544 break;
1545 case EOpPositive:
1546 outputTriplet(out, visit, "(+", "", ")");
1547 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001548 case EOpLogicalNot:
1549 outputTriplet(out, visit, "(!", "", ")");
1550 break;
1551 case EOpBitwiseNot:
1552 outputTriplet(out, visit, "(~", "", ")");
1553 break;
1554 case EOpPostIncrement:
1555 outputTriplet(out, visit, "(", "", "++)");
1556 break;
1557 case EOpPostDecrement:
1558 outputTriplet(out, visit, "(", "", "--)");
1559 break;
1560 case EOpPreIncrement:
1561 outputTriplet(out, visit, "(++", "", ")");
1562 break;
1563 case EOpPreDecrement:
1564 outputTriplet(out, visit, "(--", "", ")");
1565 break;
1566 case EOpRadians:
1567 outputTriplet(out, visit, "radians(", "", ")");
1568 break;
1569 case EOpDegrees:
1570 outputTriplet(out, visit, "degrees(", "", ")");
1571 break;
1572 case EOpSin:
1573 outputTriplet(out, visit, "sin(", "", ")");
1574 break;
1575 case EOpCos:
1576 outputTriplet(out, visit, "cos(", "", ")");
1577 break;
1578 case EOpTan:
1579 outputTriplet(out, visit, "tan(", "", ")");
1580 break;
1581 case EOpAsin:
1582 outputTriplet(out, visit, "asin(", "", ")");
1583 break;
1584 case EOpAcos:
1585 outputTriplet(out, visit, "acos(", "", ")");
1586 break;
1587 case EOpAtan:
1588 outputTriplet(out, visit, "atan(", "", ")");
1589 break;
1590 case EOpSinh:
1591 outputTriplet(out, visit, "sinh(", "", ")");
1592 break;
1593 case EOpCosh:
1594 outputTriplet(out, visit, "cosh(", "", ")");
1595 break;
1596 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001597 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001598 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001599 case EOpAtanh:
1600 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001601 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001602 break;
1603 case EOpExp:
1604 outputTriplet(out, visit, "exp(", "", ")");
1605 break;
1606 case EOpLog:
1607 outputTriplet(out, visit, "log(", "", ")");
1608 break;
1609 case EOpExp2:
1610 outputTriplet(out, visit, "exp2(", "", ")");
1611 break;
1612 case EOpLog2:
1613 outputTriplet(out, visit, "log2(", "", ")");
1614 break;
1615 case EOpSqrt:
1616 outputTriplet(out, visit, "sqrt(", "", ")");
1617 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001618 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001619 outputTriplet(out, visit, "rsqrt(", "", ")");
1620 break;
1621 case EOpAbs:
1622 outputTriplet(out, visit, "abs(", "", ")");
1623 break;
1624 case EOpSign:
1625 outputTriplet(out, visit, "sign(", "", ")");
1626 break;
1627 case EOpFloor:
1628 outputTriplet(out, visit, "floor(", "", ")");
1629 break;
1630 case EOpTrunc:
1631 outputTriplet(out, visit, "trunc(", "", ")");
1632 break;
1633 case EOpRound:
1634 outputTriplet(out, visit, "round(", "", ")");
1635 break;
1636 case EOpRoundEven:
1637 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001638 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001639 break;
1640 case EOpCeil:
1641 outputTriplet(out, visit, "ceil(", "", ")");
1642 break;
1643 case EOpFract:
1644 outputTriplet(out, visit, "frac(", "", ")");
1645 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001646 case EOpIsnan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001647 if (node->getUseEmulatedFunction())
Olli Etuahod68924e2017-01-02 17:34:40 +00001648 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001649 else
1650 outputTriplet(out, visit, "isnan(", "", ")");
1651 mRequiresIEEEStrictCompiling = true;
1652 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02001653 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001654 outputTriplet(out, visit, "isinf(", "", ")");
1655 break;
1656 case EOpFloatBitsToInt:
1657 outputTriplet(out, visit, "asint(", "", ")");
1658 break;
1659 case EOpFloatBitsToUint:
1660 outputTriplet(out, visit, "asuint(", "", ")");
1661 break;
1662 case EOpIntBitsToFloat:
1663 outputTriplet(out, visit, "asfloat(", "", ")");
1664 break;
1665 case EOpUintBitsToFloat:
1666 outputTriplet(out, visit, "asfloat(", "", ")");
1667 break;
1668 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001669 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001670 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001671 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001672 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001673 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -08001674 case EOpPackUnorm4x8:
1675 case EOpPackSnorm4x8:
1676 case EOpUnpackUnorm4x8:
1677 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001678 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001679 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001680 break;
1681 case EOpLength:
1682 outputTriplet(out, visit, "length(", "", ")");
1683 break;
1684 case EOpNormalize:
1685 outputTriplet(out, visit, "normalize(", "", ")");
1686 break;
1687 case EOpDFdx:
1688 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1689 {
1690 outputTriplet(out, visit, "(", "", ", 0.0)");
1691 }
1692 else
1693 {
1694 outputTriplet(out, visit, "ddx(", "", ")");
1695 }
1696 break;
1697 case EOpDFdy:
1698 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1699 {
1700 outputTriplet(out, visit, "(", "", ", 0.0)");
1701 }
1702 else
1703 {
1704 outputTriplet(out, visit, "ddy(", "", ")");
1705 }
1706 break;
1707 case EOpFwidth:
1708 if (mInsideDiscontinuousLoop || mOutputLod0Function)
1709 {
1710 outputTriplet(out, visit, "(", "", ", 0.0)");
1711 }
1712 else
1713 {
1714 outputTriplet(out, visit, "fwidth(", "", ")");
1715 }
1716 break;
1717 case EOpTranspose:
1718 outputTriplet(out, visit, "transpose(", "", ")");
1719 break;
1720 case EOpDeterminant:
1721 outputTriplet(out, visit, "determinant(transpose(", "", "))");
1722 break;
1723 case EOpInverse:
1724 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00001725 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001726 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001727
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001728 case EOpAny:
1729 outputTriplet(out, visit, "any(", "", ")");
1730 break;
1731 case EOpAll:
1732 outputTriplet(out, visit, "all(", "", ")");
1733 break;
Olli Etuahod68924e2017-01-02 17:34:40 +00001734 case EOpLogicalNotComponentWise:
1735 outputTriplet(out, visit, "(!", "", ")");
1736 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00001737 case EOpBitfieldReverse:
1738 outputTriplet(out, visit, "reversebits(", "", ")");
1739 break;
1740 case EOpBitCount:
1741 outputTriplet(out, visit, "countbits(", "", ")");
1742 break;
1743 case EOpFindLSB:
1744 // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
1745 // in GLSLTest and results are consistent with GL.
1746 outputTriplet(out, visit, "firstbitlow(", "", ")");
1747 break;
1748 case EOpFindMSB:
1749 // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
1750 // tested in GLSLTest and results are consistent with GL.
1751 outputTriplet(out, visit, "firstbithigh(", "", ")");
1752 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001753 default:
1754 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001755 }
1756
1757 return true;
1758}
1759
Olli Etuahofbb1c792018-01-19 16:26:59 +02001760ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
Olli Etuaho96963162016-03-21 11:54:33 +02001761{
1762 if (node->getAsSymbolNode())
1763 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001764 ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
1765 return node->getAsSymbolNode()->getName();
Olli Etuaho96963162016-03-21 11:54:33 +02001766 }
1767 TIntermBinary *nodeBinary = node->getAsBinaryNode();
1768 switch (nodeBinary->getOp())
1769 {
1770 case EOpIndexDirect:
1771 {
1772 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1773
Olli Etuahofbb1c792018-01-19 16:26:59 +02001774 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001775 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
Olli Etuahofbb1c792018-01-19 16:26:59 +02001776 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001777 }
1778 case EOpIndexDirectStruct:
1779 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02001780 const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
Olli Etuaho96963162016-03-21 11:54:33 +02001781 int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1782 const TField *field = s->fields()[index];
1783
Olli Etuahofbb1c792018-01-19 16:26:59 +02001784 std::stringstream prefixSink;
Olli Etuaho96963162016-03-21 11:54:33 +02001785 prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1786 << field->name();
Olli Etuahofbb1c792018-01-19 16:26:59 +02001787 return ImmutableString(prefixSink.str());
Olli Etuaho96963162016-03-21 11:54:33 +02001788 }
1789 default:
1790 UNREACHABLE();
Jamie Madillb779b122018-06-20 11:46:43 -04001791 return kEmptyImmutableString;
Olli Etuaho96963162016-03-21 11:54:33 +02001792 }
1793}
1794
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001795bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1796{
1797 TInfoSinkBase &out = getInfoSink();
1798
Olli Etuaho06235df2018-07-20 14:26:07 +03001799 bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
1800
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001801 if (mInsideFunction)
1802 {
1803 outputLineDirective(out, node->getLine().first_line);
1804 out << "{\n";
Olli Etuaho06235df2018-07-20 14:26:07 +03001805 if (isMainBlock)
1806 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08001807 if (mShaderType == GL_COMPUTE_SHADER)
1808 {
1809 out << "initGLBuiltins(input);\n";
1810 }
1811 else
1812 {
1813 out << "@@ MAIN PROLOGUE @@\n";
1814 }
Olli Etuaho06235df2018-07-20 14:26:07 +03001815 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001816 }
1817
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001818 for (TIntermNode *statement : *node->getSequence())
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001819 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001820 outputLineDirective(out, statement->getLine().first_line);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001821
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001822 statement->traverse(this);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001823
1824 // Don't output ; after case labels, they're terminated by :
1825 // This is needed especially since outputting a ; after a case statement would turn empty
1826 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001827 // Also the output code is clearer if we don't output ; after statements where it is not
1828 // needed:
1829 // * if statements
1830 // * switch statements
1831 // * blocks
1832 // * function definitions
1833 // * loops (do-while loops output the semicolon in VisitLoop)
1834 // * declarations that don't generate output.
1835 if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
1836 statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
1837 statement->getAsSwitchNode() == nullptr &&
1838 statement->getAsFunctionDefinition() == nullptr &&
1839 (statement->getAsDeclarationNode() == nullptr ||
1840 IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
1841 statement->getAsInvariantDeclarationNode() == nullptr)
1842 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001843 out << ";\n";
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001844 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001845 }
1846
1847 if (mInsideFunction)
1848 {
1849 outputLineDirective(out, node->getLine().last_line);
Olli Etuaho06235df2018-07-20 14:26:07 +03001850 if (isMainBlock && shaderNeedsGenerateOutput())
1851 {
1852 // We could have an empty main, a main function without a branch at the end, or a main
1853 // function with a discard statement at the end. In these cases we need to add a return
1854 // statement.
1855 bool needReturnStatement =
1856 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
1857 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
1858 if (needReturnStatement)
1859 {
1860 out << "return " << generateOutputCall() << ";\n";
1861 }
1862 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001863 out << "}\n";
1864 }
1865
1866 return false;
1867}
1868
Olli Etuaho336b1472016-10-05 16:37:55 +01001869bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1870{
1871 TInfoSinkBase &out = getInfoSink();
1872
1873 ASSERT(mCurrentFunctionMetadata == nullptr);
1874
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001875 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho336b1472016-10-05 16:37:55 +01001876 ASSERT(index != CallDAG::InvalidIndex);
1877 mCurrentFunctionMetadata = &mASTMetadataList[index];
1878
Olli Etuahod4bd9632018-03-08 16:32:44 +02001879 const TFunction *func = node->getFunction();
Olli Etuaho336b1472016-10-05 16:37:55 +01001880
Olli Etuahod4bd9632018-03-08 16:32:44 +02001881 if (func->isMain())
Olli Etuaho336b1472016-10-05 16:37:55 +01001882 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001883 // The stub strings below are replaced when shader is dynamically defined by its layout:
1884 switch (mShaderType)
1885 {
1886 case GL_VERTEX_SHADER:
1887 out << "@@ VERTEX ATTRIBUTES @@\n\n"
1888 << "@@ VERTEX OUTPUT @@\n\n"
1889 << "VS_OUTPUT main(VS_INPUT input)";
1890 break;
1891 case GL_FRAGMENT_SHADER:
1892 out << "@@ PIXEL OUTPUT @@\n\n"
1893 << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
1894 break;
1895 case GL_COMPUTE_SHADER:
1896 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
1897 << mWorkGroupSize[2] << ")]\n";
1898 out << "void main(CS_INPUT input)";
1899 break;
1900 default:
1901 UNREACHABLE();
1902 break;
1903 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001904 }
1905 else
1906 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001907 out << TypeString(node->getFunctionPrototype()->getType()) << " ";
Olli Etuahod4bd9632018-03-08 16:32:44 +02001908 out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001909 << (mOutputLod0Function ? "Lod0(" : "(");
Olli Etuaho336b1472016-10-05 16:37:55 +01001910
Olli Etuaho06235df2018-07-20 14:26:07 +03001911 size_t paramCount = func->getParamCount();
1912 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho336b1472016-10-05 16:37:55 +01001913 {
Olli Etuaho06235df2018-07-20 14:26:07 +03001914 const TVariable *param = func->getParam(i);
1915 ensureStructDefined(param->getType());
Olli Etuaho336b1472016-10-05 16:37:55 +01001916
Olli Etuaho06235df2018-07-20 14:26:07 +03001917 writeParameter(param, out);
1918
1919 if (i < paramCount - 1)
1920 {
1921 out << ", ";
1922 }
1923 }
1924
1925 out << ")\n";
1926 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001927
1928 mInsideFunction = true;
Olli Etuaho06235df2018-07-20 14:26:07 +03001929 if (func->isMain())
1930 {
1931 mInsideMain = true;
1932 }
Olli Etuaho336b1472016-10-05 16:37:55 +01001933 // The function body node will output braces.
1934 node->getBody()->traverse(this);
1935 mInsideFunction = false;
Olli Etuaho06235df2018-07-20 14:26:07 +03001936 mInsideMain = false;
Olli Etuaho336b1472016-10-05 16:37:55 +01001937
1938 mCurrentFunctionMetadata = nullptr;
1939
1940 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1941 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1942 {
Olli Etuahobeb6dc72017-12-14 16:03:03 +02001943 ASSERT(!node->getFunction()->isMain());
Olli Etuaho336b1472016-10-05 16:37:55 +01001944 mOutputLod0Function = true;
1945 node->traverse(this);
1946 mOutputLod0Function = false;
1947 }
1948
1949 return false;
1950}
1951
Olli Etuaho13389b62016-10-16 11:48:18 +01001952bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1953{
Olli Etuaho13389b62016-10-16 11:48:18 +01001954 if (visit == PreVisit)
1955 {
1956 TIntermSequence *sequence = node->getSequence();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001957 TIntermTyped *declarator = (*sequence)[0]->getAsTyped();
Olli Etuaho13389b62016-10-16 11:48:18 +01001958 ASSERT(sequence->size() == 1);
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001959 ASSERT(declarator);
Olli Etuaho13389b62016-10-16 11:48:18 +01001960
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001961 if (IsDeclarationWrittenOut(node))
Olli Etuaho13389b62016-10-16 11:48:18 +01001962 {
Olli Etuaho40dbdd62017-10-13 13:34:19 +03001963 TInfoSinkBase &out = getInfoSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001964 ensureStructDefined(declarator->getType());
Olli Etuaho13389b62016-10-16 11:48:18 +01001965
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001966 if (!declarator->getAsSymbolNode() ||
1967 declarator->getAsSymbolNode()->variable().symbolType() !=
1968 SymbolType::Empty) // Variable declaration
Olli Etuaho13389b62016-10-16 11:48:18 +01001969 {
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001970 if (declarator->getQualifier() == EvqShared)
1971 {
1972 out << "groupshared ";
1973 }
1974 else if (!mInsideFunction)
Olli Etuaho13389b62016-10-16 11:48:18 +01001975 {
1976 out << "static ";
1977 }
1978
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001979 out << TypeString(declarator->getType()) + " ";
Olli Etuaho13389b62016-10-16 11:48:18 +01001980
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001981 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho13389b62016-10-16 11:48:18 +01001982
1983 if (symbol)
1984 {
1985 symbol->traverse(this);
1986 out << ArrayString(symbol->getType());
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001987 // We don't initialize shared variables because:
1988 // 1. It is very slow for D3D11 drivers to compile a compute shader if we add
1989 // code to initialize a groupshared array variable with a large array size.
1990 // 2. It is unnecessary to initialize shared variables, as GLSL even does not
1991 // allow initializing shared variables at all.
1992 if (declarator->getQualifier() != EvqShared)
1993 {
1994 out << " = " + zeroInitializer(symbol->getType());
1995 }
Olli Etuaho13389b62016-10-16 11:48:18 +01001996 }
1997 else
1998 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001999 declarator->traverse(this);
Olli Etuaho13389b62016-10-16 11:48:18 +01002000 }
2001 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002002 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002003 else if (IsVaryingOut(declarator->getQualifier()))
Olli Etuaho13389b62016-10-16 11:48:18 +01002004 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02002005 TIntermSymbol *symbol = declarator->getAsSymbolNode();
Olli Etuaho282847e2017-07-12 14:11:01 +03002006 ASSERT(symbol); // Varying declarations can't have initializers.
Olli Etuaho13389b62016-10-16 11:48:18 +01002007
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002008 const TVariable &variable = symbol->variable();
2009
2010 if (variable.symbolType() != SymbolType::Empty)
Olli Etuaho93b059d2017-12-20 12:46:58 +02002011 {
2012 // Vertex outputs which are declared but not written to should still be declared to
2013 // allow successful linking.
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002014 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
Olli Etuaho93b059d2017-12-20 12:46:58 +02002015 }
Olli Etuaho13389b62016-10-16 11:48:18 +01002016 }
2017 }
2018 return false;
2019}
2020
Olli Etuahobf4e1b72016-12-09 11:30:15 +00002021bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
2022{
2023 // Do not do any translation
2024 return false;
2025}
2026
Olli Etuahod4bd9632018-03-08 16:32:44 +02002027void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002028{
2029 TInfoSinkBase &out = getInfoSink();
2030
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002031 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Olli Etuaho16c745a2017-01-16 17:02:27 +00002032 // Skip the prototype if it is not implemented (and thus not used)
2033 if (index == CallDAG::InvalidIndex)
2034 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002035 return;
Olli Etuaho16c745a2017-01-16 17:02:27 +00002036 }
2037
Olli Etuahod4bd9632018-03-08 16:32:44 +02002038 const TFunction *func = node->getFunction();
Olli Etuaho16c745a2017-01-16 17:02:27 +00002039
Olli Etuahod4bd9632018-03-08 16:32:44 +02002040 TString name = DecorateFunctionIfNeeded(func);
2041 out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002042 << (mOutputLod0Function ? "Lod0(" : "(");
2043
Olli Etuahod4bd9632018-03-08 16:32:44 +02002044 size_t paramCount = func->getParamCount();
2045 for (unsigned int i = 0; i < paramCount; i++)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002046 {
Olli Etuahod4bd9632018-03-08 16:32:44 +02002047 writeParameter(func->getParam(i), out);
Olli Etuaho16c745a2017-01-16 17:02:27 +00002048
Olli Etuahod4bd9632018-03-08 16:32:44 +02002049 if (i < paramCount - 1)
Olli Etuaho16c745a2017-01-16 17:02:27 +00002050 {
2051 out << ", ";
2052 }
2053 }
2054
2055 out << ");\n";
2056
2057 // Also prototype the Lod0 variant if needed
2058 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2059 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2060 {
2061 mOutputLod0Function = true;
2062 node->traverse(this);
2063 mOutputLod0Function = false;
2064 }
Olli Etuaho16c745a2017-01-16 17:02:27 +00002065}
2066
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002067bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2068{
Jamie Madill32aab012015-01-27 14:12:26 -05002069 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002070
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002071 switch (node->getOp())
2072 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002073 case EOpCallBuiltInFunction:
2074 case EOpCallFunctionInAST:
2075 case EOpCallInternalRawFunction:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002077 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002078
Corentin Wallez1239ee92015-03-19 14:38:02 -07002079 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002080 if (node->getOp() == EOpCallFunctionInAST)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002082 if (node->isArray())
2083 {
2084 UNIMPLEMENTED();
2085 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002086 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
Corentin Wallez1239ee92015-03-19 14:38:02 -07002087 ASSERT(index != CallDAG::InvalidIndex);
2088 lod0 &= mASTMetadataList[index].mNeedsLod0;
2089
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002090 out << DecorateFunctionIfNeeded(node->getFunction());
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002091 out << DisambiguateFunctionName(node->getSequence());
2092 out << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002093 }
Olli Etuaho1ecd14b2017-01-26 13:54:15 -08002094 else if (node->getOp() == EOpCallInternalRawFunction)
Olli Etuahob741c762016-06-29 15:49:22 +03002095 {
2096 // This path is used for internal functions that don't have their definitions in the
2097 // AST, such as precision emulation functions.
Olli Etuahobeb6dc72017-12-14 16:03:03 +02002098 out << DecorateFunctionIfNeeded(node->getFunction()) << "(";
Olli Etuahob741c762016-06-29 15:49:22 +03002099 }
Olli Etuaho1bb85282017-12-14 13:39:53 +02002100 else if (node->getFunction()->isImageFunction())
Xinghua Cao711b7a12017-10-09 13:38:12 +08002101 {
Jiawei Shao203b26f2018-07-25 10:30:43 +08002102 const ImmutableString &name = node->getFunction()->name();
Olli Etuaho8fbd9d92018-06-21 15:27:44 +03002103 TType type = (*arguments)[0]->getAsTyped()->getType();
2104 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
Olli Etuahobed35d72017-12-20 16:36:26 +02002105 name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
Xinghua Cao711b7a12017-10-09 13:38:12 +08002106 type.getMemoryQualifier().readonly);
2107 out << imageFunctionName << "(";
2108 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002109 else
2110 {
Olli Etuahofbb1c792018-01-19 16:26:59 +02002111 const ImmutableString &name = node->getFunction()->name();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002112 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
Olli Etuaho92db39e2017-02-15 12:11:04 +00002113 int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument.
2114 if (arguments->size() > 1)
2115 {
2116 coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2117 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +02002118 const ImmutableString &textureFunctionName =
2119 mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2120 arguments->size(), lod0, mShaderType);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03002121 out << textureFunctionName << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002122 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002123
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002124 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002125 {
Olli Etuaho96963162016-03-21 11:54:33 +02002126 TIntermTyped *typedArg = (*arg)->getAsTyped();
2127 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002128 {
2129 out << "texture_";
2130 (*arg)->traverse(this);
2131 out << ", sampler_";
2132 }
2133
2134 (*arg)->traverse(this);
2135
Olli Etuaho96963162016-03-21 11:54:33 +02002136 if (typedArg->getType().isStructureContainingSamplers())
2137 {
2138 const TType &argType = typedArg->getType();
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002139 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002140 ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2141 std::string namePrefix = "angle_";
2142 namePrefix += structName.data();
2143 argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
Olli Etuaho2d88e9b2017-07-21 16:52:03 +03002144 nullptr, mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002145 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002146 {
2147 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2148 {
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002149 out << ", texture_" << sampler->name();
2150 out << ", sampler_" << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002151 }
2152 else
2153 {
2154 // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2155 // of D3D9, it's the sampler variable.
Olli Etuahofbb1c792018-01-19 16:26:59 +02002156 out << ", " << sampler->name();
Olli Etuaho96963162016-03-21 11:54:33 +02002157 }
2158 }
2159 }
2160
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002161 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002162 {
2163 out << ", ";
2164 }
2165 }
2166
2167 out << ")";
2168
2169 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002170 }
Olli Etuaho8fab3202017-05-08 18:22:22 +03002171 case EOpConstruct:
Olli Etuahobd3cd502017-11-03 15:48:52 +02002172 outputConstructor(out, visit, node);
Olli Etuaho8fab3202017-05-08 18:22:22 +03002173 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002174 case EOpEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002175 outputTriplet(out, visit, "(", " == ", ")");
2176 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002177 case EOpNotEqualComponentWise:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002178 outputTriplet(out, visit, "(", " != ", ")");
2179 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002180 case EOpLessThanComponentWise:
2181 outputTriplet(out, visit, "(", " < ", ")");
2182 break;
2183 case EOpGreaterThanComponentWise:
2184 outputTriplet(out, visit, "(", " > ", ")");
2185 break;
2186 case EOpLessThanEqualComponentWise:
2187 outputTriplet(out, visit, "(", " <= ", ")");
2188 break;
2189 case EOpGreaterThanEqualComponentWise:
2190 outputTriplet(out, visit, "(", " >= ", ")");
2191 break;
Olli Etuaho5878f832016-10-07 10:14:58 +01002192 case EOpMod:
2193 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002194 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002195 break;
2196 case EOpModf:
2197 outputTriplet(out, visit, "modf(", ", ", ")");
2198 break;
2199 case EOpPow:
2200 outputTriplet(out, visit, "pow(", ", ", ")");
2201 break;
2202 case EOpAtan:
2203 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2204 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002205 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002206 break;
2207 case EOpMin:
2208 outputTriplet(out, visit, "min(", ", ", ")");
2209 break;
2210 case EOpMax:
2211 outputTriplet(out, visit, "max(", ", ", ")");
2212 break;
2213 case EOpClamp:
2214 outputTriplet(out, visit, "clamp(", ", ", ")");
2215 break;
2216 case EOpMix:
Arun Patoled94f6642015-05-18 16:25:12 +05302217 {
2218 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2219 if (lastParamNode->getType().getBasicType() == EbtBool)
2220 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002221 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2222 // y, genBType a)",
Arun Patoled94f6642015-05-18 16:25:12 +05302223 // so use emulated version.
2224 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002225 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Arun Patoled94f6642015-05-18 16:25:12 +05302226 }
2227 else
2228 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002229 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302230 }
Olli Etuaho5878f832016-10-07 10:14:58 +01002231 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302232 }
Jamie Madill8c46ab12015-12-07 16:39:19 -05002233 case EOpStep:
2234 outputTriplet(out, visit, "step(", ", ", ")");
2235 break;
Olli Etuahof7f0b8c2018-02-21 20:02:23 +02002236 case EOpSmoothstep:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002237 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2238 break;
Olli Etuaho74da73f2017-02-01 15:37:48 +00002239 case EOpFrexp:
2240 case EOpLdexp:
2241 ASSERT(node->getUseEmulatedFunction());
2242 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2243 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002244 case EOpDistance:
2245 outputTriplet(out, visit, "distance(", ", ", ")");
2246 break;
2247 case EOpDot:
2248 outputTriplet(out, visit, "dot(", ", ", ")");
2249 break;
2250 case EOpCross:
2251 outputTriplet(out, visit, "cross(", ", ", ")");
2252 break;
Jamie Madille72595b2017-06-06 15:12:26 -04002253 case EOpFaceforward:
Olli Etuaho5878f832016-10-07 10:14:58 +01002254 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002255 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002256 break;
2257 case EOpReflect:
2258 outputTriplet(out, visit, "reflect(", ", ", ")");
2259 break;
2260 case EOpRefract:
2261 outputTriplet(out, visit, "refract(", ", ", ")");
2262 break;
2263 case EOpOuterProduct:
2264 ASSERT(node->getUseEmulatedFunction());
Olli Etuahod68924e2017-01-02 17:34:40 +00002265 writeEmulatedFunctionTriplet(out, visit, node->getOp());
Olli Etuaho5878f832016-10-07 10:14:58 +01002266 break;
Olli Etuahoe1805592017-01-02 16:41:20 +00002267 case EOpMulMatrixComponentWise:
Olli Etuaho5878f832016-10-07 10:14:58 +01002268 outputTriplet(out, visit, "(", " * ", ")");
2269 break;
Olli Etuaho9250cb22017-01-21 10:51:27 +00002270 case EOpBitfieldExtract:
2271 case EOpBitfieldInsert:
2272 case EOpUaddCarry:
2273 case EOpUsubBorrow:
2274 case EOpUmulExtended:
2275 case EOpImulExtended:
2276 ASSERT(node->getUseEmulatedFunction());
2277 writeEmulatedFunctionTriplet(out, visit, node->getOp());
2278 break;
Xinghua Cao47335852018-02-12 15:41:55 +08002279 case EOpBarrier:
2280 // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2281 // cheapest *WithGroupSync() function, without any functionality loss, but
2282 // with the potential for severe performance loss.
2283 outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2284 break;
2285 case EOpMemoryBarrierShared:
2286 outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2287 break;
2288 case EOpMemoryBarrierAtomicCounter:
2289 case EOpMemoryBarrierBuffer:
2290 case EOpMemoryBarrierImage:
2291 outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2292 break;
2293 case EOpGroupMemoryBarrier:
2294 case EOpMemoryBarrier:
2295 outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2296 break;
Jiawei Shaoa6a78422018-06-28 08:32:54 +08002297
2298 // Single atomic function calls without return value.
2299 // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2300 case EOpAtomicAdd:
2301 case EOpAtomicMin:
2302 case EOpAtomicMax:
2303 case EOpAtomicAnd:
2304 case EOpAtomicOr:
2305 case EOpAtomicXor:
2306 outputTriplet(out, visit, GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()),
2307 ",", ")");
2308 break;
2309
2310 // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) and
2311 // InterlockedCompareExchange(dest, compare_value, value, original_value) is not optional.
2312 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2313 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2314 // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, compare_value,
2315 // value) should all be modified into the form of "int temp; temp = atomicExchange(dest,
2316 // value);" and "int temp; temp = atomicCompSwap(dest, compare_value, value);" in the
2317 // intermediate tree before traversing outputHLSL.
2318 case EOpAtomicExchange:
2319 case EOpAtomicCompSwap:
Olli Etuaho5878f832016-10-07 10:14:58 +01002320 default:
2321 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002322 }
2323
2324 return true;
2325}
2326
Olli Etuaho57961272016-09-14 13:57:46 +03002327void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002328{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002329 out << "if (";
2330
2331 node->getCondition()->traverse(this);
2332
2333 out << ")\n";
2334
Jamie Madill8c46ab12015-12-07 16:39:19 -05002335 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002336
2337 bool discard = false;
2338
2339 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002340 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002341 // The trueBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002342 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002343
Olli Etuahoa6f22092015-05-08 18:31:10 +03002344 // Detect true discard
2345 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2346 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002347 else
2348 {
2349 // TODO(oetuaho): Check if the semicolon inside is necessary.
2350 // It's there as a result of conservative refactoring of the output.
2351 out << "{;}\n";
2352 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002353
Jamie Madill8c46ab12015-12-07 16:39:19 -05002354 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002355
Olli Etuahoa6f22092015-05-08 18:31:10 +03002356 if (node->getFalseBlock())
2357 {
2358 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002359
Jamie Madill8c46ab12015-12-07 16:39:19 -05002360 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002361
Olli Etuaho32db19b2016-10-04 14:43:16 +01002362 // The falseBlock child node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002363 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002364
Jamie Madill8c46ab12015-12-07 16:39:19 -05002365 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002366
Olli Etuahoa6f22092015-05-08 18:31:10 +03002367 // Detect false discard
2368 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2369 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002370
Olli Etuahoa6f22092015-05-08 18:31:10 +03002371 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002372 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002373 {
2374 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002375 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002376}
2377
Olli Etuahod0bad2c2016-09-09 18:01:16 +03002378bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2379{
2380 // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2381 // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2382 UNREACHABLE();
2383 return false;
2384}
2385
Olli Etuaho57961272016-09-14 13:57:46 +03002386bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
Olli Etuahod81ed842015-05-12 12:46:35 +03002387{
2388 TInfoSinkBase &out = getInfoSink();
2389
Olli Etuaho3d932d82016-04-12 11:10:30 +03002390 ASSERT(mInsideFunction);
Olli Etuahod81ed842015-05-12 12:46:35 +03002391
2392 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002393 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002394 {
2395 out << "FLATTEN ";
2396 }
2397
Olli Etuaho57961272016-09-14 13:57:46 +03002398 writeIfElse(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002399
2400 return false;
2401}
2402
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002403bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002404{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002405 TInfoSinkBase &out = getInfoSink();
2406
Olli Etuaho923ecef2017-10-11 12:01:38 +03002407 ASSERT(node->getStatementList());
2408 if (visit == PreVisit)
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002409 {
Olli Etuaho89a69a02017-10-23 12:20:45 +03002410 node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002411 }
Olli Etuaho923ecef2017-10-11 12:01:38 +03002412 outputTriplet(out, visit, "switch (", ") ", "");
2413 // The curly braces get written when visiting the statementList block.
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002414 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002415}
2416
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002417bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002418{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002419 TInfoSinkBase &out = getInfoSink();
2420
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002421 if (node->hasCondition())
2422 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002423 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002424 return true;
2425 }
2426 else
2427 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002428 out << "default:\n";
2429 return false;
2430 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002431}
2432
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002433void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2434{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002435 TInfoSinkBase &out = getInfoSink();
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002436 writeConstantUnion(out, node->getType(), node->getConstantValue());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002437}
2438
2439bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2440{
Nicolas Capens655fe362014-04-11 13:12:34 -04002441 mNestedLoopDepth++;
2442
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002443 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002444 mInsideDiscontinuousLoop =
2445 mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002446
Jamie Madill8c46ab12015-12-07 16:39:19 -05002447 TInfoSinkBase &out = getInfoSink();
2448
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002449 if (mOutputType == SH_HLSL_3_0_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002450 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002451 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002452 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002453 mInsideDiscontinuousLoop = wasDiscontinuous;
2454 mNestedLoopDepth--;
2455
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002456 return false;
2457 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002458 }
2459
Corentin Wallez1239ee92015-03-19 14:38:02 -07002460 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002461 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002462 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002463 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002464
Jamie Madill8c46ab12015-12-07 16:39:19 -05002465 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002466 }
2467 else
2468 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002469 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471 if (node->getInit())
2472 {
2473 node->getInit()->traverse(this);
2474 }
2475
2476 out << "; ";
2477
alokp@chromium.org52813552010-11-16 18:36:09 +00002478 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002479 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002480 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002481 }
2482
2483 out << "; ";
2484
alokp@chromium.org52813552010-11-16 18:36:09 +00002485 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002486 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002487 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002488 }
2489
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002490 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002491
Jamie Madill8c46ab12015-12-07 16:39:19 -05002492 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002493 }
2494
2495 if (node->getBody())
2496 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002497 // The loop body node will output braces.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002498 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002499 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002500 else
2501 {
2502 // TODO(oetuaho): Check if the semicolon inside is necessary.
2503 // It's there as a result of conservative refactoring of the output.
2504 out << "{;}\n";
2505 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002506
Jamie Madill8c46ab12015-12-07 16:39:19 -05002507 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002508
alokp@chromium.org52813552010-11-16 18:36:09 +00002509 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002510 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002511 outputLineDirective(out, node->getCondition()->getLine().first_line);
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002512 out << "while (";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002513
alokp@chromium.org52813552010-11-16 18:36:09 +00002514 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002515
Olli Etuaho40dbdd62017-10-13 13:34:19 +03002516 out << ");\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002517 }
2518
daniel@transgaming.com73536982012-03-21 20:45:49 +00002519 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002520
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002521 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002522 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002523
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002524 return false;
2525}
2526
2527bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2528{
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002529 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002530 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002531 TInfoSinkBase &out = getInfoSink();
2532
2533 switch (node->getFlowOp())
2534 {
2535 case EOpKill:
2536 out << "discard";
2537 break;
2538 case EOpBreak:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002539 if (mNestedLoopDepth > 1)
2540 {
2541 mUsesNestedBreak = true;
2542 }
Nicolas Capens655fe362014-04-11 13:12:34 -04002543
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002544 if (mExcessiveLoopIndex)
2545 {
2546 out << "{Break";
2547 mExcessiveLoopIndex->traverse(this);
2548 out << " = true; break;}\n";
2549 }
2550 else
2551 {
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002552 out << "break";
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002553 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002554 break;
2555 case EOpContinue:
2556 out << "continue";
2557 break;
2558 case EOpReturn:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002559 if (node->getExpression())
2560 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002561 ASSERT(!mInsideMain);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002562 out << "return ";
2563 }
2564 else
2565 {
Olli Etuaho06235df2018-07-20 14:26:07 +03002566 if (mInsideMain && shaderNeedsGenerateOutput())
2567 {
2568 out << "return " << generateOutputCall();
2569 }
2570 else
2571 {
2572 out << "return";
2573 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002574 }
Olli Etuaho8886f0f2017-10-10 11:59:45 +03002575 break;
2576 default:
2577 UNREACHABLE();
2578 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002579 }
2580
2581 return true;
2582}
2583
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002584// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002585// (The D3D documentation says 255 iterations, but the compiler complains at anything more than
2586// 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002587bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002588{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002589 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002590
2591 // Parse loops of the form:
2592 // for(int index = initial; index [comparator] limit; index += increment)
Yunchao Hed7297bf2017-04-19 15:27:10 +08002593 TIntermSymbol *index = nullptr;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002594 TOperator comparator = EOpNull;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002595 int initial = 0;
2596 int limit = 0;
2597 int increment = 0;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002598
2599 // Parse index name and intial value
2600 if (node->getInit())
2601 {
Olli Etuaho13389b62016-10-16 11:48:18 +01002602 TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002603
2604 if (init)
2605 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002606 TIntermSequence *sequence = init->getSequence();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002607 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002608
2609 if (variable && variable->getQualifier() == EvqTemporary)
2610 {
2611 TIntermBinary *assign = variable->getAsBinaryNode();
2612
2613 if (assign->getOp() == EOpInitialize)
2614 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002615 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002616 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2617
2618 if (symbol && constant)
2619 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002620 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002621 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002622 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002623 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002624 }
2625 }
2626 }
2627 }
2628 }
2629 }
2630
2631 // Parse comparator and limit value
Yunchao He4f285442017-04-21 12:15:49 +08002632 if (index != nullptr && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002633 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002634 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002635
Olli Etuahob6af22b2017-12-15 14:05:44 +02002636 if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002637 {
2638 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2639
2640 if (constant)
2641 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002642 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002643 {
2644 comparator = test->getOp();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002645 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002646 }
2647 }
2648 }
2649 }
2650
2651 // Parse increment
Yunchao He4f285442017-04-21 12:15:49 +08002652 if (index != nullptr && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002653 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002654 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002655 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002656
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002657 if (binaryTerminal)
2658 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002659 TOperator op = binaryTerminal->getOp();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002660 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2661
2662 if (constant)
2663 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002664 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002665 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002666 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002667
2668 switch (op)
2669 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002670 case EOpAddAssign:
2671 increment = value;
2672 break;
2673 case EOpSubAssign:
2674 increment = -value;
2675 break;
2676 default:
2677 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002678 }
2679 }
2680 }
2681 }
2682 else if (unaryTerminal)
2683 {
2684 TOperator op = unaryTerminal->getOp();
2685
2686 switch (op)
2687 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002688 case EOpPostIncrement:
2689 increment = 1;
2690 break;
2691 case EOpPostDecrement:
2692 increment = -1;
2693 break;
2694 case EOpPreIncrement:
2695 increment = 1;
2696 break;
2697 case EOpPreDecrement:
2698 increment = -1;
2699 break;
2700 default:
2701 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002702 }
2703 }
2704 }
2705
Yunchao He4f285442017-04-21 12:15:49 +08002706 if (index != nullptr && comparator != EOpNull && increment != 0)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002707 {
2708 if (comparator == EOpLessThanEqual)
2709 {
2710 comparator = EOpLessThan;
2711 limit += 1;
2712 }
2713
2714 if (comparator == EOpLessThan)
2715 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002716 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002717
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002718 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002719 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002720 return false; // Not an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002721 }
2722
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002723 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002724 mExcessiveLoopIndex = index;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002725
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002726 out << "{int ";
2727 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002728 out << ";\n"
2729 "bool Break";
2730 index->traverse(this);
2731 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002732
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002733 bool firstLoopFragment = true;
2734
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002735 while (iterations > 0)
2736 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002737 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002738
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002739 if (!firstLoopFragment)
2740 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002741 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002742 index->traverse(this);
2743 out << ") {\n";
2744 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002745
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002746 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002747 {
Yunchao Hed7297bf2017-04-19 15:27:10 +08002748 mExcessiveLoopIndex = nullptr; // Stops setting the Break flag
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002749 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002750
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002751 // for(int index = initial; index < clampedLimit; index += increment)
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002752 const char *unroll =
2753 mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002754
Corentin Wallez1239ee92015-03-19 14:38:02 -07002755 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002756 index->traverse(this);
2757 out << " = ";
2758 out << initial;
2759
2760 out << "; ";
2761 index->traverse(this);
2762 out << " < ";
2763 out << clampedLimit;
2764
2765 out << "; ";
2766 index->traverse(this);
2767 out << " += ";
2768 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002769 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002770
Jamie Madill8c46ab12015-12-07 16:39:19 -05002771 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002772 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002773
2774 if (node->getBody())
2775 {
2776 node->getBody()->traverse(this);
2777 }
2778
Jamie Madill8c46ab12015-12-07 16:39:19 -05002779 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002780 out << ";}\n";
2781
2782 if (!firstLoopFragment)
2783 {
2784 out << "}\n";
2785 }
2786
2787 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002788
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002789 initial += MAX_LOOP_ITERATIONS * increment;
2790 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002791 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002792
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002793 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002794
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002795 mExcessiveLoopIndex = restoreIndex;
2796
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002797 return true;
2798 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002799 else
2800 UNIMPLEMENTED();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002801 }
2802
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002803 return false; // Not handled as an excessive loop
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002804}
2805
Jamie Madill8c46ab12015-12-07 16:39:19 -05002806void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2807 Visit visit,
2808 const char *preString,
2809 const char *inString,
2810 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002811{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002812 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002813 {
2814 out << preString;
2815 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002816 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002817 {
2818 out << inString;
2819 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002820 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002821 {
2822 out << postString;
2823 }
2824}
2825
Jamie Madill8c46ab12015-12-07 16:39:19 -05002826void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002827{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002828 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002829 {
Jamie Madill32aab012015-01-27 14:12:26 -05002830 out << "\n";
2831 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002832
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002833 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002834 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002835 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002836 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002837
Jamie Madill32aab012015-01-27 14:12:26 -05002838 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002839 }
2840}
2841
Olli Etuahod4bd9632018-03-08 16:32:44 +02002842void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002843{
Olli Etuahod4bd9632018-03-08 16:32:44 +02002844 const TType &type = param->getType();
2845 TQualifier qualifier = type.getQualifier();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002846
Olli Etuahod4bd9632018-03-08 16:32:44 +02002847 TString nameStr = DecorateVariableIfNeeded(*param);
2848 ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002849
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002850 if (IsSampler(type.getBasicType()))
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002851 {
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002852 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2853 {
2854 // Samplers are passed as indices to the sampler array.
2855 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002856 out << "const uint " << nameStr << ArrayString(type);
2857 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002858 }
2859 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2860 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002861 out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
2862 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
2863 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
2864 << ArrayString(type);
2865 return;
Olli Etuaho9b4e8622015-12-22 15:53:22 +02002866 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002867 }
2868
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002869 out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2870 << ArrayString(type);
Olli Etuaho96963162016-03-21 11:54:33 +02002871
2872 // If the structure parameter contains samplers, they need to be passed into the function as
2873 // separate parameters. HLSL doesn't natively support samplers in structs.
2874 if (type.isStructureContainingSamplers())
2875 {
2876 ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002877 TVector<const TVariable *> samplerSymbols;
Olli Etuahofbb1c792018-01-19 16:26:59 +02002878 std::string namePrefix = "angle";
2879 namePrefix += nameStr.c_str();
2880 type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
2881 mSymbolTable);
Olli Etuahobbd9d4c2017-12-21 12:02:00 +02002882 for (const TVariable *sampler : samplerSymbols)
Olli Etuaho96963162016-03-21 11:54:33 +02002883 {
Olli Etuaho28839f02017-08-15 11:38:16 +03002884 const TType &samplerType = sampler->getType();
Olli Etuaho96963162016-03-21 11:54:33 +02002885 if (mOutputType == SH_HLSL_4_1_OUTPUT)
2886 {
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002887 out << ", const uint " << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002888 }
2889 else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2890 {
Olli Etuaho96963162016-03-21 11:54:33 +02002891 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002892 out << ", " << QualifierString(qualifier) << " "
2893 << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
2894 << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
2895 << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
2896 << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002897 }
2898 else
2899 {
Olli Etuaho96963162016-03-21 11:54:33 +02002900 ASSERT(IsSampler(samplerType.getBasicType()));
Olli Etuaho2f7c04a2018-01-25 14:50:37 +02002901 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
2902 << sampler->name() << ArrayString(samplerType);
Olli Etuaho96963162016-03-21 11:54:33 +02002903 }
2904 }
2905 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002906}
2907
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002908TString OutputHLSL::zeroInitializer(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002909{
2910 TString string;
2911
Jamie Madill94bf7f22013-07-08 13:31:15 -04002912 size_t size = type.getObjectSize();
2913 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002914 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002915 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002916
Jamie Madill94bf7f22013-07-08 13:31:15 -04002917 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002918 {
2919 string += ", ";
2920 }
2921 }
2922
daniel@transgaming.comead23042010-04-29 03:35:36 +00002923 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002924}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002925
Olli Etuahobd3cd502017-11-03 15:48:52 +02002926void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002927{
Olli Etuahobd3cd502017-11-03 15:48:52 +02002928 // Array constructors should have been already pruned from the code.
2929 ASSERT(!node->getType().isArray());
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002930
2931 if (visit == PreVisit)
2932 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002933 TString constructorName;
2934 if (node->getBasicType() == EbtStruct)
2935 {
2936 constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
2937 }
2938 else
2939 {
2940 constructorName =
2941 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
2942 }
Olli Etuahobe59c2f2016-03-07 11:32:34 +02002943 out << constructorName << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002944 }
2945 else if (visit == InVisit)
2946 {
2947 out << ", ";
2948 }
2949 else if (visit == PostVisit)
2950 {
2951 out << ")";
2952 }
2953}
2954
Jamie Madill8c46ab12015-12-07 16:39:19 -05002955const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2956 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002957 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002958{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02002959 ASSERT(!type.isArray());
2960
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002961 const TConstantUnion *constUnionIterated = constUnion;
2962
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002963 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -04002964 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002965 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02002966 out << mStructureHLSL->addStructConstructor(*structure) << "(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002967
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002968 const TFieldList &fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002969
Jamie Madill98493dd2013-07-08 14:39:03 -04002970 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002971 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002972 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05002973 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002974
Jamie Madill98493dd2013-07-08 14:39:03 -04002975 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002976 {
2977 out << ", ";
2978 }
2979 }
2980
2981 out << ")";
2982 }
2983 else
2984 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05002985 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002986 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002987
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002988 if (writeType)
2989 {
Jamie Madill033dae62014-06-18 12:56:28 -04002990 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002991 }
Olli Etuaho56a2f952016-12-08 12:16:27 +00002992 constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002993 if (writeType)
2994 {
2995 out << ")";
2996 }
2997 }
2998
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002999 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003000}
3001
Olli Etuahod68924e2017-01-02 17:34:40 +00003002void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003003{
Olli Etuahod68924e2017-01-02 17:34:40 +00003004 if (visit == PreVisit)
3005 {
3006 const char *opStr = GetOperatorString(op);
3007 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
3008 out << "(";
3009 }
3010 else
3011 {
3012 outputTriplet(out, visit, nullptr, ", ", ")");
3013 }
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003014}
3015
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003016bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3017 TIntermSymbol *symbolNode,
3018 TIntermTyped *expression)
Jamie Madill37997142015-01-28 10:06:34 -05003019{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02003020 ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3021 const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
Jamie Madill37997142015-01-28 10:06:34 -05003022
Olli Etuaho4728bdc2017-12-20 17:51:08 +02003023 if (symbolInInitializer)
Jamie Madill37997142015-01-28 10:06:34 -05003024 {
3025 // Type already printed
3026 out << "t" + str(mUniqueIndex) + " = ";
3027 expression->traverse(this);
3028 out << ", ";
3029 symbolNode->traverse(this);
3030 out << " = t" + str(mUniqueIndex);
3031
3032 mUniqueIndex++;
3033 return true;
3034 }
3035
3036 return false;
3037}
3038
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003039bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3040 TIntermSymbol *symbolNode,
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003041 TIntermTyped *initializer)
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003042{
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003043 if (initializer->hasConstantValue())
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003044 {
3045 symbolNode->traverse(this);
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003046 out << ArrayString(symbolNode->getType());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003047 out << " = {";
Olli Etuahoea22b7a2018-01-04 17:09:11 +02003048 writeConstantUnionArray(out, initializer->getConstantValue(),
3049 initializer->getType().getObjectSize());
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003050 out << "}";
3051 return true;
3052 }
3053 return false;
3054}
3055
Jamie Madill55e79e02015-02-09 15:35:00 -05003056TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3057{
3058 const TFieldList &fields = structure.fields();
3059
3060 for (const auto &eqFunction : mStructEqualityFunctions)
3061 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003062 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003063 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003064 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003065 }
3066 }
3067
3068 const TString &structNameString = StructNameString(structure);
3069
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003070 StructEqualityFunction *function = new StructEqualityFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003071 function->structure = &structure;
3072 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003073
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003074 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003075
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003076 fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3077 << structNameString + " b)\n"
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003078 << "{\n"
3079 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003080
3081 for (size_t i = 0; i < fields.size(); i++)
3082 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003083 const TField *field = fields[i];
Jamie Madill55e79e02015-02-09 15:35:00 -05003084 const TType *fieldType = field->type();
3085
3086 const TString &fieldNameA = "a." + Decorate(field->name());
3087 const TString &fieldNameB = "b." + Decorate(field->name());
3088
3089 if (i > 0)
3090 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003091 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003092 }
3093
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003094 fnOut << "(";
3095 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3096 fnOut << fieldNameA;
3097 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3098 fnOut << fieldNameB;
3099 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3100 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003101 }
3102
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003103 fnOut << ";\n"
3104 << "}\n";
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003105
3106 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003107
3108 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003109 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003110
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003111 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003112}
3113
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003114TString OutputHLSL::addArrayEqualityFunction(const TType &type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003115{
3116 for (const auto &eqFunction : mArrayEqualityFunctions)
3117 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003118 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003119 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003120 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003121 }
3122 }
3123
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003124 TType elementType(type);
3125 elementType.toArrayElementType();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003126
Olli Etuaho12690762015-03-31 12:55:28 +03003127 ArrayHelperFunction *function = new ArrayHelperFunction();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003128 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003129
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003130 function->functionName = ArrayHelperFunctionName("angle_eq", type);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003131
3132 TInfoSinkBase fnOut;
3133
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003134 const TString &typeName = TypeString(type);
3135 fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3136 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003137 << "{\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003138 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003139 << type.getOutermostArraySize()
3140 << "; ++i)\n"
3141 " {\n"
3142 " if (";
Olli Etuaho7fb49552015-03-18 17:27:44 +02003143
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003144 outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003145 fnOut << "a[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003146 outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003147 fnOut << "b[i]";
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003148 outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003149
3150 fnOut << ") { return false; }\n"
3151 " }\n"
3152 " return true;\n"
3153 "}\n";
3154
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003155 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003156
3157 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003158 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003159
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003160 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003161}
3162
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003163TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
Olli Etuaho12690762015-03-31 12:55:28 +03003164{
3165 for (const auto &assignFunction : mArrayAssignmentFunctions)
3166 {
3167 if (assignFunction.type == type)
3168 {
3169 return assignFunction.functionName;
3170 }
3171 }
3172
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003173 TType elementType(type);
3174 elementType.toArrayElementType();
Olli Etuaho12690762015-03-31 12:55:28 +03003175
3176 ArrayHelperFunction function;
3177 function.type = type;
3178
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003179 function.functionName = ArrayHelperFunctionName("angle_assign", type);
Olli Etuaho12690762015-03-31 12:55:28 +03003180
3181 TInfoSinkBase fnOut;
3182
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003183 const TString &typeName = TypeString(type);
3184 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3185 << ", " << typeName << " b" << ArrayString(type) << ")\n"
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003186 << "{\n"
3187 " for (int i = 0; i < "
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003188 << type.getOutermostArraySize()
3189 << "; ++i)\n"
3190 " {\n"
3191 " ";
3192
3193 outputAssign(PreVisit, elementType, fnOut);
3194 fnOut << "a[i]";
3195 outputAssign(InVisit, elementType, fnOut);
3196 fnOut << "b[i]";
3197 outputAssign(PostVisit, elementType, fnOut);
3198
3199 fnOut << ";\n"
3200 " }\n"
3201 "}\n";
Olli Etuaho12690762015-03-31 12:55:28 +03003202
3203 function.functionDefinition = fnOut.c_str();
3204
3205 mArrayAssignmentFunctions.push_back(function);
3206
3207 return function.functionName;
3208}
3209
Jamie Madilld7b1ab52016-12-12 14:42:19 -05003210TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
Olli Etuaho9638c352015-04-01 14:34:52 +03003211{
3212 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3213 {
3214 if (constructIntoFunction.type == type)
3215 {
3216 return constructIntoFunction.functionName;
3217 }
3218 }
3219
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003220 TType elementType(type);
3221 elementType.toArrayElementType();
Olli Etuaho9638c352015-04-01 14:34:52 +03003222
3223 ArrayHelperFunction function;
3224 function.type = type;
3225
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003226 function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
Olli Etuaho9638c352015-04-01 14:34:52 +03003227
3228 TInfoSinkBase fnOut;
3229
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003230 const TString &typeName = TypeString(type);
3231 fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3232 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003233 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003234 fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
Olli Etuaho9638c352015-04-01 14:34:52 +03003235 }
3236 fnOut << ")\n"
3237 "{\n";
3238
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003239 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
Olli Etuaho9638c352015-04-01 14:34:52 +03003240 {
Olli Etuaho96f6adf2017-08-16 11:18:54 +03003241 fnOut << " ";
3242 outputAssign(PreVisit, elementType, fnOut);
3243 fnOut << "a[" << i << "]";
3244 outputAssign(InVisit, elementType, fnOut);
3245 fnOut << "b" << i;
3246 outputAssign(PostVisit, elementType, fnOut);
3247 fnOut << ";\n";
Olli Etuaho9638c352015-04-01 14:34:52 +03003248 }
3249 fnOut << "}\n";
3250
3251 function.functionDefinition = fnOut.c_str();
3252
3253 mArrayConstructIntoFunctions.push_back(function);
3254
3255 return function.functionName;
3256}
3257
Jamie Madill2e295e22015-04-29 10:41:33 -04003258void OutputHLSL::ensureStructDefined(const TType &type)
3259{
Olli Etuahobd3cd502017-11-03 15:48:52 +02003260 const TStructure *structure = type.getStruct();
Jamie Madill2e295e22015-04-29 10:41:33 -04003261 if (structure)
3262 {
Olli Etuahobd3cd502017-11-03 15:48:52 +02003263 ASSERT(type.getBasicType() == EbtStruct);
3264 mStructureHLSL->ensureStructDefined(*structure);
Jamie Madill2e295e22015-04-29 10:41:33 -04003265 }
3266}
3267
Olli Etuaho06235df2018-07-20 14:26:07 +03003268bool OutputHLSL::shaderNeedsGenerateOutput() const
3269{
3270 return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3271}
3272
3273const char *OutputHLSL::generateOutputCall() const
3274{
3275 if (mShaderType == GL_VERTEX_SHADER)
3276 {
3277 return "generateOutput(input)";
3278 }
3279 else
3280 {
3281 return "generateOutput()";
3282 }
3283}
3284
Jamie Madill45bcc782016-11-07 13:58:48 -05003285} // namespace sh