blob: 634f3df12650b95a209ae192fb09402597b04010 [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
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00009#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000010#include <cfloat>
11#include <stdio.h>
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"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "compiler/translator/FlagStd140Structs.h"
19#include "compiler/translator/InfoSink.h"
20#include "compiler/translator/NodeSearch.h"
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +020021#include "compiler/translator/RemoveSwitchFallThrough.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050022#include "compiler/translator/SearchSymbol.h"
23#include "compiler/translator/StructureHLSL.h"
24#include "compiler/translator/TranslatorHLSL.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050025#include "compiler/translator/UniformHLSL.h"
26#include "compiler/translator/UtilsHLSL.h"
27#include "compiler/translator/blocklayout.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050028#include "compiler/translator/util.h"
29
Olli Etuaho4785fec2015-05-18 16:09:37 +030030namespace
31{
32
33bool IsSequence(TIntermNode *node)
34{
35 return node->getAsAggregate() != nullptr && node->getAsAggregate()->getOp() == EOpSequence;
36}
37
Olli Etuaho18b9deb2015-11-05 12:14:50 +020038void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
39{
40 ASSERT(constUnion != nullptr);
41 switch (constUnion->getType())
42 {
43 case EbtFloat:
44 out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst()));
45 break;
46 case EbtInt:
47 out << constUnion->getIConst();
48 break;
49 case EbtUInt:
50 out << constUnion->getUConst();
51 break;
52 case EbtBool:
53 out << constUnion->getBConst();
54 break;
55 default:
56 UNREACHABLE();
57 }
58}
59
60const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
61 const TConstantUnion *const constUnion,
62 const size_t size)
63{
64 const TConstantUnion *constUnionIterated = constUnion;
65 for (size_t i = 0; i < size; i++, constUnionIterated++)
66 {
67 WriteSingleConstant(out, constUnionIterated);
68
69 if (i != size - 1)
70 {
71 out << ", ";
72 }
73 }
74 return constUnionIterated;
75}
76
Olli Etuaho4785fec2015-05-18 16:09:37 +030077} // namespace
78
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079namespace sh
80{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000081
Nicolas Capense0ba27a2013-06-24 16:10:52 -040082TString OutputHLSL::TextureFunction::name() const
83{
84 TString name = "gl_texture";
85
Nicolas Capens6d232bb2013-07-08 15:56:38 -040086 if (IsSampler2D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040087 {
88 name += "2D";
89 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040090 else if (IsSampler3D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040091 {
92 name += "3D";
93 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040094 else if (IsSamplerCube(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040095 {
96 name += "Cube";
97 }
98 else UNREACHABLE();
99
100 if (proj)
101 {
102 name += "Proj";
103 }
104
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500105 if (offset)
106 {
107 name += "Offset";
108 }
109
Nicolas Capens75fb4752013-07-10 15:14:47 -0400110 switch(method)
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400111 {
Nicolas Capensfc014542014-02-18 14:47:13 -0500112 case IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400113 case BIAS: break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -0500114 case LOD: name += "Lod"; break;
115 case LOD0: name += "Lod0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400116 case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -0500117 case SIZE: name += "Size"; break;
118 case FETCH: name += "Fetch"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -0500119 case GRAD: name += "Grad"; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400120 default: UNREACHABLE();
121 }
122
123 return name + "(";
124}
125
126bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
127{
128 if (sampler < rhs.sampler) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400129 if (sampler > rhs.sampler) return false;
130
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400131 if (coords < rhs.coords) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400132 if (coords > rhs.coords) return false;
133
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400134 if (!proj && rhs.proj) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400135 if (proj && !rhs.proj) return false;
136
137 if (!offset && rhs.offset) return true;
138 if (offset && !rhs.offset) return false;
139
Nicolas Capens75fb4752013-07-10 15:14:47 -0400140 if (method < rhs.method) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400141 if (method > rhs.method) return false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400142
143 return false;
144}
145
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200146OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
147 const TExtensionBehavior &extensionBehavior,
148 const char *sourcePath, ShShaderOutput outputType,
149 int numRenderTargets, const std::vector<Uniform> &uniforms,
150 int compileOptions)
Jamie Madill54ad4f82014-09-03 09:40:46 -0400151 : TIntermTraverser(true, true, true),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200152 mShaderType(shaderType),
153 mShaderVersion(shaderVersion),
154 mExtensionBehavior(extensionBehavior),
155 mSourcePath(sourcePath),
156 mOutputType(outputType),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700157 mCompileOptions(compileOptions),
Sam McNally5a0edc62015-06-30 12:36:07 +1000158 mNumRenderTargets(numRenderTargets),
Corentin Wallez1239ee92015-03-19 14:38:02 -0700159 mCurrentFunctionMetadata(nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160{
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000161 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000162
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000163 mUsesFragColor = false;
164 mUsesFragData = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000165 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000166 mUsesFragCoord = false;
167 mUsesPointCoord = false;
168 mUsesFrontFacing = false;
169 mUsesPointSize = false;
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000170 mUsesInstanceID = false;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400171 mUsesFragDepth = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000172 mUsesXor = false;
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500173 mUsesDiscardRewriting = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400174 mUsesNestedBreak = false;
Arun Patole44efa0b2015-03-04 17:11:05 +0530175 mRequiresIEEEStrictCompiling = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000176
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000177 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000178
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000179 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000180 mInsideDiscontinuousLoop = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400181 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000182
183 mExcessiveLoopIndex = NULL;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000184
Jamie Madill8daaba12014-06-13 10:04:33 -0400185 mStructureHLSL = new StructureHLSL;
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200186 mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
Jamie Madill8daaba12014-06-13 10:04:33 -0400187
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000188 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000189 {
Arun Patole63419392015-03-13 11:51:07 +0530190 // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
191 // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust.
192 // In both cases total 3 uniform registers need to be reserved.
193 mUniformHLSL->reserveUniformRegisters(3);
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000194 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000195
Jamie Madillf91ce812014-06-13 10:04:34 -0400196 // Reserve registers for the default uniform block and driver constants
197 mUniformHLSL->reserveInterfaceBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000198}
199
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000200OutputHLSL::~OutputHLSL()
201{
Jamie Madill8daaba12014-06-13 10:04:33 -0400202 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400203 SafeDelete(mUniformHLSL);
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200204 for (auto &eqFunction : mStructEqualityFunctions)
205 {
206 SafeDelete(eqFunction);
207 }
208 for (auto &eqFunction : mArrayEqualityFunctions)
209 {
210 SafeDelete(eqFunction);
211 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000212}
213
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200214void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000215{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200216 const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400217 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000218
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200219 BuiltInFunctionEmulator builtInFunctionEmulator;
220 InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200221 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
Jamie Madill32aab012015-01-27 14:12:26 -0500222
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700223 // Now that we are done changing the AST, do the analyses need for HLSL generation
Corentin Wallez1239ee92015-03-19 14:38:02 -0700224 CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink);
225 ASSERT(success == CallDAG::INITDAG_SUCCESS);
Olli Etuahod57e0db2015-04-24 15:05:08 +0300226 UNUSED_ASSERTION_VARIABLE(success);
Corentin Wallez1239ee92015-03-19 14:38:02 -0700227 mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
Corentin Wallezf4eab3b2015-03-18 12:55:45 -0700228
Jamie Madill37997142015-01-28 10:06:34 -0500229 // Output the body and footer first to determine what has to go in the header
Jamie Madill32aab012015-01-27 14:12:26 -0500230 mInfoSinkStack.push(&mBody);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200231 treeRoot->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500232 mInfoSinkStack.pop();
233
Jamie Madill37997142015-01-28 10:06:34 -0500234 mInfoSinkStack.push(&mFooter);
235 if (!mDeferredGlobalInitializers.empty())
236 {
237 writeDeferredGlobalInitializers(mFooter);
238 }
239 mInfoSinkStack.pop();
240
Jamie Madill32aab012015-01-27 14:12:26 -0500241 mInfoSinkStack.push(&mHeader);
Jamie Madill8c46ab12015-12-07 16:39:19 -0500242 header(mHeader, &builtInFunctionEmulator);
Jamie Madill32aab012015-01-27 14:12:26 -0500243 mInfoSinkStack.pop();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000244
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200245 objSink << mHeader.c_str();
246 objSink << mBody.c_str();
247 objSink << mFooter.c_str();
Olli Etuahoe17e3192015-01-02 12:47:59 +0200248
249 builtInFunctionEmulator.Cleanup();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000250}
251
Jamie Madill570e04d2013-06-21 09:15:33 -0400252void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
253{
254 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
255 {
256 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
257
Jamie Madill32aab012015-01-27 14:12:26 -0500258 TInfoSinkBase structInfoSink;
259 mInfoSinkStack.push(&structInfoSink);
260
Jamie Madill570e04d2013-06-21 09:15:33 -0400261 // This will mark the necessary block elements as referenced
262 flaggedNode->traverse(this);
Jamie Madill32aab012015-01-27 14:12:26 -0500263
264 TString structName(structInfoSink.c_str());
265 mInfoSinkStack.pop();
Jamie Madill570e04d2013-06-21 09:15:33 -0400266
267 mFlaggedStructOriginalNames[flaggedNode] = structName;
268
269 for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
270 {
271 structName.erase(pos, 1);
272 }
273
274 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
275 }
276}
277
Jamie Madill4e1fd412014-07-10 17:50:10 -0400278const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
279{
280 return mUniformHLSL->getInterfaceBlockRegisterMap();
281}
282
Jamie Madill9fe25e92014-07-18 10:33:08 -0400283const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
284{
285 return mUniformHLSL->getUniformRegisterMap();
286}
287
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000288int OutputHLSL::vectorSize(const TType &type) const
289{
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000290 int elementSize = type.isMatrix() ? type.getCols() : 1;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000291 int arraySize = type.isArray() ? type.getArraySize() : 1;
292
293 return elementSize * arraySize;
294}
295
Jamie Madill98493dd2013-07-08 14:39:03 -0400296TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
Jamie Madill570e04d2013-06-21 09:15:33 -0400297{
298 TString init;
299
300 TString preIndentString;
301 TString fullIndentString;
302
303 for (int spaces = 0; spaces < (indent * 4); spaces++)
304 {
305 preIndentString += ' ';
306 }
307
308 for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
309 {
310 fullIndentString += ' ';
311 }
312
313 init += preIndentString + "{\n";
314
Jamie Madill98493dd2013-07-08 14:39:03 -0400315 const TFieldList &fields = structure.fields();
316 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400317 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400318 const TField &field = *fields[fieldIndex];
Jamie Madill033dae62014-06-18 12:56:28 -0400319 const TString &fieldName = rhsStructName + "." + Decorate(field.name());
Jamie Madill98493dd2013-07-08 14:39:03 -0400320 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400321
Jamie Madill98493dd2013-07-08 14:39:03 -0400322 if (fieldType.getStruct())
Jamie Madill570e04d2013-06-21 09:15:33 -0400323 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400324 init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400325 }
326 else
327 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400328 init += fullIndentString + fieldName + ",\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400329 }
330 }
331
332 init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
333
334 return init;
335}
336
Jamie Madill8c46ab12015-12-07 16:39:19 -0500337void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338{
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000339 TString varyings;
340 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400341 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000342
Jamie Madill829f59e2013-11-13 19:40:54 -0500343 for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400344 {
345 TIntermTyped *structNode = flaggedStructIt->first;
346 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400347 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400348 const TString &originalName = mFlaggedStructOriginalNames[structNode];
349
Jamie Madill033dae62014-06-18 12:56:28 -0400350 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400351 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400352 flaggedStructs += "\n";
353 }
354
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000355 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
356 {
357 const TType &type = varying->second->getType();
358 const TString &name = varying->second->getSymbol();
359
360 // Program linking depends on this exact format
Jamie Madill033dae62014-06-18 12:56:28 -0400361 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
362 Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000363 }
364
365 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
366 {
367 const TType &type = attribute->second->getType();
368 const TString &name = attribute->second->getSymbol();
369
Jamie Madill033dae62014-06-18 12:56:28 -0400370 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000371 }
372
Jamie Madill8daaba12014-06-13 10:04:33 -0400373 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400374
Jamie Madillf91ce812014-06-13 10:04:34 -0400375 out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms);
376 out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
377
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200378 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500379 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200380 out << "\n// Equality functions\n\n";
381 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500382 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200383 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200384 }
385 }
Olli Etuaho12690762015-03-31 12:55:28 +0300386 if (!mArrayAssignmentFunctions.empty())
387 {
388 out << "\n// Assignment functions\n\n";
389 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
390 {
391 out << assignmentFunction.functionDefinition << "\n";
392 }
393 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300394 if (!mArrayConstructIntoFunctions.empty())
395 {
396 out << "\n// Array constructor functions\n\n";
397 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
398 {
399 out << constructIntoFunction.functionDefinition << "\n";
400 }
401 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200402
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500403 if (mUsesDiscardRewriting)
404 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400405 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500406 }
407
Nicolas Capens655fe362014-04-11 13:12:34 -0400408 if (mUsesNestedBreak)
409 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400410 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400411 }
412
Arun Patole44efa0b2015-03-04 17:11:05 +0530413 if (mRequiresIEEEStrictCompiling)
414 {
415 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
416 }
417
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400418 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
419 "#define LOOP [loop]\n"
420 "#define FLATTEN [flatten]\n"
421 "#else\n"
422 "#define LOOP\n"
423 "#define FLATTEN\n"
424 "#endif\n";
425
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200426 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200428 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
429 const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000430
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000431 out << "// Varyings\n";
432 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400433 out << "\n";
434
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200435 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000436 {
Jamie Madill829f59e2013-11-13 19:40:54 -0500437 for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000438 {
Jamie Madill46131a32013-06-20 11:55:50 -0400439 const TString &variableName = outputVariableIt->first;
440 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400441
Jamie Madill033dae62014-06-18 12:56:28 -0400442 out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
Jamie Madill46131a32013-06-20 11:55:50 -0400443 " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000444 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000445 }
Jamie Madill46131a32013-06-20 11:55:50 -0400446 else
447 {
448 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
449
450 out << "static float4 gl_Color[" << numColorValues << "] =\n"
451 "{\n";
452 for (unsigned int i = 0; i < numColorValues; i++)
453 {
454 out << " float4(0, 0, 0, 0)";
455 if (i + 1 != numColorValues)
456 {
457 out << ",";
458 }
459 out << "\n";
460 }
461
462 out << "};\n";
463 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000464
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400465 if (mUsesFragDepth)
466 {
467 out << "static float gl_Depth = 0.0;\n";
468 }
469
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000470 if (mUsesFragCoord)
471 {
472 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
473 }
474
475 if (mUsesPointCoord)
476 {
477 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
478 }
479
480 if (mUsesFrontFacing)
481 {
482 out << "static bool gl_FrontFacing = false;\n";
483 }
484
485 out << "\n";
486
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000487 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000488 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000489 out << "struct gl_DepthRangeParameters\n"
490 "{\n"
491 " float near;\n"
492 " float far;\n"
493 " float diff;\n"
494 "};\n"
495 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000496 }
497
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000498 if (mOutputType == SH_HLSL11_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000499 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000500 out << "cbuffer DriverConstants : register(b1)\n"
501 "{\n";
502
503 if (mUsesDepthRange)
504 {
505 out << " float3 dx_DepthRange : packoffset(c0);\n";
506 }
507
508 if (mUsesFragCoord)
509 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000510 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000511 }
512
513 if (mUsesFragCoord || mUsesFrontFacing)
514 {
515 out << " float3 dx_DepthFront : packoffset(c2);\n";
516 }
517
518 out << "};\n";
519 }
520 else
521 {
522 if (mUsesDepthRange)
523 {
524 out << "uniform float3 dx_DepthRange : register(c0);";
525 }
526
527 if (mUsesFragCoord)
528 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000529 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000530 }
531
532 if (mUsesFragCoord || mUsesFrontFacing)
533 {
534 out << "uniform float3 dx_DepthFront : register(c2);\n";
535 }
536 }
537
538 out << "\n";
539
540 if (mUsesDepthRange)
541 {
542 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
543 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000544 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000545
Jamie Madillf91ce812014-06-13 10:04:34 -0400546 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000547 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400548 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000549 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400550 out << flaggedStructs;
551 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000552 }
553
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000554 if (usingMRTExtension && mNumRenderTargets > 1)
555 {
556 out << "#define GL_USES_MRT\n";
557 }
558
559 if (mUsesFragColor)
560 {
561 out << "#define GL_USES_FRAG_COLOR\n";
562 }
563
564 if (mUsesFragData)
565 {
566 out << "#define GL_USES_FRAG_DATA\n";
567 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000568 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000569 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000571 out << "// Attributes\n";
572 out << attributes;
573 out << "\n"
574 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400575
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000576 if (mUsesPointSize)
577 {
578 out << "static float gl_PointSize = float(1);\n";
579 }
580
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000581 if (mUsesInstanceID)
582 {
583 out << "static int gl_InstanceID;";
584 }
585
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000586 out << "\n"
587 "// Varyings\n";
588 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000589 out << "\n";
590
591 if (mUsesDepthRange)
592 {
593 out << "struct gl_DepthRangeParameters\n"
594 "{\n"
595 " float near;\n"
596 " float far;\n"
597 " float diff;\n"
598 "};\n"
599 "\n";
600 }
601
602 if (mOutputType == SH_HLSL11_OUTPUT)
603 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800604 out << "cbuffer DriverConstants : register(b1)\n"
605 "{\n";
606
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000607 if (mUsesDepthRange)
608 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800609 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000610 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800611
Cooper Partine6664f02015-01-09 16:22:24 -0800612 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800613 // However, we declare it for all shaders (including Feature Level 10+).
614 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused.
615 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800616 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800617
618 out << "};\n"
619 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000620 }
621 else
622 {
623 if (mUsesDepthRange)
624 {
625 out << "uniform float3 dx_DepthRange : register(c0);\n";
626 }
627
Cooper Partine6664f02015-01-09 16:22:24 -0800628 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
629 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000630 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000631 }
632
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000633 if (mUsesDepthRange)
634 {
635 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
636 "\n";
637 }
638
Jamie Madillf91ce812014-06-13 10:04:34 -0400639 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000640 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400641 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000642 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400643 out << flaggedStructs;
644 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000645 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400646 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000647
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400648 for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
649 {
650 // Return type
Nicolas Capens75fb4752013-07-10 15:14:47 -0400651 if (textureFunction->method == TextureFunction::SIZE)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000652 {
Nicolas Capens75fb4752013-07-10 15:14:47 -0400653 switch(textureFunction->sampler)
654 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400655 case EbtSampler2D: out << "int2 "; break;
656 case EbtSampler3D: out << "int3 "; break;
657 case EbtSamplerCube: out << "int2 "; break;
658 case EbtSampler2DArray: out << "int3 "; break;
659 case EbtISampler2D: out << "int2 "; break;
660 case EbtISampler3D: out << "int3 "; break;
661 case EbtISamplerCube: out << "int2 "; break;
662 case EbtISampler2DArray: out << "int3 "; break;
663 case EbtUSampler2D: out << "int2 "; break;
664 case EbtUSampler3D: out << "int3 "; break;
665 case EbtUSamplerCube: out << "int2 "; break;
666 case EbtUSampler2DArray: out << "int3 "; break;
667 case EbtSampler2DShadow: out << "int2 "; break;
668 case EbtSamplerCubeShadow: out << "int2 "; break;
669 case EbtSampler2DArrayShadow: out << "int3 "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400670 default: UNREACHABLE();
671 }
672 }
673 else // Sampling function
674 {
675 switch(textureFunction->sampler)
676 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400677 case EbtSampler2D: out << "float4 "; break;
678 case EbtSampler3D: out << "float4 "; break;
679 case EbtSamplerCube: out << "float4 "; break;
680 case EbtSampler2DArray: out << "float4 "; break;
681 case EbtISampler2D: out << "int4 "; break;
682 case EbtISampler3D: out << "int4 "; break;
683 case EbtISamplerCube: out << "int4 "; break;
684 case EbtISampler2DArray: out << "int4 "; break;
685 case EbtUSampler2D: out << "uint4 "; break;
686 case EbtUSampler3D: out << "uint4 "; break;
687 case EbtUSamplerCube: out << "uint4 "; break;
688 case EbtUSampler2DArray: out << "uint4 "; break;
689 case EbtSampler2DShadow: out << "float "; break;
690 case EbtSamplerCubeShadow: out << "float "; break;
691 case EbtSampler2DArrayShadow: out << "float "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400692 default: UNREACHABLE();
693 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000694 }
695
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400696 // Function name
697 out << textureFunction->name();
698
699 // Argument list
700 int hlslCoords = 4;
701
702 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000703 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400704 switch(textureFunction->sampler)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000705 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400706 case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
707 case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
708 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000709 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400710
Nicolas Capens75fb4752013-07-10 15:14:47 -0400711 switch(textureFunction->method)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000712 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400713 case TextureFunction::IMPLICIT: break;
714 case TextureFunction::BIAS: hlslCoords = 4; break;
715 case TextureFunction::LOD: hlslCoords = 4; break;
716 case TextureFunction::LOD0: hlslCoords = 4; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400717 case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400718 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000719 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400720 }
721 else if (mOutputType == SH_HLSL11_OUTPUT)
722 {
723 switch(textureFunction->sampler)
724 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400725 case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
726 case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
727 case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
728 case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
729 case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
730 case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500731 case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400732 case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
733 case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
734 case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500735 case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400736 case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
737 case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
738 case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
739 case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400740 default: UNREACHABLE();
741 }
742 }
743 else UNREACHABLE();
744
Nicolas Capensfc014542014-02-18 14:47:13 -0500745 if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400746 {
Nicolas Capensfc014542014-02-18 14:47:13 -0500747 switch(textureFunction->coords)
748 {
749 case 2: out << ", int2 t"; break;
750 case 3: out << ", int3 t"; break;
751 default: UNREACHABLE();
752 }
753 }
754 else // Floating-point coordinates (except textureSize)
755 {
756 switch(textureFunction->coords)
757 {
758 case 1: out << ", int lod"; break; // textureSize()
759 case 2: out << ", float2 t"; break;
760 case 3: out << ", float3 t"; break;
761 case 4: out << ", float4 t"; break;
762 default: UNREACHABLE();
763 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000764 }
765
Nicolas Capensd11d5492014-02-19 17:06:10 -0500766 if (textureFunction->method == TextureFunction::GRAD)
767 {
768 switch(textureFunction->sampler)
769 {
770 case EbtSampler2D:
771 case EbtISampler2D:
772 case EbtUSampler2D:
773 case EbtSampler2DArray:
774 case EbtISampler2DArray:
775 case EbtUSampler2DArray:
776 case EbtSampler2DShadow:
777 case EbtSampler2DArrayShadow:
778 out << ", float2 ddx, float2 ddy";
779 break;
780 case EbtSampler3D:
781 case EbtISampler3D:
782 case EbtUSampler3D:
783 case EbtSamplerCube:
784 case EbtISamplerCube:
785 case EbtUSamplerCube:
786 case EbtSamplerCubeShadow:
787 out << ", float3 ddx, float3 ddy";
788 break;
789 default: UNREACHABLE();
790 }
791 }
792
Nicolas Capens75fb4752013-07-10 15:14:47 -0400793 switch(textureFunction->method)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000794 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400795 case TextureFunction::IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400796 case TextureFunction::BIAS: break; // Comes after the offset parameter
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400797 case TextureFunction::LOD: out << ", float lod"; break;
798 case TextureFunction::LOD0: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400799 case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
Nicolas Capens75fb4752013-07-10 15:14:47 -0400800 case TextureFunction::SIZE: break;
Nicolas Capensfc014542014-02-18 14:47:13 -0500801 case TextureFunction::FETCH: out << ", int mip"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -0500802 case TextureFunction::GRAD: break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400803 default: UNREACHABLE();
daniel@transgaming.com15795192011-05-11 15:36:20 +0000804 }
805
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500806 if (textureFunction->offset)
807 {
808 switch(textureFunction->sampler)
809 {
810 case EbtSampler2D: out << ", int2 offset"; break;
811 case EbtSampler3D: out << ", int3 offset"; break;
812 case EbtSampler2DArray: out << ", int2 offset"; break;
813 case EbtISampler2D: out << ", int2 offset"; break;
814 case EbtISampler3D: out << ", int3 offset"; break;
815 case EbtISampler2DArray: out << ", int2 offset"; break;
816 case EbtUSampler2D: out << ", int2 offset"; break;
817 case EbtUSampler3D: out << ", int3 offset"; break;
818 case EbtUSampler2DArray: out << ", int2 offset"; break;
819 case EbtSampler2DShadow: out << ", int2 offset"; break;
Nicolas Capensbf7db102014-02-19 17:20:28 -0500820 case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500821 default: UNREACHABLE();
822 }
823 }
824
Nicolas Capens84cfa122014-04-14 13:48:45 -0400825 if (textureFunction->method == TextureFunction::BIAS ||
826 textureFunction->method == TextureFunction::LOD0BIAS)
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500827 {
828 out << ", float bias";
829 }
830
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400831 out << ")\n"
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400832 "{\n";
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400833
Nicolas Capens75fb4752013-07-10 15:14:47 -0400834 if (textureFunction->method == TextureFunction::SIZE)
835 {
836 if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
837 {
838 if (IsSamplerArray(textureFunction->sampler))
839 {
840 out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
841 " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
842 }
843 else
844 {
845 out << " uint width; uint height; uint numberOfLevels;\n"
846 " x.GetDimensions(lod, width, height, numberOfLevels);\n";
847 }
848 }
849 else if (IsSampler3D(textureFunction->sampler))
850 {
851 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
852 " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
853 }
854 else UNREACHABLE();
855
856 switch(textureFunction->sampler)
857 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400858 case EbtSampler2D: out << " return int2(width, height);"; break;
859 case EbtSampler3D: out << " return int3(width, height, depth);"; break;
860 case EbtSamplerCube: out << " return int2(width, height);"; break;
861 case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
862 case EbtISampler2D: out << " return int2(width, height);"; break;
863 case EbtISampler3D: out << " return int3(width, height, depth);"; break;
864 case EbtISamplerCube: out << " return int2(width, height);"; break;
865 case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
866 case EbtUSampler2D: out << " return int2(width, height);"; break;
867 case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
868 case EbtUSamplerCube: out << " return int2(width, height);"; break;
869 case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
870 case EbtSampler2DShadow: out << " return int2(width, height);"; break;
871 case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
872 case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400873 default: UNREACHABLE();
874 }
875 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400876 else
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400877 {
Nicolas Capens0027fa92014-02-20 14:26:42 -0500878 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
879 {
880 out << " float width; float height; float layers; float levels;\n";
881
882 out << " uint mip = 0;\n";
883
884 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
885
886 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
887 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
888 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
889 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
890
891 // FACE_POSITIVE_X = 000b
892 // FACE_NEGATIVE_X = 001b
893 // FACE_POSITIVE_Y = 010b
894 // FACE_NEGATIVE_Y = 011b
895 // FACE_POSITIVE_Z = 100b
896 // FACE_NEGATIVE_Z = 101b
897 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
898
899 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
900 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
901 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
902
903 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
904 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
Jamie Madill8d9f35f2015-11-24 16:10:20 -0500905
906 // Mip level computation.
907 if (textureFunction->method == TextureFunction::IMPLICIT)
908 {
909 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
910 " float2 dx = ddx(tSized);\n"
911 " float2 dy = ddy(tSized);\n"
912 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n"
913 " mip = uint(min(max(round(lod), 0), levels - 1));\n"
914 " x.GetDimensions(mip, width, height, layers, levels);\n";
915 }
Nicolas Capens0027fa92014-02-20 14:26:42 -0500916 }
917 else if (IsIntegerSampler(textureFunction->sampler) &&
918 textureFunction->method != TextureFunction::FETCH)
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400919 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400920 if (IsSampler2D(textureFunction->sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400921 {
Nicolas Capens93e50de2013-07-09 13:46:28 -0400922 if (IsSamplerArray(textureFunction->sampler))
923 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400924 out << " float width; float height; float layers; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400925
Nicolas Capens9edebd62013-08-06 10:59:10 -0400926 if (textureFunction->method == TextureFunction::LOD0)
927 {
928 out << " uint mip = 0;\n";
929 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400930 else if (textureFunction->method == TextureFunction::LOD0BIAS)
931 {
932 out << " uint mip = bias;\n";
933 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400934 else
935 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200936
937 out << " x.GetDimensions(0, width, height, layers, levels);\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400938 if (textureFunction->method == TextureFunction::IMPLICIT ||
939 textureFunction->method == TextureFunction::BIAS)
940 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200941 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
Nicolas Capens9edebd62013-08-06 10:59:10 -0400942 " float dx = length(ddx(tSized));\n"
943 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500944 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400945
946 if (textureFunction->method == TextureFunction::BIAS)
947 {
948 out << " lod += bias;\n";
949 }
950 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500951 else if (textureFunction->method == TextureFunction::GRAD)
952 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200953 out << " float lod = log2(max(length(ddx), length(ddy)));\n";
Nicolas Capensd11d5492014-02-19 17:06:10 -0500954 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400955
956 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
957 }
958
959 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400960 }
961 else
962 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400963 out << " float width; float height; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400964
Nicolas Capens9edebd62013-08-06 10:59:10 -0400965 if (textureFunction->method == TextureFunction::LOD0)
966 {
967 out << " uint mip = 0;\n";
968 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400969 else if (textureFunction->method == TextureFunction::LOD0BIAS)
970 {
971 out << " uint mip = bias;\n";
972 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400973 else
974 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200975 out << " x.GetDimensions(0, width, height, levels);\n";
976
Nicolas Capens9edebd62013-08-06 10:59:10 -0400977 if (textureFunction->method == TextureFunction::IMPLICIT ||
978 textureFunction->method == TextureFunction::BIAS)
979 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200980 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
Nicolas Capens9edebd62013-08-06 10:59:10 -0400981 " float dx = length(ddx(tSized));\n"
982 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500983 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400984
985 if (textureFunction->method == TextureFunction::BIAS)
986 {
987 out << " lod += bias;\n";
988 }
989 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500990 else if (textureFunction->method == TextureFunction::GRAD)
991 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +0200992 out << " float lod = log2(max(length(ddx), length(ddy)));\n";
Nicolas Capensd11d5492014-02-19 17:06:10 -0500993 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400994
995 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
996 }
997
998 out << " x.GetDimensions(mip, width, height, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400999 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001000 }
1001 else if (IsSampler3D(textureFunction->sampler))
1002 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001003 out << " float width; float height; float depth; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001004
Nicolas Capens9edebd62013-08-06 10:59:10 -04001005 if (textureFunction->method == TextureFunction::LOD0)
1006 {
1007 out << " uint mip = 0;\n";
1008 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001009 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1010 {
1011 out << " uint mip = bias;\n";
1012 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001013 else
1014 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +02001015 out << " x.GetDimensions(0, width, height, depth, levels);\n";
1016
Nicolas Capens9edebd62013-08-06 10:59:10 -04001017 if (textureFunction->method == TextureFunction::IMPLICIT ||
1018 textureFunction->method == TextureFunction::BIAS)
1019 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +02001020 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * "
1021 "depth);\n"
Nicolas Capens9edebd62013-08-06 10:59:10 -04001022 " float dx = length(ddx(tSized));\n"
1023 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001024 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001025
1026 if (textureFunction->method == TextureFunction::BIAS)
1027 {
1028 out << " lod += bias;\n";
1029 }
1030 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001031 else if (textureFunction->method == TextureFunction::GRAD)
1032 {
Olli Etuahoe8e4deb2015-11-18 17:15:38 +02001033 out << " float lod = log2(max(length(ddx), length(ddy)));\n";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001034 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001035
1036 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1037 }
1038
1039 out << " x.GetDimensions(mip, width, height, depth, levels);\n";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001040 }
1041 else UNREACHABLE();
1042 }
1043
1044 out << " return ";
1045
1046 // HLSL intrinsic
1047 if (mOutputType == SH_HLSL9_OUTPUT)
1048 {
1049 switch(textureFunction->sampler)
1050 {
1051 case EbtSampler2D: out << "tex2D"; break;
1052 case EbtSamplerCube: out << "texCUBE"; break;
1053 default: UNREACHABLE();
1054 }
1055
Nicolas Capens75fb4752013-07-10 15:14:47 -04001056 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001057 {
1058 case TextureFunction::IMPLICIT: out << "(s, "; break;
1059 case TextureFunction::BIAS: out << "bias(s, "; break;
1060 case TextureFunction::LOD: out << "lod(s, "; break;
1061 case TextureFunction::LOD0: out << "lod(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001062 case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001063 default: UNREACHABLE();
1064 }
1065 }
1066 else if (mOutputType == SH_HLSL11_OUTPUT)
1067 {
Nicolas Capensd11d5492014-02-19 17:06:10 -05001068 if (textureFunction->method == TextureFunction::GRAD)
1069 {
1070 if (IsIntegerSampler(textureFunction->sampler))
1071 {
1072 out << "x.Load(";
1073 }
1074 else if (IsShadowSampler(textureFunction->sampler))
1075 {
1076 out << "x.SampleCmpLevelZero(s, ";
1077 }
1078 else
1079 {
1080 out << "x.SampleGrad(s, ";
1081 }
1082 }
1083 else if (IsIntegerSampler(textureFunction->sampler) ||
1084 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001085 {
1086 out << "x.Load(";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001087 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001088 else if (IsShadowSampler(textureFunction->sampler))
1089 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001090 switch(textureFunction->method)
1091 {
1092 case TextureFunction::IMPLICIT: out << "x.SampleCmp(s, "; break;
1093 case TextureFunction::BIAS: out << "x.SampleCmp(s, "; break;
1094 case TextureFunction::LOD: out << "x.SampleCmp(s, "; break;
1095 case TextureFunction::LOD0: out << "x.SampleCmpLevelZero(s, "; break;
1096 case TextureFunction::LOD0BIAS: out << "x.SampleCmpLevelZero(s, "; break;
1097 default: UNREACHABLE();
1098 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001099 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001100 else
1101 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001102 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001103 {
1104 case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
1105 case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
1106 case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
1107 case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001108 case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001109 default: UNREACHABLE();
1110 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001111 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001112 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001113 else UNREACHABLE();
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001114
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001115 // Integer sampling requires integer addresses
1116 TString addressx = "";
1117 TString addressy = "";
1118 TString addressz = "";
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001119 TString close = "";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001120
Nicolas Capensfc014542014-02-18 14:47:13 -05001121 if (IsIntegerSampler(textureFunction->sampler) ||
1122 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001123 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001124 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001125 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001126 case 2: out << "int3("; break;
1127 case 3: out << "int4("; break;
1128 default: UNREACHABLE();
1129 }
Jamie Madillf91ce812014-06-13 10:04:34 -04001130
Nicolas Capensfc014542014-02-18 14:47:13 -05001131 // Convert from normalized floating-point to integer
1132 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001133 {
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001134 addressx = "int(floor(width * frac((";
1135 addressy = "int(floor(height * frac((";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001136
Nicolas Capensfc014542014-02-18 14:47:13 -05001137 if (IsSamplerArray(textureFunction->sampler))
1138 {
1139 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
1140 }
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001141 else if (IsSamplerCube(textureFunction->sampler))
Nicolas Capens0027fa92014-02-20 14:26:42 -05001142 {
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001143 addressz = "((((";
Nicolas Capens0027fa92014-02-20 14:26:42 -05001144 }
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001145 else
1146 {
1147 addressz = "int(floor(depth * frac((";
1148 }
1149
1150 close = "))))";
Nicolas Capensfc014542014-02-18 14:47:13 -05001151 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001152 }
1153 else
1154 {
1155 switch(hlslCoords)
1156 {
1157 case 2: out << "float2("; break;
1158 case 3: out << "float3("; break;
1159 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001160 default: UNREACHABLE();
1161 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001162 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001163
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001164 TString proj = ""; // Only used for projected textures
Jamie Madillf91ce812014-06-13 10:04:34 -04001165
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001166 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001167 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001168 switch(textureFunction->coords)
1169 {
1170 case 3: proj = " / t.z"; break;
1171 case 4: proj = " / t.w"; break;
1172 default: UNREACHABLE();
1173 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001174 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001175
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001176 out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001177
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001178 if (mOutputType == SH_HLSL9_OUTPUT)
1179 {
1180 if (hlslCoords >= 3)
1181 {
1182 if (textureFunction->coords < 3)
1183 {
1184 out << ", 0";
1185 }
1186 else
1187 {
1188 out << ", t.z" + proj;
1189 }
1190 }
1191
1192 if (hlslCoords == 4)
1193 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001194 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001195 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001196 case TextureFunction::BIAS: out << ", bias"; break;
1197 case TextureFunction::LOD: out << ", lod"; break;
1198 case TextureFunction::LOD0: out << ", 0"; break;
1199 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001200 default: UNREACHABLE();
1201 }
1202 }
1203
1204 out << "));\n";
1205 }
1206 else if (mOutputType == SH_HLSL11_OUTPUT)
1207 {
1208 if (hlslCoords >= 3)
1209 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001210 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1211 {
1212 out << ", face";
1213 }
1214 else
1215 {
Jamie Madill6c9b2ae2015-12-08 13:43:11 +00001216 out << ", " + addressz + ("t.z" + proj) + close;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001217 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001218 }
1219
Nicolas Capensd11d5492014-02-19 17:06:10 -05001220 if (textureFunction->method == TextureFunction::GRAD)
1221 {
1222 if (IsIntegerSampler(textureFunction->sampler))
1223 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001224 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001225 }
1226 else if (IsShadowSampler(textureFunction->sampler))
1227 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001228 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001229 if (textureFunction->proj)
Nicolas Capensd11d5492014-02-19 17:06:10 -05001230 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001231 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1232 // The resulting third component of P' in the shadow forms is used as Dref
1233 out << "), t.z" << proj;
1234 }
1235 else
1236 {
1237 switch(textureFunction->coords)
1238 {
1239 case 3: out << "), t.z"; break;
1240 case 4: out << "), t.w"; break;
1241 default: UNREACHABLE();
1242 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001243 }
1244 }
1245 else
1246 {
1247 out << "), ddx, ddy";
1248 }
1249 }
1250 else if (IsIntegerSampler(textureFunction->sampler) ||
1251 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001252 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001253 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001254 }
1255 else if (IsShadowSampler(textureFunction->sampler))
1256 {
1257 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001258 if (textureFunction->proj)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001259 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001260 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1261 // The resulting third component of P' in the shadow forms is used as Dref
1262 out << "), t.z" << proj;
1263 }
1264 else
1265 {
1266 switch(textureFunction->coords)
1267 {
1268 case 3: out << "), t.z"; break;
1269 case 4: out << "), t.w"; break;
1270 default: UNREACHABLE();
1271 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001272 }
1273 }
1274 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001275 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001276 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001277 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001278 case TextureFunction::IMPLICIT: out << ")"; break;
1279 case TextureFunction::BIAS: out << "), bias"; break;
1280 case TextureFunction::LOD: out << "), lod"; break;
1281 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001282 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001283 default: UNREACHABLE();
1284 }
1285 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001286
1287 if (textureFunction->offset)
1288 {
1289 out << ", offset";
1290 }
1291
1292 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001293 }
1294 else UNREACHABLE();
1295 }
1296
1297 out << "\n"
1298 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001299 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001300 }
1301
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001302 if (mUsesFragCoord)
1303 {
1304 out << "#define GL_USES_FRAG_COORD\n";
1305 }
1306
1307 if (mUsesPointCoord)
1308 {
1309 out << "#define GL_USES_POINT_COORD\n";
1310 }
1311
1312 if (mUsesFrontFacing)
1313 {
1314 out << "#define GL_USES_FRONT_FACING\n";
1315 }
1316
1317 if (mUsesPointSize)
1318 {
1319 out << "#define GL_USES_POINT_SIZE\n";
1320 }
1321
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001322 if (mUsesFragDepth)
1323 {
1324 out << "#define GL_USES_FRAG_DEPTH\n";
1325 }
1326
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001327 if (mUsesDepthRange)
1328 {
1329 out << "#define GL_USES_DEPTH_RANGE\n";
1330 }
1331
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001332 if (mUsesXor)
1333 {
1334 out << "bool xor(bool p, bool q)\n"
1335 "{\n"
1336 " return (p || q) && !(p && q);\n"
1337 "}\n"
1338 "\n";
1339 }
1340
Olli Etuaho95cd3c62015-03-03 16:45:32 +02001341 builtInFunctionEmulator->OutputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001342}
1343
1344void OutputHLSL::visitSymbol(TIntermSymbol *node)
1345{
Jamie Madill32aab012015-01-27 14:12:26 -05001346 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001347
Jamie Madill570e04d2013-06-21 09:15:33 -04001348 // Handle accessing std140 structs by value
1349 if (mFlaggedStructMappedNames.count(node) > 0)
1350 {
1351 out << mFlaggedStructMappedNames[node];
1352 return;
1353 }
1354
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355 TString name = node->getSymbol();
1356
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001357 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001358 {
1359 mUsesDepthRange = true;
1360 out << name;
1361 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001362 else
1363 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001364 TQualifier qualifier = node->getQualifier();
1365
1366 if (qualifier == EvqUniform)
1367 {
Jamie Madill2e295e22015-04-29 10:41:33 -04001368 const TType &nodeType = node->getType();
1369 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001370
1371 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001372 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001373 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001374 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001375 else
1376 {
1377 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001378 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001379
Jamie Madill2e295e22015-04-29 10:41:33 -04001380 ensureStructDefined(nodeType);
1381
Jamie Madill033dae62014-06-18 12:56:28 -04001382 out << DecorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001383 }
Jamie Madill19571812013-08-12 15:26:34 -07001384 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001385 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001386 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001387 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001388 }
Jamie Madill033dae62014-06-18 12:56:28 -04001389 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001390 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001391 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001392 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001393 }
Jamie Madill19571812013-08-12 15:26:34 -07001394 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001395 {
1396 mReferencedOutputVariables[name] = node;
1397 out << "out_" << name;
1398 }
1399 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001400 {
1401 out << "gl_Color[0]";
1402 mUsesFragColor = true;
1403 }
1404 else if (qualifier == EvqFragData)
1405 {
1406 out << "gl_Color";
1407 mUsesFragData = true;
1408 }
1409 else if (qualifier == EvqFragCoord)
1410 {
1411 mUsesFragCoord = true;
1412 out << name;
1413 }
1414 else if (qualifier == EvqPointCoord)
1415 {
1416 mUsesPointCoord = true;
1417 out << name;
1418 }
1419 else if (qualifier == EvqFrontFacing)
1420 {
1421 mUsesFrontFacing = true;
1422 out << name;
1423 }
1424 else if (qualifier == EvqPointSize)
1425 {
1426 mUsesPointSize = true;
1427 out << name;
1428 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001429 else if (qualifier == EvqInstanceID)
1430 {
1431 mUsesInstanceID = true;
1432 out << name;
1433 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001434 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001435 {
1436 mUsesFragDepth = true;
1437 out << "gl_Depth";
1438 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001439 else
1440 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03001441 out << DecorateIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001442 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001443 }
1444}
1445
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001446void OutputHLSL::visitRaw(TIntermRaw *node)
1447{
Jamie Madill32aab012015-01-27 14:12:26 -05001448 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001449}
1450
Olli Etuaho7fb49552015-03-18 17:27:44 +02001451void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1452{
1453 if (type.isScalar() && !type.isArray())
1454 {
1455 if (op == EOpEqual)
1456 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001457 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001458 }
1459 else
1460 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001461 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001462 }
1463 }
1464 else
1465 {
1466 if (visit == PreVisit && op == EOpNotEqual)
1467 {
1468 out << "!";
1469 }
1470
1471 if (type.isArray())
1472 {
1473 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001474 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001475 }
1476 else if (type.getBasicType() == EbtStruct)
1477 {
1478 const TStructure &structure = *type.getStruct();
1479 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001480 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001481 }
1482 else
1483 {
1484 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001485 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001486 }
1487 }
1488}
1489
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001490bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1491{
Jamie Madill32aab012015-01-27 14:12:26 -05001492 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493
Jamie Madill570e04d2013-06-21 09:15:33 -04001494 // Handle accessing std140 structs by value
1495 if (mFlaggedStructMappedNames.count(node) > 0)
1496 {
1497 out << mFlaggedStructMappedNames[node];
1498 return false;
1499 }
1500
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001501 switch (node->getOp())
1502 {
Olli Etuahoe79904c2015-03-18 16:56:42 +02001503 case EOpAssign:
1504 if (node->getLeft()->isArray())
1505 {
Olli Etuaho9638c352015-04-01 14:34:52 +03001506 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1507 if (rightAgg != nullptr && rightAgg->isConstructor())
1508 {
1509 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1510 out << functionName << "(";
1511 node->getLeft()->traverse(this);
1512 TIntermSequence *seq = rightAgg->getSequence();
1513 for (auto &arrayElement : *seq)
1514 {
1515 out << ", ";
1516 arrayElement->traverse(this);
1517 }
1518 out << ")";
1519 return false;
1520 }
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001521 // ArrayReturnValueToOutParameter should have eliminated expressions where a function call is assigned.
1522 ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
1523
1524 const TString &functionName = addArrayAssignmentFunction(node->getType());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001525 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuahoe79904c2015-03-18 16:56:42 +02001526 }
1527 else
1528 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001529 outputTriplet(out, visit, "(", " = ", ")");
Olli Etuahoe79904c2015-03-18 16:56:42 +02001530 }
1531 break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001532 case EOpInitialize:
1533 if (visit == PreVisit)
1534 {
1535 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1536 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1537 // new variable is created before the assignment is evaluated), so we need to convert
1538 // this to "float t = x, x = t;".
1539
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001540 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
Jamie Madill37997142015-01-28 10:06:34 -05001541 ASSERT(symbolNode);
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001542 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001543
Jamie Madill37997142015-01-28 10:06:34 -05001544 // TODO (jmadill): do a 'deep' scan to know if an expression is statically const
1545 if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst)
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001546 {
Jamie Madill37997142015-01-28 10:06:34 -05001547 // For variables which are not constant, defer their real initialization until
Olli Etuahod81ed842015-05-12 12:46:35 +03001548 // after we initialize uniforms.
1549 TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
1550 deferredInit->setLeft(node->getLeft());
1551 deferredInit->setRight(node->getRight());
1552 deferredInit->setType(node->getType());
1553 mDeferredGlobalInitializers.push_back(deferredInit);
Jamie Madill37997142015-01-28 10:06:34 -05001554 const TString &initString = initializer(node->getType());
1555 node->setRight(new TIntermRaw(node->getType(), initString));
1556 }
1557 else if (writeSameSymbolInitializer(out, symbolNode, expression))
1558 {
1559 // Skip initializing the rest of the expression
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001560 return false;
1561 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001562 else if (writeConstantInitialization(out, symbolNode, expression))
1563 {
1564 return false;
1565 }
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001566 }
1567 else if (visit == InVisit)
1568 {
1569 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001570 }
1571 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001572 case EOpAddAssign:
1573 outputTriplet(out, visit, "(", " += ", ")");
1574 break;
1575 case EOpSubAssign:
1576 outputTriplet(out, visit, "(", " -= ", ")");
1577 break;
1578 case EOpMulAssign:
1579 outputTriplet(out, visit, "(", " *= ", ")");
1580 break;
1581 case EOpVectorTimesScalarAssign:
1582 outputTriplet(out, visit, "(", " *= ", ")");
1583 break;
1584 case EOpMatrixTimesScalarAssign:
1585 outputTriplet(out, visit, "(", " *= ", ")");
1586 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001587 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001588 if (visit == PreVisit)
1589 {
1590 out << "(";
1591 }
1592 else if (visit == InVisit)
1593 {
1594 out << " = mul(";
1595 node->getLeft()->traverse(this);
Jamie Madillf91ce812014-06-13 10:04:34 -04001596 out << ", transpose(";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001597 }
1598 else
1599 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001600 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001601 }
1602 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001603 case EOpMatrixTimesMatrixAssign:
1604 if (visit == PreVisit)
1605 {
1606 out << "(";
1607 }
1608 else if (visit == InVisit)
1609 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001610 out << " = transpose(mul(transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001611 node->getLeft()->traverse(this);
Olli Etuahofc7fab72015-03-06 12:03:18 +02001612 out << "), transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001613 }
1614 else
1615 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001616 out << "))))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001617 }
1618 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001619 case EOpDivAssign:
1620 outputTriplet(out, visit, "(", " /= ", ")");
1621 break;
1622 case EOpIModAssign:
1623 outputTriplet(out, visit, "(", " %= ", ")");
1624 break;
1625 case EOpBitShiftLeftAssign:
1626 outputTriplet(out, visit, "(", " <<= ", ")");
1627 break;
1628 case EOpBitShiftRightAssign:
1629 outputTriplet(out, visit, "(", " >>= ", ")");
1630 break;
1631 case EOpBitwiseAndAssign:
1632 outputTriplet(out, visit, "(", " &= ", ")");
1633 break;
1634 case EOpBitwiseXorAssign:
1635 outputTriplet(out, visit, "(", " ^= ", ")");
1636 break;
1637 case EOpBitwiseOrAssign:
1638 outputTriplet(out, visit, "(", " |= ", ")");
1639 break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001640 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001641 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001642 const TType& leftType = node->getLeft()->getType();
1643 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001644 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001645 if (visit == PreVisit)
1646 {
1647 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1648 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001649 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001650 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001651 return false;
1652 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001653 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001654 else
1655 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001656 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001657 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001658 }
1659 break;
1660 case EOpIndexIndirect:
1661 // We do not currently support indirect references to interface blocks
1662 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001663 outputTriplet(out, visit, "", "[", "]");
Jamie Madillb4e664b2013-06-20 11:55:54 -04001664 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001665 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001666 if (visit == InVisit)
1667 {
1668 const TStructure* structure = node->getLeft()->getType().getStruct();
1669 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1670 const TField* field = structure->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001671 out << "." + DecorateField(field->name(), *structure);
Jamie Madill98493dd2013-07-08 14:39:03 -04001672
1673 return false;
1674 }
1675 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001676 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001677 if (visit == InVisit)
1678 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001679 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1680 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1681 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001682 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001683
1684 return false;
1685 }
1686 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001687 case EOpVectorSwizzle:
1688 if (visit == InVisit)
1689 {
1690 out << ".";
1691
1692 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1693
1694 if (swizzle)
1695 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001696 TIntermSequence *sequence = swizzle->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001697
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001698 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001699 {
1700 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1701
1702 if (element)
1703 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00001704 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001705
1706 switch (i)
1707 {
1708 case 0: out << "x"; break;
1709 case 1: out << "y"; break;
1710 case 2: out << "z"; break;
1711 case 3: out << "w"; break;
1712 default: UNREACHABLE();
1713 }
1714 }
1715 else UNREACHABLE();
1716 }
1717 }
1718 else UNREACHABLE();
1719
1720 return false; // Fully processed
1721 }
1722 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001723 case EOpAdd:
1724 outputTriplet(out, visit, "(", " + ", ")");
1725 break;
1726 case EOpSub:
1727 outputTriplet(out, visit, "(", " - ", ")");
1728 break;
1729 case EOpMul:
1730 outputTriplet(out, visit, "(", " * ", ")");
1731 break;
1732 case EOpDiv:
1733 outputTriplet(out, visit, "(", " / ", ")");
1734 break;
1735 case EOpIMod:
1736 outputTriplet(out, visit, "(", " % ", ")");
1737 break;
1738 case EOpBitShiftLeft:
1739 outputTriplet(out, visit, "(", " << ", ")");
1740 break;
1741 case EOpBitShiftRight:
1742 outputTriplet(out, visit, "(", " >> ", ")");
1743 break;
1744 case EOpBitwiseAnd:
1745 outputTriplet(out, visit, "(", " & ", ")");
1746 break;
1747 case EOpBitwiseXor:
1748 outputTriplet(out, visit, "(", " ^ ", ")");
1749 break;
1750 case EOpBitwiseOr:
1751 outputTriplet(out, visit, "(", " | ", ")");
1752 break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001753 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001754 case EOpNotEqual:
Olli Etuaho7fb49552015-03-18 17:27:44 +02001755 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001756 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001757 case EOpLessThan:
1758 outputTriplet(out, visit, "(", " < ", ")");
1759 break;
1760 case EOpGreaterThan:
1761 outputTriplet(out, visit, "(", " > ", ")");
1762 break;
1763 case EOpLessThanEqual:
1764 outputTriplet(out, visit, "(", " <= ", ")");
1765 break;
1766 case EOpGreaterThanEqual:
1767 outputTriplet(out, visit, "(", " >= ", ")");
1768 break;
1769 case EOpVectorTimesScalar:
1770 outputTriplet(out, visit, "(", " * ", ")");
1771 break;
1772 case EOpMatrixTimesScalar:
1773 outputTriplet(out, visit, "(", " * ", ")");
1774 break;
1775 case EOpVectorTimesMatrix:
1776 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1777 break;
1778 case EOpMatrixTimesVector:
1779 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1780 break;
1781 case EOpMatrixTimesMatrix:
1782 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1783 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001784 case EOpLogicalOr:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001785 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
1786 ASSERT(!node->getRight()->hasSideEffects());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001787 outputTriplet(out, visit, "(", " || ", ")");
Olli Etuahoa6f22092015-05-08 18:31:10 +03001788 return true;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001789 case EOpLogicalXor:
1790 mUsesXor = true;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001791 outputTriplet(out, visit, "xor(", ", ", ")");
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001792 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001793 case EOpLogicalAnd:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001794 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
1795 ASSERT(!node->getRight()->hasSideEffects());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001796 outputTriplet(out, visit, "(", " && ", ")");
Olli Etuahoa6f22092015-05-08 18:31:10 +03001797 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001798 default: UNREACHABLE();
1799 }
1800
1801 return true;
1802}
1803
1804bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1805{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001806 TInfoSinkBase &out = getInfoSink();
1807
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001808 switch (node->getOp())
1809 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001810 case EOpNegative:
1811 outputTriplet(out, visit, "(-", "", ")");
1812 break;
1813 case EOpPositive:
1814 outputTriplet(out, visit, "(+", "", ")");
1815 break;
1816 case EOpVectorLogicalNot:
1817 outputTriplet(out, visit, "(!", "", ")");
1818 break;
1819 case EOpLogicalNot:
1820 outputTriplet(out, visit, "(!", "", ")");
1821 break;
1822 case EOpBitwiseNot:
1823 outputTriplet(out, visit, "(~", "", ")");
1824 break;
1825 case EOpPostIncrement:
1826 outputTriplet(out, visit, "(", "", "++)");
1827 break;
1828 case EOpPostDecrement:
1829 outputTriplet(out, visit, "(", "", "--)");
1830 break;
1831 case EOpPreIncrement:
1832 outputTriplet(out, visit, "(++", "", ")");
1833 break;
1834 case EOpPreDecrement:
1835 outputTriplet(out, visit, "(--", "", ")");
1836 break;
1837 case EOpRadians:
1838 outputTriplet(out, visit, "radians(", "", ")");
1839 break;
1840 case EOpDegrees:
1841 outputTriplet(out, visit, "degrees(", "", ")");
1842 break;
1843 case EOpSin:
1844 outputTriplet(out, visit, "sin(", "", ")");
1845 break;
1846 case EOpCos:
1847 outputTriplet(out, visit, "cos(", "", ")");
1848 break;
1849 case EOpTan:
1850 outputTriplet(out, visit, "tan(", "", ")");
1851 break;
1852 case EOpAsin:
1853 outputTriplet(out, visit, "asin(", "", ")");
1854 break;
1855 case EOpAcos:
1856 outputTriplet(out, visit, "acos(", "", ")");
1857 break;
1858 case EOpAtan:
1859 outputTriplet(out, visit, "atan(", "", ")");
1860 break;
1861 case EOpSinh:
1862 outputTriplet(out, visit, "sinh(", "", ")");
1863 break;
1864 case EOpCosh:
1865 outputTriplet(out, visit, "cosh(", "", ")");
1866 break;
1867 case EOpTanh:
1868 outputTriplet(out, visit, "tanh(", "", ")");
1869 break;
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001870 case EOpAsinh:
1871 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001872 writeEmulatedFunctionTriplet(out, visit, "asinh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001873 break;
1874 case EOpAcosh:
1875 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001876 writeEmulatedFunctionTriplet(out, visit, "acosh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001877 break;
1878 case EOpAtanh:
1879 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001880 writeEmulatedFunctionTriplet(out, visit, "atanh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001881 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001882 case EOpExp:
1883 outputTriplet(out, visit, "exp(", "", ")");
1884 break;
1885 case EOpLog:
1886 outputTriplet(out, visit, "log(", "", ")");
1887 break;
1888 case EOpExp2:
1889 outputTriplet(out, visit, "exp2(", "", ")");
1890 break;
1891 case EOpLog2:
1892 outputTriplet(out, visit, "log2(", "", ")");
1893 break;
1894 case EOpSqrt:
1895 outputTriplet(out, visit, "sqrt(", "", ")");
1896 break;
1897 case EOpInverseSqrt:
1898 outputTriplet(out, visit, "rsqrt(", "", ")");
1899 break;
1900 case EOpAbs:
1901 outputTriplet(out, visit, "abs(", "", ")");
1902 break;
1903 case EOpSign:
1904 outputTriplet(out, visit, "sign(", "", ")");
1905 break;
1906 case EOpFloor:
1907 outputTriplet(out, visit, "floor(", "", ")");
1908 break;
1909 case EOpTrunc:
1910 outputTriplet(out, visit, "trunc(", "", ")");
1911 break;
1912 case EOpRound:
1913 outputTriplet(out, visit, "round(", "", ")");
1914 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -08001915 case EOpRoundEven:
1916 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001917 writeEmulatedFunctionTriplet(out, visit, "roundEven(");
Qingqing Deng5dbece52015-02-27 20:35:38 -08001918 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001919 case EOpCeil:
1920 outputTriplet(out, visit, "ceil(", "", ")");
1921 break;
1922 case EOpFract:
1923 outputTriplet(out, visit, "frac(", "", ")");
1924 break;
Arun Patole44efa0b2015-03-04 17:11:05 +05301925 case EOpIsNan:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001926 outputTriplet(out, visit, "isnan(", "", ")");
Arun Patole44efa0b2015-03-04 17:11:05 +05301927 mRequiresIEEEStrictCompiling = true;
1928 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001929 case EOpIsInf:
1930 outputTriplet(out, visit, "isinf(", "", ")");
1931 break;
1932 case EOpFloatBitsToInt:
1933 outputTriplet(out, visit, "asint(", "", ")");
1934 break;
1935 case EOpFloatBitsToUint:
1936 outputTriplet(out, visit, "asuint(", "", ")");
1937 break;
1938 case EOpIntBitsToFloat:
1939 outputTriplet(out, visit, "asfloat(", "", ")");
1940 break;
1941 case EOpUintBitsToFloat:
1942 outputTriplet(out, visit, "asfloat(", "", ")");
1943 break;
Olli Etuaho7700ff62015-01-15 12:16:29 +02001944 case EOpPackSnorm2x16:
1945 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001946 writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001947 break;
1948 case EOpPackUnorm2x16:
1949 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001950 writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001951 break;
1952 case EOpPackHalf2x16:
1953 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001954 writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001955 break;
1956 case EOpUnpackSnorm2x16:
1957 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001958 writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001959 break;
1960 case EOpUnpackUnorm2x16:
1961 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001962 writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001963 break;
1964 case EOpUnpackHalf2x16:
1965 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001966 writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001967 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001968 case EOpLength:
1969 outputTriplet(out, visit, "length(", "", ")");
1970 break;
1971 case EOpNormalize:
1972 outputTriplet(out, visit, "normalize(", "", ")");
1973 break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001974 case EOpDFdx:
1975 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1976 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001977 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001978 }
1979 else
1980 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001981 outputTriplet(out, visit, "ddx(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001982 }
1983 break;
1984 case EOpDFdy:
1985 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1986 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001987 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001988 }
1989 else
1990 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001991 outputTriplet(out, visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001992 }
1993 break;
1994 case EOpFwidth:
1995 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1996 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001997 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001998 }
1999 else
2000 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002001 outputTriplet(out, visit, "fwidth(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002002 }
2003 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002004 case EOpTranspose:
2005 outputTriplet(out, visit, "transpose(", "", ")");
2006 break;
2007 case EOpDeterminant:
2008 outputTriplet(out, visit, "determinant(transpose(", "", "))");
2009 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +02002010 case EOpInverse:
2011 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002012 writeEmulatedFunctionTriplet(out, visit, "inverse(");
Olli Etuahoabf6dad2015-01-14 14:45:16 +02002013 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02002014
Jamie Madill8c46ab12015-12-07 16:39:19 -05002015 case EOpAny:
2016 outputTriplet(out, visit, "any(", "", ")");
2017 break;
2018 case EOpAll:
2019 outputTriplet(out, visit, "all(", "", ")");
2020 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002021 default: UNREACHABLE();
2022 }
2023
2024 return true;
2025}
2026
2027bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2028{
Jamie Madill32aab012015-01-27 14:12:26 -05002029 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002030
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002031 switch (node->getOp())
2032 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002033 case EOpSequence:
2034 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002035 if (mInsideFunction)
2036 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002037 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002038 out << "{\n";
2039 }
2040
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002041 for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002042 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002043 outputLineDirective(out, (*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002044
Olli Etuahoa6f22092015-05-08 18:31:10 +03002045 (*sit)->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002046
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002047 // Don't output ; after case labels, they're terminated by :
2048 // This is needed especially since outputting a ; after a case statement would turn empty
2049 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho4785fec2015-05-18 16:09:37 +03002050 // Also no need to output ; after selection (if) statements or sequences. This is done just
2051 // for code clarity.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002052 TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
2053 ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
Olli Etuaho4785fec2015-05-18 16:09:37 +03002054 if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002055 out << ";\n";
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002056 }
2057
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002058 if (mInsideFunction)
2059 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002060 outputLineDirective(out, node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002061 out << "}\n";
2062 }
2063
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002064 return false;
2065 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002066 case EOpDeclaration:
2067 if (visit == PreVisit)
2068 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002069 TIntermSequence *sequence = node->getSequence();
2070 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
Olli Etuahoa6f22092015-05-08 18:31:10 +03002071 ASSERT(sequence->size() == 1);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002072
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002073 if (variable &&
2074 (variable->getQualifier() == EvqTemporary ||
2075 variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 {
Jamie Madill2e295e22015-04-29 10:41:33 -04002077 ensureStructDefined(variable->getType());
daniel@transgaming.comead23042010-04-29 03:35:36 +00002078
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002079 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002080 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03002081 if (!mInsideFunction)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002082 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03002083 out << "static ";
2084 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04002085
Olli Etuahoa6f22092015-05-08 18:31:10 +03002086 out << TypeString(variable->getType()) + " ";
Nicolas Capensd974db42014-10-07 10:50:19 -04002087
Olli Etuahoa6f22092015-05-08 18:31:10 +03002088 TIntermSymbol *symbol = variable->getAsSymbolNode();
Nicolas Capensd974db42014-10-07 10:50:19 -04002089
Olli Etuahoa6f22092015-05-08 18:31:10 +03002090 if (symbol)
2091 {
2092 symbol->traverse(this);
2093 out << ArrayString(symbol->getType());
2094 out << " = " + initializer(symbol->getType());
2095 }
2096 else
2097 {
2098 variable->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002099 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002100 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002101 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
2102 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002103 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002104 }
2105 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002106 }
Jamie Madill033dae62014-06-18 12:56:28 -04002107 else if (variable && IsVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002108 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002109 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002110 {
2111 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
2112
2113 if (symbol)
2114 {
2115 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
2116 mReferencedVaryings[symbol->getSymbol()] = symbol;
2117 }
2118 else
2119 {
2120 (*sit)->traverse(this);
2121 }
2122 }
2123 }
2124
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002125 return false;
2126 }
2127 else if (visit == InVisit)
2128 {
2129 out << ", ";
2130 }
2131 break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -04002132 case EOpInvariantDeclaration:
2133 // Do not do any translation
2134 return false;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002135 case EOpPrototype:
2136 if (visit == PreVisit)
2137 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002138 size_t index = mCallDag.findIndex(node);
2139 // Skip the prototype if it is not implemented (and thus not used)
2140 if (index == CallDAG::InvalidIndex)
2141 {
2142 return false;
2143 }
2144
Olli Etuaho59f9a642015-08-06 20:38:26 +03002145 TString name = DecorateFunctionIfNeeded(node->getNameObj());
2146 out << TypeString(node->getType()) << " " << name
2147 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002148
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002149 TIntermSequence *arguments = node->getSequence();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002150
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002151 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002152 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002153 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002154
2155 if (symbol)
2156 {
2157 out << argumentString(symbol);
2158
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002159 if (i < arguments->size() - 1)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002160 {
2161 out << ", ";
2162 }
2163 }
2164 else UNREACHABLE();
2165 }
2166
2167 out << ");\n";
2168
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002169 // Also prototype the Lod0 variant if needed
Corentin Wallez1239ee92015-03-19 14:38:02 -07002170 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2171 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002172 {
2173 mOutputLod0Function = true;
2174 node->traverse(this);
2175 mOutputLod0Function = false;
2176 }
2177
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002178 return false;
2179 }
2180 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002181 case EOpComma:
2182 outputTriplet(out, visit, "(", ", ", ")");
2183 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002184 case EOpFunction:
2185 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002186 ASSERT(mCurrentFunctionMetadata == nullptr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03002187 TString name = TFunction::unmangleName(node->getNameObj().getString());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002188
Corentin Wallez1239ee92015-03-19 14:38:02 -07002189 size_t index = mCallDag.findIndex(node);
2190 ASSERT(index != CallDAG::InvalidIndex);
2191 mCurrentFunctionMetadata = &mASTMetadataList[index];
2192
Jamie Madill033dae62014-06-18 12:56:28 -04002193 out << TypeString(node->getType()) << " ";
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002194
2195 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002196 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002197 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002199 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002201 out << DecorateFunctionIfNeeded(node->getNameObj())
2202 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002203 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002204
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002205 TIntermSequence *sequence = node->getSequence();
2206 TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002207
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002208 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002209 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002210 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002211
2212 if (symbol)
2213 {
Jamie Madill2e295e22015-04-29 10:41:33 -04002214 ensureStructDefined(symbol->getType());
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002215
2216 out << argumentString(symbol);
2217
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002218 if (i < arguments->size() - 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002219 {
2220 out << ", ";
2221 }
2222 }
2223 else UNREACHABLE();
2224 }
2225
Olli Etuaho4785fec2015-05-18 16:09:37 +03002226 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002227
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002228 if (sequence->size() > 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002229 {
2230 mInsideFunction = true;
Olli Etuaho4785fec2015-05-18 16:09:37 +03002231 TIntermNode *body = (*sequence)[1];
2232 // The function body node will output braces.
2233 ASSERT(IsSequence(body));
2234 body->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002235 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002236 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002237 else
2238 {
2239 out << "{}\n";
2240 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002241
Corentin Wallez1239ee92015-03-19 14:38:02 -07002242 mCurrentFunctionMetadata = nullptr;
2243
2244 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2245 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002246 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002247 ASSERT(name != "main");
2248 mOutputLod0Function = true;
2249 node->traverse(this);
2250 mOutputLod0Function = false;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002251 }
2252
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002253 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
2255 break;
2256 case EOpFunctionCall:
2257 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002258 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002259
Corentin Wallez1239ee92015-03-19 14:38:02 -07002260 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002261 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002262 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002263 if (node->isArray())
2264 {
2265 UNIMPLEMENTED();
2266 }
Corentin Wallez1239ee92015-03-19 14:38:02 -07002267 size_t index = mCallDag.findIndex(node);
2268 ASSERT(index != CallDAG::InvalidIndex);
2269 lod0 &= mASTMetadataList[index].mNeedsLod0;
2270
Olli Etuaho59f9a642015-08-06 20:38:26 +03002271 out << DecorateFunctionIfNeeded(node->getNameObj()) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002272 }
2273 else
2274 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002275 TString name = TFunction::unmangleName(node->getNameObj().getString());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002276 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002277
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002278 TextureFunction textureFunction;
2279 textureFunction.sampler = samplerType;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002280 textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002281 textureFunction.method = TextureFunction::IMPLICIT;
2282 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002283 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002284
2285 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002286 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002287 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002288 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002289 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002290 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002291 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002292 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002293 }
Nicolas Capens46485082014-04-15 13:12:50 -04002294 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
2295 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002296 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002297 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002298 }
Nicolas Capens46485082014-04-15 13:12:50 -04002299 else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002300 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002301 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002302 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002303 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002304 else if (name == "textureSize")
2305 {
2306 textureFunction.method = TextureFunction::SIZE;
2307 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002308 else if (name == "textureOffset")
2309 {
2310 textureFunction.method = TextureFunction::IMPLICIT;
2311 textureFunction.offset = true;
2312 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002313 else if (name == "textureProjOffset")
2314 {
2315 textureFunction.method = TextureFunction::IMPLICIT;
2316 textureFunction.offset = true;
2317 textureFunction.proj = true;
2318 }
2319 else if (name == "textureLodOffset")
2320 {
2321 textureFunction.method = TextureFunction::LOD;
2322 textureFunction.offset = true;
2323 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002324 else if (name == "textureProjLodOffset")
2325 {
2326 textureFunction.method = TextureFunction::LOD;
2327 textureFunction.proj = true;
2328 textureFunction.offset = true;
2329 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002330 else if (name == "texelFetch")
2331 {
2332 textureFunction.method = TextureFunction::FETCH;
2333 }
2334 else if (name == "texelFetchOffset")
2335 {
2336 textureFunction.method = TextureFunction::FETCH;
2337 textureFunction.offset = true;
2338 }
Nicolas Capens46485082014-04-15 13:12:50 -04002339 else if (name == "textureGrad" || name == "texture2DGradEXT")
Nicolas Capensd11d5492014-02-19 17:06:10 -05002340 {
2341 textureFunction.method = TextureFunction::GRAD;
2342 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002343 else if (name == "textureGradOffset")
2344 {
2345 textureFunction.method = TextureFunction::GRAD;
2346 textureFunction.offset = true;
2347 }
Nicolas Capens46485082014-04-15 13:12:50 -04002348 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
Nicolas Capensf7378e32014-02-19 17:29:32 -05002349 {
2350 textureFunction.method = TextureFunction::GRAD;
2351 textureFunction.proj = true;
2352 }
2353 else if (name == "textureProjGradOffset")
2354 {
2355 textureFunction.method = TextureFunction::GRAD;
2356 textureFunction.proj = true;
2357 textureFunction.offset = true;
2358 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002359 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002360
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002361 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002362 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002363 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2364
2365 if (textureFunction.offset)
2366 {
2367 mandatoryArgumentCount++;
2368 }
2369
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002370 bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional
Nicolas Capens84cfa122014-04-14 13:48:45 -04002371
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002372 if (lod0 || mShaderType == GL_VERTEX_SHADER)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002373 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002374 if (bias)
2375 {
2376 textureFunction.method = TextureFunction::LOD0BIAS;
2377 }
2378 else
2379 {
2380 textureFunction.method = TextureFunction::LOD0;
2381 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002382 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002383 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002384 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002385 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002386 }
2387 }
2388
2389 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002390
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002391 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002392 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002393
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002394 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002395 {
2396 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2397 {
2398 out << "texture_";
2399 (*arg)->traverse(this);
2400 out << ", sampler_";
2401 }
2402
2403 (*arg)->traverse(this);
2404
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002405 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002406 {
2407 out << ", ";
2408 }
2409 }
2410
2411 out << ")";
2412
2413 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002414 }
2415 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002416 case EOpParameters:
2417 outputTriplet(out, visit, "(", ", ", ")\n{\n");
2418 break;
2419 case EOpConstructFloat:
2420 outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
2421 break;
2422 case EOpConstructVec2:
2423 outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
2424 break;
2425 case EOpConstructVec3:
2426 outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
2427 break;
2428 case EOpConstructVec4:
2429 outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
2430 break;
2431 case EOpConstructBool:
2432 outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
2433 break;
2434 case EOpConstructBVec2:
2435 outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
2436 break;
2437 case EOpConstructBVec3:
2438 outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
2439 break;
2440 case EOpConstructBVec4:
2441 outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
2442 break;
2443 case EOpConstructInt:
2444 outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
2445 break;
2446 case EOpConstructIVec2:
2447 outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
2448 break;
2449 case EOpConstructIVec3:
2450 outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
2451 break;
2452 case EOpConstructIVec4:
2453 outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
2454 break;
2455 case EOpConstructUInt:
2456 outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
2457 break;
2458 case EOpConstructUVec2:
2459 outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
2460 break;
2461 case EOpConstructUVec3:
2462 outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
2463 break;
2464 case EOpConstructUVec4:
2465 outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
2466 break;
2467 case EOpConstructMat2:
2468 outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
2469 break;
2470 case EOpConstructMat2x3:
2471 outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
2472 break;
2473 case EOpConstructMat2x4:
2474 outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
2475 break;
2476 case EOpConstructMat3x2:
2477 outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
2478 break;
2479 case EOpConstructMat3:
2480 outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
2481 break;
2482 case EOpConstructMat3x4:
2483 outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
2484 break;
2485 case EOpConstructMat4x2:
2486 outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
2487 break;
2488 case EOpConstructMat4x3:
2489 outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
2490 break;
2491 case EOpConstructMat4:
2492 outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
2493 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002494 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04002495 {
Olli Etuahof40319e2015-03-10 14:33:00 +02002496 if (node->getType().isArray())
2497 {
2498 UNIMPLEMENTED();
2499 }
Jamie Madill033dae62014-06-18 12:56:28 -04002500 const TString &structName = StructNameString(*node->getType().getStruct());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002501 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002502 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Jamie Madillbfa91f42014-06-05 15:45:18 -04002503 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002504 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002505 case EOpLessThan:
2506 outputTriplet(out, visit, "(", " < ", ")");
2507 break;
2508 case EOpGreaterThan:
2509 outputTriplet(out, visit, "(", " > ", ")");
2510 break;
2511 case EOpLessThanEqual:
2512 outputTriplet(out, visit, "(", " <= ", ")");
2513 break;
2514 case EOpGreaterThanEqual:
2515 outputTriplet(out, visit, "(", " >= ", ")");
2516 break;
2517 case EOpVectorEqual:
2518 outputTriplet(out, visit, "(", " == ", ")");
2519 break;
2520 case EOpVectorNotEqual:
2521 outputTriplet(out, visit, "(", " != ", ")");
2522 break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002523 case EOpMod:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002524 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002525 writeEmulatedFunctionTriplet(out, visit, "mod(");
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002526 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002527 case EOpModf:
2528 outputTriplet(out, visit, "modf(", ", ", ")");
2529 break;
2530 case EOpPow:
2531 outputTriplet(out, visit, "pow(", ", ", ")");
2532 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002533 case EOpAtan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002534 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
Olli Etuahoe17e3192015-01-02 12:47:59 +02002535 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002536 writeEmulatedFunctionTriplet(out, visit, "atan(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002537 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002538 case EOpMin:
2539 outputTriplet(out, visit, "min(", ", ", ")");
2540 break;
2541 case EOpMax:
2542 outputTriplet(out, visit, "max(", ", ", ")");
2543 break;
2544 case EOpClamp:
2545 outputTriplet(out, visit, "clamp(", ", ", ")");
2546 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302547 case EOpMix:
2548 {
2549 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2550 if (lastParamNode->getType().getBasicType() == EbtBool)
2551 {
2552 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
2553 // so use emulated version.
2554 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002555 writeEmulatedFunctionTriplet(out, visit, "mix(");
Arun Patoled94f6642015-05-18 16:25:12 +05302556 }
2557 else
2558 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002559 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302560 }
2561 }
2562 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002563 case EOpStep:
2564 outputTriplet(out, visit, "step(", ", ", ")");
2565 break;
2566 case EOpSmoothStep:
2567 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2568 break;
2569 case EOpDistance:
2570 outputTriplet(out, visit, "distance(", ", ", ")");
2571 break;
2572 case EOpDot:
2573 outputTriplet(out, visit, "dot(", ", ", ")");
2574 break;
2575 case EOpCross:
2576 outputTriplet(out, visit, "cross(", ", ", ")");
2577 break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002578 case EOpFaceForward:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002579 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002580 writeEmulatedFunctionTriplet(out, visit, "faceforward(");
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002581 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002582 case EOpReflect:
2583 outputTriplet(out, visit, "reflect(", ", ", ")");
2584 break;
2585 case EOpRefract:
2586 outputTriplet(out, visit, "refract(", ", ", ")");
2587 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02002588 case EOpOuterProduct:
2589 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002590 writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
Olli Etuahoe39706d2014-12-30 16:40:36 +02002591 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002592 case EOpMul:
2593 outputTriplet(out, visit, "(", " * ", ")");
2594 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002595 default: UNREACHABLE();
2596 }
2597
2598 return true;
2599}
2600
Jamie Madill8c46ab12015-12-07 16:39:19 -05002601void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002602{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002603 out << "if (";
2604
2605 node->getCondition()->traverse(this);
2606
2607 out << ")\n";
2608
Jamie Madill8c46ab12015-12-07 16:39:19 -05002609 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002610
2611 bool discard = false;
2612
2613 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002614 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002615 // The trueBlock child node will output braces.
2616 ASSERT(IsSequence(node->getTrueBlock()));
2617
Olli Etuahoa6f22092015-05-08 18:31:10 +03002618 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002619
Olli Etuahoa6f22092015-05-08 18:31:10 +03002620 // Detect true discard
2621 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2622 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002623 else
2624 {
2625 // TODO(oetuaho): Check if the semicolon inside is necessary.
2626 // It's there as a result of conservative refactoring of the output.
2627 out << "{;}\n";
2628 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002629
Jamie Madill8c46ab12015-12-07 16:39:19 -05002630 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002631
Olli Etuahoa6f22092015-05-08 18:31:10 +03002632 if (node->getFalseBlock())
2633 {
2634 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002635
Jamie Madill8c46ab12015-12-07 16:39:19 -05002636 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002637
Olli Etuaho4785fec2015-05-18 16:09:37 +03002638 // Either this is "else if" or the falseBlock child node will output braces.
2639 ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr);
2640
Olli Etuahoa6f22092015-05-08 18:31:10 +03002641 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002642
Jamie Madill8c46ab12015-12-07 16:39:19 -05002643 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002644
Olli Etuahoa6f22092015-05-08 18:31:10 +03002645 // Detect false discard
2646 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2647 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002648
Olli Etuahoa6f22092015-05-08 18:31:10 +03002649 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002650 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002651 {
2652 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002653 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002654}
2655
2656bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2657{
2658 TInfoSinkBase &out = getInfoSink();
2659
2660 ASSERT(!node->usesTernaryOperator());
2661
2662 if (!mInsideFunction)
2663 {
2664 // This is part of unfolded global initialization.
2665 mDeferredGlobalInitializers.push_back(node);
2666 return false;
2667 }
2668
2669 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002670 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002671 {
2672 out << "FLATTEN ";
2673 }
2674
Jamie Madill8c46ab12015-12-07 16:39:19 -05002675 writeSelection(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002676
2677 return false;
2678}
2679
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002680bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002681{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002682 TInfoSinkBase &out = getInfoSink();
2683
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002684 if (node->getStatementList())
2685 {
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +02002686 node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002687 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002688 // The curly braces get written when visiting the statementList aggregate
2689 }
2690 else
2691 {
2692 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002693 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002694 }
2695 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002696}
2697
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002698bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002699{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002700 TInfoSinkBase &out = getInfoSink();
2701
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002702 if (node->hasCondition())
2703 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002704 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002705 return true;
2706 }
2707 else
2708 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002709 out << "default:\n";
2710 return false;
2711 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002712}
2713
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002714void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2715{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002716 TInfoSinkBase &out = getInfoSink();
2717 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002718}
2719
2720bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2721{
Nicolas Capens655fe362014-04-11 13:12:34 -04002722 mNestedLoopDepth++;
2723
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002724 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Corentin Wallez1239ee92015-03-19 14:38:02 -07002725 mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
Corentin Walleza1884f22015-04-29 10:15:16 -07002726 mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002727
Jamie Madill8c46ab12015-12-07 16:39:19 -05002728 TInfoSinkBase &out = getInfoSink();
2729
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002730 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002731 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002732 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002733 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002734 mInsideDiscontinuousLoop = wasDiscontinuous;
2735 mNestedLoopDepth--;
2736
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002737 return false;
2738 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002739 }
2740
Corentin Wallez1239ee92015-03-19 14:38:02 -07002741 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002742 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002743 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002744 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002745
Jamie Madill8c46ab12015-12-07 16:39:19 -05002746 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002747 }
2748 else
2749 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002750 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002751
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002752 if (node->getInit())
2753 {
2754 node->getInit()->traverse(this);
2755 }
2756
2757 out << "; ";
2758
alokp@chromium.org52813552010-11-16 18:36:09 +00002759 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002760 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002761 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002762 }
2763
2764 out << "; ";
2765
alokp@chromium.org52813552010-11-16 18:36:09 +00002766 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002767 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002768 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002769 }
2770
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002771 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002772
Jamie Madill8c46ab12015-12-07 16:39:19 -05002773 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002774 }
2775
2776 if (node->getBody())
2777 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002778 // The loop body node will output braces.
2779 ASSERT(IsSequence(node->getBody()));
Olli Etuahoa6f22092015-05-08 18:31:10 +03002780 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002781 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002782 else
2783 {
2784 // TODO(oetuaho): Check if the semicolon inside is necessary.
2785 // It's there as a result of conservative refactoring of the output.
2786 out << "{;}\n";
2787 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002788
Jamie Madill8c46ab12015-12-07 16:39:19 -05002789 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002790
alokp@chromium.org52813552010-11-16 18:36:09 +00002791 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002792 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002793 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002794 out << "while(\n";
2795
alokp@chromium.org52813552010-11-16 18:36:09 +00002796 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002797
daniel@transgaming.com73536982012-03-21 20:45:49 +00002798 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002799 }
2800
daniel@transgaming.com73536982012-03-21 20:45:49 +00002801 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002802
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002803 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002804 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002806 return false;
2807}
2808
2809bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2810{
Jamie Madill32aab012015-01-27 14:12:26 -05002811 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002812
2813 switch (node->getFlowOp())
2814 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002815 case EOpKill:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002816 outputTriplet(out, visit, "discard;\n", "", "");
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002817 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002818 case EOpBreak:
2819 if (visit == PreVisit)
2820 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002821 if (mNestedLoopDepth > 1)
2822 {
2823 mUsesNestedBreak = true;
2824 }
2825
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002826 if (mExcessiveLoopIndex)
2827 {
2828 out << "{Break";
2829 mExcessiveLoopIndex->traverse(this);
2830 out << " = true; break;}\n";
2831 }
2832 else
2833 {
2834 out << "break;\n";
2835 }
2836 }
2837 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002838 case EOpContinue:
2839 outputTriplet(out, visit, "continue;\n", "", "");
2840 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002841 case EOpReturn:
2842 if (visit == PreVisit)
2843 {
2844 if (node->getExpression())
2845 {
2846 out << "return ";
2847 }
2848 else
2849 {
2850 out << "return;\n";
2851 }
2852 }
2853 else if (visit == PostVisit)
2854 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002855 if (node->getExpression())
2856 {
2857 out << ";\n";
2858 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002859 }
2860 break;
2861 default: UNREACHABLE();
2862 }
2863
2864 return true;
2865}
2866
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002867bool OutputHLSL::isSingleStatement(TIntermNode *node)
2868{
2869 TIntermAggregate *aggregate = node->getAsAggregate();
2870
2871 if (aggregate)
2872 {
2873 if (aggregate->getOp() == EOpSequence)
2874 {
2875 return false;
2876 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04002877 else if (aggregate->getOp() == EOpDeclaration)
2878 {
2879 // Declaring multiple comma-separated variables must be considered multiple statements
2880 // because each individual declaration has side effects which are visible in the next.
2881 return false;
2882 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002883 else
2884 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002885 for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002886 {
2887 if (!isSingleStatement(*sit))
2888 {
2889 return false;
2890 }
2891 }
2892
2893 return true;
2894 }
2895 }
2896
2897 return true;
2898}
2899
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002900// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2901// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002902bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002903{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002904 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002905
2906 // Parse loops of the form:
2907 // for(int index = initial; index [comparator] limit; index += increment)
2908 TIntermSymbol *index = NULL;
2909 TOperator comparator = EOpNull;
2910 int initial = 0;
2911 int limit = 0;
2912 int increment = 0;
2913
2914 // Parse index name and intial value
2915 if (node->getInit())
2916 {
2917 TIntermAggregate *init = node->getInit()->getAsAggregate();
2918
2919 if (init)
2920 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002921 TIntermSequence *sequence = init->getSequence();
2922 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002923
2924 if (variable && variable->getQualifier() == EvqTemporary)
2925 {
2926 TIntermBinary *assign = variable->getAsBinaryNode();
2927
2928 if (assign->getOp() == EOpInitialize)
2929 {
2930 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2931 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2932
2933 if (symbol && constant)
2934 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002935 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002936 {
2937 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002938 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002939 }
2940 }
2941 }
2942 }
2943 }
2944 }
2945
2946 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002947 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002948 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002949 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002950
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002951 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2952 {
2953 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2954
2955 if (constant)
2956 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002957 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002958 {
2959 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002960 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002961 }
2962 }
2963 }
2964 }
2965
2966 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002967 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002968 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002969 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2970 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002971
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002972 if (binaryTerminal)
2973 {
2974 TOperator op = binaryTerminal->getOp();
2975 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2976
2977 if (constant)
2978 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002979 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002980 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002981 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002982
2983 switch (op)
2984 {
2985 case EOpAddAssign: increment = value; break;
2986 case EOpSubAssign: increment = -value; break;
2987 default: UNIMPLEMENTED();
2988 }
2989 }
2990 }
2991 }
2992 else if (unaryTerminal)
2993 {
2994 TOperator op = unaryTerminal->getOp();
2995
2996 switch (op)
2997 {
2998 case EOpPostIncrement: increment = 1; break;
2999 case EOpPostDecrement: increment = -1; break;
3000 case EOpPreIncrement: increment = 1; break;
3001 case EOpPreDecrement: increment = -1; break;
3002 default: UNIMPLEMENTED();
3003 }
3004 }
3005 }
3006
3007 if (index != NULL && comparator != EOpNull && increment != 0)
3008 {
3009 if (comparator == EOpLessThanEqual)
3010 {
3011 comparator = EOpLessThan;
3012 limit += 1;
3013 }
3014
3015 if (comparator == EOpLessThan)
3016 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00003017 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003018
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003019 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003020 {
3021 return false; // Not an excessive loop
3022 }
3023
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003024 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
3025 mExcessiveLoopIndex = index;
3026
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003027 out << "{int ";
3028 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003029 out << ";\n"
3030 "bool Break";
3031 index->traverse(this);
3032 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003033
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003034 bool firstLoopFragment = true;
3035
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003036 while (iterations > 0)
3037 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003038 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003039
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003040 if (!firstLoopFragment)
3041 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05003042 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003043 index->traverse(this);
3044 out << ") {\n";
3045 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00003046
3047 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
3048 {
3049 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
3050 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003051
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003052 // for(int index = initial; index < clampedLimit; index += increment)
Corentin Wallez1239ee92015-03-19 14:38:02 -07003053 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003054
Corentin Wallez1239ee92015-03-19 14:38:02 -07003055 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003056 index->traverse(this);
3057 out << " = ";
3058 out << initial;
3059
3060 out << "; ";
3061 index->traverse(this);
3062 out << " < ";
3063 out << clampedLimit;
3064
3065 out << "; ";
3066 index->traverse(this);
3067 out << " += ";
3068 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003069 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04003070
Jamie Madill8c46ab12015-12-07 16:39:19 -05003071 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003072 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003073
3074 if (node->getBody())
3075 {
3076 node->getBody()->traverse(this);
3077 }
3078
Jamie Madill8c46ab12015-12-07 16:39:19 -05003079 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003080 out << ";}\n";
3081
3082 if (!firstLoopFragment)
3083 {
3084 out << "}\n";
3085 }
3086
3087 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003088
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003089 initial += MAX_LOOP_ITERATIONS * increment;
3090 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003091 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003092
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003093 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003094
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003095 mExcessiveLoopIndex = restoreIndex;
3096
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003097 return true;
3098 }
3099 else UNIMPLEMENTED();
3100 }
3101
3102 return false; // Not handled as an excessive loop
3103}
3104
Jamie Madill8c46ab12015-12-07 16:39:19 -05003105void OutputHLSL::outputTriplet(TInfoSinkBase &out,
3106 Visit visit,
3107 const char *preString,
3108 const char *inString,
3109 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003110{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003111 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003112 {
3113 out << preString;
3114 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003115 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003116 {
3117 out << inString;
3118 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003119 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003120 {
3121 out << postString;
3122 }
3123}
3124
Jamie Madill8c46ab12015-12-07 16:39:19 -05003125void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003126{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003127 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003128 {
Jamie Madill32aab012015-01-27 14:12:26 -05003129 out << "\n";
3130 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003131
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003132 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003133 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003134 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003135 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003136
Jamie Madill32aab012015-01-27 14:12:26 -05003137 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003138 }
3139}
3140
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003141TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
3142{
3143 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003144 const TType &type = symbol->getType();
3145 const TName &name = symbol->getName();
3146 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003147
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003148 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003149 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003150 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003151 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003152 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003153 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003154 nameStr = DecorateIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003155 }
3156
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003157 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
3158 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003159 return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + nameStr +
3160 ArrayString(type) + ", " + QualifierString(qualifier) + " " + SamplerString(type) +
3161 " sampler_" + nameStr + ArrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003162 }
3163
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003164 return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003165}
3166
3167TString OutputHLSL::initializer(const TType &type)
3168{
3169 TString string;
3170
Jamie Madill94bf7f22013-07-08 13:31:15 -04003171 size_t size = type.getObjectSize();
3172 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003173 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00003174 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003175
Jamie Madill94bf7f22013-07-08 13:31:15 -04003176 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003177 {
3178 string += ", ";
3179 }
3180 }
3181
daniel@transgaming.comead23042010-04-29 03:35:36 +00003182 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003183}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003184
Jamie Madill8c46ab12015-12-07 16:39:19 -05003185void OutputHLSL::outputConstructor(TInfoSinkBase &out,
3186 Visit visit,
3187 const TType &type,
3188 const char *name,
3189 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003190{
Olli Etuahof40319e2015-03-10 14:33:00 +02003191 if (type.isArray())
3192 {
3193 UNIMPLEMENTED();
3194 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003195
3196 if (visit == PreVisit)
3197 {
Jamie Madill8daaba12014-06-13 10:04:33 -04003198 mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003199
Daniel Bratell29190082015-02-20 16:42:54 +01003200 out << name << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003201 }
3202 else if (visit == InVisit)
3203 {
3204 out << ", ";
3205 }
3206 else if (visit == PostVisit)
3207 {
3208 out << ")";
3209 }
3210}
3211
Jamie Madill8c46ab12015-12-07 16:39:19 -05003212const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3213 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003214 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003215{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003216 const TConstantUnion *constUnionIterated = constUnion;
3217
Jamie Madill98493dd2013-07-08 14:39:03 -04003218 const TStructure* structure = type.getStruct();
3219 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003220 {
Jamie Madill033dae62014-06-18 12:56:28 -04003221 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003222
Jamie Madill98493dd2013-07-08 14:39:03 -04003223 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003224
Jamie Madill98493dd2013-07-08 14:39:03 -04003225 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003226 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003227 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003228 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003229
Jamie Madill98493dd2013-07-08 14:39:03 -04003230 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003231 {
3232 out << ", ";
3233 }
3234 }
3235
3236 out << ")";
3237 }
3238 else
3239 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003240 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003241 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003242
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003243 if (writeType)
3244 {
Jamie Madill033dae62014-06-18 12:56:28 -04003245 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003246 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003247 constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003248 if (writeType)
3249 {
3250 out << ")";
3251 }
3252 }
3253
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003254 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003255}
3256
Jamie Madill8c46ab12015-12-07 16:39:19 -05003257void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003258{
3259 TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
Jamie Madill8c46ab12015-12-07 16:39:19 -05003260 outputTriplet(out, visit, preString.c_str(), ", ", ")");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003261}
3262
Jamie Madill37997142015-01-28 10:06:34 -05003263bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
3264{
3265 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
3266 expression->traverse(&searchSymbol);
3267
3268 if (searchSymbol.foundMatch())
3269 {
3270 // Type already printed
3271 out << "t" + str(mUniqueIndex) + " = ";
3272 expression->traverse(this);
3273 out << ", ";
3274 symbolNode->traverse(this);
3275 out << " = t" + str(mUniqueIndex);
3276
3277 mUniqueIndex++;
3278 return true;
3279 }
3280
3281 return false;
3282}
3283
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003284bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
3285{
3286 // We support writing constant unions and constructors that only take constant unions as
3287 // parameters as HLSL literals.
3288 if (expression->getAsConstantUnion())
3289 {
3290 return true;
3291 }
3292 if (expression->getQualifier() != EvqConst || !expression->getAsAggregate() ||
3293 !expression->getAsAggregate()->isConstructor())
3294 {
3295 return false;
3296 }
3297 TIntermAggregate *constructor = expression->getAsAggregate();
3298 for (TIntermNode *&node : *constructor->getSequence())
3299 {
3300 if (!node->getAsConstantUnion())
3301 return false;
3302 }
3303 return true;
3304}
3305
3306bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3307 TIntermSymbol *symbolNode,
3308 TIntermTyped *expression)
3309{
3310 if (canWriteAsHLSLLiteral(expression))
3311 {
3312 symbolNode->traverse(this);
3313 if (expression->getType().isArray())
3314 {
3315 out << "[" << expression->getType().getArraySize() << "]";
3316 }
3317 out << " = {";
3318 if (expression->getAsConstantUnion())
3319 {
3320 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
3321 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3322 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3323 }
3324 else
3325 {
3326 TIntermAggregate *constructor = expression->getAsAggregate();
3327 ASSERT(constructor != nullptr);
3328 for (TIntermNode *&node : *constructor->getSequence())
3329 {
3330 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
3331 ASSERT(nodeConst);
3332 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3333 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3334 if (node != constructor->getSequence()->back())
3335 {
3336 out << ", ";
3337 }
3338 }
3339 }
3340 out << "}";
3341 return true;
3342 }
3343 return false;
3344}
3345
Jamie Madill37997142015-01-28 10:06:34 -05003346void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
3347{
3348 out << "#define ANGLE_USES_DEFERRED_INIT\n"
3349 << "\n"
3350 << "void initializeDeferredGlobals()\n"
3351 << "{\n";
3352
3353 for (const auto &deferredGlobal : mDeferredGlobalInitializers)
3354 {
Olli Etuahod81ed842015-05-12 12:46:35 +03003355 TIntermBinary *binary = deferredGlobal->getAsBinaryNode();
3356 TIntermSelection *selection = deferredGlobal->getAsSelectionNode();
3357 if (binary != nullptr)
3358 {
3359 TIntermSymbol *symbol = binary->getLeft()->getAsSymbolNode();
3360 TIntermTyped *expression = binary->getRight();
3361 ASSERT(symbol);
3362 ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
Jamie Madill37997142015-01-28 10:06:34 -05003363
Olli Etuahod81ed842015-05-12 12:46:35 +03003364 out << " " << Decorate(symbol->getSymbol()) << " = ";
Jamie Madill37997142015-01-28 10:06:34 -05003365
Olli Etuahod81ed842015-05-12 12:46:35 +03003366 if (!writeSameSymbolInitializer(out, symbol, expression))
3367 {
3368 ASSERT(mInfoSinkStack.top() == &out);
3369 expression->traverse(this);
3370 }
3371 out << ";\n";
3372 }
3373 else if (selection != nullptr)
Jamie Madill37997142015-01-28 10:06:34 -05003374 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05003375 writeSelection(out, selection);
Jamie Madill37997142015-01-28 10:06:34 -05003376 }
Olli Etuahod81ed842015-05-12 12:46:35 +03003377 else
3378 {
3379 UNREACHABLE();
3380 }
Jamie Madill37997142015-01-28 10:06:34 -05003381 }
3382
3383 out << "}\n"
3384 << "\n";
3385}
3386
Jamie Madill55e79e02015-02-09 15:35:00 -05003387TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3388{
3389 const TFieldList &fields = structure.fields();
3390
3391 for (const auto &eqFunction : mStructEqualityFunctions)
3392 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003393 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003394 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003395 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003396 }
3397 }
3398
3399 const TString &structNameString = StructNameString(structure);
3400
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003401 StructEqualityFunction *function = new StructEqualityFunction();
3402 function->structure = &structure;
3403 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003404
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003405 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003406
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003407 fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n"
3408 << "{\n"
3409 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003410
3411 for (size_t i = 0; i < fields.size(); i++)
3412 {
3413 const TField *field = fields[i];
3414 const TType *fieldType = field->type();
3415
3416 const TString &fieldNameA = "a." + Decorate(field->name());
3417 const TString &fieldNameB = "b." + Decorate(field->name());
3418
3419 if (i > 0)
3420 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003421 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003422 }
3423
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003424 fnOut << "(";
3425 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3426 fnOut << fieldNameA;
3427 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3428 fnOut << fieldNameB;
3429 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3430 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003431 }
3432
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003433 fnOut << ";\n" << "}\n";
3434
3435 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003436
3437 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003438 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003439
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003440 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003441}
3442
Olli Etuaho7fb49552015-03-18 17:27:44 +02003443TString OutputHLSL::addArrayEqualityFunction(const TType& type)
3444{
3445 for (const auto &eqFunction : mArrayEqualityFunctions)
3446 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003447 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003448 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003449 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003450 }
3451 }
3452
3453 const TString &typeName = TypeString(type);
3454
Olli Etuaho12690762015-03-31 12:55:28 +03003455 ArrayHelperFunction *function = new ArrayHelperFunction();
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003456 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003457
3458 TInfoSinkBase fnNameOut;
3459 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003460 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003461
3462 TType nonArrayType = type;
3463 nonArrayType.clearArrayness();
3464
3465 TInfoSinkBase fnOut;
3466
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003467 fnOut << "bool " << function->functionName << "("
Olli Etuahofc7cfd12015-03-31 14:46:18 +03003468 << typeName << " a[" << type.getArraySize() << "], "
3469 << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003470 << "{\n"
3471 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3472 " {\n"
3473 " if (";
3474
3475 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
3476 fnOut << "a[i]";
3477 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
3478 fnOut << "b[i]";
3479 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
3480
3481 fnOut << ") { return false; }\n"
3482 " }\n"
3483 " return true;\n"
3484 "}\n";
3485
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003486 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003487
3488 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003489 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003490
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003491 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003492}
3493
Olli Etuaho12690762015-03-31 12:55:28 +03003494TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
3495{
3496 for (const auto &assignFunction : mArrayAssignmentFunctions)
3497 {
3498 if (assignFunction.type == type)
3499 {
3500 return assignFunction.functionName;
3501 }
3502 }
3503
3504 const TString &typeName = TypeString(type);
3505
3506 ArrayHelperFunction function;
3507 function.type = type;
3508
3509 TInfoSinkBase fnNameOut;
3510 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
3511 function.functionName = fnNameOut.c_str();
3512
3513 TInfoSinkBase fnOut;
3514
3515 fnOut << "void " << function.functionName << "(out "
3516 << typeName << " a[" << type.getArraySize() << "], "
3517 << typeName << " b[" << type.getArraySize() << "])\n"
3518 << "{\n"
3519 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3520 " {\n"
3521 " a[i] = b[i];\n"
3522 " }\n"
3523 "}\n";
3524
3525 function.functionDefinition = fnOut.c_str();
3526
3527 mArrayAssignmentFunctions.push_back(function);
3528
3529 return function.functionName;
3530}
3531
Olli Etuaho9638c352015-04-01 14:34:52 +03003532TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
3533{
3534 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3535 {
3536 if (constructIntoFunction.type == type)
3537 {
3538 return constructIntoFunction.functionName;
3539 }
3540 }
3541
3542 const TString &typeName = TypeString(type);
3543
3544 ArrayHelperFunction function;
3545 function.type = type;
3546
3547 TInfoSinkBase fnNameOut;
3548 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
3549 function.functionName = fnNameOut.c_str();
3550
3551 TInfoSinkBase fnOut;
3552
3553 fnOut << "void " << function.functionName << "(out "
3554 << typeName << " a[" << type.getArraySize() << "]";
3555 for (int i = 0; i < type.getArraySize(); ++i)
3556 {
3557 fnOut << ", " << typeName << " b" << i;
3558 }
3559 fnOut << ")\n"
3560 "{\n";
3561
3562 for (int i = 0; i < type.getArraySize(); ++i)
3563 {
3564 fnOut << " a[" << i << "] = b" << i << ";\n";
3565 }
3566 fnOut << "}\n";
3567
3568 function.functionDefinition = fnOut.c_str();
3569
3570 mArrayConstructIntoFunctions.push_back(function);
3571
3572 return function.functionName;
3573}
3574
Jamie Madill2e295e22015-04-29 10:41:33 -04003575void OutputHLSL::ensureStructDefined(const TType &type)
3576{
3577 TStructure *structure = type.getStruct();
3578
3579 if (structure)
3580 {
3581 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3582 }
3583}
3584
3585
Olli Etuaho9638c352015-04-01 14:34:52 +03003586
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003587}