Line data Source code
1 : //
2 : // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3 : // Use of this source code is governed by a BSD-style license that can be
4 : // found in the LICENSE file.
5 : //
6 :
7 : #include "compiler/translator/OutputHLSL.h"
8 :
9 : #include <algorithm>
10 : #include <cfloat>
11 : #include <stdio.h>
12 :
13 : #include "common/angleutils.h"
14 : #include "common/debug.h"
15 : #include "common/utilities.h"
16 : #include "compiler/translator/BuiltInFunctionEmulator.h"
17 : #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
18 : #include "compiler/translator/FlagStd140Structs.h"
19 : #include "compiler/translator/InfoSink.h"
20 : #include "compiler/translator/NodeSearch.h"
21 : #include "compiler/translator/RemoveSwitchFallThrough.h"
22 : #include "compiler/translator/SearchSymbol.h"
23 : #include "compiler/translator/StructureHLSL.h"
24 : #include "compiler/translator/TextureFunctionHLSL.h"
25 : #include "compiler/translator/TranslatorHLSL.h"
26 : #include "compiler/translator/UniformHLSL.h"
27 : #include "compiler/translator/UtilsHLSL.h"
28 : #include "compiler/translator/blocklayout.h"
29 : #include "compiler/translator/util.h"
30 :
31 : namespace sh
32 : {
33 :
34 0 : void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
35 : {
36 : // This is known not to work for NaN on all drivers but make the best effort to output NaNs
37 : // regardless.
38 0 : if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
39 0 : mOutputType == SH_HLSL_4_1_OUTPUT)
40 : {
41 0 : out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
42 : }
43 : else
44 : {
45 0 : out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
46 : }
47 0 : }
48 :
49 0 : void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
50 : {
51 0 : ASSERT(constUnion != nullptr);
52 0 : switch (constUnion->getType())
53 : {
54 : case EbtFloat:
55 0 : writeFloat(out, constUnion->getFConst());
56 0 : break;
57 : case EbtInt:
58 0 : out << constUnion->getIConst();
59 0 : break;
60 : case EbtUInt:
61 0 : out << constUnion->getUConst();
62 0 : break;
63 : case EbtBool:
64 0 : out << constUnion->getBConst();
65 0 : break;
66 : default:
67 0 : UNREACHABLE();
68 : }
69 0 : }
70 :
71 0 : const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
72 : const TConstantUnion *const constUnion,
73 : const size_t size)
74 : {
75 0 : const TConstantUnion *constUnionIterated = constUnion;
76 0 : for (size_t i = 0; i < size; i++, constUnionIterated++)
77 : {
78 0 : writeSingleConstant(out, constUnionIterated);
79 :
80 0 : if (i != size - 1)
81 : {
82 0 : out << ", ";
83 : }
84 : }
85 0 : return constUnionIterated;
86 : }
87 :
88 0 : OutputHLSL::OutputHLSL(sh::GLenum shaderType,
89 : int shaderVersion,
90 : const TExtensionBehavior &extensionBehavior,
91 : const char *sourcePath,
92 : ShShaderOutput outputType,
93 : int numRenderTargets,
94 : const std::vector<Uniform> &uniforms,
95 0 : ShCompileOptions compileOptions)
96 : : TIntermTraverser(true, true, true),
97 : mShaderType(shaderType),
98 : mShaderVersion(shaderVersion),
99 : mExtensionBehavior(extensionBehavior),
100 : mSourcePath(sourcePath),
101 : mOutputType(outputType),
102 : mCompileOptions(compileOptions),
103 : mNumRenderTargets(numRenderTargets),
104 0 : mCurrentFunctionMetadata(nullptr)
105 : {
106 0 : mInsideFunction = false;
107 :
108 0 : mUsesFragColor = false;
109 0 : mUsesFragData = false;
110 0 : mUsesDepthRange = false;
111 0 : mUsesFragCoord = false;
112 0 : mUsesPointCoord = false;
113 0 : mUsesFrontFacing = false;
114 0 : mUsesPointSize = false;
115 0 : mUsesInstanceID = false;
116 0 : mUsesVertexID = false;
117 0 : mUsesFragDepth = false;
118 0 : mUsesXor = false;
119 0 : mUsesDiscardRewriting = false;
120 0 : mUsesNestedBreak = false;
121 0 : mRequiresIEEEStrictCompiling = false;
122 :
123 0 : mUniqueIndex = 0;
124 :
125 0 : mOutputLod0Function = false;
126 0 : mInsideDiscontinuousLoop = false;
127 0 : mNestedLoopDepth = 0;
128 :
129 0 : mExcessiveLoopIndex = NULL;
130 :
131 0 : mStructureHLSL = new StructureHLSL;
132 0 : mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
133 0 : mTextureFunctionHLSL = new TextureFunctionHLSL;
134 :
135 0 : if (mOutputType == SH_HLSL_3_0_OUTPUT)
136 : {
137 : // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
138 : // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust.
139 : // In both cases total 3 uniform registers need to be reserved.
140 0 : mUniformHLSL->reserveUniformRegisters(3);
141 : }
142 :
143 : // Reserve registers for the default uniform block and driver constants
144 0 : mUniformHLSL->reserveInterfaceBlockRegisters(2);
145 0 : }
146 :
147 0 : OutputHLSL::~OutputHLSL()
148 : {
149 0 : SafeDelete(mStructureHLSL);
150 0 : SafeDelete(mUniformHLSL);
151 0 : SafeDelete(mTextureFunctionHLSL);
152 0 : for (auto &eqFunction : mStructEqualityFunctions)
153 : {
154 0 : SafeDelete(eqFunction);
155 : }
156 0 : for (auto &eqFunction : mArrayEqualityFunctions)
157 : {
158 0 : SafeDelete(eqFunction);
159 : }
160 0 : }
161 :
162 0 : void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
163 : {
164 0 : const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
165 0 : makeFlaggedStructMaps(flaggedStructs);
166 :
167 0 : BuiltInFunctionEmulator builtInFunctionEmulator;
168 0 : InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
169 0 : if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
170 : {
171 0 : InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
172 0 : mShaderVersion);
173 : }
174 :
175 0 : builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
176 :
177 : // Now that we are done changing the AST, do the analyses need for HLSL generation
178 0 : CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink);
179 0 : ASSERT(success == CallDAG::INITDAG_SUCCESS);
180 0 : mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
181 :
182 : // Output the body and footer first to determine what has to go in the header
183 0 : mInfoSinkStack.push(&mBody);
184 0 : treeRoot->traverse(this);
185 0 : mInfoSinkStack.pop();
186 :
187 0 : mInfoSinkStack.push(&mFooter);
188 0 : mInfoSinkStack.pop();
189 :
190 0 : mInfoSinkStack.push(&mHeader);
191 0 : header(mHeader, &builtInFunctionEmulator);
192 0 : mInfoSinkStack.pop();
193 :
194 0 : objSink << mHeader.c_str();
195 0 : objSink << mBody.c_str();
196 0 : objSink << mFooter.c_str();
197 :
198 0 : builtInFunctionEmulator.Cleanup();
199 0 : }
200 :
201 0 : void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
202 : {
203 0 : for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
204 : {
205 0 : TIntermTyped *flaggedNode = flaggedStructs[structIndex];
206 :
207 0 : TInfoSinkBase structInfoSink;
208 0 : mInfoSinkStack.push(&structInfoSink);
209 :
210 : // This will mark the necessary block elements as referenced
211 0 : flaggedNode->traverse(this);
212 :
213 0 : TString structName(structInfoSink.c_str());
214 0 : mInfoSinkStack.pop();
215 :
216 0 : mFlaggedStructOriginalNames[flaggedNode] = structName;
217 :
218 0 : for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
219 : {
220 0 : structName.erase(pos, 1);
221 : }
222 :
223 0 : mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
224 : }
225 0 : }
226 :
227 0 : const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
228 : {
229 0 : return mUniformHLSL->getInterfaceBlockRegisterMap();
230 : }
231 :
232 0 : const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
233 : {
234 0 : return mUniformHLSL->getUniformRegisterMap();
235 : }
236 :
237 0 : int OutputHLSL::vectorSize(const TType &type) const
238 : {
239 0 : int elementSize = type.isMatrix() ? type.getCols() : 1;
240 0 : unsigned int arraySize = type.isArray() ? type.getArraySize() : 1u;
241 :
242 0 : return elementSize * arraySize;
243 : }
244 :
245 0 : TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
246 : {
247 0 : TString init;
248 :
249 0 : TString preIndentString;
250 0 : TString fullIndentString;
251 :
252 0 : for (int spaces = 0; spaces < (indent * 4); spaces++)
253 : {
254 0 : preIndentString += ' ';
255 : }
256 :
257 0 : for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
258 : {
259 0 : fullIndentString += ' ';
260 : }
261 :
262 0 : init += preIndentString + "{\n";
263 :
264 0 : const TFieldList &fields = structure.fields();
265 0 : for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
266 : {
267 0 : const TField &field = *fields[fieldIndex];
268 0 : const TString &fieldName = rhsStructName + "." + Decorate(field.name());
269 0 : const TType &fieldType = *field.type();
270 :
271 0 : if (fieldType.getStruct())
272 : {
273 0 : init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
274 : }
275 : else
276 : {
277 0 : init += fullIndentString + fieldName + ",\n";
278 : }
279 : }
280 :
281 0 : init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
282 :
283 0 : return init;
284 : }
285 :
286 0 : void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
287 : {
288 0 : TString varyings;
289 0 : TString attributes;
290 0 : TString flaggedStructs;
291 :
292 0 : for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
293 : {
294 0 : TIntermTyped *structNode = flaggedStructIt->first;
295 0 : const TString &mappedName = flaggedStructIt->second;
296 0 : const TStructure &structure = *structNode->getType().getStruct();
297 0 : const TString &originalName = mFlaggedStructOriginalNames[structNode];
298 :
299 0 : flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
300 0 : flaggedStructs += structInitializerString(0, structure, originalName);
301 0 : flaggedStructs += "\n";
302 : }
303 :
304 0 : for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
305 : {
306 0 : const TType &type = varying->second->getType();
307 0 : const TString &name = varying->second->getSymbol();
308 :
309 : // Program linking depends on this exact format
310 0 : varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
311 0 : Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
312 : }
313 :
314 0 : for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
315 : {
316 0 : const TType &type = attribute->second->getType();
317 0 : const TString &name = attribute->second->getSymbol();
318 :
319 0 : attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
320 : }
321 :
322 0 : out << mStructureHLSL->structsHeader();
323 :
324 0 : mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
325 0 : out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
326 :
327 0 : if (!mEqualityFunctions.empty())
328 : {
329 0 : out << "\n// Equality functions\n\n";
330 0 : for (const auto &eqFunction : mEqualityFunctions)
331 : {
332 0 : out << eqFunction->functionDefinition << "\n";
333 : }
334 : }
335 0 : if (!mArrayAssignmentFunctions.empty())
336 : {
337 0 : out << "\n// Assignment functions\n\n";
338 0 : for (const auto &assignmentFunction : mArrayAssignmentFunctions)
339 : {
340 0 : out << assignmentFunction.functionDefinition << "\n";
341 : }
342 : }
343 0 : if (!mArrayConstructIntoFunctions.empty())
344 : {
345 0 : out << "\n// Array constructor functions\n\n";
346 0 : for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
347 : {
348 0 : out << constructIntoFunction.functionDefinition << "\n";
349 : }
350 : }
351 :
352 0 : if (mUsesDiscardRewriting)
353 : {
354 0 : out << "#define ANGLE_USES_DISCARD_REWRITING\n";
355 : }
356 :
357 0 : if (mUsesNestedBreak)
358 : {
359 0 : out << "#define ANGLE_USES_NESTED_BREAK\n";
360 : }
361 :
362 0 : if (mRequiresIEEEStrictCompiling)
363 : {
364 0 : out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
365 : }
366 :
367 : out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
368 : "#define LOOP [loop]\n"
369 : "#define FLATTEN [flatten]\n"
370 : "#else\n"
371 : "#define LOOP\n"
372 : "#define FLATTEN\n"
373 0 : "#endif\n";
374 :
375 0 : if (mShaderType == GL_FRAGMENT_SHADER)
376 : {
377 0 : TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
378 0 : const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
379 :
380 0 : out << "// Varyings\n";
381 0 : out << varyings;
382 0 : out << "\n";
383 :
384 0 : if (mShaderVersion >= 300)
385 : {
386 0 : for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
387 : {
388 0 : const TString &variableName = outputVariableIt->first;
389 0 : const TType &variableType = outputVariableIt->second->getType();
390 :
391 0 : out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
392 0 : " = " + initializer(variableType) + ";\n";
393 : }
394 : }
395 : else
396 : {
397 0 : const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
398 :
399 0 : out << "static float4 gl_Color[" << numColorValues << "] =\n"
400 0 : "{\n";
401 0 : for (unsigned int i = 0; i < numColorValues; i++)
402 : {
403 0 : out << " float4(0, 0, 0, 0)";
404 0 : if (i + 1 != numColorValues)
405 : {
406 0 : out << ",";
407 : }
408 0 : out << "\n";
409 : }
410 :
411 0 : out << "};\n";
412 : }
413 :
414 0 : if (mUsesFragDepth)
415 : {
416 0 : out << "static float gl_Depth = 0.0;\n";
417 : }
418 :
419 0 : if (mUsesFragCoord)
420 : {
421 0 : out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
422 : }
423 :
424 0 : if (mUsesPointCoord)
425 : {
426 0 : out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
427 : }
428 :
429 0 : if (mUsesFrontFacing)
430 : {
431 0 : out << "static bool gl_FrontFacing = false;\n";
432 : }
433 :
434 0 : out << "\n";
435 :
436 0 : if (mUsesDepthRange)
437 : {
438 : out << "struct gl_DepthRangeParameters\n"
439 : "{\n"
440 : " float near;\n"
441 : " float far;\n"
442 : " float diff;\n"
443 : "};\n"
444 0 : "\n";
445 : }
446 :
447 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
448 : {
449 : out << "cbuffer DriverConstants : register(b1)\n"
450 0 : "{\n";
451 :
452 0 : if (mUsesDepthRange)
453 : {
454 0 : out << " float3 dx_DepthRange : packoffset(c0);\n";
455 : }
456 :
457 0 : if (mUsesFragCoord)
458 : {
459 0 : out << " float4 dx_ViewCoords : packoffset(c1);\n";
460 : }
461 :
462 0 : if (mUsesFragCoord || mUsesFrontFacing)
463 : {
464 0 : out << " float3 dx_DepthFront : packoffset(c2);\n";
465 : }
466 :
467 0 : if (mUsesFragCoord)
468 : {
469 : // dx_ViewScale is only used in the fragment shader to correct
470 : // the value for glFragCoord if necessary
471 0 : out << " float2 dx_ViewScale : packoffset(c3);\n";
472 : }
473 :
474 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT)
475 : {
476 0 : mUniformHLSL->samplerMetadataUniforms(out, "c4");
477 : }
478 :
479 0 : out << "};\n";
480 : }
481 : else
482 : {
483 0 : if (mUsesDepthRange)
484 : {
485 0 : out << "uniform float3 dx_DepthRange : register(c0);";
486 : }
487 :
488 0 : if (mUsesFragCoord)
489 : {
490 0 : out << "uniform float4 dx_ViewCoords : register(c1);\n";
491 : }
492 :
493 0 : if (mUsesFragCoord || mUsesFrontFacing)
494 : {
495 0 : out << "uniform float3 dx_DepthFront : register(c2);\n";
496 : }
497 : }
498 :
499 0 : out << "\n";
500 :
501 0 : if (mUsesDepthRange)
502 : {
503 : out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
504 0 : "\n";
505 : }
506 :
507 0 : if (!flaggedStructs.empty())
508 : {
509 0 : out << "// Std140 Structures accessed by value\n";
510 0 : out << "\n";
511 0 : out << flaggedStructs;
512 0 : out << "\n";
513 : }
514 :
515 0 : if (usingMRTExtension && mNumRenderTargets > 1)
516 : {
517 0 : out << "#define GL_USES_MRT\n";
518 : }
519 :
520 0 : if (mUsesFragColor)
521 : {
522 0 : out << "#define GL_USES_FRAG_COLOR\n";
523 : }
524 :
525 0 : if (mUsesFragData)
526 : {
527 0 : out << "#define GL_USES_FRAG_DATA\n";
528 : }
529 : }
530 : else // Vertex shader
531 : {
532 0 : out << "// Attributes\n";
533 0 : out << attributes;
534 : out << "\n"
535 0 : "static float4 gl_Position = float4(0, 0, 0, 0);\n";
536 :
537 0 : if (mUsesPointSize)
538 : {
539 0 : out << "static float gl_PointSize = float(1);\n";
540 : }
541 :
542 0 : if (mUsesInstanceID)
543 : {
544 0 : out << "static int gl_InstanceID;";
545 : }
546 :
547 0 : if (mUsesVertexID)
548 : {
549 0 : out << "static int gl_VertexID;";
550 : }
551 :
552 : out << "\n"
553 0 : "// Varyings\n";
554 0 : out << varyings;
555 0 : out << "\n";
556 :
557 0 : if (mUsesDepthRange)
558 : {
559 : out << "struct gl_DepthRangeParameters\n"
560 : "{\n"
561 : " float near;\n"
562 : " float far;\n"
563 : " float diff;\n"
564 : "};\n"
565 0 : "\n";
566 : }
567 :
568 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
569 : {
570 : out << "cbuffer DriverConstants : register(b1)\n"
571 0 : "{\n";
572 :
573 0 : if (mUsesDepthRange)
574 : {
575 0 : out << " float3 dx_DepthRange : packoffset(c0);\n";
576 : }
577 :
578 : // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
579 : // shaders. However, we declare it for all shaders (including Feature Level 10+).
580 : // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
581 : // if it's unused.
582 0 : out << " float4 dx_ViewAdjust : packoffset(c1);\n";
583 0 : out << " float2 dx_ViewCoords : packoffset(c2);\n";
584 0 : out << " float2 dx_ViewScale : packoffset(c3);\n";
585 :
586 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT)
587 : {
588 0 : mUniformHLSL->samplerMetadataUniforms(out, "c4");
589 : }
590 :
591 : out << "};\n"
592 0 : "\n";
593 : }
594 : else
595 : {
596 0 : if (mUsesDepthRange)
597 : {
598 0 : out << "uniform float3 dx_DepthRange : register(c0);\n";
599 : }
600 :
601 0 : out << "uniform float4 dx_ViewAdjust : register(c1);\n";
602 : out << "uniform float2 dx_ViewCoords : register(c2);\n"
603 0 : "\n";
604 : }
605 :
606 0 : if (mUsesDepthRange)
607 : {
608 : out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
609 0 : "\n";
610 : }
611 :
612 0 : if (!flaggedStructs.empty())
613 : {
614 0 : out << "// Std140 Structures accessed by value\n";
615 0 : out << "\n";
616 0 : out << flaggedStructs;
617 0 : out << "\n";
618 : }
619 : }
620 :
621 : bool getDimensionsIgnoresBaseLevel =
622 0 : (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
623 0 : mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
624 :
625 0 : if (mUsesFragCoord)
626 : {
627 0 : out << "#define GL_USES_FRAG_COORD\n";
628 : }
629 :
630 0 : if (mUsesPointCoord)
631 : {
632 0 : out << "#define GL_USES_POINT_COORD\n";
633 : }
634 :
635 0 : if (mUsesFrontFacing)
636 : {
637 0 : out << "#define GL_USES_FRONT_FACING\n";
638 : }
639 :
640 0 : if (mUsesPointSize)
641 : {
642 0 : out << "#define GL_USES_POINT_SIZE\n";
643 : }
644 :
645 0 : if (mUsesFragDepth)
646 : {
647 0 : out << "#define GL_USES_FRAG_DEPTH\n";
648 : }
649 :
650 0 : if (mUsesDepthRange)
651 : {
652 0 : out << "#define GL_USES_DEPTH_RANGE\n";
653 : }
654 :
655 0 : if (mUsesXor)
656 : {
657 : out << "bool xor(bool p, bool q)\n"
658 : "{\n"
659 : " return (p || q) && !(p && q);\n"
660 : "}\n"
661 0 : "\n";
662 : }
663 :
664 0 : builtInFunctionEmulator->OutputEmulatedFunctions(out);
665 0 : }
666 :
667 0 : void OutputHLSL::visitSymbol(TIntermSymbol *node)
668 : {
669 0 : TInfoSinkBase &out = getInfoSink();
670 :
671 : // Handle accessing std140 structs by value
672 0 : if (mFlaggedStructMappedNames.count(node) > 0)
673 : {
674 0 : out << mFlaggedStructMappedNames[node];
675 0 : return;
676 : }
677 :
678 0 : TString name = node->getSymbol();
679 :
680 0 : if (name == "gl_DepthRange")
681 : {
682 0 : mUsesDepthRange = true;
683 0 : out << name;
684 : }
685 : else
686 : {
687 0 : TQualifier qualifier = node->getQualifier();
688 :
689 0 : if (qualifier == EvqUniform)
690 : {
691 0 : const TType &nodeType = node->getType();
692 0 : const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
693 :
694 0 : if (interfaceBlock)
695 : {
696 0 : mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
697 : }
698 : else
699 : {
700 0 : mReferencedUniforms[name] = node;
701 : }
702 :
703 0 : ensureStructDefined(nodeType);
704 :
705 0 : const TName &nameWithMetadata = node->getName();
706 0 : out << DecorateUniform(nameWithMetadata, nodeType);
707 : }
708 0 : else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
709 : {
710 0 : mReferencedAttributes[name] = node;
711 0 : out << Decorate(name);
712 : }
713 0 : else if (IsVarying(qualifier))
714 : {
715 0 : mReferencedVaryings[name] = node;
716 0 : out << Decorate(name);
717 : }
718 0 : else if (qualifier == EvqFragmentOut)
719 : {
720 0 : mReferencedOutputVariables[name] = node;
721 0 : out << "out_" << name;
722 : }
723 0 : else if (qualifier == EvqFragColor)
724 : {
725 0 : out << "gl_Color[0]";
726 0 : mUsesFragColor = true;
727 : }
728 0 : else if (qualifier == EvqFragData)
729 : {
730 0 : out << "gl_Color";
731 0 : mUsesFragData = true;
732 : }
733 0 : else if (qualifier == EvqFragCoord)
734 : {
735 0 : mUsesFragCoord = true;
736 0 : out << name;
737 : }
738 0 : else if (qualifier == EvqPointCoord)
739 : {
740 0 : mUsesPointCoord = true;
741 0 : out << name;
742 : }
743 0 : else if (qualifier == EvqFrontFacing)
744 : {
745 0 : mUsesFrontFacing = true;
746 0 : out << name;
747 : }
748 0 : else if (qualifier == EvqPointSize)
749 : {
750 0 : mUsesPointSize = true;
751 0 : out << name;
752 : }
753 0 : else if (qualifier == EvqInstanceID)
754 : {
755 0 : mUsesInstanceID = true;
756 0 : out << name;
757 : }
758 0 : else if (qualifier == EvqVertexID)
759 : {
760 0 : mUsesVertexID = true;
761 0 : out << name;
762 : }
763 0 : else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
764 : {
765 0 : mUsesFragDepth = true;
766 0 : out << "gl_Depth";
767 : }
768 : else
769 : {
770 0 : out << DecorateIfNeeded(node->getName());
771 : }
772 : }
773 : }
774 :
775 0 : void OutputHLSL::visitRaw(TIntermRaw *node)
776 : {
777 0 : getInfoSink() << node->getRawText();
778 0 : }
779 :
780 0 : void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
781 : {
782 0 : if (type.isScalar() && !type.isArray())
783 : {
784 0 : if (op == EOpEqual)
785 : {
786 0 : outputTriplet(out, visit, "(", " == ", ")");
787 : }
788 : else
789 : {
790 0 : outputTriplet(out, visit, "(", " != ", ")");
791 : }
792 : }
793 : else
794 : {
795 0 : if (visit == PreVisit && op == EOpNotEqual)
796 : {
797 0 : out << "!";
798 : }
799 :
800 0 : if (type.isArray())
801 : {
802 0 : const TString &functionName = addArrayEqualityFunction(type);
803 0 : outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
804 : }
805 0 : else if (type.getBasicType() == EbtStruct)
806 : {
807 0 : const TStructure &structure = *type.getStruct();
808 0 : const TString &functionName = addStructEqualityFunction(structure);
809 0 : outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
810 : }
811 : else
812 : {
813 0 : ASSERT(type.isMatrix() || type.isVector());
814 0 : outputTriplet(out, visit, "all(", " == ", ")");
815 : }
816 : }
817 0 : }
818 :
819 0 : bool OutputHLSL::ancestorEvaluatesToSamplerInStruct(Visit visit)
820 : {
821 : // Inside InVisit the current node is already in the path.
822 0 : const unsigned int initialN = visit == InVisit ? 1u : 0u;
823 0 : for (unsigned int n = initialN; getAncestorNode(n) != nullptr; ++n)
824 : {
825 0 : TIntermNode *ancestor = getAncestorNode(n);
826 0 : const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
827 0 : if (ancestorBinary == nullptr)
828 : {
829 0 : return false;
830 : }
831 0 : switch (ancestorBinary->getOp())
832 : {
833 : case EOpIndexDirectStruct:
834 : {
835 0 : const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
836 : const TIntermConstantUnion *index =
837 0 : ancestorBinary->getRight()->getAsConstantUnion();
838 0 : const TField *field = structure->fields()[index->getIConst(0)];
839 0 : if (IsSampler(field->type()->getBasicType()))
840 : {
841 0 : return true;
842 : }
843 0 : break;
844 : }
845 : case EOpIndexDirect:
846 0 : break;
847 : default:
848 : // Returning a sampler from indirect indexing is not supported.
849 0 : return false;
850 : }
851 : }
852 0 : return false;
853 : }
854 :
855 0 : bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
856 : {
857 0 : TInfoSinkBase &out = getInfoSink();
858 0 : if (visit == PostVisit)
859 : {
860 0 : out << ".";
861 0 : node->writeOffsetsAsXYZW(&out);
862 : }
863 0 : return true;
864 : }
865 :
866 0 : bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
867 : {
868 0 : TInfoSinkBase &out = getInfoSink();
869 :
870 : // Handle accessing std140 structs by value
871 0 : if (mFlaggedStructMappedNames.count(node) > 0)
872 : {
873 0 : out << mFlaggedStructMappedNames[node];
874 0 : return false;
875 : }
876 :
877 0 : switch (node->getOp())
878 : {
879 : case EOpComma:
880 0 : outputTriplet(out, visit, "(", ", ", ")");
881 0 : break;
882 : case EOpAssign:
883 0 : if (node->getLeft()->isArray())
884 : {
885 0 : TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
886 0 : if (rightAgg != nullptr && rightAgg->isConstructor())
887 : {
888 0 : const TString &functionName = addArrayConstructIntoFunction(node->getType());
889 0 : out << functionName << "(";
890 0 : node->getLeft()->traverse(this);
891 0 : TIntermSequence *seq = rightAgg->getSequence();
892 0 : for (auto &arrayElement : *seq)
893 : {
894 0 : out << ", ";
895 0 : arrayElement->traverse(this);
896 : }
897 0 : out << ")";
898 0 : return false;
899 : }
900 : // ArrayReturnValueToOutParameter should have eliminated expressions where a
901 : // function call is assigned.
902 0 : ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
903 :
904 0 : const TString &functionName = addArrayAssignmentFunction(node->getType());
905 0 : outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
906 : }
907 : else
908 : {
909 0 : outputTriplet(out, visit, "(", " = ", ")");
910 : }
911 0 : break;
912 : case EOpInitialize:
913 0 : if (visit == PreVisit)
914 : {
915 0 : TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
916 0 : ASSERT(symbolNode);
917 0 : TIntermTyped *expression = node->getRight();
918 :
919 : // Global initializers must be constant at this point.
920 0 : ASSERT(symbolNode->getQualifier() != EvqGlobal ||
921 : canWriteAsHLSLLiteral(expression));
922 :
923 : // GLSL allows to write things like "float x = x;" where a new variable x is defined
924 : // and the value of an existing variable x is assigned. HLSL uses C semantics (the
925 : // new variable is created before the assignment is evaluated), so we need to
926 : // convert
927 : // this to "float t = x, x = t;".
928 0 : if (writeSameSymbolInitializer(out, symbolNode, expression))
929 : {
930 : // Skip initializing the rest of the expression
931 0 : return false;
932 : }
933 0 : else if (writeConstantInitialization(out, symbolNode, expression))
934 : {
935 0 : return false;
936 : }
937 : }
938 0 : else if (visit == InVisit)
939 : {
940 0 : out << " = ";
941 : }
942 0 : break;
943 : case EOpAddAssign:
944 0 : outputTriplet(out, visit, "(", " += ", ")");
945 0 : break;
946 : case EOpSubAssign:
947 0 : outputTriplet(out, visit, "(", " -= ", ")");
948 0 : break;
949 : case EOpMulAssign:
950 0 : outputTriplet(out, visit, "(", " *= ", ")");
951 0 : break;
952 : case EOpVectorTimesScalarAssign:
953 0 : outputTriplet(out, visit, "(", " *= ", ")");
954 0 : break;
955 : case EOpMatrixTimesScalarAssign:
956 0 : outputTriplet(out, visit, "(", " *= ", ")");
957 0 : break;
958 : case EOpVectorTimesMatrixAssign:
959 0 : if (visit == PreVisit)
960 : {
961 0 : out << "(";
962 : }
963 0 : else if (visit == InVisit)
964 : {
965 0 : out << " = mul(";
966 0 : node->getLeft()->traverse(this);
967 0 : out << ", transpose(";
968 : }
969 : else
970 : {
971 0 : out << ")))";
972 : }
973 0 : break;
974 : case EOpMatrixTimesMatrixAssign:
975 0 : if (visit == PreVisit)
976 : {
977 0 : out << "(";
978 : }
979 0 : else if (visit == InVisit)
980 : {
981 0 : out << " = transpose(mul(transpose(";
982 0 : node->getLeft()->traverse(this);
983 0 : out << "), transpose(";
984 : }
985 : else
986 : {
987 0 : out << "))))";
988 : }
989 0 : break;
990 : case EOpDivAssign:
991 0 : outputTriplet(out, visit, "(", " /= ", ")");
992 0 : break;
993 : case EOpIModAssign:
994 0 : outputTriplet(out, visit, "(", " %= ", ")");
995 0 : break;
996 : case EOpBitShiftLeftAssign:
997 0 : outputTriplet(out, visit, "(", " <<= ", ")");
998 0 : break;
999 : case EOpBitShiftRightAssign:
1000 0 : outputTriplet(out, visit, "(", " >>= ", ")");
1001 0 : break;
1002 : case EOpBitwiseAndAssign:
1003 0 : outputTriplet(out, visit, "(", " &= ", ")");
1004 0 : break;
1005 : case EOpBitwiseXorAssign:
1006 0 : outputTriplet(out, visit, "(", " ^= ", ")");
1007 0 : break;
1008 : case EOpBitwiseOrAssign:
1009 0 : outputTriplet(out, visit, "(", " |= ", ")");
1010 0 : break;
1011 : case EOpIndexDirect:
1012 : {
1013 0 : const TType& leftType = node->getLeft()->getType();
1014 0 : if (leftType.isInterfaceBlock())
1015 : {
1016 0 : if (visit == PreVisit)
1017 : {
1018 0 : TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1019 0 : const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
1020 0 : mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
1021 0 : out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
1022 0 : return false;
1023 : }
1024 : }
1025 0 : else if (ancestorEvaluatesToSamplerInStruct(visit))
1026 : {
1027 : // All parts of an expression that access a sampler in a struct need to use _ as
1028 : // separator to access the sampler variable that has been moved out of the struct.
1029 0 : outputTriplet(out, visit, "", "_", "");
1030 : }
1031 : else
1032 : {
1033 0 : outputTriplet(out, visit, "", "[", "]");
1034 : }
1035 : }
1036 0 : break;
1037 : case EOpIndexIndirect:
1038 : // We do not currently support indirect references to interface blocks
1039 0 : ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1040 0 : outputTriplet(out, visit, "", "[", "]");
1041 0 : break;
1042 : case EOpIndexDirectStruct:
1043 : {
1044 0 : const TStructure* structure = node->getLeft()->getType().getStruct();
1045 0 : const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1046 0 : const TField* field = structure->fields()[index->getIConst(0)];
1047 :
1048 : // In cases where indexing returns a sampler, we need to access the sampler variable
1049 : // that has been moved out of the struct.
1050 0 : bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1051 0 : if (visit == PreVisit && indexingReturnsSampler)
1052 : {
1053 : // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1054 : // This prefix is only output at the beginning of the indexing expression, which
1055 : // may have multiple parts.
1056 0 : out << "angle";
1057 : }
1058 0 : if (!indexingReturnsSampler)
1059 : {
1060 : // All parts of an expression that access a sampler in a struct need to use _ as
1061 : // separator to access the sampler variable that has been moved out of the struct.
1062 0 : indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct(visit);
1063 : }
1064 0 : if (visit == InVisit)
1065 : {
1066 0 : if (indexingReturnsSampler)
1067 : {
1068 0 : out << "_" + field->name();
1069 : }
1070 : else
1071 : {
1072 0 : out << "." + DecorateField(field->name(), *structure);
1073 : }
1074 :
1075 0 : return false;
1076 : }
1077 : }
1078 0 : break;
1079 : case EOpIndexDirectInterfaceBlock:
1080 0 : if (visit == InVisit)
1081 : {
1082 0 : const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1083 0 : const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1084 0 : const TField* field = interfaceBlock->fields()[index->getIConst(0)];
1085 0 : out << "." + Decorate(field->name());
1086 :
1087 0 : return false;
1088 : }
1089 0 : break;
1090 : case EOpAdd:
1091 0 : outputTriplet(out, visit, "(", " + ", ")");
1092 0 : break;
1093 : case EOpSub:
1094 0 : outputTriplet(out, visit, "(", " - ", ")");
1095 0 : break;
1096 : case EOpMul:
1097 0 : outputTriplet(out, visit, "(", " * ", ")");
1098 0 : break;
1099 : case EOpDiv:
1100 0 : outputTriplet(out, visit, "(", " / ", ")");
1101 0 : break;
1102 : case EOpIMod:
1103 0 : outputTriplet(out, visit, "(", " % ", ")");
1104 0 : break;
1105 : case EOpBitShiftLeft:
1106 0 : outputTriplet(out, visit, "(", " << ", ")");
1107 0 : break;
1108 : case EOpBitShiftRight:
1109 0 : outputTriplet(out, visit, "(", " >> ", ")");
1110 0 : break;
1111 : case EOpBitwiseAnd:
1112 0 : outputTriplet(out, visit, "(", " & ", ")");
1113 0 : break;
1114 : case EOpBitwiseXor:
1115 0 : outputTriplet(out, visit, "(", " ^ ", ")");
1116 0 : break;
1117 : case EOpBitwiseOr:
1118 0 : outputTriplet(out, visit, "(", " | ", ")");
1119 0 : break;
1120 : case EOpEqual:
1121 : case EOpNotEqual:
1122 0 : outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1123 0 : break;
1124 : case EOpLessThan:
1125 0 : outputTriplet(out, visit, "(", " < ", ")");
1126 0 : break;
1127 : case EOpGreaterThan:
1128 0 : outputTriplet(out, visit, "(", " > ", ")");
1129 0 : break;
1130 : case EOpLessThanEqual:
1131 0 : outputTriplet(out, visit, "(", " <= ", ")");
1132 0 : break;
1133 : case EOpGreaterThanEqual:
1134 0 : outputTriplet(out, visit, "(", " >= ", ")");
1135 0 : break;
1136 : case EOpVectorTimesScalar:
1137 0 : outputTriplet(out, visit, "(", " * ", ")");
1138 0 : break;
1139 : case EOpMatrixTimesScalar:
1140 0 : outputTriplet(out, visit, "(", " * ", ")");
1141 0 : break;
1142 : case EOpVectorTimesMatrix:
1143 0 : outputTriplet(out, visit, "mul(", ", transpose(", "))");
1144 0 : break;
1145 : case EOpMatrixTimesVector:
1146 0 : outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1147 0 : break;
1148 : case EOpMatrixTimesMatrix:
1149 0 : outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1150 0 : break;
1151 : case EOpLogicalOr:
1152 : // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
1153 0 : ASSERT(!node->getRight()->hasSideEffects());
1154 0 : outputTriplet(out, visit, "(", " || ", ")");
1155 0 : return true;
1156 : case EOpLogicalXor:
1157 0 : mUsesXor = true;
1158 0 : outputTriplet(out, visit, "xor(", ", ", ")");
1159 0 : break;
1160 : case EOpLogicalAnd:
1161 : // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
1162 0 : ASSERT(!node->getRight()->hasSideEffects());
1163 0 : outputTriplet(out, visit, "(", " && ", ")");
1164 0 : return true;
1165 0 : default: UNREACHABLE();
1166 : }
1167 :
1168 0 : return true;
1169 : }
1170 :
1171 0 : bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1172 : {
1173 0 : TInfoSinkBase &out = getInfoSink();
1174 :
1175 0 : switch (node->getOp())
1176 : {
1177 : case EOpNegative:
1178 0 : outputTriplet(out, visit, "(-", "", ")");
1179 0 : break;
1180 : case EOpPositive:
1181 0 : outputTriplet(out, visit, "(+", "", ")");
1182 0 : break;
1183 : case EOpVectorLogicalNot:
1184 0 : outputTriplet(out, visit, "(!", "", ")");
1185 0 : break;
1186 : case EOpLogicalNot:
1187 0 : outputTriplet(out, visit, "(!", "", ")");
1188 0 : break;
1189 : case EOpBitwiseNot:
1190 0 : outputTriplet(out, visit, "(~", "", ")");
1191 0 : break;
1192 : case EOpPostIncrement:
1193 0 : outputTriplet(out, visit, "(", "", "++)");
1194 0 : break;
1195 : case EOpPostDecrement:
1196 0 : outputTriplet(out, visit, "(", "", "--)");
1197 0 : break;
1198 : case EOpPreIncrement:
1199 0 : outputTriplet(out, visit, "(++", "", ")");
1200 0 : break;
1201 : case EOpPreDecrement:
1202 0 : outputTriplet(out, visit, "(--", "", ")");
1203 0 : break;
1204 : case EOpRadians:
1205 0 : outputTriplet(out, visit, "radians(", "", ")");
1206 0 : break;
1207 : case EOpDegrees:
1208 0 : outputTriplet(out, visit, "degrees(", "", ")");
1209 0 : break;
1210 : case EOpSin:
1211 0 : outputTriplet(out, visit, "sin(", "", ")");
1212 0 : break;
1213 : case EOpCos:
1214 0 : outputTriplet(out, visit, "cos(", "", ")");
1215 0 : break;
1216 : case EOpTan:
1217 0 : outputTriplet(out, visit, "tan(", "", ")");
1218 0 : break;
1219 : case EOpAsin:
1220 0 : outputTriplet(out, visit, "asin(", "", ")");
1221 0 : break;
1222 : case EOpAcos:
1223 0 : outputTriplet(out, visit, "acos(", "", ")");
1224 0 : break;
1225 : case EOpAtan:
1226 0 : outputTriplet(out, visit, "atan(", "", ")");
1227 0 : break;
1228 : case EOpSinh:
1229 0 : outputTriplet(out, visit, "sinh(", "", ")");
1230 0 : break;
1231 : case EOpCosh:
1232 0 : outputTriplet(out, visit, "cosh(", "", ")");
1233 0 : break;
1234 : case EOpTanh:
1235 0 : outputTriplet(out, visit, "tanh(", "", ")");
1236 0 : break;
1237 : case EOpAsinh:
1238 0 : ASSERT(node->getUseEmulatedFunction());
1239 0 : writeEmulatedFunctionTriplet(out, visit, "asinh(");
1240 0 : break;
1241 : case EOpAcosh:
1242 0 : ASSERT(node->getUseEmulatedFunction());
1243 0 : writeEmulatedFunctionTriplet(out, visit, "acosh(");
1244 0 : break;
1245 : case EOpAtanh:
1246 0 : ASSERT(node->getUseEmulatedFunction());
1247 0 : writeEmulatedFunctionTriplet(out, visit, "atanh(");
1248 0 : break;
1249 : case EOpExp:
1250 0 : outputTriplet(out, visit, "exp(", "", ")");
1251 0 : break;
1252 : case EOpLog:
1253 0 : outputTriplet(out, visit, "log(", "", ")");
1254 0 : break;
1255 : case EOpExp2:
1256 0 : outputTriplet(out, visit, "exp2(", "", ")");
1257 0 : break;
1258 : case EOpLog2:
1259 0 : outputTriplet(out, visit, "log2(", "", ")");
1260 0 : break;
1261 : case EOpSqrt:
1262 0 : outputTriplet(out, visit, "sqrt(", "", ")");
1263 0 : break;
1264 : case EOpInverseSqrt:
1265 0 : outputTriplet(out, visit, "rsqrt(", "", ")");
1266 0 : break;
1267 : case EOpAbs:
1268 0 : outputTriplet(out, visit, "abs(", "", ")");
1269 0 : break;
1270 : case EOpSign:
1271 0 : outputTriplet(out, visit, "sign(", "", ")");
1272 0 : break;
1273 : case EOpFloor:
1274 0 : outputTriplet(out, visit, "floor(", "", ")");
1275 0 : break;
1276 : case EOpTrunc:
1277 0 : outputTriplet(out, visit, "trunc(", "", ")");
1278 0 : break;
1279 : case EOpRound:
1280 0 : outputTriplet(out, visit, "round(", "", ")");
1281 0 : break;
1282 : case EOpRoundEven:
1283 0 : ASSERT(node->getUseEmulatedFunction());
1284 0 : writeEmulatedFunctionTriplet(out, visit, "roundEven(");
1285 0 : break;
1286 : case EOpCeil:
1287 0 : outputTriplet(out, visit, "ceil(", "", ")");
1288 0 : break;
1289 : case EOpFract:
1290 0 : outputTriplet(out, visit, "frac(", "", ")");
1291 0 : break;
1292 : case EOpIsNan:
1293 0 : if (node->getUseEmulatedFunction())
1294 0 : writeEmulatedFunctionTriplet(out, visit, "isnan(");
1295 : else
1296 0 : outputTriplet(out, visit, "isnan(", "", ")");
1297 0 : mRequiresIEEEStrictCompiling = true;
1298 0 : break;
1299 : case EOpIsInf:
1300 0 : outputTriplet(out, visit, "isinf(", "", ")");
1301 0 : break;
1302 : case EOpFloatBitsToInt:
1303 0 : outputTriplet(out, visit, "asint(", "", ")");
1304 0 : break;
1305 : case EOpFloatBitsToUint:
1306 0 : outputTriplet(out, visit, "asuint(", "", ")");
1307 0 : break;
1308 : case EOpIntBitsToFloat:
1309 0 : outputTriplet(out, visit, "asfloat(", "", ")");
1310 0 : break;
1311 : case EOpUintBitsToFloat:
1312 0 : outputTriplet(out, visit, "asfloat(", "", ")");
1313 0 : break;
1314 : case EOpPackSnorm2x16:
1315 0 : ASSERT(node->getUseEmulatedFunction());
1316 0 : writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
1317 0 : break;
1318 : case EOpPackUnorm2x16:
1319 0 : ASSERT(node->getUseEmulatedFunction());
1320 0 : writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
1321 0 : break;
1322 : case EOpPackHalf2x16:
1323 0 : ASSERT(node->getUseEmulatedFunction());
1324 0 : writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
1325 0 : break;
1326 : case EOpUnpackSnorm2x16:
1327 0 : ASSERT(node->getUseEmulatedFunction());
1328 0 : writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
1329 0 : break;
1330 : case EOpUnpackUnorm2x16:
1331 0 : ASSERT(node->getUseEmulatedFunction());
1332 0 : writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
1333 0 : break;
1334 : case EOpUnpackHalf2x16:
1335 0 : ASSERT(node->getUseEmulatedFunction());
1336 0 : writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
1337 0 : break;
1338 : case EOpLength:
1339 0 : outputTriplet(out, visit, "length(", "", ")");
1340 0 : break;
1341 : case EOpNormalize:
1342 0 : outputTriplet(out, visit, "normalize(", "", ")");
1343 0 : break;
1344 : case EOpDFdx:
1345 0 : if(mInsideDiscontinuousLoop || mOutputLod0Function)
1346 : {
1347 0 : outputTriplet(out, visit, "(", "", ", 0.0)");
1348 : }
1349 : else
1350 : {
1351 0 : outputTriplet(out, visit, "ddx(", "", ")");
1352 : }
1353 0 : break;
1354 : case EOpDFdy:
1355 0 : if(mInsideDiscontinuousLoop || mOutputLod0Function)
1356 : {
1357 0 : outputTriplet(out, visit, "(", "", ", 0.0)");
1358 : }
1359 : else
1360 : {
1361 0 : outputTriplet(out, visit, "ddy(", "", ")");
1362 : }
1363 0 : break;
1364 : case EOpFwidth:
1365 0 : if(mInsideDiscontinuousLoop || mOutputLod0Function)
1366 : {
1367 0 : outputTriplet(out, visit, "(", "", ", 0.0)");
1368 : }
1369 : else
1370 : {
1371 0 : outputTriplet(out, visit, "fwidth(", "", ")");
1372 : }
1373 0 : break;
1374 : case EOpTranspose:
1375 0 : outputTriplet(out, visit, "transpose(", "", ")");
1376 0 : break;
1377 : case EOpDeterminant:
1378 0 : outputTriplet(out, visit, "determinant(transpose(", "", "))");
1379 0 : break;
1380 : case EOpInverse:
1381 0 : ASSERT(node->getUseEmulatedFunction());
1382 0 : writeEmulatedFunctionTriplet(out, visit, "inverse(");
1383 0 : break;
1384 :
1385 : case EOpAny:
1386 0 : outputTriplet(out, visit, "any(", "", ")");
1387 0 : break;
1388 : case EOpAll:
1389 0 : outputTriplet(out, visit, "all(", "", ")");
1390 0 : break;
1391 0 : default: UNREACHABLE();
1392 : }
1393 :
1394 0 : return true;
1395 : }
1396 :
1397 0 : TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
1398 : {
1399 0 : if (node->getAsSymbolNode())
1400 : {
1401 0 : return node->getAsSymbolNode()->getSymbol();
1402 : }
1403 0 : TIntermBinary *nodeBinary = node->getAsBinaryNode();
1404 0 : switch (nodeBinary->getOp())
1405 : {
1406 : case EOpIndexDirect:
1407 : {
1408 0 : int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1409 :
1410 0 : TInfoSinkBase prefixSink;
1411 0 : prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
1412 0 : return TString(prefixSink.c_str());
1413 : }
1414 : case EOpIndexDirectStruct:
1415 : {
1416 0 : TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
1417 0 : int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
1418 0 : const TField *field = s->fields()[index];
1419 :
1420 0 : TInfoSinkBase prefixSink;
1421 0 : prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
1422 0 : << field->name();
1423 0 : return TString(prefixSink.c_str());
1424 : }
1425 : default:
1426 0 : UNREACHABLE();
1427 : return TString("");
1428 : }
1429 : }
1430 :
1431 0 : bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
1432 : {
1433 0 : TInfoSinkBase &out = getInfoSink();
1434 :
1435 0 : if (mInsideFunction)
1436 : {
1437 0 : outputLineDirective(out, node->getLine().first_line);
1438 0 : out << "{\n";
1439 : }
1440 :
1441 0 : for (TIntermSequence::iterator sit = node->getSequence()->begin();
1442 0 : sit != node->getSequence()->end(); sit++)
1443 : {
1444 0 : outputLineDirective(out, (*sit)->getLine().first_line);
1445 :
1446 0 : (*sit)->traverse(this);
1447 :
1448 : // Don't output ; after case labels, they're terminated by :
1449 : // This is needed especially since outputting a ; after a case statement would turn empty
1450 : // case statements into non-empty case statements, disallowing fall-through from them.
1451 : // Also no need to output ; after if statements or sequences. This is done just for
1452 : // code clarity.
1453 0 : if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
1454 0 : (*sit)->getAsBlock() == nullptr)
1455 0 : out << ";\n";
1456 : }
1457 :
1458 0 : if (mInsideFunction)
1459 : {
1460 0 : outputLineDirective(out, node->getLine().last_line);
1461 0 : out << "}\n";
1462 : }
1463 :
1464 0 : return false;
1465 : }
1466 :
1467 0 : bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1468 : {
1469 0 : TInfoSinkBase &out = getInfoSink();
1470 :
1471 0 : ASSERT(mCurrentFunctionMetadata == nullptr);
1472 :
1473 0 : size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1474 0 : ASSERT(index != CallDAG::InvalidIndex);
1475 0 : mCurrentFunctionMetadata = &mASTMetadataList[index];
1476 :
1477 0 : out << TypeString(node->getType()) << " ";
1478 :
1479 0 : TIntermSequence *parameters = node->getFunctionParameters()->getSequence();
1480 :
1481 0 : if (node->getFunctionSymbolInfo()->isMain())
1482 : {
1483 0 : out << "gl_main(";
1484 : }
1485 : else
1486 : {
1487 0 : out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
1488 0 : << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
1489 : }
1490 :
1491 0 : for (unsigned int i = 0; i < parameters->size(); i++)
1492 : {
1493 0 : TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
1494 :
1495 0 : if (symbol)
1496 : {
1497 0 : ensureStructDefined(symbol->getType());
1498 :
1499 0 : out << argumentString(symbol);
1500 :
1501 0 : if (i < parameters->size() - 1)
1502 : {
1503 0 : out << ", ";
1504 : }
1505 : }
1506 : else
1507 0 : UNREACHABLE();
1508 : }
1509 :
1510 0 : out << ")\n";
1511 :
1512 0 : mInsideFunction = true;
1513 : // The function body node will output braces.
1514 0 : node->getBody()->traverse(this);
1515 0 : mInsideFunction = false;
1516 :
1517 0 : mCurrentFunctionMetadata = nullptr;
1518 :
1519 0 : bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1520 0 : if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1521 : {
1522 0 : ASSERT(!node->getFunctionSymbolInfo()->isMain());
1523 0 : mOutputLod0Function = true;
1524 0 : node->traverse(this);
1525 0 : mOutputLod0Function = false;
1526 : }
1527 :
1528 0 : return false;
1529 : }
1530 :
1531 0 : bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
1532 : {
1533 0 : TInfoSinkBase &out = getInfoSink();
1534 0 : if (visit == PreVisit)
1535 : {
1536 0 : TIntermSequence *sequence = node->getSequence();
1537 0 : TIntermTyped *variable = (*sequence)[0]->getAsTyped();
1538 0 : ASSERT(sequence->size() == 1);
1539 :
1540 0 : if (variable &&
1541 0 : (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
1542 0 : variable->getQualifier() == EvqConst))
1543 : {
1544 0 : ensureStructDefined(variable->getType());
1545 :
1546 0 : if (!variable->getAsSymbolNode() ||
1547 0 : variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
1548 : {
1549 0 : if (!mInsideFunction)
1550 : {
1551 0 : out << "static ";
1552 : }
1553 :
1554 0 : out << TypeString(variable->getType()) + " ";
1555 :
1556 0 : TIntermSymbol *symbol = variable->getAsSymbolNode();
1557 :
1558 0 : if (symbol)
1559 : {
1560 0 : symbol->traverse(this);
1561 0 : out << ArrayString(symbol->getType());
1562 0 : out << " = " + initializer(symbol->getType());
1563 : }
1564 : else
1565 : {
1566 0 : variable->traverse(this);
1567 : }
1568 : }
1569 0 : else if (variable->getAsSymbolNode() &&
1570 0 : variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1571 : {
1572 : // Already added to constructor map
1573 : }
1574 : else
1575 0 : UNREACHABLE();
1576 : }
1577 0 : else if (variable && IsVaryingOut(variable->getQualifier()))
1578 : {
1579 0 : for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
1580 : {
1581 0 : TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1582 :
1583 0 : if (symbol)
1584 : {
1585 : // Vertex (output) varyings which are declared but not written to should
1586 : // still be declared to allow successful linking
1587 0 : mReferencedVaryings[symbol->getSymbol()] = symbol;
1588 : }
1589 : else
1590 : {
1591 0 : (*sit)->traverse(this);
1592 : }
1593 : }
1594 : }
1595 : }
1596 0 : return false;
1597 : }
1598 :
1599 0 : bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1600 : {
1601 0 : TInfoSinkBase &out = getInfoSink();
1602 :
1603 0 : switch (node->getOp())
1604 : {
1605 : case EOpInvariantDeclaration:
1606 : // Do not do any translation
1607 0 : return false;
1608 : case EOpPrototype:
1609 0 : if (visit == PreVisit)
1610 : {
1611 0 : size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1612 : // Skip the prototype if it is not implemented (and thus not used)
1613 0 : if (index == CallDAG::InvalidIndex)
1614 : {
1615 0 : return false;
1616 : }
1617 :
1618 0 : TIntermSequence *arguments = node->getSequence();
1619 :
1620 : TString name =
1621 0 : DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
1622 0 : out << TypeString(node->getType()) << " " << name
1623 0 : << DisambiguateFunctionName(arguments) << (mOutputLod0Function ? "Lod0(" : "(");
1624 :
1625 0 : for (unsigned int i = 0; i < arguments->size(); i++)
1626 : {
1627 0 : TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
1628 :
1629 0 : if (symbol)
1630 : {
1631 0 : out << argumentString(symbol);
1632 :
1633 0 : if (i < arguments->size() - 1)
1634 : {
1635 0 : out << ", ";
1636 : }
1637 : }
1638 : else
1639 0 : UNREACHABLE();
1640 : }
1641 :
1642 0 : out << ");\n";
1643 :
1644 : // Also prototype the Lod0 variant if needed
1645 0 : bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
1646 0 : if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
1647 : {
1648 0 : mOutputLod0Function = true;
1649 0 : node->traverse(this);
1650 0 : mOutputLod0Function = false;
1651 : }
1652 :
1653 0 : return false;
1654 : }
1655 0 : break;
1656 : case EOpFunctionCall:
1657 : {
1658 0 : TIntermSequence *arguments = node->getSequence();
1659 :
1660 0 : bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
1661 0 : if (node->isUserDefined())
1662 : {
1663 0 : if (node->isArray())
1664 : {
1665 0 : UNIMPLEMENTED();
1666 : }
1667 0 : size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
1668 0 : ASSERT(index != CallDAG::InvalidIndex);
1669 0 : lod0 &= mASTMetadataList[index].mNeedsLod0;
1670 :
1671 0 : out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
1672 0 : out << DisambiguateFunctionName(node->getSequence());
1673 0 : out << (lod0 ? "Lod0(" : "(");
1674 : }
1675 0 : else if (node->getFunctionSymbolInfo()->getNameObj().isInternal())
1676 : {
1677 : // This path is used for internal functions that don't have their definitions in the
1678 : // AST, such as precision emulation functions.
1679 0 : out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
1680 : }
1681 : else
1682 : {
1683 0 : TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
1684 0 : TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
1685 0 : int coords = (*arguments)[1]->getAsTyped()->getNominalSize();
1686 0 : TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
1687 0 : name, samplerType, coords, arguments->size(), lod0, mShaderType);
1688 0 : out << textureFunctionName << "(";
1689 : }
1690 :
1691 0 : for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
1692 : {
1693 0 : TIntermTyped *typedArg = (*arg)->getAsTyped();
1694 0 : if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
1695 : {
1696 0 : out << "texture_";
1697 0 : (*arg)->traverse(this);
1698 0 : out << ", sampler_";
1699 : }
1700 :
1701 0 : (*arg)->traverse(this);
1702 :
1703 0 : if (typedArg->getType().isStructureContainingSamplers())
1704 : {
1705 0 : const TType &argType = typedArg->getType();
1706 0 : TVector<TIntermSymbol *> samplerSymbols;
1707 0 : TString structName = samplerNamePrefixFromStruct(typedArg);
1708 0 : argType.createSamplerSymbols("angle_" + structName, "",
1709 0 : argType.isArray() ? argType.getArraySize() : 0u,
1710 0 : &samplerSymbols, nullptr);
1711 0 : for (const TIntermSymbol *sampler : samplerSymbols)
1712 : {
1713 0 : if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1714 : {
1715 0 : out << ", texture_" << sampler->getSymbol();
1716 0 : out << ", sampler_" << sampler->getSymbol();
1717 : }
1718 : else
1719 : {
1720 : // In case of HLSL 4.1+, this symbol is the sampler index, and in case
1721 : // of D3D9, it's the sampler variable.
1722 0 : out << ", " + sampler->getSymbol();
1723 : }
1724 : }
1725 : }
1726 :
1727 0 : if (arg < arguments->end() - 1)
1728 : {
1729 0 : out << ", ";
1730 : }
1731 : }
1732 :
1733 0 : out << ")";
1734 :
1735 0 : return false;
1736 : }
1737 : case EOpParameters:
1738 0 : outputTriplet(out, visit, "(", ", ", ")\n{\n");
1739 0 : break;
1740 : case EOpConstructFloat:
1741 0 : outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
1742 0 : break;
1743 : case EOpConstructVec2:
1744 0 : outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
1745 0 : break;
1746 : case EOpConstructVec3:
1747 0 : outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
1748 0 : break;
1749 : case EOpConstructVec4:
1750 0 : outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
1751 0 : break;
1752 : case EOpConstructBool:
1753 0 : outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
1754 0 : break;
1755 : case EOpConstructBVec2:
1756 0 : outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
1757 0 : break;
1758 : case EOpConstructBVec3:
1759 0 : outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
1760 0 : break;
1761 : case EOpConstructBVec4:
1762 0 : outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
1763 0 : break;
1764 : case EOpConstructInt:
1765 0 : outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
1766 0 : break;
1767 : case EOpConstructIVec2:
1768 0 : outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
1769 0 : break;
1770 : case EOpConstructIVec3:
1771 0 : outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
1772 0 : break;
1773 : case EOpConstructIVec4:
1774 0 : outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
1775 0 : break;
1776 : case EOpConstructUInt:
1777 0 : outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
1778 0 : break;
1779 : case EOpConstructUVec2:
1780 0 : outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
1781 0 : break;
1782 : case EOpConstructUVec3:
1783 0 : outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
1784 0 : break;
1785 : case EOpConstructUVec4:
1786 0 : outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
1787 0 : break;
1788 : case EOpConstructMat2:
1789 0 : outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
1790 0 : break;
1791 : case EOpConstructMat2x3:
1792 0 : outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
1793 0 : break;
1794 : case EOpConstructMat2x4:
1795 0 : outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
1796 0 : break;
1797 : case EOpConstructMat3x2:
1798 0 : outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
1799 0 : break;
1800 : case EOpConstructMat3:
1801 0 : outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
1802 0 : break;
1803 : case EOpConstructMat3x4:
1804 0 : outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
1805 0 : break;
1806 : case EOpConstructMat4x2:
1807 0 : outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
1808 0 : break;
1809 : case EOpConstructMat4x3:
1810 0 : outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
1811 0 : break;
1812 : case EOpConstructMat4:
1813 0 : outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
1814 0 : break;
1815 : case EOpConstructStruct:
1816 : {
1817 0 : if (node->getType().isArray())
1818 : {
1819 0 : UNIMPLEMENTED();
1820 : }
1821 0 : const TString &structName = StructNameString(*node->getType().getStruct());
1822 0 : mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
1823 0 : outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
1824 : }
1825 0 : break;
1826 : case EOpLessThan:
1827 0 : outputTriplet(out, visit, "(", " < ", ")");
1828 0 : break;
1829 : case EOpGreaterThan:
1830 0 : outputTriplet(out, visit, "(", " > ", ")");
1831 0 : break;
1832 : case EOpLessThanEqual:
1833 0 : outputTriplet(out, visit, "(", " <= ", ")");
1834 0 : break;
1835 : case EOpGreaterThanEqual:
1836 0 : outputTriplet(out, visit, "(", " >= ", ")");
1837 0 : break;
1838 : case EOpVectorEqual:
1839 0 : outputTriplet(out, visit, "(", " == ", ")");
1840 0 : break;
1841 : case EOpVectorNotEqual:
1842 0 : outputTriplet(out, visit, "(", " != ", ")");
1843 0 : break;
1844 : case EOpMod:
1845 0 : ASSERT(node->getUseEmulatedFunction());
1846 0 : writeEmulatedFunctionTriplet(out, visit, "mod(");
1847 0 : break;
1848 : case EOpModf:
1849 0 : outputTriplet(out, visit, "modf(", ", ", ")");
1850 0 : break;
1851 : case EOpPow:
1852 0 : outputTriplet(out, visit, "pow(", ", ", ")");
1853 0 : break;
1854 : case EOpAtan:
1855 0 : ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
1856 0 : ASSERT(node->getUseEmulatedFunction());
1857 0 : writeEmulatedFunctionTriplet(out, visit, "atan(");
1858 0 : break;
1859 : case EOpMin:
1860 0 : outputTriplet(out, visit, "min(", ", ", ")");
1861 0 : break;
1862 : case EOpMax:
1863 0 : outputTriplet(out, visit, "max(", ", ", ")");
1864 0 : break;
1865 : case EOpClamp:
1866 0 : outputTriplet(out, visit, "clamp(", ", ", ")");
1867 0 : break;
1868 : case EOpMix:
1869 : {
1870 0 : TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
1871 0 : if (lastParamNode->getType().getBasicType() == EbtBool)
1872 : {
1873 : // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
1874 : // so use emulated version.
1875 0 : ASSERT(node->getUseEmulatedFunction());
1876 0 : writeEmulatedFunctionTriplet(out, visit, "mix(");
1877 : }
1878 : else
1879 : {
1880 0 : outputTriplet(out, visit, "lerp(", ", ", ")");
1881 : }
1882 0 : break;
1883 : }
1884 : case EOpStep:
1885 0 : outputTriplet(out, visit, "step(", ", ", ")");
1886 0 : break;
1887 : case EOpSmoothStep:
1888 0 : outputTriplet(out, visit, "smoothstep(", ", ", ")");
1889 0 : break;
1890 : case EOpDistance:
1891 0 : outputTriplet(out, visit, "distance(", ", ", ")");
1892 0 : break;
1893 : case EOpDot:
1894 0 : outputTriplet(out, visit, "dot(", ", ", ")");
1895 0 : break;
1896 : case EOpCross:
1897 0 : outputTriplet(out, visit, "cross(", ", ", ")");
1898 0 : break;
1899 : case EOpFaceForward:
1900 0 : ASSERT(node->getUseEmulatedFunction());
1901 0 : writeEmulatedFunctionTriplet(out, visit, "faceforward(");
1902 0 : break;
1903 : case EOpReflect:
1904 0 : outputTriplet(out, visit, "reflect(", ", ", ")");
1905 0 : break;
1906 : case EOpRefract:
1907 0 : outputTriplet(out, visit, "refract(", ", ", ")");
1908 0 : break;
1909 : case EOpOuterProduct:
1910 0 : ASSERT(node->getUseEmulatedFunction());
1911 0 : writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
1912 0 : break;
1913 : case EOpMul:
1914 0 : outputTriplet(out, visit, "(", " * ", ")");
1915 0 : break;
1916 : default:
1917 0 : UNREACHABLE();
1918 : }
1919 :
1920 0 : return true;
1921 : }
1922 :
1923 0 : void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
1924 : {
1925 0 : out << "if (";
1926 :
1927 0 : node->getCondition()->traverse(this);
1928 :
1929 0 : out << ")\n";
1930 :
1931 0 : outputLineDirective(out, node->getLine().first_line);
1932 :
1933 0 : bool discard = false;
1934 :
1935 0 : if (node->getTrueBlock())
1936 : {
1937 : // The trueBlock child node will output braces.
1938 0 : node->getTrueBlock()->traverse(this);
1939 :
1940 : // Detect true discard
1941 0 : discard = (discard || FindDiscard::search(node->getTrueBlock()));
1942 : }
1943 : else
1944 : {
1945 : // TODO(oetuaho): Check if the semicolon inside is necessary.
1946 : // It's there as a result of conservative refactoring of the output.
1947 0 : out << "{;}\n";
1948 : }
1949 :
1950 0 : outputLineDirective(out, node->getLine().first_line);
1951 :
1952 0 : if (node->getFalseBlock())
1953 : {
1954 0 : out << "else\n";
1955 :
1956 0 : outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
1957 :
1958 : // The falseBlock child node will output braces.
1959 0 : node->getFalseBlock()->traverse(this);
1960 :
1961 0 : outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
1962 :
1963 : // Detect false discard
1964 0 : discard = (discard || FindDiscard::search(node->getFalseBlock()));
1965 : }
1966 :
1967 : // ANGLE issue 486: Detect problematic conditional discard
1968 0 : if (discard)
1969 : {
1970 0 : mUsesDiscardRewriting = true;
1971 : }
1972 0 : }
1973 :
1974 0 : bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
1975 : {
1976 : // Ternary ops should have been already converted to something else in the AST. HLSL ternary
1977 : // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
1978 0 : UNREACHABLE();
1979 : return false;
1980 : }
1981 :
1982 0 : bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
1983 : {
1984 0 : TInfoSinkBase &out = getInfoSink();
1985 :
1986 0 : ASSERT(mInsideFunction);
1987 :
1988 : // D3D errors when there is a gradient operation in a loop in an unflattened if.
1989 0 : if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
1990 : {
1991 0 : out << "FLATTEN ";
1992 : }
1993 :
1994 0 : writeIfElse(out, node);
1995 :
1996 0 : return false;
1997 : }
1998 :
1999 0 : bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
2000 : {
2001 0 : TInfoSinkBase &out = getInfoSink();
2002 :
2003 0 : if (node->getStatementList())
2004 : {
2005 0 : node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
2006 0 : outputTriplet(out, visit, "switch (", ") ", "");
2007 : // The curly braces get written when visiting the statementList aggregate
2008 : }
2009 : else
2010 : {
2011 : // No statementList, so it won't output curly braces
2012 0 : outputTriplet(out, visit, "switch (", ") {", "}\n");
2013 : }
2014 0 : return true;
2015 : }
2016 :
2017 0 : bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
2018 : {
2019 0 : TInfoSinkBase &out = getInfoSink();
2020 :
2021 0 : if (node->hasCondition())
2022 : {
2023 0 : outputTriplet(out, visit, "case (", "", "):\n");
2024 0 : return true;
2025 : }
2026 : else
2027 : {
2028 0 : out << "default:\n";
2029 0 : return false;
2030 : }
2031 : }
2032 :
2033 0 : void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2034 : {
2035 0 : TInfoSinkBase &out = getInfoSink();
2036 0 : writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
2037 0 : }
2038 :
2039 0 : bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2040 : {
2041 0 : mNestedLoopDepth++;
2042 :
2043 0 : bool wasDiscontinuous = mInsideDiscontinuousLoop;
2044 0 : mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
2045 0 : mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
2046 :
2047 0 : TInfoSinkBase &out = getInfoSink();
2048 :
2049 0 : if (mOutputType == SH_HLSL_3_0_OUTPUT)
2050 : {
2051 0 : if (handleExcessiveLoop(out, node))
2052 : {
2053 0 : mInsideDiscontinuousLoop = wasDiscontinuous;
2054 0 : mNestedLoopDepth--;
2055 :
2056 0 : return false;
2057 : }
2058 : }
2059 :
2060 0 : const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
2061 0 : if (node->getType() == ELoopDoWhile)
2062 : {
2063 0 : out << "{" << unroll << " do\n";
2064 :
2065 0 : outputLineDirective(out, node->getLine().first_line);
2066 : }
2067 : else
2068 : {
2069 0 : out << "{" << unroll << " for(";
2070 :
2071 0 : if (node->getInit())
2072 : {
2073 0 : node->getInit()->traverse(this);
2074 : }
2075 :
2076 0 : out << "; ";
2077 :
2078 0 : if (node->getCondition())
2079 : {
2080 0 : node->getCondition()->traverse(this);
2081 : }
2082 :
2083 0 : out << "; ";
2084 :
2085 0 : if (node->getExpression())
2086 : {
2087 0 : node->getExpression()->traverse(this);
2088 : }
2089 :
2090 0 : out << ")\n";
2091 :
2092 0 : outputLineDirective(out, node->getLine().first_line);
2093 : }
2094 :
2095 0 : if (node->getBody())
2096 : {
2097 : // The loop body node will output braces.
2098 0 : node->getBody()->traverse(this);
2099 : }
2100 : else
2101 : {
2102 : // TODO(oetuaho): Check if the semicolon inside is necessary.
2103 : // It's there as a result of conservative refactoring of the output.
2104 0 : out << "{;}\n";
2105 : }
2106 :
2107 0 : outputLineDirective(out, node->getLine().first_line);
2108 :
2109 0 : if (node->getType() == ELoopDoWhile)
2110 : {
2111 0 : outputLineDirective(out, node->getCondition()->getLine().first_line);
2112 0 : out << "while(\n";
2113 :
2114 0 : node->getCondition()->traverse(this);
2115 :
2116 0 : out << ");";
2117 : }
2118 :
2119 0 : out << "}\n";
2120 :
2121 0 : mInsideDiscontinuousLoop = wasDiscontinuous;
2122 0 : mNestedLoopDepth--;
2123 :
2124 0 : return false;
2125 : }
2126 :
2127 0 : bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2128 : {
2129 0 : TInfoSinkBase &out = getInfoSink();
2130 :
2131 0 : switch (node->getFlowOp())
2132 : {
2133 : case EOpKill:
2134 0 : outputTriplet(out, visit, "discard;\n", "", "");
2135 0 : break;
2136 : case EOpBreak:
2137 0 : if (visit == PreVisit)
2138 : {
2139 0 : if (mNestedLoopDepth > 1)
2140 : {
2141 0 : mUsesNestedBreak = true;
2142 : }
2143 :
2144 0 : if (mExcessiveLoopIndex)
2145 : {
2146 0 : out << "{Break";
2147 0 : mExcessiveLoopIndex->traverse(this);
2148 0 : out << " = true; break;}\n";
2149 : }
2150 : else
2151 : {
2152 0 : out << "break;\n";
2153 : }
2154 : }
2155 0 : break;
2156 : case EOpContinue:
2157 0 : outputTriplet(out, visit, "continue;\n", "", "");
2158 0 : break;
2159 : case EOpReturn:
2160 0 : if (visit == PreVisit)
2161 : {
2162 0 : if (node->getExpression())
2163 : {
2164 0 : out << "return ";
2165 : }
2166 : else
2167 : {
2168 0 : out << "return;\n";
2169 : }
2170 : }
2171 0 : else if (visit == PostVisit)
2172 : {
2173 0 : if (node->getExpression())
2174 : {
2175 0 : out << ";\n";
2176 : }
2177 : }
2178 0 : break;
2179 0 : default: UNREACHABLE();
2180 : }
2181 :
2182 0 : return true;
2183 : }
2184 :
2185 : // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2186 : // (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
2187 0 : bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
2188 : {
2189 0 : const int MAX_LOOP_ITERATIONS = 254;
2190 :
2191 : // Parse loops of the form:
2192 : // for(int index = initial; index [comparator] limit; index += increment)
2193 0 : TIntermSymbol *index = NULL;
2194 0 : TOperator comparator = EOpNull;
2195 0 : int initial = 0;
2196 0 : int limit = 0;
2197 0 : int increment = 0;
2198 :
2199 : // Parse index name and intial value
2200 0 : if (node->getInit())
2201 : {
2202 0 : TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
2203 :
2204 0 : if (init)
2205 : {
2206 0 : TIntermSequence *sequence = init->getSequence();
2207 0 : TIntermTyped *variable = (*sequence)[0]->getAsTyped();
2208 :
2209 0 : if (variable && variable->getQualifier() == EvqTemporary)
2210 : {
2211 0 : TIntermBinary *assign = variable->getAsBinaryNode();
2212 :
2213 0 : if (assign->getOp() == EOpInitialize)
2214 : {
2215 0 : TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2216 0 : TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2217 :
2218 0 : if (symbol && constant)
2219 : {
2220 0 : if (constant->getBasicType() == EbtInt && constant->isScalar())
2221 : {
2222 0 : index = symbol;
2223 0 : initial = constant->getIConst(0);
2224 : }
2225 : }
2226 : }
2227 : }
2228 : }
2229 : }
2230 :
2231 : // Parse comparator and limit value
2232 0 : if (index != NULL && node->getCondition())
2233 : {
2234 0 : TIntermBinary *test = node->getCondition()->getAsBinaryNode();
2235 :
2236 0 : if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2237 : {
2238 0 : TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2239 :
2240 0 : if (constant)
2241 : {
2242 0 : if (constant->getBasicType() == EbtInt && constant->isScalar())
2243 : {
2244 0 : comparator = test->getOp();
2245 0 : limit = constant->getIConst(0);
2246 : }
2247 : }
2248 : }
2249 : }
2250 :
2251 : // Parse increment
2252 0 : if (index != NULL && comparator != EOpNull && node->getExpression())
2253 : {
2254 0 : TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2255 0 : TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
2256 :
2257 0 : if (binaryTerminal)
2258 : {
2259 0 : TOperator op = binaryTerminal->getOp();
2260 0 : TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2261 :
2262 0 : if (constant)
2263 : {
2264 0 : if (constant->getBasicType() == EbtInt && constant->isScalar())
2265 : {
2266 0 : int value = constant->getIConst(0);
2267 :
2268 0 : switch (op)
2269 : {
2270 0 : case EOpAddAssign: increment = value; break;
2271 0 : case EOpSubAssign: increment = -value; break;
2272 0 : default: UNIMPLEMENTED();
2273 : }
2274 : }
2275 : }
2276 : }
2277 0 : else if (unaryTerminal)
2278 : {
2279 0 : TOperator op = unaryTerminal->getOp();
2280 :
2281 0 : switch (op)
2282 : {
2283 0 : case EOpPostIncrement: increment = 1; break;
2284 0 : case EOpPostDecrement: increment = -1; break;
2285 0 : case EOpPreIncrement: increment = 1; break;
2286 0 : case EOpPreDecrement: increment = -1; break;
2287 0 : default: UNIMPLEMENTED();
2288 : }
2289 : }
2290 : }
2291 :
2292 0 : if (index != NULL && comparator != EOpNull && increment != 0)
2293 : {
2294 0 : if (comparator == EOpLessThanEqual)
2295 : {
2296 0 : comparator = EOpLessThan;
2297 0 : limit += 1;
2298 : }
2299 :
2300 0 : if (comparator == EOpLessThan)
2301 : {
2302 0 : int iterations = (limit - initial) / increment;
2303 :
2304 0 : if (iterations <= MAX_LOOP_ITERATIONS)
2305 : {
2306 0 : return false; // Not an excessive loop
2307 : }
2308 :
2309 0 : TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
2310 0 : mExcessiveLoopIndex = index;
2311 :
2312 0 : out << "{int ";
2313 0 : index->traverse(this);
2314 : out << ";\n"
2315 0 : "bool Break";
2316 0 : index->traverse(this);
2317 0 : out << " = false;\n";
2318 :
2319 0 : bool firstLoopFragment = true;
2320 :
2321 0 : while (iterations > 0)
2322 : {
2323 0 : int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
2324 :
2325 0 : if (!firstLoopFragment)
2326 : {
2327 0 : out << "if (!Break";
2328 0 : index->traverse(this);
2329 0 : out << ") {\n";
2330 : }
2331 :
2332 0 : if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
2333 : {
2334 0 : mExcessiveLoopIndex = NULL; // Stops setting the Break flag
2335 : }
2336 :
2337 : // for(int index = initial; index < clampedLimit; index += increment)
2338 0 : const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
2339 :
2340 0 : out << unroll << " for(";
2341 0 : index->traverse(this);
2342 0 : out << " = ";
2343 0 : out << initial;
2344 :
2345 0 : out << "; ";
2346 0 : index->traverse(this);
2347 0 : out << " < ";
2348 0 : out << clampedLimit;
2349 :
2350 0 : out << "; ";
2351 0 : index->traverse(this);
2352 0 : out << " += ";
2353 0 : out << increment;
2354 0 : out << ")\n";
2355 :
2356 0 : outputLineDirective(out, node->getLine().first_line);
2357 0 : out << "{\n";
2358 :
2359 0 : if (node->getBody())
2360 : {
2361 0 : node->getBody()->traverse(this);
2362 : }
2363 :
2364 0 : outputLineDirective(out, node->getLine().first_line);
2365 0 : out << ";}\n";
2366 :
2367 0 : if (!firstLoopFragment)
2368 : {
2369 0 : out << "}\n";
2370 : }
2371 :
2372 0 : firstLoopFragment = false;
2373 :
2374 0 : initial += MAX_LOOP_ITERATIONS * increment;
2375 0 : iterations -= MAX_LOOP_ITERATIONS;
2376 : }
2377 :
2378 0 : out << "}";
2379 :
2380 0 : mExcessiveLoopIndex = restoreIndex;
2381 :
2382 0 : return true;
2383 : }
2384 0 : else UNIMPLEMENTED();
2385 : }
2386 :
2387 0 : return false; // Not handled as an excessive loop
2388 : }
2389 :
2390 0 : void OutputHLSL::outputTriplet(TInfoSinkBase &out,
2391 : Visit visit,
2392 : const char *preString,
2393 : const char *inString,
2394 : const char *postString)
2395 : {
2396 0 : if (visit == PreVisit)
2397 : {
2398 0 : out << preString;
2399 : }
2400 0 : else if (visit == InVisit)
2401 : {
2402 0 : out << inString;
2403 : }
2404 0 : else if (visit == PostVisit)
2405 : {
2406 0 : out << postString;
2407 : }
2408 0 : }
2409 :
2410 0 : void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
2411 : {
2412 0 : if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
2413 : {
2414 0 : out << "\n";
2415 0 : out << "#line " << line;
2416 :
2417 0 : if (mSourcePath)
2418 : {
2419 0 : out << " \"" << mSourcePath << "\"";
2420 : }
2421 :
2422 0 : out << "\n";
2423 : }
2424 0 : }
2425 :
2426 0 : TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2427 : {
2428 0 : TQualifier qualifier = symbol->getQualifier();
2429 0 : const TType &type = symbol->getType();
2430 0 : const TName &name = symbol->getName();
2431 0 : TString nameStr;
2432 :
2433 0 : if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
2434 : {
2435 0 : nameStr = "x" + str(mUniqueIndex++);
2436 : }
2437 : else
2438 : {
2439 0 : nameStr = DecorateIfNeeded(name);
2440 : }
2441 :
2442 0 : if (IsSampler(type.getBasicType()))
2443 : {
2444 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT)
2445 : {
2446 : // Samplers are passed as indices to the sampler array.
2447 0 : ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2448 0 : return "const uint " + nameStr + ArrayString(type);
2449 : }
2450 0 : if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2451 : {
2452 0 : return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
2453 0 : " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
2454 0 : " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
2455 0 : ArrayString(type);
2456 : }
2457 : }
2458 :
2459 0 : TStringStream argString;
2460 0 : argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
2461 0 : << ArrayString(type);
2462 :
2463 : // If the structure parameter contains samplers, they need to be passed into the function as
2464 : // separate parameters. HLSL doesn't natively support samplers in structs.
2465 0 : if (type.isStructureContainingSamplers())
2466 : {
2467 0 : ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
2468 0 : TVector<TIntermSymbol *> samplerSymbols;
2469 0 : type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
2470 0 : for (const TIntermSymbol *sampler : samplerSymbols)
2471 : {
2472 0 : if (mOutputType == SH_HLSL_4_1_OUTPUT)
2473 : {
2474 0 : argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
2475 : }
2476 0 : else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2477 : {
2478 0 : const TType &samplerType = sampler->getType();
2479 0 : ASSERT((!type.isArray() && !samplerType.isArray()) ||
2480 : type.getArraySize() == samplerType.getArraySize());
2481 0 : ASSERT(IsSampler(samplerType.getBasicType()));
2482 0 : argString << ", " << QualifierString(qualifier) << " "
2483 0 : << TextureString(samplerType.getBasicType()) << " texture_"
2484 0 : << sampler->getSymbol() << ArrayString(type) << ", "
2485 0 : << QualifierString(qualifier) << " "
2486 0 : << SamplerString(samplerType.getBasicType()) << " sampler_"
2487 0 : << sampler->getSymbol() << ArrayString(type);
2488 : }
2489 : else
2490 : {
2491 0 : const TType &samplerType = sampler->getType();
2492 0 : ASSERT((!type.isArray() && !samplerType.isArray()) ||
2493 : type.getArraySize() == samplerType.getArraySize());
2494 0 : ASSERT(IsSampler(samplerType.getBasicType()));
2495 0 : argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
2496 0 : << " " << sampler->getSymbol() << ArrayString(type);
2497 : }
2498 : }
2499 : }
2500 :
2501 0 : return argString.str();
2502 : }
2503 :
2504 0 : TString OutputHLSL::initializer(const TType &type)
2505 : {
2506 0 : TString string;
2507 :
2508 0 : size_t size = type.getObjectSize();
2509 0 : for (size_t component = 0; component < size; component++)
2510 : {
2511 0 : string += "0";
2512 :
2513 0 : if (component + 1 < size)
2514 : {
2515 0 : string += ", ";
2516 : }
2517 : }
2518 :
2519 0 : return "{" + string + "}";
2520 : }
2521 :
2522 0 : void OutputHLSL::outputConstructor(TInfoSinkBase &out,
2523 : Visit visit,
2524 : const TType &type,
2525 : const char *name,
2526 : const TIntermSequence *parameters)
2527 : {
2528 0 : if (type.isArray())
2529 : {
2530 0 : UNIMPLEMENTED();
2531 : }
2532 :
2533 0 : if (visit == PreVisit)
2534 : {
2535 0 : TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
2536 :
2537 0 : out << constructorName << "(";
2538 : }
2539 0 : else if (visit == InVisit)
2540 : {
2541 0 : out << ", ";
2542 : }
2543 0 : else if (visit == PostVisit)
2544 : {
2545 0 : out << ")";
2546 : }
2547 0 : }
2548 :
2549 0 : const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
2550 : const TType &type,
2551 : const TConstantUnion *const constUnion)
2552 : {
2553 0 : const TConstantUnion *constUnionIterated = constUnion;
2554 :
2555 0 : const TStructure* structure = type.getStruct();
2556 0 : if (structure)
2557 : {
2558 0 : out << StructNameString(*structure) + "_ctor(";
2559 :
2560 0 : const TFieldList& fields = structure->fields();
2561 :
2562 0 : for (size_t i = 0; i < fields.size(); i++)
2563 : {
2564 0 : const TType *fieldType = fields[i]->type();
2565 0 : constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
2566 :
2567 0 : if (i != fields.size() - 1)
2568 : {
2569 0 : out << ", ";
2570 : }
2571 : }
2572 :
2573 0 : out << ")";
2574 : }
2575 : else
2576 : {
2577 0 : size_t size = type.getObjectSize();
2578 0 : bool writeType = size > 1;
2579 :
2580 0 : if (writeType)
2581 : {
2582 0 : out << TypeString(type) << "(";
2583 : }
2584 0 : constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
2585 0 : if (writeType)
2586 : {
2587 0 : out << ")";
2588 : }
2589 : }
2590 :
2591 0 : return constUnionIterated;
2592 : }
2593 :
2594 0 : void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
2595 : {
2596 0 : TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
2597 0 : outputTriplet(out, visit, preString.c_str(), ", ", ")");
2598 0 : }
2599 :
2600 0 : bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
2601 : {
2602 0 : sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
2603 0 : expression->traverse(&searchSymbol);
2604 :
2605 0 : if (searchSymbol.foundMatch())
2606 : {
2607 : // Type already printed
2608 0 : out << "t" + str(mUniqueIndex) + " = ";
2609 0 : expression->traverse(this);
2610 0 : out << ", ";
2611 0 : symbolNode->traverse(this);
2612 0 : out << " = t" + str(mUniqueIndex);
2613 :
2614 0 : mUniqueIndex++;
2615 0 : return true;
2616 : }
2617 :
2618 0 : return false;
2619 : }
2620 :
2621 0 : bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
2622 : {
2623 : // We support writing constant unions and constructors that only take constant unions as
2624 : // parameters as HLSL literals.
2625 0 : return expression->getAsConstantUnion() ||
2626 0 : expression->isConstructorWithOnlyConstantUnionParameters();
2627 : }
2628 :
2629 0 : bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
2630 : TIntermSymbol *symbolNode,
2631 : TIntermTyped *expression)
2632 : {
2633 0 : if (canWriteAsHLSLLiteral(expression))
2634 : {
2635 0 : symbolNode->traverse(this);
2636 0 : if (expression->getType().isArray())
2637 : {
2638 0 : out << "[" << expression->getType().getArraySize() << "]";
2639 : }
2640 0 : out << " = {";
2641 0 : if (expression->getAsConstantUnion())
2642 : {
2643 0 : TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
2644 0 : const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
2645 0 : writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
2646 : }
2647 : else
2648 : {
2649 0 : TIntermAggregate *constructor = expression->getAsAggregate();
2650 0 : ASSERT(constructor != nullptr);
2651 0 : for (TIntermNode *&node : *constructor->getSequence())
2652 : {
2653 0 : TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
2654 0 : ASSERT(nodeConst);
2655 0 : const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
2656 0 : writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
2657 0 : if (node != constructor->getSequence()->back())
2658 : {
2659 0 : out << ", ";
2660 : }
2661 : }
2662 : }
2663 0 : out << "}";
2664 0 : return true;
2665 : }
2666 0 : return false;
2667 : }
2668 :
2669 0 : TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
2670 : {
2671 0 : const TFieldList &fields = structure.fields();
2672 :
2673 0 : for (const auto &eqFunction : mStructEqualityFunctions)
2674 : {
2675 0 : if (eqFunction->structure == &structure)
2676 : {
2677 0 : return eqFunction->functionName;
2678 : }
2679 : }
2680 :
2681 0 : const TString &structNameString = StructNameString(structure);
2682 :
2683 0 : StructEqualityFunction *function = new StructEqualityFunction();
2684 0 : function->structure = &structure;
2685 0 : function->functionName = "angle_eq_" + structNameString;
2686 :
2687 0 : TInfoSinkBase fnOut;
2688 :
2689 0 : fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n"
2690 : << "{\n"
2691 0 : " return ";
2692 :
2693 0 : for (size_t i = 0; i < fields.size(); i++)
2694 : {
2695 0 : const TField *field = fields[i];
2696 0 : const TType *fieldType = field->type();
2697 :
2698 0 : const TString &fieldNameA = "a." + Decorate(field->name());
2699 0 : const TString &fieldNameB = "b." + Decorate(field->name());
2700 :
2701 0 : if (i > 0)
2702 : {
2703 0 : fnOut << " && ";
2704 : }
2705 :
2706 0 : fnOut << "(";
2707 0 : outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
2708 0 : fnOut << fieldNameA;
2709 0 : outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
2710 0 : fnOut << fieldNameB;
2711 0 : outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
2712 0 : fnOut << ")";
2713 : }
2714 :
2715 0 : fnOut << ";\n" << "}\n";
2716 :
2717 0 : function->functionDefinition = fnOut.c_str();
2718 :
2719 0 : mStructEqualityFunctions.push_back(function);
2720 0 : mEqualityFunctions.push_back(function);
2721 :
2722 0 : return function->functionName;
2723 : }
2724 :
2725 0 : TString OutputHLSL::addArrayEqualityFunction(const TType& type)
2726 : {
2727 0 : for (const auto &eqFunction : mArrayEqualityFunctions)
2728 : {
2729 0 : if (eqFunction->type == type)
2730 : {
2731 0 : return eqFunction->functionName;
2732 : }
2733 : }
2734 :
2735 0 : const TString &typeName = TypeString(type);
2736 :
2737 0 : ArrayHelperFunction *function = new ArrayHelperFunction();
2738 0 : function->type = type;
2739 :
2740 0 : TInfoSinkBase fnNameOut;
2741 0 : fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
2742 0 : function->functionName = fnNameOut.c_str();
2743 :
2744 0 : TType nonArrayType = type;
2745 0 : nonArrayType.clearArrayness();
2746 :
2747 0 : TInfoSinkBase fnOut;
2748 :
2749 0 : fnOut << "bool " << function->functionName << "("
2750 0 : << typeName << " a[" << type.getArraySize() << "], "
2751 0 : << typeName << " b[" << type.getArraySize() << "])\n"
2752 : << "{\n"
2753 0 : " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
2754 : " {\n"
2755 0 : " if (";
2756 :
2757 0 : outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
2758 0 : fnOut << "a[i]";
2759 0 : outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
2760 0 : fnOut << "b[i]";
2761 0 : outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
2762 :
2763 : fnOut << ") { return false; }\n"
2764 : " }\n"
2765 : " return true;\n"
2766 0 : "}\n";
2767 :
2768 0 : function->functionDefinition = fnOut.c_str();
2769 :
2770 0 : mArrayEqualityFunctions.push_back(function);
2771 0 : mEqualityFunctions.push_back(function);
2772 :
2773 0 : return function->functionName;
2774 : }
2775 :
2776 0 : TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
2777 : {
2778 0 : for (const auto &assignFunction : mArrayAssignmentFunctions)
2779 : {
2780 0 : if (assignFunction.type == type)
2781 : {
2782 0 : return assignFunction.functionName;
2783 : }
2784 : }
2785 :
2786 0 : const TString &typeName = TypeString(type);
2787 :
2788 0 : ArrayHelperFunction function;
2789 0 : function.type = type;
2790 :
2791 0 : TInfoSinkBase fnNameOut;
2792 0 : fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
2793 0 : function.functionName = fnNameOut.c_str();
2794 :
2795 0 : TInfoSinkBase fnOut;
2796 :
2797 0 : fnOut << "void " << function.functionName << "(out "
2798 0 : << typeName << " a[" << type.getArraySize() << "], "
2799 0 : << typeName << " b[" << type.getArraySize() << "])\n"
2800 : << "{\n"
2801 0 : " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
2802 : " {\n"
2803 : " a[i] = b[i];\n"
2804 : " }\n"
2805 0 : "}\n";
2806 :
2807 0 : function.functionDefinition = fnOut.c_str();
2808 :
2809 0 : mArrayAssignmentFunctions.push_back(function);
2810 :
2811 0 : return function.functionName;
2812 : }
2813 :
2814 0 : TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
2815 : {
2816 0 : for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
2817 : {
2818 0 : if (constructIntoFunction.type == type)
2819 : {
2820 0 : return constructIntoFunction.functionName;
2821 : }
2822 : }
2823 :
2824 0 : const TString &typeName = TypeString(type);
2825 :
2826 0 : ArrayHelperFunction function;
2827 0 : function.type = type;
2828 :
2829 0 : TInfoSinkBase fnNameOut;
2830 0 : fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
2831 0 : function.functionName = fnNameOut.c_str();
2832 :
2833 0 : TInfoSinkBase fnOut;
2834 :
2835 0 : fnOut << "void " << function.functionName << "(out "
2836 0 : << typeName << " a[" << type.getArraySize() << "]";
2837 0 : for (unsigned int i = 0u; i < type.getArraySize(); ++i)
2838 : {
2839 0 : fnOut << ", " << typeName << " b" << i;
2840 : }
2841 : fnOut << ")\n"
2842 0 : "{\n";
2843 :
2844 0 : for (unsigned int i = 0u; i < type.getArraySize(); ++i)
2845 : {
2846 0 : fnOut << " a[" << i << "] = b" << i << ";\n";
2847 : }
2848 0 : fnOut << "}\n";
2849 :
2850 0 : function.functionDefinition = fnOut.c_str();
2851 :
2852 0 : mArrayConstructIntoFunctions.push_back(function);
2853 :
2854 0 : return function.functionName;
2855 : }
2856 :
2857 0 : void OutputHLSL::ensureStructDefined(const TType &type)
2858 : {
2859 0 : TStructure *structure = type.getStruct();
2860 :
2861 0 : if (structure)
2862 : {
2863 0 : mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
2864 : }
2865 0 : }
2866 :
2867 : } // namespace sh
|