blob: 36c423ca659acf00dbdb4f58a752443115ad8d44 [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 Madill7a6a1ff2015-12-07 16:32:58 -05001119 TString closex = "";
1120 TString closey = "";
1121 TString closez = "";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001122
Nicolas Capensfc014542014-02-18 14:47:13 -05001123 if (IsIntegerSampler(textureFunction->sampler) ||
1124 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001125 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001126 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001127 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001128 case 2: out << "int3("; break;
1129 case 3: out << "int4("; break;
1130 default: UNREACHABLE();
1131 }
Jamie Madillf91ce812014-06-13 10:04:34 -04001132
Nicolas Capensfc014542014-02-18 14:47:13 -05001133 // Convert from normalized floating-point to integer
1134 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001135 {
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001136 // We hard-code the clamp wrap mode for integer textures.
1137 // TODO(jmadill): Figure out how to integer texture wrap modes.
1138 addressx = "int(clamp(round((width *";
1139 addressy = "int(clamp(round((height * ";
1140 closex = ") - 0.5f), 0.0f, width - 1.0f))";
1141 closey = ") - 0.5f), 0.0f, height - 1.0f))";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001142
Nicolas Capensfc014542014-02-18 14:47:13 -05001143 if (IsSamplerArray(textureFunction->sampler))
1144 {
1145 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001146 closez = "))))";
Nicolas Capensfc014542014-02-18 14:47:13 -05001147 }
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001148 else if (IsSampler3D(textureFunction->sampler))
Nicolas Capens0027fa92014-02-20 14:26:42 -05001149 {
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001150 addressz = "int(clamp(round((depth * ";
1151 closez = ") - 0.5f), 0.0f, depth - 1.0f))";
Nicolas Capens0027fa92014-02-20 14:26:42 -05001152 }
Nicolas Capensfc014542014-02-18 14:47:13 -05001153 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001154 }
1155 else
1156 {
1157 switch(hlslCoords)
1158 {
1159 case 2: out << "float2("; break;
1160 case 3: out << "float3("; break;
1161 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001162 default: UNREACHABLE();
1163 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001164 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001165
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001166 TString proj = ""; // Only used for projected textures
Jamie Madillf91ce812014-06-13 10:04:34 -04001167
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001168 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001169 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001170 switch(textureFunction->coords)
1171 {
1172 case 3: proj = " / t.z"; break;
1173 case 4: proj = " / t.w"; break;
1174 default: UNREACHABLE();
1175 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001176 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001177
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001178 out << addressx + ("t.x" + proj) + closex + ", " + addressy + ("t.y" + proj) + closey;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001179
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001180 if (mOutputType == SH_HLSL9_OUTPUT)
1181 {
1182 if (hlslCoords >= 3)
1183 {
1184 if (textureFunction->coords < 3)
1185 {
1186 out << ", 0";
1187 }
1188 else
1189 {
1190 out << ", t.z" + proj;
1191 }
1192 }
1193
1194 if (hlslCoords == 4)
1195 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001196 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001197 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001198 case TextureFunction::BIAS: out << ", bias"; break;
1199 case TextureFunction::LOD: out << ", lod"; break;
1200 case TextureFunction::LOD0: out << ", 0"; break;
1201 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001202 default: UNREACHABLE();
1203 }
1204 }
1205
1206 out << "));\n";
1207 }
1208 else if (mOutputType == SH_HLSL11_OUTPUT)
1209 {
1210 if (hlslCoords >= 3)
1211 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001212 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1213 {
1214 out << ", face";
1215 }
1216 else
1217 {
Jamie Madill7a6a1ff2015-12-07 16:32:58 -05001218 out << ", " + addressz + ("t.z" + proj) + closez;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001219 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001220 }
1221
Nicolas Capensd11d5492014-02-19 17:06:10 -05001222 if (textureFunction->method == TextureFunction::GRAD)
1223 {
1224 if (IsIntegerSampler(textureFunction->sampler))
1225 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001226 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001227 }
1228 else if (IsShadowSampler(textureFunction->sampler))
1229 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001230 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001231 if (textureFunction->proj)
Nicolas Capensd11d5492014-02-19 17:06:10 -05001232 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001233 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1234 // The resulting third component of P' in the shadow forms is used as Dref
1235 out << "), t.z" << proj;
1236 }
1237 else
1238 {
1239 switch(textureFunction->coords)
1240 {
1241 case 3: out << "), t.z"; break;
1242 case 4: out << "), t.w"; break;
1243 default: UNREACHABLE();
1244 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001245 }
1246 }
1247 else
1248 {
1249 out << "), ddx, ddy";
1250 }
1251 }
1252 else if (IsIntegerSampler(textureFunction->sampler) ||
1253 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001254 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001255 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001256 }
1257 else if (IsShadowSampler(textureFunction->sampler))
1258 {
1259 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001260 if (textureFunction->proj)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001261 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001262 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1263 // The resulting third component of P' in the shadow forms is used as Dref
1264 out << "), t.z" << proj;
1265 }
1266 else
1267 {
1268 switch(textureFunction->coords)
1269 {
1270 case 3: out << "), t.z"; break;
1271 case 4: out << "), t.w"; break;
1272 default: UNREACHABLE();
1273 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001274 }
1275 }
1276 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001277 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001278 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001279 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001280 case TextureFunction::IMPLICIT: out << ")"; break;
1281 case TextureFunction::BIAS: out << "), bias"; break;
1282 case TextureFunction::LOD: out << "), lod"; break;
1283 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001284 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001285 default: UNREACHABLE();
1286 }
1287 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001288
1289 if (textureFunction->offset)
1290 {
1291 out << ", offset";
1292 }
1293
1294 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001295 }
1296 else UNREACHABLE();
1297 }
1298
1299 out << "\n"
1300 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001301 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001302 }
1303
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001304 if (mUsesFragCoord)
1305 {
1306 out << "#define GL_USES_FRAG_COORD\n";
1307 }
1308
1309 if (mUsesPointCoord)
1310 {
1311 out << "#define GL_USES_POINT_COORD\n";
1312 }
1313
1314 if (mUsesFrontFacing)
1315 {
1316 out << "#define GL_USES_FRONT_FACING\n";
1317 }
1318
1319 if (mUsesPointSize)
1320 {
1321 out << "#define GL_USES_POINT_SIZE\n";
1322 }
1323
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001324 if (mUsesFragDepth)
1325 {
1326 out << "#define GL_USES_FRAG_DEPTH\n";
1327 }
1328
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001329 if (mUsesDepthRange)
1330 {
1331 out << "#define GL_USES_DEPTH_RANGE\n";
1332 }
1333
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001334 if (mUsesXor)
1335 {
1336 out << "bool xor(bool p, bool q)\n"
1337 "{\n"
1338 " return (p || q) && !(p && q);\n"
1339 "}\n"
1340 "\n";
1341 }
1342
Olli Etuaho95cd3c62015-03-03 16:45:32 +02001343 builtInFunctionEmulator->OutputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001344}
1345
1346void OutputHLSL::visitSymbol(TIntermSymbol *node)
1347{
Jamie Madill32aab012015-01-27 14:12:26 -05001348 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349
Jamie Madill570e04d2013-06-21 09:15:33 -04001350 // Handle accessing std140 structs by value
1351 if (mFlaggedStructMappedNames.count(node) > 0)
1352 {
1353 out << mFlaggedStructMappedNames[node];
1354 return;
1355 }
1356
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001357 TString name = node->getSymbol();
1358
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001359 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001360 {
1361 mUsesDepthRange = true;
1362 out << name;
1363 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001364 else
1365 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001366 TQualifier qualifier = node->getQualifier();
1367
1368 if (qualifier == EvqUniform)
1369 {
Jamie Madill2e295e22015-04-29 10:41:33 -04001370 const TType &nodeType = node->getType();
1371 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001372
1373 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001374 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001375 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001376 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001377 else
1378 {
1379 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001380 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001381
Jamie Madill2e295e22015-04-29 10:41:33 -04001382 ensureStructDefined(nodeType);
1383
Jamie Madill033dae62014-06-18 12:56:28 -04001384 out << DecorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001385 }
Jamie Madill19571812013-08-12 15:26:34 -07001386 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001387 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001388 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001389 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001390 }
Jamie Madill033dae62014-06-18 12:56:28 -04001391 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001392 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001393 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001394 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001395 }
Jamie Madill19571812013-08-12 15:26:34 -07001396 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001397 {
1398 mReferencedOutputVariables[name] = node;
1399 out << "out_" << name;
1400 }
1401 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001402 {
1403 out << "gl_Color[0]";
1404 mUsesFragColor = true;
1405 }
1406 else if (qualifier == EvqFragData)
1407 {
1408 out << "gl_Color";
1409 mUsesFragData = true;
1410 }
1411 else if (qualifier == EvqFragCoord)
1412 {
1413 mUsesFragCoord = true;
1414 out << name;
1415 }
1416 else if (qualifier == EvqPointCoord)
1417 {
1418 mUsesPointCoord = true;
1419 out << name;
1420 }
1421 else if (qualifier == EvqFrontFacing)
1422 {
1423 mUsesFrontFacing = true;
1424 out << name;
1425 }
1426 else if (qualifier == EvqPointSize)
1427 {
1428 mUsesPointSize = true;
1429 out << name;
1430 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001431 else if (qualifier == EvqInstanceID)
1432 {
1433 mUsesInstanceID = true;
1434 out << name;
1435 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001436 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001437 {
1438 mUsesFragDepth = true;
1439 out << "gl_Depth";
1440 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001441 else
1442 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03001443 out << DecorateIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001444 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001445 }
1446}
1447
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001448void OutputHLSL::visitRaw(TIntermRaw *node)
1449{
Jamie Madill32aab012015-01-27 14:12:26 -05001450 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001451}
1452
Olli Etuaho7fb49552015-03-18 17:27:44 +02001453void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1454{
1455 if (type.isScalar() && !type.isArray())
1456 {
1457 if (op == EOpEqual)
1458 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001459 outputTriplet(out, visit, "(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001460 }
1461 else
1462 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001463 outputTriplet(out, visit, "(", " != ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001464 }
1465 }
1466 else
1467 {
1468 if (visit == PreVisit && op == EOpNotEqual)
1469 {
1470 out << "!";
1471 }
1472
1473 if (type.isArray())
1474 {
1475 const TString &functionName = addArrayEqualityFunction(type);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001476 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001477 }
1478 else if (type.getBasicType() == EbtStruct)
1479 {
1480 const TStructure &structure = *type.getStruct();
1481 const TString &functionName = addStructEqualityFunction(structure);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001482 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001483 }
1484 else
1485 {
1486 ASSERT(type.isMatrix() || type.isVector());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001487 outputTriplet(out, visit, "all(", " == ", ")");
Olli Etuaho7fb49552015-03-18 17:27:44 +02001488 }
1489 }
1490}
1491
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001492bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1493{
Jamie Madill32aab012015-01-27 14:12:26 -05001494 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495
Jamie Madill570e04d2013-06-21 09:15:33 -04001496 // Handle accessing std140 structs by value
1497 if (mFlaggedStructMappedNames.count(node) > 0)
1498 {
1499 out << mFlaggedStructMappedNames[node];
1500 return false;
1501 }
1502
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001503 switch (node->getOp())
1504 {
Olli Etuahoe79904c2015-03-18 16:56:42 +02001505 case EOpAssign:
1506 if (node->getLeft()->isArray())
1507 {
Olli Etuaho9638c352015-04-01 14:34:52 +03001508 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1509 if (rightAgg != nullptr && rightAgg->isConstructor())
1510 {
1511 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1512 out << functionName << "(";
1513 node->getLeft()->traverse(this);
1514 TIntermSequence *seq = rightAgg->getSequence();
1515 for (auto &arrayElement : *seq)
1516 {
1517 out << ", ";
1518 arrayElement->traverse(this);
1519 }
1520 out << ")";
1521 return false;
1522 }
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001523 // ArrayReturnValueToOutParameter should have eliminated expressions where a function call is assigned.
1524 ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
1525
1526 const TString &functionName = addArrayAssignmentFunction(node->getType());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001527 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuahoe79904c2015-03-18 16:56:42 +02001528 }
1529 else
1530 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001531 outputTriplet(out, visit, "(", " = ", ")");
Olli Etuahoe79904c2015-03-18 16:56:42 +02001532 }
1533 break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001534 case EOpInitialize:
1535 if (visit == PreVisit)
1536 {
1537 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1538 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1539 // new variable is created before the assignment is evaluated), so we need to convert
1540 // this to "float t = x, x = t;".
1541
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001542 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
Jamie Madill37997142015-01-28 10:06:34 -05001543 ASSERT(symbolNode);
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001544 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001545
Jamie Madill37997142015-01-28 10:06:34 -05001546 // TODO (jmadill): do a 'deep' scan to know if an expression is statically const
1547 if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst)
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001548 {
Jamie Madill37997142015-01-28 10:06:34 -05001549 // For variables which are not constant, defer their real initialization until
Olli Etuahod81ed842015-05-12 12:46:35 +03001550 // after we initialize uniforms.
1551 TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
1552 deferredInit->setLeft(node->getLeft());
1553 deferredInit->setRight(node->getRight());
1554 deferredInit->setType(node->getType());
1555 mDeferredGlobalInitializers.push_back(deferredInit);
Jamie Madill37997142015-01-28 10:06:34 -05001556 const TString &initString = initializer(node->getType());
1557 node->setRight(new TIntermRaw(node->getType(), initString));
1558 }
1559 else if (writeSameSymbolInitializer(out, symbolNode, expression))
1560 {
1561 // Skip initializing the rest of the expression
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001562 return false;
1563 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001564 else if (writeConstantInitialization(out, symbolNode, expression))
1565 {
1566 return false;
1567 }
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001568 }
1569 else if (visit == InVisit)
1570 {
1571 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001572 }
1573 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001574 case EOpAddAssign:
1575 outputTriplet(out, visit, "(", " += ", ")");
1576 break;
1577 case EOpSubAssign:
1578 outputTriplet(out, visit, "(", " -= ", ")");
1579 break;
1580 case EOpMulAssign:
1581 outputTriplet(out, visit, "(", " *= ", ")");
1582 break;
1583 case EOpVectorTimesScalarAssign:
1584 outputTriplet(out, visit, "(", " *= ", ")");
1585 break;
1586 case EOpMatrixTimesScalarAssign:
1587 outputTriplet(out, visit, "(", " *= ", ")");
1588 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001589 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001590 if (visit == PreVisit)
1591 {
1592 out << "(";
1593 }
1594 else if (visit == InVisit)
1595 {
1596 out << " = mul(";
1597 node->getLeft()->traverse(this);
Jamie Madillf91ce812014-06-13 10:04:34 -04001598 out << ", transpose(";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001599 }
1600 else
1601 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001602 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001603 }
1604 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001605 case EOpMatrixTimesMatrixAssign:
1606 if (visit == PreVisit)
1607 {
1608 out << "(";
1609 }
1610 else if (visit == InVisit)
1611 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001612 out << " = transpose(mul(transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001613 node->getLeft()->traverse(this);
Olli Etuahofc7fab72015-03-06 12:03:18 +02001614 out << "), transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001615 }
1616 else
1617 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001618 out << "))))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001619 }
1620 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001621 case EOpDivAssign:
1622 outputTriplet(out, visit, "(", " /= ", ")");
1623 break;
1624 case EOpIModAssign:
1625 outputTriplet(out, visit, "(", " %= ", ")");
1626 break;
1627 case EOpBitShiftLeftAssign:
1628 outputTriplet(out, visit, "(", " <<= ", ")");
1629 break;
1630 case EOpBitShiftRightAssign:
1631 outputTriplet(out, visit, "(", " >>= ", ")");
1632 break;
1633 case EOpBitwiseAndAssign:
1634 outputTriplet(out, visit, "(", " &= ", ")");
1635 break;
1636 case EOpBitwiseXorAssign:
1637 outputTriplet(out, visit, "(", " ^= ", ")");
1638 break;
1639 case EOpBitwiseOrAssign:
1640 outputTriplet(out, visit, "(", " |= ", ")");
1641 break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001642 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001643 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001644 const TType& leftType = node->getLeft()->getType();
1645 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001646 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001647 if (visit == PreVisit)
1648 {
1649 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1650 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001651 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001652 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001653 return false;
1654 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001655 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001656 else
1657 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001658 outputTriplet(out, visit, "", "[", "]");
Jamie Madill98493dd2013-07-08 14:39:03 -04001659 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001660 }
1661 break;
1662 case EOpIndexIndirect:
1663 // We do not currently support indirect references to interface blocks
1664 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
Jamie Madill8c46ab12015-12-07 16:39:19 -05001665 outputTriplet(out, visit, "", "[", "]");
Jamie Madillb4e664b2013-06-20 11:55:54 -04001666 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001667 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001668 if (visit == InVisit)
1669 {
1670 const TStructure* structure = node->getLeft()->getType().getStruct();
1671 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1672 const TField* field = structure->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001673 out << "." + DecorateField(field->name(), *structure);
Jamie Madill98493dd2013-07-08 14:39:03 -04001674
1675 return false;
1676 }
1677 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001678 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001679 if (visit == InVisit)
1680 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001681 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1682 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1683 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001684 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001685
1686 return false;
1687 }
1688 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001689 case EOpVectorSwizzle:
1690 if (visit == InVisit)
1691 {
1692 out << ".";
1693
1694 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1695
1696 if (swizzle)
1697 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001698 TIntermSequence *sequence = swizzle->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001699
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001700 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001701 {
1702 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1703
1704 if (element)
1705 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00001706 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707
1708 switch (i)
1709 {
1710 case 0: out << "x"; break;
1711 case 1: out << "y"; break;
1712 case 2: out << "z"; break;
1713 case 3: out << "w"; break;
1714 default: UNREACHABLE();
1715 }
1716 }
1717 else UNREACHABLE();
1718 }
1719 }
1720 else UNREACHABLE();
1721
1722 return false; // Fully processed
1723 }
1724 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001725 case EOpAdd:
1726 outputTriplet(out, visit, "(", " + ", ")");
1727 break;
1728 case EOpSub:
1729 outputTriplet(out, visit, "(", " - ", ")");
1730 break;
1731 case EOpMul:
1732 outputTriplet(out, visit, "(", " * ", ")");
1733 break;
1734 case EOpDiv:
1735 outputTriplet(out, visit, "(", " / ", ")");
1736 break;
1737 case EOpIMod:
1738 outputTriplet(out, visit, "(", " % ", ")");
1739 break;
1740 case EOpBitShiftLeft:
1741 outputTriplet(out, visit, "(", " << ", ")");
1742 break;
1743 case EOpBitShiftRight:
1744 outputTriplet(out, visit, "(", " >> ", ")");
1745 break;
1746 case EOpBitwiseAnd:
1747 outputTriplet(out, visit, "(", " & ", ")");
1748 break;
1749 case EOpBitwiseXor:
1750 outputTriplet(out, visit, "(", " ^ ", ")");
1751 break;
1752 case EOpBitwiseOr:
1753 outputTriplet(out, visit, "(", " | ", ")");
1754 break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001755 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001756 case EOpNotEqual:
Olli Etuaho7fb49552015-03-18 17:27:44 +02001757 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001758 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001759 case EOpLessThan:
1760 outputTriplet(out, visit, "(", " < ", ")");
1761 break;
1762 case EOpGreaterThan:
1763 outputTriplet(out, visit, "(", " > ", ")");
1764 break;
1765 case EOpLessThanEqual:
1766 outputTriplet(out, visit, "(", " <= ", ")");
1767 break;
1768 case EOpGreaterThanEqual:
1769 outputTriplet(out, visit, "(", " >= ", ")");
1770 break;
1771 case EOpVectorTimesScalar:
1772 outputTriplet(out, visit, "(", " * ", ")");
1773 break;
1774 case EOpMatrixTimesScalar:
1775 outputTriplet(out, visit, "(", " * ", ")");
1776 break;
1777 case EOpVectorTimesMatrix:
1778 outputTriplet(out, visit, "mul(", ", transpose(", "))");
1779 break;
1780 case EOpMatrixTimesVector:
1781 outputTriplet(out, visit, "mul(transpose(", "), ", ")");
1782 break;
1783 case EOpMatrixTimesMatrix:
1784 outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
1785 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001786 case EOpLogicalOr:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001787 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
1788 ASSERT(!node->getRight()->hasSideEffects());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001789 outputTriplet(out, visit, "(", " || ", ")");
Olli Etuahoa6f22092015-05-08 18:31:10 +03001790 return true;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001791 case EOpLogicalXor:
1792 mUsesXor = true;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001793 outputTriplet(out, visit, "xor(", ", ", ")");
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001794 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001795 case EOpLogicalAnd:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001796 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
1797 ASSERT(!node->getRight()->hasSideEffects());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001798 outputTriplet(out, visit, "(", " && ", ")");
Olli Etuahoa6f22092015-05-08 18:31:10 +03001799 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001800 default: UNREACHABLE();
1801 }
1802
1803 return true;
1804}
1805
1806bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1807{
Jamie Madill8c46ab12015-12-07 16:39:19 -05001808 TInfoSinkBase &out = getInfoSink();
1809
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001810 switch (node->getOp())
1811 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001812 case EOpNegative:
1813 outputTriplet(out, visit, "(-", "", ")");
1814 break;
1815 case EOpPositive:
1816 outputTriplet(out, visit, "(+", "", ")");
1817 break;
1818 case EOpVectorLogicalNot:
1819 outputTriplet(out, visit, "(!", "", ")");
1820 break;
1821 case EOpLogicalNot:
1822 outputTriplet(out, visit, "(!", "", ")");
1823 break;
1824 case EOpBitwiseNot:
1825 outputTriplet(out, visit, "(~", "", ")");
1826 break;
1827 case EOpPostIncrement:
1828 outputTriplet(out, visit, "(", "", "++)");
1829 break;
1830 case EOpPostDecrement:
1831 outputTriplet(out, visit, "(", "", "--)");
1832 break;
1833 case EOpPreIncrement:
1834 outputTriplet(out, visit, "(++", "", ")");
1835 break;
1836 case EOpPreDecrement:
1837 outputTriplet(out, visit, "(--", "", ")");
1838 break;
1839 case EOpRadians:
1840 outputTriplet(out, visit, "radians(", "", ")");
1841 break;
1842 case EOpDegrees:
1843 outputTriplet(out, visit, "degrees(", "", ")");
1844 break;
1845 case EOpSin:
1846 outputTriplet(out, visit, "sin(", "", ")");
1847 break;
1848 case EOpCos:
1849 outputTriplet(out, visit, "cos(", "", ")");
1850 break;
1851 case EOpTan:
1852 outputTriplet(out, visit, "tan(", "", ")");
1853 break;
1854 case EOpAsin:
1855 outputTriplet(out, visit, "asin(", "", ")");
1856 break;
1857 case EOpAcos:
1858 outputTriplet(out, visit, "acos(", "", ")");
1859 break;
1860 case EOpAtan:
1861 outputTriplet(out, visit, "atan(", "", ")");
1862 break;
1863 case EOpSinh:
1864 outputTriplet(out, visit, "sinh(", "", ")");
1865 break;
1866 case EOpCosh:
1867 outputTriplet(out, visit, "cosh(", "", ")");
1868 break;
1869 case EOpTanh:
1870 outputTriplet(out, visit, "tanh(", "", ")");
1871 break;
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001872 case EOpAsinh:
1873 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001874 writeEmulatedFunctionTriplet(out, visit, "asinh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001875 break;
1876 case EOpAcosh:
1877 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001878 writeEmulatedFunctionTriplet(out, visit, "acosh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001879 break;
1880 case EOpAtanh:
1881 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001882 writeEmulatedFunctionTriplet(out, visit, "atanh(");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001883 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001884 case EOpExp:
1885 outputTriplet(out, visit, "exp(", "", ")");
1886 break;
1887 case EOpLog:
1888 outputTriplet(out, visit, "log(", "", ")");
1889 break;
1890 case EOpExp2:
1891 outputTriplet(out, visit, "exp2(", "", ")");
1892 break;
1893 case EOpLog2:
1894 outputTriplet(out, visit, "log2(", "", ")");
1895 break;
1896 case EOpSqrt:
1897 outputTriplet(out, visit, "sqrt(", "", ")");
1898 break;
1899 case EOpInverseSqrt:
1900 outputTriplet(out, visit, "rsqrt(", "", ")");
1901 break;
1902 case EOpAbs:
1903 outputTriplet(out, visit, "abs(", "", ")");
1904 break;
1905 case EOpSign:
1906 outputTriplet(out, visit, "sign(", "", ")");
1907 break;
1908 case EOpFloor:
1909 outputTriplet(out, visit, "floor(", "", ")");
1910 break;
1911 case EOpTrunc:
1912 outputTriplet(out, visit, "trunc(", "", ")");
1913 break;
1914 case EOpRound:
1915 outputTriplet(out, visit, "round(", "", ")");
1916 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -08001917 case EOpRoundEven:
1918 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001919 writeEmulatedFunctionTriplet(out, visit, "roundEven(");
Qingqing Deng5dbece52015-02-27 20:35:38 -08001920 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001921 case EOpCeil:
1922 outputTriplet(out, visit, "ceil(", "", ")");
1923 break;
1924 case EOpFract:
1925 outputTriplet(out, visit, "frac(", "", ")");
1926 break;
Arun Patole44efa0b2015-03-04 17:11:05 +05301927 case EOpIsNan:
Jamie Madill8c46ab12015-12-07 16:39:19 -05001928 outputTriplet(out, visit, "isnan(", "", ")");
Arun Patole44efa0b2015-03-04 17:11:05 +05301929 mRequiresIEEEStrictCompiling = true;
1930 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001931 case EOpIsInf:
1932 outputTriplet(out, visit, "isinf(", "", ")");
1933 break;
1934 case EOpFloatBitsToInt:
1935 outputTriplet(out, visit, "asint(", "", ")");
1936 break;
1937 case EOpFloatBitsToUint:
1938 outputTriplet(out, visit, "asuint(", "", ")");
1939 break;
1940 case EOpIntBitsToFloat:
1941 outputTriplet(out, visit, "asfloat(", "", ")");
1942 break;
1943 case EOpUintBitsToFloat:
1944 outputTriplet(out, visit, "asfloat(", "", ")");
1945 break;
Olli Etuaho7700ff62015-01-15 12:16:29 +02001946 case EOpPackSnorm2x16:
1947 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001948 writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001949 break;
1950 case EOpPackUnorm2x16:
1951 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001952 writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001953 break;
1954 case EOpPackHalf2x16:
1955 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001956 writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001957 break;
1958 case EOpUnpackSnorm2x16:
1959 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001960 writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001961 break;
1962 case EOpUnpackUnorm2x16:
1963 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001964 writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001965 break;
1966 case EOpUnpackHalf2x16:
1967 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05001968 writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
Olli Etuaho7700ff62015-01-15 12:16:29 +02001969 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05001970 case EOpLength:
1971 outputTriplet(out, visit, "length(", "", ")");
1972 break;
1973 case EOpNormalize:
1974 outputTriplet(out, visit, "normalize(", "", ")");
1975 break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001976 case EOpDFdx:
1977 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1978 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001979 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001980 }
1981 else
1982 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001983 outputTriplet(out, visit, "ddx(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001984 }
1985 break;
1986 case EOpDFdy:
1987 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1988 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001989 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001990 }
1991 else
1992 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001993 outputTriplet(out, visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001994 }
1995 break;
1996 case EOpFwidth:
1997 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1998 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05001999 outputTriplet(out, visit, "(", "", ", 0.0)");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002000 }
2001 else
2002 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002003 outputTriplet(out, visit, "fwidth(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002004 }
2005 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002006 case EOpTranspose:
2007 outputTriplet(out, visit, "transpose(", "", ")");
2008 break;
2009 case EOpDeterminant:
2010 outputTriplet(out, visit, "determinant(transpose(", "", "))");
2011 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +02002012 case EOpInverse:
2013 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002014 writeEmulatedFunctionTriplet(out, visit, "inverse(");
Olli Etuahoabf6dad2015-01-14 14:45:16 +02002015 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02002016
Jamie Madill8c46ab12015-12-07 16:39:19 -05002017 case EOpAny:
2018 outputTriplet(out, visit, "any(", "", ")");
2019 break;
2020 case EOpAll:
2021 outputTriplet(out, visit, "all(", "", ")");
2022 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 default: UNREACHABLE();
2024 }
2025
2026 return true;
2027}
2028
2029bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2030{
Jamie Madill32aab012015-01-27 14:12:26 -05002031 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002032
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002033 switch (node->getOp())
2034 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002035 case EOpSequence:
2036 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002037 if (mInsideFunction)
2038 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002039 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002040 out << "{\n";
2041 }
2042
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002043 for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002044 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002045 outputLineDirective(out, (*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002046
Olli Etuahoa6f22092015-05-08 18:31:10 +03002047 (*sit)->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002048
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002049 // Don't output ; after case labels, they're terminated by :
2050 // This is needed especially since outputting a ; after a case statement would turn empty
2051 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho4785fec2015-05-18 16:09:37 +03002052 // Also no need to output ; after selection (if) statements or sequences. This is done just
2053 // for code clarity.
Olli Etuahoa6f22092015-05-08 18:31:10 +03002054 TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
2055 ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
Olli Etuaho4785fec2015-05-18 16:09:37 +03002056 if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002057 out << ";\n";
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002058 }
2059
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002060 if (mInsideFunction)
2061 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002062 outputLineDirective(out, node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002063 out << "}\n";
2064 }
2065
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002066 return false;
2067 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002068 case EOpDeclaration:
2069 if (visit == PreVisit)
2070 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002071 TIntermSequence *sequence = node->getSequence();
2072 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
Olli Etuahoa6f22092015-05-08 18:31:10 +03002073 ASSERT(sequence->size() == 1);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002074
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002075 if (variable &&
2076 (variable->getQualifier() == EvqTemporary ||
2077 variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002078 {
Jamie Madill2e295e22015-04-29 10:41:33 -04002079 ensureStructDefined(variable->getType());
daniel@transgaming.comead23042010-04-29 03:35:36 +00002080
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002081 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002082 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03002083 if (!mInsideFunction)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002084 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03002085 out << "static ";
2086 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04002087
Olli Etuahoa6f22092015-05-08 18:31:10 +03002088 out << TypeString(variable->getType()) + " ";
Nicolas Capensd974db42014-10-07 10:50:19 -04002089
Olli Etuahoa6f22092015-05-08 18:31:10 +03002090 TIntermSymbol *symbol = variable->getAsSymbolNode();
Nicolas Capensd974db42014-10-07 10:50:19 -04002091
Olli Etuahoa6f22092015-05-08 18:31:10 +03002092 if (symbol)
2093 {
2094 symbol->traverse(this);
2095 out << ArrayString(symbol->getType());
2096 out << " = " + initializer(symbol->getType());
2097 }
2098 else
2099 {
2100 variable->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002101 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002102 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002103 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
2104 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002105 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002106 }
2107 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002108 }
Jamie Madill033dae62014-06-18 12:56:28 -04002109 else if (variable && IsVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002110 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002111 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002112 {
2113 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
2114
2115 if (symbol)
2116 {
2117 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
2118 mReferencedVaryings[symbol->getSymbol()] = symbol;
2119 }
2120 else
2121 {
2122 (*sit)->traverse(this);
2123 }
2124 }
2125 }
2126
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002127 return false;
2128 }
2129 else if (visit == InVisit)
2130 {
2131 out << ", ";
2132 }
2133 break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -04002134 case EOpInvariantDeclaration:
2135 // Do not do any translation
2136 return false;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002137 case EOpPrototype:
2138 if (visit == PreVisit)
2139 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002140 size_t index = mCallDag.findIndex(node);
2141 // Skip the prototype if it is not implemented (and thus not used)
2142 if (index == CallDAG::InvalidIndex)
2143 {
2144 return false;
2145 }
2146
Olli Etuaho59f9a642015-08-06 20:38:26 +03002147 TString name = DecorateFunctionIfNeeded(node->getNameObj());
2148 out << TypeString(node->getType()) << " " << name
2149 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002150
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002151 TIntermSequence *arguments = node->getSequence();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002152
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002153 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002154 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002155 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002156
2157 if (symbol)
2158 {
2159 out << argumentString(symbol);
2160
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002161 if (i < arguments->size() - 1)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002162 {
2163 out << ", ";
2164 }
2165 }
2166 else UNREACHABLE();
2167 }
2168
2169 out << ");\n";
2170
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002171 // Also prototype the Lod0 variant if needed
Corentin Wallez1239ee92015-03-19 14:38:02 -07002172 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2173 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002174 {
2175 mOutputLod0Function = true;
2176 node->traverse(this);
2177 mOutputLod0Function = false;
2178 }
2179
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002180 return false;
2181 }
2182 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002183 case EOpComma:
2184 outputTriplet(out, visit, "(", ", ", ")");
2185 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002186 case EOpFunction:
2187 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002188 ASSERT(mCurrentFunctionMetadata == nullptr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03002189 TString name = TFunction::unmangleName(node->getNameObj().getString());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002190
Corentin Wallez1239ee92015-03-19 14:38:02 -07002191 size_t index = mCallDag.findIndex(node);
2192 ASSERT(index != CallDAG::InvalidIndex);
2193 mCurrentFunctionMetadata = &mASTMetadataList[index];
2194
Jamie Madill033dae62014-06-18 12:56:28 -04002195 out << TypeString(node->getType()) << " ";
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002196
2197 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002198 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002199 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002200 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002201 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002203 out << DecorateFunctionIfNeeded(node->getNameObj())
2204 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002205 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002206
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002207 TIntermSequence *sequence = node->getSequence();
2208 TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002209
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002210 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002211 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002212 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002213
2214 if (symbol)
2215 {
Jamie Madill2e295e22015-04-29 10:41:33 -04002216 ensureStructDefined(symbol->getType());
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002217
2218 out << argumentString(symbol);
2219
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002220 if (i < arguments->size() - 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002221 {
2222 out << ", ";
2223 }
2224 }
2225 else UNREACHABLE();
2226 }
2227
Olli Etuaho4785fec2015-05-18 16:09:37 +03002228 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002229
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002230 if (sequence->size() > 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002231 {
2232 mInsideFunction = true;
Olli Etuaho4785fec2015-05-18 16:09:37 +03002233 TIntermNode *body = (*sequence)[1];
2234 // The function body node will output braces.
2235 ASSERT(IsSequence(body));
2236 body->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002237 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002239 else
2240 {
2241 out << "{}\n";
2242 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002243
Corentin Wallez1239ee92015-03-19 14:38:02 -07002244 mCurrentFunctionMetadata = nullptr;
2245
2246 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2247 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002248 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002249 ASSERT(name != "main");
2250 mOutputLod0Function = true;
2251 node->traverse(this);
2252 mOutputLod0Function = false;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002253 }
2254
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002255 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002256 }
2257 break;
2258 case EOpFunctionCall:
2259 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002260 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002261
Corentin Wallez1239ee92015-03-19 14:38:02 -07002262 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002263 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002264 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002265 if (node->isArray())
2266 {
2267 UNIMPLEMENTED();
2268 }
Corentin Wallez1239ee92015-03-19 14:38:02 -07002269 size_t index = mCallDag.findIndex(node);
2270 ASSERT(index != CallDAG::InvalidIndex);
2271 lod0 &= mASTMetadataList[index].mNeedsLod0;
2272
Olli Etuaho59f9a642015-08-06 20:38:26 +03002273 out << DecorateFunctionIfNeeded(node->getNameObj()) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002274 }
2275 else
2276 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002277 TString name = TFunction::unmangleName(node->getNameObj().getString());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002278 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002279
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002280 TextureFunction textureFunction;
2281 textureFunction.sampler = samplerType;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002282 textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002283 textureFunction.method = TextureFunction::IMPLICIT;
2284 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002285 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002286
2287 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002288 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002289 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002290 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002291 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002292 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002293 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002294 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002295 }
Nicolas Capens46485082014-04-15 13:12:50 -04002296 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
2297 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002298 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002299 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002300 }
Nicolas Capens46485082014-04-15 13:12:50 -04002301 else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002302 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002303 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002304 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002305 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002306 else if (name == "textureSize")
2307 {
2308 textureFunction.method = TextureFunction::SIZE;
2309 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002310 else if (name == "textureOffset")
2311 {
2312 textureFunction.method = TextureFunction::IMPLICIT;
2313 textureFunction.offset = true;
2314 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002315 else if (name == "textureProjOffset")
2316 {
2317 textureFunction.method = TextureFunction::IMPLICIT;
2318 textureFunction.offset = true;
2319 textureFunction.proj = true;
2320 }
2321 else if (name == "textureLodOffset")
2322 {
2323 textureFunction.method = TextureFunction::LOD;
2324 textureFunction.offset = true;
2325 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002326 else if (name == "textureProjLodOffset")
2327 {
2328 textureFunction.method = TextureFunction::LOD;
2329 textureFunction.proj = true;
2330 textureFunction.offset = true;
2331 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002332 else if (name == "texelFetch")
2333 {
2334 textureFunction.method = TextureFunction::FETCH;
2335 }
2336 else if (name == "texelFetchOffset")
2337 {
2338 textureFunction.method = TextureFunction::FETCH;
2339 textureFunction.offset = true;
2340 }
Nicolas Capens46485082014-04-15 13:12:50 -04002341 else if (name == "textureGrad" || name == "texture2DGradEXT")
Nicolas Capensd11d5492014-02-19 17:06:10 -05002342 {
2343 textureFunction.method = TextureFunction::GRAD;
2344 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002345 else if (name == "textureGradOffset")
2346 {
2347 textureFunction.method = TextureFunction::GRAD;
2348 textureFunction.offset = true;
2349 }
Nicolas Capens46485082014-04-15 13:12:50 -04002350 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
Nicolas Capensf7378e32014-02-19 17:29:32 -05002351 {
2352 textureFunction.method = TextureFunction::GRAD;
2353 textureFunction.proj = true;
2354 }
2355 else if (name == "textureProjGradOffset")
2356 {
2357 textureFunction.method = TextureFunction::GRAD;
2358 textureFunction.proj = true;
2359 textureFunction.offset = true;
2360 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002361 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002362
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002363 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002364 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002365 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2366
2367 if (textureFunction.offset)
2368 {
2369 mandatoryArgumentCount++;
2370 }
2371
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002372 bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional
Nicolas Capens84cfa122014-04-14 13:48:45 -04002373
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002374 if (lod0 || mShaderType == GL_VERTEX_SHADER)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002375 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002376 if (bias)
2377 {
2378 textureFunction.method = TextureFunction::LOD0BIAS;
2379 }
2380 else
2381 {
2382 textureFunction.method = TextureFunction::LOD0;
2383 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002384 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002385 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002386 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002387 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002388 }
2389 }
2390
2391 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002392
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002393 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002394 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002395
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002396 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002397 {
2398 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2399 {
2400 out << "texture_";
2401 (*arg)->traverse(this);
2402 out << ", sampler_";
2403 }
2404
2405 (*arg)->traverse(this);
2406
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002407 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002408 {
2409 out << ", ";
2410 }
2411 }
2412
2413 out << ")";
2414
2415 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002416 }
2417 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002418 case EOpParameters:
2419 outputTriplet(out, visit, "(", ", ", ")\n{\n");
2420 break;
2421 case EOpConstructFloat:
2422 outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
2423 break;
2424 case EOpConstructVec2:
2425 outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
2426 break;
2427 case EOpConstructVec3:
2428 outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
2429 break;
2430 case EOpConstructVec4:
2431 outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
2432 break;
2433 case EOpConstructBool:
2434 outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
2435 break;
2436 case EOpConstructBVec2:
2437 outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
2438 break;
2439 case EOpConstructBVec3:
2440 outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
2441 break;
2442 case EOpConstructBVec4:
2443 outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
2444 break;
2445 case EOpConstructInt:
2446 outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
2447 break;
2448 case EOpConstructIVec2:
2449 outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
2450 break;
2451 case EOpConstructIVec3:
2452 outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
2453 break;
2454 case EOpConstructIVec4:
2455 outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
2456 break;
2457 case EOpConstructUInt:
2458 outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
2459 break;
2460 case EOpConstructUVec2:
2461 outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
2462 break;
2463 case EOpConstructUVec3:
2464 outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
2465 break;
2466 case EOpConstructUVec4:
2467 outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
2468 break;
2469 case EOpConstructMat2:
2470 outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
2471 break;
2472 case EOpConstructMat2x3:
2473 outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
2474 break;
2475 case EOpConstructMat2x4:
2476 outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
2477 break;
2478 case EOpConstructMat3x2:
2479 outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
2480 break;
2481 case EOpConstructMat3:
2482 outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
2483 break;
2484 case EOpConstructMat3x4:
2485 outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
2486 break;
2487 case EOpConstructMat4x2:
2488 outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
2489 break;
2490 case EOpConstructMat4x3:
2491 outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
2492 break;
2493 case EOpConstructMat4:
2494 outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
2495 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002496 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04002497 {
Olli Etuahof40319e2015-03-10 14:33:00 +02002498 if (node->getType().isArray())
2499 {
2500 UNIMPLEMENTED();
2501 }
Jamie Madill033dae62014-06-18 12:56:28 -04002502 const TString &structName = StructNameString(*node->getType().getStruct());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002503 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002504 outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
Jamie Madillbfa91f42014-06-05 15:45:18 -04002505 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002506 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002507 case EOpLessThan:
2508 outputTriplet(out, visit, "(", " < ", ")");
2509 break;
2510 case EOpGreaterThan:
2511 outputTriplet(out, visit, "(", " > ", ")");
2512 break;
2513 case EOpLessThanEqual:
2514 outputTriplet(out, visit, "(", " <= ", ")");
2515 break;
2516 case EOpGreaterThanEqual:
2517 outputTriplet(out, visit, "(", " >= ", ")");
2518 break;
2519 case EOpVectorEqual:
2520 outputTriplet(out, visit, "(", " == ", ")");
2521 break;
2522 case EOpVectorNotEqual:
2523 outputTriplet(out, visit, "(", " != ", ")");
2524 break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002525 case EOpMod:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002526 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002527 writeEmulatedFunctionTriplet(out, visit, "mod(");
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002528 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002529 case EOpModf:
2530 outputTriplet(out, visit, "modf(", ", ", ")");
2531 break;
2532 case EOpPow:
2533 outputTriplet(out, visit, "pow(", ", ", ")");
2534 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002535 case EOpAtan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002536 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
Olli Etuahoe17e3192015-01-02 12:47:59 +02002537 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002538 writeEmulatedFunctionTriplet(out, visit, "atan(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002539 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002540 case EOpMin:
2541 outputTriplet(out, visit, "min(", ", ", ")");
2542 break;
2543 case EOpMax:
2544 outputTriplet(out, visit, "max(", ", ", ")");
2545 break;
2546 case EOpClamp:
2547 outputTriplet(out, visit, "clamp(", ", ", ")");
2548 break;
Arun Patoled94f6642015-05-18 16:25:12 +05302549 case EOpMix:
2550 {
2551 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2552 if (lastParamNode->getType().getBasicType() == EbtBool)
2553 {
2554 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
2555 // so use emulated version.
2556 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002557 writeEmulatedFunctionTriplet(out, visit, "mix(");
Arun Patoled94f6642015-05-18 16:25:12 +05302558 }
2559 else
2560 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002561 outputTriplet(out, visit, "lerp(", ", ", ")");
Arun Patoled94f6642015-05-18 16:25:12 +05302562 }
2563 }
2564 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002565 case EOpStep:
2566 outputTriplet(out, visit, "step(", ", ", ")");
2567 break;
2568 case EOpSmoothStep:
2569 outputTriplet(out, visit, "smoothstep(", ", ", ")");
2570 break;
2571 case EOpDistance:
2572 outputTriplet(out, visit, "distance(", ", ", ")");
2573 break;
2574 case EOpDot:
2575 outputTriplet(out, visit, "dot(", ", ", ")");
2576 break;
2577 case EOpCross:
2578 outputTriplet(out, visit, "cross(", ", ", ")");
2579 break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002580 case EOpFaceForward:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002581 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002582 writeEmulatedFunctionTriplet(out, visit, "faceforward(");
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002583 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002584 case EOpReflect:
2585 outputTriplet(out, visit, "reflect(", ", ", ")");
2586 break;
2587 case EOpRefract:
2588 outputTriplet(out, visit, "refract(", ", ", ")");
2589 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02002590 case EOpOuterProduct:
2591 ASSERT(node->getUseEmulatedFunction());
Jamie Madill8c46ab12015-12-07 16:39:19 -05002592 writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
Olli Etuahoe39706d2014-12-30 16:40:36 +02002593 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002594 case EOpMul:
2595 outputTriplet(out, visit, "(", " * ", ")");
2596 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002597 default: UNREACHABLE();
2598 }
2599
2600 return true;
2601}
2602
Jamie Madill8c46ab12015-12-07 16:39:19 -05002603void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002604{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002605 out << "if (";
2606
2607 node->getCondition()->traverse(this);
2608
2609 out << ")\n";
2610
Jamie Madill8c46ab12015-12-07 16:39:19 -05002611 outputLineDirective(out, node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002612
2613 bool discard = false;
2614
2615 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002616 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002617 // The trueBlock child node will output braces.
2618 ASSERT(IsSequence(node->getTrueBlock()));
2619
Olli Etuahoa6f22092015-05-08 18:31:10 +03002620 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002621
Olli Etuahoa6f22092015-05-08 18:31:10 +03002622 // Detect true discard
2623 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2624 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002625 else
2626 {
2627 // TODO(oetuaho): Check if the semicolon inside is necessary.
2628 // It's there as a result of conservative refactoring of the output.
2629 out << "{;}\n";
2630 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002631
Jamie Madill8c46ab12015-12-07 16:39:19 -05002632 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002633
Olli Etuahoa6f22092015-05-08 18:31:10 +03002634 if (node->getFalseBlock())
2635 {
2636 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002637
Jamie Madill8c46ab12015-12-07 16:39:19 -05002638 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002639
Olli Etuaho4785fec2015-05-18 16:09:37 +03002640 // Either this is "else if" or the falseBlock child node will output braces.
2641 ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr);
2642
Olli Etuahoa6f22092015-05-08 18:31:10 +03002643 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002644
Jamie Madill8c46ab12015-12-07 16:39:19 -05002645 outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002646
Olli Etuahoa6f22092015-05-08 18:31:10 +03002647 // Detect false discard
2648 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2649 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002650
Olli Etuahoa6f22092015-05-08 18:31:10 +03002651 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002652 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002653 {
2654 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002655 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002656}
2657
2658bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2659{
2660 TInfoSinkBase &out = getInfoSink();
2661
2662 ASSERT(!node->usesTernaryOperator());
2663
2664 if (!mInsideFunction)
2665 {
2666 // This is part of unfolded global initialization.
2667 mDeferredGlobalInitializers.push_back(node);
2668 return false;
2669 }
2670
2671 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002672 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002673 {
2674 out << "FLATTEN ";
2675 }
2676
Jamie Madill8c46ab12015-12-07 16:39:19 -05002677 writeSelection(out, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002678
2679 return false;
2680}
2681
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002682bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002683{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002684 TInfoSinkBase &out = getInfoSink();
2685
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002686 if (node->getStatementList())
2687 {
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +02002688 node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Jamie Madill8c46ab12015-12-07 16:39:19 -05002689 outputTriplet(out, visit, "switch (", ") ", "");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002690 // The curly braces get written when visiting the statementList aggregate
2691 }
2692 else
2693 {
2694 // No statementList, so it won't output curly braces
Jamie Madill8c46ab12015-12-07 16:39:19 -05002695 outputTriplet(out, visit, "switch (", ") {", "}\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002696 }
2697 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002698}
2699
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002700bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002701{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002702 TInfoSinkBase &out = getInfoSink();
2703
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002704 if (node->hasCondition())
2705 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002706 outputTriplet(out, visit, "case (", "", "):\n");
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002707 return true;
2708 }
2709 else
2710 {
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002711 out << "default:\n";
2712 return false;
2713 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002714}
2715
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002716void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2717{
Jamie Madill8c46ab12015-12-07 16:39:19 -05002718 TInfoSinkBase &out = getInfoSink();
2719 writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002720}
2721
2722bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2723{
Nicolas Capens655fe362014-04-11 13:12:34 -04002724 mNestedLoopDepth++;
2725
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002726 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Corentin Wallez1239ee92015-03-19 14:38:02 -07002727 mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
Corentin Walleza1884f22015-04-29 10:15:16 -07002728 mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002729
Jamie Madill8c46ab12015-12-07 16:39:19 -05002730 TInfoSinkBase &out = getInfoSink();
2731
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002732 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002733 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002734 if (handleExcessiveLoop(out, node))
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002735 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002736 mInsideDiscontinuousLoop = wasDiscontinuous;
2737 mNestedLoopDepth--;
2738
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002739 return false;
2740 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002741 }
2742
Corentin Wallez1239ee92015-03-19 14:38:02 -07002743 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002744 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002745 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002746 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002747
Jamie Madill8c46ab12015-12-07 16:39:19 -05002748 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002749 }
2750 else
2751 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002752 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002753
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002754 if (node->getInit())
2755 {
2756 node->getInit()->traverse(this);
2757 }
2758
2759 out << "; ";
2760
alokp@chromium.org52813552010-11-16 18:36:09 +00002761 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002762 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002763 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002764 }
2765
2766 out << "; ";
2767
alokp@chromium.org52813552010-11-16 18:36:09 +00002768 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002769 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002770 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002771 }
2772
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002773 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002774
Jamie Madill8c46ab12015-12-07 16:39:19 -05002775 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002776 }
2777
2778 if (node->getBody())
2779 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002780 // The loop body node will output braces.
2781 ASSERT(IsSequence(node->getBody()));
Olli Etuahoa6f22092015-05-08 18:31:10 +03002782 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002783 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002784 else
2785 {
2786 // TODO(oetuaho): Check if the semicolon inside is necessary.
2787 // It's there as a result of conservative refactoring of the output.
2788 out << "{;}\n";
2789 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002790
Jamie Madill8c46ab12015-12-07 16:39:19 -05002791 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002792
alokp@chromium.org52813552010-11-16 18:36:09 +00002793 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002794 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05002795 outputLineDirective(out, node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002796 out << "while(\n";
2797
alokp@chromium.org52813552010-11-16 18:36:09 +00002798 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002799
daniel@transgaming.com73536982012-03-21 20:45:49 +00002800 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002801 }
2802
daniel@transgaming.com73536982012-03-21 20:45:49 +00002803 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002804
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002805 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002806 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002807
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002808 return false;
2809}
2810
2811bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2812{
Jamie Madill32aab012015-01-27 14:12:26 -05002813 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002814
2815 switch (node->getFlowOp())
2816 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002817 case EOpKill:
Jamie Madill8c46ab12015-12-07 16:39:19 -05002818 outputTriplet(out, visit, "discard;\n", "", "");
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002819 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002820 case EOpBreak:
2821 if (visit == PreVisit)
2822 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002823 if (mNestedLoopDepth > 1)
2824 {
2825 mUsesNestedBreak = true;
2826 }
2827
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002828 if (mExcessiveLoopIndex)
2829 {
2830 out << "{Break";
2831 mExcessiveLoopIndex->traverse(this);
2832 out << " = true; break;}\n";
2833 }
2834 else
2835 {
2836 out << "break;\n";
2837 }
2838 }
2839 break;
Jamie Madill8c46ab12015-12-07 16:39:19 -05002840 case EOpContinue:
2841 outputTriplet(out, visit, "continue;\n", "", "");
2842 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002843 case EOpReturn:
2844 if (visit == PreVisit)
2845 {
2846 if (node->getExpression())
2847 {
2848 out << "return ";
2849 }
2850 else
2851 {
2852 out << "return;\n";
2853 }
2854 }
2855 else if (visit == PostVisit)
2856 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002857 if (node->getExpression())
2858 {
2859 out << ";\n";
2860 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002861 }
2862 break;
2863 default: UNREACHABLE();
2864 }
2865
2866 return true;
2867}
2868
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002869bool OutputHLSL::isSingleStatement(TIntermNode *node)
2870{
2871 TIntermAggregate *aggregate = node->getAsAggregate();
2872
2873 if (aggregate)
2874 {
2875 if (aggregate->getOp() == EOpSequence)
2876 {
2877 return false;
2878 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04002879 else if (aggregate->getOp() == EOpDeclaration)
2880 {
2881 // Declaring multiple comma-separated variables must be considered multiple statements
2882 // because each individual declaration has side effects which are visible in the next.
2883 return false;
2884 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002885 else
2886 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002887 for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002888 {
2889 if (!isSingleStatement(*sit))
2890 {
2891 return false;
2892 }
2893 }
2894
2895 return true;
2896 }
2897 }
2898
2899 return true;
2900}
2901
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002902// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2903// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
Jamie Madill8c46ab12015-12-07 16:39:19 -05002904bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002905{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002906 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002907
2908 // Parse loops of the form:
2909 // for(int index = initial; index [comparator] limit; index += increment)
2910 TIntermSymbol *index = NULL;
2911 TOperator comparator = EOpNull;
2912 int initial = 0;
2913 int limit = 0;
2914 int increment = 0;
2915
2916 // Parse index name and intial value
2917 if (node->getInit())
2918 {
2919 TIntermAggregate *init = node->getInit()->getAsAggregate();
2920
2921 if (init)
2922 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002923 TIntermSequence *sequence = init->getSequence();
2924 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002925
2926 if (variable && variable->getQualifier() == EvqTemporary)
2927 {
2928 TIntermBinary *assign = variable->getAsBinaryNode();
2929
2930 if (assign->getOp() == EOpInitialize)
2931 {
2932 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2933 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2934
2935 if (symbol && constant)
2936 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002937 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002938 {
2939 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002940 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002941 }
2942 }
2943 }
2944 }
2945 }
2946 }
2947
2948 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002949 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002950 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002951 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002952
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002953 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2954 {
2955 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2956
2957 if (constant)
2958 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002959 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002960 {
2961 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002962 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002963 }
2964 }
2965 }
2966 }
2967
2968 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002969 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002970 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002971 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2972 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002973
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002974 if (binaryTerminal)
2975 {
2976 TOperator op = binaryTerminal->getOp();
2977 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2978
2979 if (constant)
2980 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002981 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002982 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002983 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002984
2985 switch (op)
2986 {
2987 case EOpAddAssign: increment = value; break;
2988 case EOpSubAssign: increment = -value; break;
2989 default: UNIMPLEMENTED();
2990 }
2991 }
2992 }
2993 }
2994 else if (unaryTerminal)
2995 {
2996 TOperator op = unaryTerminal->getOp();
2997
2998 switch (op)
2999 {
3000 case EOpPostIncrement: increment = 1; break;
3001 case EOpPostDecrement: increment = -1; break;
3002 case EOpPreIncrement: increment = 1; break;
3003 case EOpPreDecrement: increment = -1; break;
3004 default: UNIMPLEMENTED();
3005 }
3006 }
3007 }
3008
3009 if (index != NULL && comparator != EOpNull && increment != 0)
3010 {
3011 if (comparator == EOpLessThanEqual)
3012 {
3013 comparator = EOpLessThan;
3014 limit += 1;
3015 }
3016
3017 if (comparator == EOpLessThan)
3018 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00003019 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003020
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003021 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003022 {
3023 return false; // Not an excessive loop
3024 }
3025
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003026 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
3027 mExcessiveLoopIndex = index;
3028
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003029 out << "{int ";
3030 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003031 out << ";\n"
3032 "bool Break";
3033 index->traverse(this);
3034 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003035
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003036 bool firstLoopFragment = true;
3037
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003038 while (iterations > 0)
3039 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003040 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003041
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003042 if (!firstLoopFragment)
3043 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05003044 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003045 index->traverse(this);
3046 out << ") {\n";
3047 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00003048
3049 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
3050 {
3051 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
3052 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003053
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003054 // for(int index = initial; index < clampedLimit; index += increment)
Corentin Wallez1239ee92015-03-19 14:38:02 -07003055 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003056
Corentin Wallez1239ee92015-03-19 14:38:02 -07003057 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003058 index->traverse(this);
3059 out << " = ";
3060 out << initial;
3061
3062 out << "; ";
3063 index->traverse(this);
3064 out << " < ";
3065 out << clampedLimit;
3066
3067 out << "; ";
3068 index->traverse(this);
3069 out << " += ";
3070 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003071 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04003072
Jamie Madill8c46ab12015-12-07 16:39:19 -05003073 outputLineDirective(out, node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003074 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003075
3076 if (node->getBody())
3077 {
3078 node->getBody()->traverse(this);
3079 }
3080
Jamie Madill8c46ab12015-12-07 16:39:19 -05003081 outputLineDirective(out, node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003082 out << ";}\n";
3083
3084 if (!firstLoopFragment)
3085 {
3086 out << "}\n";
3087 }
3088
3089 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003090
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003091 initial += MAX_LOOP_ITERATIONS * increment;
3092 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003093 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003094
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003095 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003096
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003097 mExcessiveLoopIndex = restoreIndex;
3098
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003099 return true;
3100 }
3101 else UNIMPLEMENTED();
3102 }
3103
3104 return false; // Not handled as an excessive loop
3105}
3106
Jamie Madill8c46ab12015-12-07 16:39:19 -05003107void OutputHLSL::outputTriplet(TInfoSinkBase &out,
3108 Visit visit,
3109 const char *preString,
3110 const char *inString,
3111 const char *postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003112{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003113 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003114 {
3115 out << preString;
3116 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003117 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003118 {
3119 out << inString;
3120 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003121 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003122 {
3123 out << postString;
3124 }
3125}
3126
Jamie Madill8c46ab12015-12-07 16:39:19 -05003127void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003128{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003129 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003130 {
Jamie Madill32aab012015-01-27 14:12:26 -05003131 out << "\n";
3132 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003133
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003134 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003135 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02003136 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003137 }
Jamie Madillf91ce812014-06-13 10:04:34 -04003138
Jamie Madill32aab012015-01-27 14:12:26 -05003139 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003140 }
3141}
3142
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003143TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
3144{
3145 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003146 const TType &type = symbol->getType();
3147 const TName &name = symbol->getName();
3148 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003149
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003150 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003151 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003152 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003153 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003154 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003155 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003156 nameStr = DecorateIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003157 }
3158
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003159 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
3160 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003161 return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + nameStr +
3162 ArrayString(type) + ", " + QualifierString(qualifier) + " " + SamplerString(type) +
3163 " sampler_" + nameStr + ArrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003164 }
3165
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03003166 return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003167}
3168
3169TString OutputHLSL::initializer(const TType &type)
3170{
3171 TString string;
3172
Jamie Madill94bf7f22013-07-08 13:31:15 -04003173 size_t size = type.getObjectSize();
3174 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003175 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00003176 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003177
Jamie Madill94bf7f22013-07-08 13:31:15 -04003178 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003179 {
3180 string += ", ";
3181 }
3182 }
3183
daniel@transgaming.comead23042010-04-29 03:35:36 +00003184 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003185}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003186
Jamie Madill8c46ab12015-12-07 16:39:19 -05003187void OutputHLSL::outputConstructor(TInfoSinkBase &out,
3188 Visit visit,
3189 const TType &type,
3190 const char *name,
3191 const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003192{
Olli Etuahof40319e2015-03-10 14:33:00 +02003193 if (type.isArray())
3194 {
3195 UNIMPLEMENTED();
3196 }
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003197
3198 if (visit == PreVisit)
3199 {
Jamie Madill8daaba12014-06-13 10:04:33 -04003200 mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003201
Daniel Bratell29190082015-02-20 16:42:54 +01003202 out << name << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003203 }
3204 else if (visit == InVisit)
3205 {
3206 out << ", ";
3207 }
3208 else if (visit == PostVisit)
3209 {
3210 out << ")";
3211 }
3212}
3213
Jamie Madill8c46ab12015-12-07 16:39:19 -05003214const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3215 const TType &type,
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003216 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003217{
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003218 const TConstantUnion *constUnionIterated = constUnion;
3219
Jamie Madill98493dd2013-07-08 14:39:03 -04003220 const TStructure* structure = type.getStruct();
3221 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003222 {
Jamie Madill033dae62014-06-18 12:56:28 -04003223 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04003224
Jamie Madill98493dd2013-07-08 14:39:03 -04003225 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003226
Jamie Madill98493dd2013-07-08 14:39:03 -04003227 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003228 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003229 const TType *fieldType = fields[i]->type();
Jamie Madill8c46ab12015-12-07 16:39:19 -05003230 constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003231
Jamie Madill98493dd2013-07-08 14:39:03 -04003232 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003233 {
3234 out << ", ";
3235 }
3236 }
3237
3238 out << ")";
3239 }
3240 else
3241 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003242 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003243 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04003244
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003245 if (writeType)
3246 {
Jamie Madill033dae62014-06-18 12:56:28 -04003247 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003248 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003249 constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003250 if (writeType)
3251 {
3252 out << ")";
3253 }
3254 }
3255
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003256 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003257}
3258
Jamie Madill8c46ab12015-12-07 16:39:19 -05003259void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003260{
3261 TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
Jamie Madill8c46ab12015-12-07 16:39:19 -05003262 outputTriplet(out, visit, preString.c_str(), ", ", ")");
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003263}
3264
Jamie Madill37997142015-01-28 10:06:34 -05003265bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
3266{
3267 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
3268 expression->traverse(&searchSymbol);
3269
3270 if (searchSymbol.foundMatch())
3271 {
3272 // Type already printed
3273 out << "t" + str(mUniqueIndex) + " = ";
3274 expression->traverse(this);
3275 out << ", ";
3276 symbolNode->traverse(this);
3277 out << " = t" + str(mUniqueIndex);
3278
3279 mUniqueIndex++;
3280 return true;
3281 }
3282
3283 return false;
3284}
3285
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003286bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
3287{
3288 // We support writing constant unions and constructors that only take constant unions as
3289 // parameters as HLSL literals.
3290 if (expression->getAsConstantUnion())
3291 {
3292 return true;
3293 }
3294 if (expression->getQualifier() != EvqConst || !expression->getAsAggregate() ||
3295 !expression->getAsAggregate()->isConstructor())
3296 {
3297 return false;
3298 }
3299 TIntermAggregate *constructor = expression->getAsAggregate();
3300 for (TIntermNode *&node : *constructor->getSequence())
3301 {
3302 if (!node->getAsConstantUnion())
3303 return false;
3304 }
3305 return true;
3306}
3307
3308bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3309 TIntermSymbol *symbolNode,
3310 TIntermTyped *expression)
3311{
3312 if (canWriteAsHLSLLiteral(expression))
3313 {
3314 symbolNode->traverse(this);
3315 if (expression->getType().isArray())
3316 {
3317 out << "[" << expression->getType().getArraySize() << "]";
3318 }
3319 out << " = {";
3320 if (expression->getAsConstantUnion())
3321 {
3322 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
3323 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3324 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3325 }
3326 else
3327 {
3328 TIntermAggregate *constructor = expression->getAsAggregate();
3329 ASSERT(constructor != nullptr);
3330 for (TIntermNode *&node : *constructor->getSequence())
3331 {
3332 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
3333 ASSERT(nodeConst);
3334 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3335 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3336 if (node != constructor->getSequence()->back())
3337 {
3338 out << ", ";
3339 }
3340 }
3341 }
3342 out << "}";
3343 return true;
3344 }
3345 return false;
3346}
3347
Jamie Madill37997142015-01-28 10:06:34 -05003348void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
3349{
3350 out << "#define ANGLE_USES_DEFERRED_INIT\n"
3351 << "\n"
3352 << "void initializeDeferredGlobals()\n"
3353 << "{\n";
3354
3355 for (const auto &deferredGlobal : mDeferredGlobalInitializers)
3356 {
Olli Etuahod81ed842015-05-12 12:46:35 +03003357 TIntermBinary *binary = deferredGlobal->getAsBinaryNode();
3358 TIntermSelection *selection = deferredGlobal->getAsSelectionNode();
3359 if (binary != nullptr)
3360 {
3361 TIntermSymbol *symbol = binary->getLeft()->getAsSymbolNode();
3362 TIntermTyped *expression = binary->getRight();
3363 ASSERT(symbol);
3364 ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
Jamie Madill37997142015-01-28 10:06:34 -05003365
Olli Etuahod81ed842015-05-12 12:46:35 +03003366 out << " " << Decorate(symbol->getSymbol()) << " = ";
Jamie Madill37997142015-01-28 10:06:34 -05003367
Olli Etuahod81ed842015-05-12 12:46:35 +03003368 if (!writeSameSymbolInitializer(out, symbol, expression))
3369 {
3370 ASSERT(mInfoSinkStack.top() == &out);
3371 expression->traverse(this);
3372 }
3373 out << ";\n";
3374 }
3375 else if (selection != nullptr)
Jamie Madill37997142015-01-28 10:06:34 -05003376 {
Jamie Madill8c46ab12015-12-07 16:39:19 -05003377 writeSelection(out, selection);
Jamie Madill37997142015-01-28 10:06:34 -05003378 }
Olli Etuahod81ed842015-05-12 12:46:35 +03003379 else
3380 {
3381 UNREACHABLE();
3382 }
Jamie Madill37997142015-01-28 10:06:34 -05003383 }
3384
3385 out << "}\n"
3386 << "\n";
3387}
3388
Jamie Madill55e79e02015-02-09 15:35:00 -05003389TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3390{
3391 const TFieldList &fields = structure.fields();
3392
3393 for (const auto &eqFunction : mStructEqualityFunctions)
3394 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003395 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003396 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003397 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003398 }
3399 }
3400
3401 const TString &structNameString = StructNameString(structure);
3402
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003403 StructEqualityFunction *function = new StructEqualityFunction();
3404 function->structure = &structure;
3405 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003406
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003407 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003408
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003409 fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n"
3410 << "{\n"
3411 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003412
3413 for (size_t i = 0; i < fields.size(); i++)
3414 {
3415 const TField *field = fields[i];
3416 const TType *fieldType = field->type();
3417
3418 const TString &fieldNameA = "a." + Decorate(field->name());
3419 const TString &fieldNameB = "b." + Decorate(field->name());
3420
3421 if (i > 0)
3422 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003423 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003424 }
3425
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003426 fnOut << "(";
3427 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3428 fnOut << fieldNameA;
3429 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3430 fnOut << fieldNameB;
3431 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3432 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003433 }
3434
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003435 fnOut << ";\n" << "}\n";
3436
3437 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003438
3439 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003440 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003441
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003442 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003443}
3444
Olli Etuaho7fb49552015-03-18 17:27:44 +02003445TString OutputHLSL::addArrayEqualityFunction(const TType& type)
3446{
3447 for (const auto &eqFunction : mArrayEqualityFunctions)
3448 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003449 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003450 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003451 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003452 }
3453 }
3454
3455 const TString &typeName = TypeString(type);
3456
Olli Etuaho12690762015-03-31 12:55:28 +03003457 ArrayHelperFunction *function = new ArrayHelperFunction();
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003458 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003459
3460 TInfoSinkBase fnNameOut;
3461 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003462 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003463
3464 TType nonArrayType = type;
3465 nonArrayType.clearArrayness();
3466
3467 TInfoSinkBase fnOut;
3468
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003469 fnOut << "bool " << function->functionName << "("
Olli Etuahofc7cfd12015-03-31 14:46:18 +03003470 << typeName << " a[" << type.getArraySize() << "], "
3471 << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003472 << "{\n"
3473 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3474 " {\n"
3475 " if (";
3476
3477 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
3478 fnOut << "a[i]";
3479 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
3480 fnOut << "b[i]";
3481 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
3482
3483 fnOut << ") { return false; }\n"
3484 " }\n"
3485 " return true;\n"
3486 "}\n";
3487
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003488 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003489
3490 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003491 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003492
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003493 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003494}
3495
Olli Etuaho12690762015-03-31 12:55:28 +03003496TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
3497{
3498 for (const auto &assignFunction : mArrayAssignmentFunctions)
3499 {
3500 if (assignFunction.type == type)
3501 {
3502 return assignFunction.functionName;
3503 }
3504 }
3505
3506 const TString &typeName = TypeString(type);
3507
3508 ArrayHelperFunction function;
3509 function.type = type;
3510
3511 TInfoSinkBase fnNameOut;
3512 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
3513 function.functionName = fnNameOut.c_str();
3514
3515 TInfoSinkBase fnOut;
3516
3517 fnOut << "void " << function.functionName << "(out "
3518 << typeName << " a[" << type.getArraySize() << "], "
3519 << typeName << " b[" << type.getArraySize() << "])\n"
3520 << "{\n"
3521 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3522 " {\n"
3523 " a[i] = b[i];\n"
3524 " }\n"
3525 "}\n";
3526
3527 function.functionDefinition = fnOut.c_str();
3528
3529 mArrayAssignmentFunctions.push_back(function);
3530
3531 return function.functionName;
3532}
3533
Olli Etuaho9638c352015-04-01 14:34:52 +03003534TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
3535{
3536 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3537 {
3538 if (constructIntoFunction.type == type)
3539 {
3540 return constructIntoFunction.functionName;
3541 }
3542 }
3543
3544 const TString &typeName = TypeString(type);
3545
3546 ArrayHelperFunction function;
3547 function.type = type;
3548
3549 TInfoSinkBase fnNameOut;
3550 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
3551 function.functionName = fnNameOut.c_str();
3552
3553 TInfoSinkBase fnOut;
3554
3555 fnOut << "void " << function.functionName << "(out "
3556 << typeName << " a[" << type.getArraySize() << "]";
3557 for (int i = 0; i < type.getArraySize(); ++i)
3558 {
3559 fnOut << ", " << typeName << " b" << i;
3560 }
3561 fnOut << ")\n"
3562 "{\n";
3563
3564 for (int i = 0; i < type.getArraySize(); ++i)
3565 {
3566 fnOut << " a[" << i << "] = b" << i << ";\n";
3567 }
3568 fnOut << "}\n";
3569
3570 function.functionDefinition = fnOut.c_str();
3571
3572 mArrayConstructIntoFunctions.push_back(function);
3573
3574 return function.functionName;
3575}
3576
Jamie Madill2e295e22015-04-29 10:41:33 -04003577void OutputHLSL::ensureStructDefined(const TType &type)
3578{
3579 TStructure *structure = type.getStruct();
3580
3581 if (structure)
3582 {
3583 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3584 }
3585}
3586
3587
Olli Etuaho9638c352015-04-01 14:34:52 +03003588
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003589}