blob: dea6fc619dacc0d8c136d6242edb743ba3423a4f [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);
Olli Etuahoe17e3192015-01-02 12:47:59 +0200242 header(&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
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200337void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338{
Jamie Madill32aab012015-01-27 14:12:26 -0500339 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000341 TString varyings;
342 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400343 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000344
Jamie Madill829f59e2013-11-13 19:40:54 -0500345 for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400346 {
347 TIntermTyped *structNode = flaggedStructIt->first;
348 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400349 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400350 const TString &originalName = mFlaggedStructOriginalNames[structNode];
351
Jamie Madill033dae62014-06-18 12:56:28 -0400352 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400353 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400354 flaggedStructs += "\n";
355 }
356
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000357 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
358 {
359 const TType &type = varying->second->getType();
360 const TString &name = varying->second->getSymbol();
361
362 // Program linking depends on this exact format
Jamie Madill033dae62014-06-18 12:56:28 -0400363 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
364 Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000365 }
366
367 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
368 {
369 const TType &type = attribute->second->getType();
370 const TString &name = attribute->second->getSymbol();
371
Jamie Madill033dae62014-06-18 12:56:28 -0400372 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000373 }
374
Jamie Madill8daaba12014-06-13 10:04:33 -0400375 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400376
Jamie Madillf91ce812014-06-13 10:04:34 -0400377 out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms);
378 out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
379
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200380 if (!mEqualityFunctions.empty())
Jamie Madill55e79e02015-02-09 15:35:00 -0500381 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200382 out << "\n// Equality functions\n\n";
383 for (const auto &eqFunction : mEqualityFunctions)
Jamie Madill55e79e02015-02-09 15:35:00 -0500384 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +0200385 out << eqFunction->functionDefinition << "\n";
Olli Etuaho7fb49552015-03-18 17:27:44 +0200386 }
387 }
Olli Etuaho12690762015-03-31 12:55:28 +0300388 if (!mArrayAssignmentFunctions.empty())
389 {
390 out << "\n// Assignment functions\n\n";
391 for (const auto &assignmentFunction : mArrayAssignmentFunctions)
392 {
393 out << assignmentFunction.functionDefinition << "\n";
394 }
395 }
Olli Etuaho9638c352015-04-01 14:34:52 +0300396 if (!mArrayConstructIntoFunctions.empty())
397 {
398 out << "\n// Array constructor functions\n\n";
399 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
400 {
401 out << constructIntoFunction.functionDefinition << "\n";
402 }
403 }
Olli Etuaho7fb49552015-03-18 17:27:44 +0200404
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500405 if (mUsesDiscardRewriting)
406 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400407 out << "#define ANGLE_USES_DISCARD_REWRITING\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500408 }
409
Nicolas Capens655fe362014-04-11 13:12:34 -0400410 if (mUsesNestedBreak)
411 {
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400412 out << "#define ANGLE_USES_NESTED_BREAK\n";
Nicolas Capens655fe362014-04-11 13:12:34 -0400413 }
414
Arun Patole44efa0b2015-03-04 17:11:05 +0530415 if (mRequiresIEEEStrictCompiling)
416 {
417 out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
418 }
419
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400420 out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
421 "#define LOOP [loop]\n"
422 "#define FLATTEN [flatten]\n"
423 "#else\n"
424 "#define LOOP\n"
425 "#define FLATTEN\n"
426 "#endif\n";
427
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200428 if (mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000429 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200430 TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
431 const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000432
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000433 out << "// Varyings\n";
434 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400435 out << "\n";
436
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200437 if (mShaderVersion >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000438 {
Jamie Madill829f59e2013-11-13 19:40:54 -0500439 for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000440 {
Jamie Madill46131a32013-06-20 11:55:50 -0400441 const TString &variableName = outputVariableIt->first;
442 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400443
Jamie Madill033dae62014-06-18 12:56:28 -0400444 out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
Jamie Madill46131a32013-06-20 11:55:50 -0400445 " = " + initializer(variableType) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000446 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000447 }
Jamie Madill46131a32013-06-20 11:55:50 -0400448 else
449 {
450 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
451
452 out << "static float4 gl_Color[" << numColorValues << "] =\n"
453 "{\n";
454 for (unsigned int i = 0; i < numColorValues; i++)
455 {
456 out << " float4(0, 0, 0, 0)";
457 if (i + 1 != numColorValues)
458 {
459 out << ",";
460 }
461 out << "\n";
462 }
463
464 out << "};\n";
465 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000466
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400467 if (mUsesFragDepth)
468 {
469 out << "static float gl_Depth = 0.0;\n";
470 }
471
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000472 if (mUsesFragCoord)
473 {
474 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
475 }
476
477 if (mUsesPointCoord)
478 {
479 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
480 }
481
482 if (mUsesFrontFacing)
483 {
484 out << "static bool gl_FrontFacing = false;\n";
485 }
486
487 out << "\n";
488
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000489 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000490 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000491 out << "struct gl_DepthRangeParameters\n"
492 "{\n"
493 " float near;\n"
494 " float far;\n"
495 " float diff;\n"
496 "};\n"
497 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000498 }
499
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000500 if (mOutputType == SH_HLSL11_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000501 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000502 out << "cbuffer DriverConstants : register(b1)\n"
503 "{\n";
504
505 if (mUsesDepthRange)
506 {
507 out << " float3 dx_DepthRange : packoffset(c0);\n";
508 }
509
510 if (mUsesFragCoord)
511 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000512 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000513 }
514
515 if (mUsesFragCoord || mUsesFrontFacing)
516 {
517 out << " float3 dx_DepthFront : packoffset(c2);\n";
518 }
519
520 out << "};\n";
521 }
522 else
523 {
524 if (mUsesDepthRange)
525 {
526 out << "uniform float3 dx_DepthRange : register(c0);";
527 }
528
529 if (mUsesFragCoord)
530 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000531 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000532 }
533
534 if (mUsesFragCoord || mUsesFrontFacing)
535 {
536 out << "uniform float3 dx_DepthFront : register(c2);\n";
537 }
538 }
539
540 out << "\n";
541
542 if (mUsesDepthRange)
543 {
544 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
545 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000546 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000547
Jamie Madillf91ce812014-06-13 10:04:34 -0400548 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000549 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400550 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000551 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400552 out << flaggedStructs;
553 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000554 }
555
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000556 if (usingMRTExtension && mNumRenderTargets > 1)
557 {
558 out << "#define GL_USES_MRT\n";
559 }
560
561 if (mUsesFragColor)
562 {
563 out << "#define GL_USES_FRAG_COLOR\n";
564 }
565
566 if (mUsesFragData)
567 {
568 out << "#define GL_USES_FRAG_DATA\n";
569 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000571 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000573 out << "// Attributes\n";
574 out << attributes;
575 out << "\n"
576 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400577
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000578 if (mUsesPointSize)
579 {
580 out << "static float gl_PointSize = float(1);\n";
581 }
582
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000583 if (mUsesInstanceID)
584 {
585 out << "static int gl_InstanceID;";
586 }
587
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000588 out << "\n"
589 "// Varyings\n";
590 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000591 out << "\n";
592
593 if (mUsesDepthRange)
594 {
595 out << "struct gl_DepthRangeParameters\n"
596 "{\n"
597 " float near;\n"
598 " float far;\n"
599 " float diff;\n"
600 "};\n"
601 "\n";
602 }
603
604 if (mOutputType == SH_HLSL11_OUTPUT)
605 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800606 out << "cbuffer DriverConstants : register(b1)\n"
607 "{\n";
608
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000609 if (mUsesDepthRange)
610 {
Austin Kinross4fd18b12014-12-22 12:32:05 -0800611 out << " float3 dx_DepthRange : packoffset(c0);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000612 }
Austin Kinross4fd18b12014-12-22 12:32:05 -0800613
Cooper Partine6664f02015-01-09 16:22:24 -0800614 // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders.
Austin Kinross4fd18b12014-12-22 12:32:05 -0800615 // However, we declare it for all shaders (including Feature Level 10+).
616 // The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused.
617 out << " float4 dx_ViewAdjust : packoffset(c1);\n";
Cooper Partine6664f02015-01-09 16:22:24 -0800618 out << " float2 dx_ViewCoords : packoffset(c2);\n";
Austin Kinross4fd18b12014-12-22 12:32:05 -0800619
620 out << "};\n"
621 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000622 }
623 else
624 {
625 if (mUsesDepthRange)
626 {
627 out << "uniform float3 dx_DepthRange : register(c0);\n";
628 }
629
Cooper Partine6664f02015-01-09 16:22:24 -0800630 out << "uniform float4 dx_ViewAdjust : register(c1);\n";
631 out << "uniform float2 dx_ViewCoords : register(c2);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000632 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000633 }
634
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000635 if (mUsesDepthRange)
636 {
637 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
638 "\n";
639 }
640
Jamie Madillf91ce812014-06-13 10:04:34 -0400641 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000642 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400643 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000644 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400645 out << flaggedStructs;
646 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000647 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400648 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000649
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400650 for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
651 {
652 // Return type
Nicolas Capens75fb4752013-07-10 15:14:47 -0400653 if (textureFunction->method == TextureFunction::SIZE)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000654 {
Nicolas Capens75fb4752013-07-10 15:14:47 -0400655 switch(textureFunction->sampler)
656 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400657 case EbtSampler2D: out << "int2 "; break;
658 case EbtSampler3D: out << "int3 "; break;
659 case EbtSamplerCube: out << "int2 "; break;
660 case EbtSampler2DArray: out << "int3 "; break;
661 case EbtISampler2D: out << "int2 "; break;
662 case EbtISampler3D: out << "int3 "; break;
663 case EbtISamplerCube: out << "int2 "; break;
664 case EbtISampler2DArray: out << "int3 "; break;
665 case EbtUSampler2D: out << "int2 "; break;
666 case EbtUSampler3D: out << "int3 "; break;
667 case EbtUSamplerCube: out << "int2 "; break;
668 case EbtUSampler2DArray: out << "int3 "; break;
669 case EbtSampler2DShadow: out << "int2 "; break;
670 case EbtSamplerCubeShadow: out << "int2 "; break;
671 case EbtSampler2DArrayShadow: out << "int3 "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400672 default: UNREACHABLE();
673 }
674 }
675 else // Sampling function
676 {
677 switch(textureFunction->sampler)
678 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400679 case EbtSampler2D: out << "float4 "; break;
680 case EbtSampler3D: out << "float4 "; break;
681 case EbtSamplerCube: out << "float4 "; break;
682 case EbtSampler2DArray: out << "float4 "; break;
683 case EbtISampler2D: out << "int4 "; break;
684 case EbtISampler3D: out << "int4 "; break;
685 case EbtISamplerCube: out << "int4 "; break;
686 case EbtISampler2DArray: out << "int4 "; break;
687 case EbtUSampler2D: out << "uint4 "; break;
688 case EbtUSampler3D: out << "uint4 "; break;
689 case EbtUSamplerCube: out << "uint4 "; break;
690 case EbtUSampler2DArray: out << "uint4 "; break;
691 case EbtSampler2DShadow: out << "float "; break;
692 case EbtSamplerCubeShadow: out << "float "; break;
693 case EbtSampler2DArrayShadow: out << "float "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400694 default: UNREACHABLE();
695 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000696 }
697
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400698 // Function name
699 out << textureFunction->name();
700
701 // Argument list
702 int hlslCoords = 4;
703
704 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000705 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400706 switch(textureFunction->sampler)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000707 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400708 case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
709 case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
710 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000711 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400712
Nicolas Capens75fb4752013-07-10 15:14:47 -0400713 switch(textureFunction->method)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000714 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400715 case TextureFunction::IMPLICIT: break;
716 case TextureFunction::BIAS: hlslCoords = 4; break;
717 case TextureFunction::LOD: hlslCoords = 4; break;
718 case TextureFunction::LOD0: hlslCoords = 4; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400719 case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400720 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000721 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400722 }
723 else if (mOutputType == SH_HLSL11_OUTPUT)
724 {
725 switch(textureFunction->sampler)
726 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400727 case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
728 case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
729 case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
730 case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
731 case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
732 case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500733 case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400734 case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
735 case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
736 case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500737 case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400738 case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
739 case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
740 case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
741 case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400742 default: UNREACHABLE();
743 }
744 }
745 else UNREACHABLE();
746
Nicolas Capensfc014542014-02-18 14:47:13 -0500747 if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400748 {
Nicolas Capensfc014542014-02-18 14:47:13 -0500749 switch(textureFunction->coords)
750 {
751 case 2: out << ", int2 t"; break;
752 case 3: out << ", int3 t"; break;
753 default: UNREACHABLE();
754 }
755 }
756 else // Floating-point coordinates (except textureSize)
757 {
758 switch(textureFunction->coords)
759 {
760 case 1: out << ", int lod"; break; // textureSize()
761 case 2: out << ", float2 t"; break;
762 case 3: out << ", float3 t"; break;
763 case 4: out << ", float4 t"; break;
764 default: UNREACHABLE();
765 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000766 }
767
Nicolas Capensd11d5492014-02-19 17:06:10 -0500768 if (textureFunction->method == TextureFunction::GRAD)
769 {
770 switch(textureFunction->sampler)
771 {
772 case EbtSampler2D:
773 case EbtISampler2D:
774 case EbtUSampler2D:
775 case EbtSampler2DArray:
776 case EbtISampler2DArray:
777 case EbtUSampler2DArray:
778 case EbtSampler2DShadow:
779 case EbtSampler2DArrayShadow:
780 out << ", float2 ddx, float2 ddy";
781 break;
782 case EbtSampler3D:
783 case EbtISampler3D:
784 case EbtUSampler3D:
785 case EbtSamplerCube:
786 case EbtISamplerCube:
787 case EbtUSamplerCube:
788 case EbtSamplerCubeShadow:
789 out << ", float3 ddx, float3 ddy";
790 break;
791 default: UNREACHABLE();
792 }
793 }
794
Nicolas Capens75fb4752013-07-10 15:14:47 -0400795 switch(textureFunction->method)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000796 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400797 case TextureFunction::IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400798 case TextureFunction::BIAS: break; // Comes after the offset parameter
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400799 case TextureFunction::LOD: out << ", float lod"; break;
800 case TextureFunction::LOD0: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400801 case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
Nicolas Capens75fb4752013-07-10 15:14:47 -0400802 case TextureFunction::SIZE: break;
Nicolas Capensfc014542014-02-18 14:47:13 -0500803 case TextureFunction::FETCH: out << ", int mip"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -0500804 case TextureFunction::GRAD: break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400805 default: UNREACHABLE();
daniel@transgaming.com15795192011-05-11 15:36:20 +0000806 }
807
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500808 if (textureFunction->offset)
809 {
810 switch(textureFunction->sampler)
811 {
812 case EbtSampler2D: out << ", int2 offset"; break;
813 case EbtSampler3D: out << ", int3 offset"; break;
814 case EbtSampler2DArray: out << ", int2 offset"; break;
815 case EbtISampler2D: out << ", int2 offset"; break;
816 case EbtISampler3D: out << ", int3 offset"; break;
817 case EbtISampler2DArray: out << ", int2 offset"; break;
818 case EbtUSampler2D: out << ", int2 offset"; break;
819 case EbtUSampler3D: out << ", int3 offset"; break;
820 case EbtUSampler2DArray: out << ", int2 offset"; break;
821 case EbtSampler2DShadow: out << ", int2 offset"; break;
Nicolas Capensbf7db102014-02-19 17:20:28 -0500822 case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500823 default: UNREACHABLE();
824 }
825 }
826
Nicolas Capens84cfa122014-04-14 13:48:45 -0400827 if (textureFunction->method == TextureFunction::BIAS ||
828 textureFunction->method == TextureFunction::LOD0BIAS)
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500829 {
830 out << ", float bias";
831 }
832
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400833 out << ")\n"
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400834 "{\n";
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400835
Nicolas Capens75fb4752013-07-10 15:14:47 -0400836 if (textureFunction->method == TextureFunction::SIZE)
837 {
838 if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
839 {
840 if (IsSamplerArray(textureFunction->sampler))
841 {
842 out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
843 " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
844 }
845 else
846 {
847 out << " uint width; uint height; uint numberOfLevels;\n"
848 " x.GetDimensions(lod, width, height, numberOfLevels);\n";
849 }
850 }
851 else if (IsSampler3D(textureFunction->sampler))
852 {
853 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
854 " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
855 }
856 else UNREACHABLE();
857
858 switch(textureFunction->sampler)
859 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400860 case EbtSampler2D: out << " return int2(width, height);"; break;
861 case EbtSampler3D: out << " return int3(width, height, depth);"; break;
862 case EbtSamplerCube: out << " return int2(width, height);"; break;
863 case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
864 case EbtISampler2D: out << " return int2(width, height);"; break;
865 case EbtISampler3D: out << " return int3(width, height, depth);"; break;
866 case EbtISamplerCube: out << " return int2(width, height);"; break;
867 case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
868 case EbtUSampler2D: out << " return int2(width, height);"; break;
869 case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
870 case EbtUSamplerCube: out << " return int2(width, height);"; break;
871 case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
872 case EbtSampler2DShadow: out << " return int2(width, height);"; break;
873 case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
874 case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400875 default: UNREACHABLE();
876 }
877 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400878 else
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400879 {
Nicolas Capens0027fa92014-02-20 14:26:42 -0500880 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
881 {
882 out << " float width; float height; float layers; float levels;\n";
883
884 out << " uint mip = 0;\n";
885
886 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
887
888 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
889 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
890 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
891 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
892
893 // FACE_POSITIVE_X = 000b
894 // FACE_NEGATIVE_X = 001b
895 // FACE_POSITIVE_Y = 010b
896 // FACE_NEGATIVE_Y = 011b
897 // FACE_POSITIVE_Z = 100b
898 // FACE_NEGATIVE_Z = 101b
899 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
900
901 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
902 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
903 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
904
905 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
906 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
907 }
908 else if (IsIntegerSampler(textureFunction->sampler) &&
909 textureFunction->method != TextureFunction::FETCH)
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400910 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400911 if (IsSampler2D(textureFunction->sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400912 {
Nicolas Capens93e50de2013-07-09 13:46:28 -0400913 if (IsSamplerArray(textureFunction->sampler))
914 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400915 out << " float width; float height; float layers; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400916
Nicolas Capens9edebd62013-08-06 10:59:10 -0400917 if (textureFunction->method == TextureFunction::LOD0)
918 {
919 out << " uint mip = 0;\n";
920 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400921 else if (textureFunction->method == TextureFunction::LOD0BIAS)
922 {
923 out << " uint mip = bias;\n";
924 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400925 else
926 {
927 if (textureFunction->method == TextureFunction::IMPLICIT ||
928 textureFunction->method == TextureFunction::BIAS)
929 {
930 out << " x.GetDimensions(0, width, height, layers, levels);\n"
931 " float2 tSized = float2(t.x * width, t.y * height);\n"
932 " float dx = length(ddx(tSized));\n"
933 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500934 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400935
936 if (textureFunction->method == TextureFunction::BIAS)
937 {
938 out << " lod += bias;\n";
939 }
940 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500941 else if (textureFunction->method == TextureFunction::GRAD)
942 {
943 out << " x.GetDimensions(0, width, height, layers, levels);\n"
944 " float lod = log2(max(length(ddx), length(ddy)));\n";
945 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400946
947 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
948 }
949
950 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400951 }
952 else
953 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400954 out << " float width; float height; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400955
Nicolas Capens9edebd62013-08-06 10:59:10 -0400956 if (textureFunction->method == TextureFunction::LOD0)
957 {
958 out << " uint mip = 0;\n";
959 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400960 else if (textureFunction->method == TextureFunction::LOD0BIAS)
961 {
962 out << " uint mip = bias;\n";
963 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400964 else
965 {
966 if (textureFunction->method == TextureFunction::IMPLICIT ||
967 textureFunction->method == TextureFunction::BIAS)
968 {
969 out << " x.GetDimensions(0, width, height, levels);\n"
970 " float2 tSized = float2(t.x * width, t.y * height);\n"
971 " float dx = length(ddx(tSized));\n"
972 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500973 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400974
975 if (textureFunction->method == TextureFunction::BIAS)
976 {
977 out << " lod += bias;\n";
978 }
979 }
Nicolas Capens2adc2562014-02-14 23:50:59 -0500980 else if (textureFunction->method == TextureFunction::LOD)
981 {
982 out << " x.GetDimensions(0, width, height, levels);\n";
983 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500984 else if (textureFunction->method == TextureFunction::GRAD)
985 {
986 out << " x.GetDimensions(0, width, height, levels);\n"
987 " float lod = log2(max(length(ddx), length(ddy)));\n";
988 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400989
990 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
991 }
992
993 out << " x.GetDimensions(mip, width, height, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400994 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400995 }
996 else if (IsSampler3D(textureFunction->sampler))
997 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400998 out << " float width; float height; float depth; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400999
Nicolas Capens9edebd62013-08-06 10:59:10 -04001000 if (textureFunction->method == TextureFunction::LOD0)
1001 {
1002 out << " uint mip = 0;\n";
1003 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001004 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1005 {
1006 out << " uint mip = bias;\n";
1007 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001008 else
1009 {
1010 if (textureFunction->method == TextureFunction::IMPLICIT ||
1011 textureFunction->method == TextureFunction::BIAS)
1012 {
1013 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1014 " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
1015 " float dx = length(ddx(tSized));\n"
1016 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001017 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001018
1019 if (textureFunction->method == TextureFunction::BIAS)
1020 {
1021 out << " lod += bias;\n";
1022 }
1023 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001024 else if (textureFunction->method == TextureFunction::GRAD)
1025 {
1026 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1027 " float lod = log2(max(length(ddx), length(ddy)));\n";
1028 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001029
1030 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1031 }
1032
1033 out << " x.GetDimensions(mip, width, height, depth, levels);\n";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001034 }
1035 else UNREACHABLE();
1036 }
1037
1038 out << " return ";
1039
1040 // HLSL intrinsic
1041 if (mOutputType == SH_HLSL9_OUTPUT)
1042 {
1043 switch(textureFunction->sampler)
1044 {
1045 case EbtSampler2D: out << "tex2D"; break;
1046 case EbtSamplerCube: out << "texCUBE"; break;
1047 default: UNREACHABLE();
1048 }
1049
Nicolas Capens75fb4752013-07-10 15:14:47 -04001050 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001051 {
1052 case TextureFunction::IMPLICIT: out << "(s, "; break;
1053 case TextureFunction::BIAS: out << "bias(s, "; break;
1054 case TextureFunction::LOD: out << "lod(s, "; break;
1055 case TextureFunction::LOD0: out << "lod(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001056 case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001057 default: UNREACHABLE();
1058 }
1059 }
1060 else if (mOutputType == SH_HLSL11_OUTPUT)
1061 {
Nicolas Capensd11d5492014-02-19 17:06:10 -05001062 if (textureFunction->method == TextureFunction::GRAD)
1063 {
1064 if (IsIntegerSampler(textureFunction->sampler))
1065 {
1066 out << "x.Load(";
1067 }
1068 else if (IsShadowSampler(textureFunction->sampler))
1069 {
1070 out << "x.SampleCmpLevelZero(s, ";
1071 }
1072 else
1073 {
1074 out << "x.SampleGrad(s, ";
1075 }
1076 }
1077 else if (IsIntegerSampler(textureFunction->sampler) ||
1078 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001079 {
1080 out << "x.Load(";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001081 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001082 else if (IsShadowSampler(textureFunction->sampler))
1083 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001084 switch(textureFunction->method)
1085 {
1086 case TextureFunction::IMPLICIT: out << "x.SampleCmp(s, "; break;
1087 case TextureFunction::BIAS: out << "x.SampleCmp(s, "; break;
1088 case TextureFunction::LOD: out << "x.SampleCmp(s, "; break;
1089 case TextureFunction::LOD0: out << "x.SampleCmpLevelZero(s, "; break;
1090 case TextureFunction::LOD0BIAS: out << "x.SampleCmpLevelZero(s, "; break;
1091 default: UNREACHABLE();
1092 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001093 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001094 else
1095 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001096 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001097 {
1098 case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
1099 case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
1100 case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
1101 case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001102 case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001103 default: UNREACHABLE();
1104 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001105 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001106 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001107 else UNREACHABLE();
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001108
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001109 // Integer sampling requires integer addresses
1110 TString addressx = "";
1111 TString addressy = "";
1112 TString addressz = "";
1113 TString close = "";
1114
Nicolas Capensfc014542014-02-18 14:47:13 -05001115 if (IsIntegerSampler(textureFunction->sampler) ||
1116 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001117 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001118 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001119 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001120 case 2: out << "int3("; break;
1121 case 3: out << "int4("; break;
1122 default: UNREACHABLE();
1123 }
Jamie Madillf91ce812014-06-13 10:04:34 -04001124
Nicolas Capensfc014542014-02-18 14:47:13 -05001125 // Convert from normalized floating-point to integer
1126 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001127 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001128 addressx = "int(floor(width * frac((";
1129 addressy = "int(floor(height * frac((";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001130
Nicolas Capensfc014542014-02-18 14:47:13 -05001131 if (IsSamplerArray(textureFunction->sampler))
1132 {
1133 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
1134 }
Nicolas Capens0027fa92014-02-20 14:26:42 -05001135 else if (IsSamplerCube(textureFunction->sampler))
1136 {
1137 addressz = "((((";
1138 }
Nicolas Capensfc014542014-02-18 14:47:13 -05001139 else
1140 {
1141 addressz = "int(floor(depth * frac((";
1142 }
1143
1144 close = "))))";
1145 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001146 }
1147 else
1148 {
1149 switch(hlslCoords)
1150 {
1151 case 2: out << "float2("; break;
1152 case 3: out << "float3("; break;
1153 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001154 default: UNREACHABLE();
1155 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001156 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001157
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001158 TString proj = ""; // Only used for projected textures
Jamie Madillf91ce812014-06-13 10:04:34 -04001159
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001160 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001161 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001162 switch(textureFunction->coords)
1163 {
1164 case 3: proj = " / t.z"; break;
1165 case 4: proj = " / t.w"; break;
1166 default: UNREACHABLE();
1167 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001168 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001169
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001170 out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001171
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001172 if (mOutputType == SH_HLSL9_OUTPUT)
1173 {
1174 if (hlslCoords >= 3)
1175 {
1176 if (textureFunction->coords < 3)
1177 {
1178 out << ", 0";
1179 }
1180 else
1181 {
1182 out << ", t.z" + proj;
1183 }
1184 }
1185
1186 if (hlslCoords == 4)
1187 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001188 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001189 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001190 case TextureFunction::BIAS: out << ", bias"; break;
1191 case TextureFunction::LOD: out << ", lod"; break;
1192 case TextureFunction::LOD0: out << ", 0"; break;
1193 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001194 default: UNREACHABLE();
1195 }
1196 }
1197
1198 out << "));\n";
1199 }
1200 else if (mOutputType == SH_HLSL11_OUTPUT)
1201 {
1202 if (hlslCoords >= 3)
1203 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001204 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1205 {
1206 out << ", face";
1207 }
1208 else
1209 {
1210 out << ", " + addressz + ("t.z" + proj) + close;
1211 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001212 }
1213
Nicolas Capensd11d5492014-02-19 17:06:10 -05001214 if (textureFunction->method == TextureFunction::GRAD)
1215 {
1216 if (IsIntegerSampler(textureFunction->sampler))
1217 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001218 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001219 }
1220 else if (IsShadowSampler(textureFunction->sampler))
1221 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001222 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001223 if (textureFunction->proj)
Nicolas Capensd11d5492014-02-19 17:06:10 -05001224 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001225 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1226 // The resulting third component of P' in the shadow forms is used as Dref
1227 out << "), t.z" << proj;
1228 }
1229 else
1230 {
1231 switch(textureFunction->coords)
1232 {
1233 case 3: out << "), t.z"; break;
1234 case 4: out << "), t.w"; break;
1235 default: UNREACHABLE();
1236 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001237 }
1238 }
1239 else
1240 {
1241 out << "), ddx, ddy";
1242 }
1243 }
1244 else if (IsIntegerSampler(textureFunction->sampler) ||
1245 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001246 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001247 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001248 }
1249 else if (IsShadowSampler(textureFunction->sampler))
1250 {
1251 // Compare value
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001252 if (textureFunction->proj)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001253 {
Gregoire Payen de La Garanderie5cc9ac82015-02-20 11:27:56 +00001254 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1255 // The resulting third component of P' in the shadow forms is used as Dref
1256 out << "), t.z" << proj;
1257 }
1258 else
1259 {
1260 switch(textureFunction->coords)
1261 {
1262 case 3: out << "), t.z"; break;
1263 case 4: out << "), t.w"; break;
1264 default: UNREACHABLE();
1265 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001266 }
1267 }
1268 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001269 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001270 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001271 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001272 case TextureFunction::IMPLICIT: out << ")"; break;
1273 case TextureFunction::BIAS: out << "), bias"; break;
1274 case TextureFunction::LOD: out << "), lod"; break;
1275 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001276 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001277 default: UNREACHABLE();
1278 }
1279 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001280
1281 if (textureFunction->offset)
1282 {
1283 out << ", offset";
1284 }
1285
1286 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001287 }
1288 else UNREACHABLE();
1289 }
1290
1291 out << "\n"
1292 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001293 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001294 }
1295
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001296 if (mUsesFragCoord)
1297 {
1298 out << "#define GL_USES_FRAG_COORD\n";
1299 }
1300
1301 if (mUsesPointCoord)
1302 {
1303 out << "#define GL_USES_POINT_COORD\n";
1304 }
1305
1306 if (mUsesFrontFacing)
1307 {
1308 out << "#define GL_USES_FRONT_FACING\n";
1309 }
1310
1311 if (mUsesPointSize)
1312 {
1313 out << "#define GL_USES_POINT_SIZE\n";
1314 }
1315
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001316 if (mUsesFragDepth)
1317 {
1318 out << "#define GL_USES_FRAG_DEPTH\n";
1319 }
1320
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001321 if (mUsesDepthRange)
1322 {
1323 out << "#define GL_USES_DEPTH_RANGE\n";
1324 }
1325
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001326 if (mUsesXor)
1327 {
1328 out << "bool xor(bool p, bool q)\n"
1329 "{\n"
1330 " return (p || q) && !(p && q);\n"
1331 "}\n"
1332 "\n";
1333 }
1334
Olli Etuaho95cd3c62015-03-03 16:45:32 +02001335 builtInFunctionEmulator->OutputEmulatedFunctions(out);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001336}
1337
1338void OutputHLSL::visitSymbol(TIntermSymbol *node)
1339{
Jamie Madill32aab012015-01-27 14:12:26 -05001340 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001341
Jamie Madill570e04d2013-06-21 09:15:33 -04001342 // Handle accessing std140 structs by value
1343 if (mFlaggedStructMappedNames.count(node) > 0)
1344 {
1345 out << mFlaggedStructMappedNames[node];
1346 return;
1347 }
1348
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349 TString name = node->getSymbol();
1350
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001351 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001352 {
1353 mUsesDepthRange = true;
1354 out << name;
1355 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001356 else
1357 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001358 TQualifier qualifier = node->getQualifier();
1359
1360 if (qualifier == EvqUniform)
1361 {
Jamie Madill2e295e22015-04-29 10:41:33 -04001362 const TType &nodeType = node->getType();
1363 const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
Jamie Madill98493dd2013-07-08 14:39:03 -04001364
1365 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001366 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001367 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001368 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001369 else
1370 {
1371 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001372 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001373
Jamie Madill2e295e22015-04-29 10:41:33 -04001374 ensureStructDefined(nodeType);
1375
Jamie Madill033dae62014-06-18 12:56:28 -04001376 out << DecorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001377 }
Jamie Madill19571812013-08-12 15:26:34 -07001378 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001379 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001380 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001381 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001382 }
Jamie Madill033dae62014-06-18 12:56:28 -04001383 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001384 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001385 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001386 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001387 }
Jamie Madill19571812013-08-12 15:26:34 -07001388 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001389 {
1390 mReferencedOutputVariables[name] = node;
1391 out << "out_" << name;
1392 }
1393 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001394 {
1395 out << "gl_Color[0]";
1396 mUsesFragColor = true;
1397 }
1398 else if (qualifier == EvqFragData)
1399 {
1400 out << "gl_Color";
1401 mUsesFragData = true;
1402 }
1403 else if (qualifier == EvqFragCoord)
1404 {
1405 mUsesFragCoord = true;
1406 out << name;
1407 }
1408 else if (qualifier == EvqPointCoord)
1409 {
1410 mUsesPointCoord = true;
1411 out << name;
1412 }
1413 else if (qualifier == EvqFrontFacing)
1414 {
1415 mUsesFrontFacing = true;
1416 out << name;
1417 }
1418 else if (qualifier == EvqPointSize)
1419 {
1420 mUsesPointSize = true;
1421 out << name;
1422 }
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +00001423 else if (qualifier == EvqInstanceID)
1424 {
1425 mUsesInstanceID = true;
1426 out << name;
1427 }
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +03001428 else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001429 {
1430 mUsesFragDepth = true;
1431 out << "gl_Depth";
1432 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001433 else
1434 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03001435 out << DecorateIfNeeded(node->getName());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001436 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001437 }
1438}
1439
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001440void OutputHLSL::visitRaw(TIntermRaw *node)
1441{
Jamie Madill32aab012015-01-27 14:12:26 -05001442 getInfoSink() << node->getRawText();
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001443}
1444
Olli Etuaho7fb49552015-03-18 17:27:44 +02001445void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1446{
1447 if (type.isScalar() && !type.isArray())
1448 {
1449 if (op == EOpEqual)
1450 {
1451 outputTriplet(visit, "(", " == ", ")", out);
1452 }
1453 else
1454 {
1455 outputTriplet(visit, "(", " != ", ")", out);
1456 }
1457 }
1458 else
1459 {
1460 if (visit == PreVisit && op == EOpNotEqual)
1461 {
1462 out << "!";
1463 }
1464
1465 if (type.isArray())
1466 {
1467 const TString &functionName = addArrayEqualityFunction(type);
1468 outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out);
1469 }
1470 else if (type.getBasicType() == EbtStruct)
1471 {
1472 const TStructure &structure = *type.getStruct();
1473 const TString &functionName = addStructEqualityFunction(structure);
1474 outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out);
1475 }
1476 else
1477 {
1478 ASSERT(type.isMatrix() || type.isVector());
1479 outputTriplet(visit, "all(", " == ", ")", out);
1480 }
1481 }
1482}
1483
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1485{
Jamie Madill32aab012015-01-27 14:12:26 -05001486 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001487
Jamie Madill570e04d2013-06-21 09:15:33 -04001488 // Handle accessing std140 structs by value
1489 if (mFlaggedStructMappedNames.count(node) > 0)
1490 {
1491 out << mFlaggedStructMappedNames[node];
1492 return false;
1493 }
1494
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495 switch (node->getOp())
1496 {
Olli Etuahoe79904c2015-03-18 16:56:42 +02001497 case EOpAssign:
1498 if (node->getLeft()->isArray())
1499 {
Olli Etuaho9638c352015-04-01 14:34:52 +03001500 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1501 if (rightAgg != nullptr && rightAgg->isConstructor())
1502 {
1503 const TString &functionName = addArrayConstructIntoFunction(node->getType());
1504 out << functionName << "(";
1505 node->getLeft()->traverse(this);
1506 TIntermSequence *seq = rightAgg->getSequence();
1507 for (auto &arrayElement : *seq)
1508 {
1509 out << ", ";
1510 arrayElement->traverse(this);
1511 }
1512 out << ")";
1513 return false;
1514 }
Olli Etuahoa8c414b2015-04-16 15:51:03 +03001515 // ArrayReturnValueToOutParameter should have eliminated expressions where a function call is assigned.
1516 ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
1517
1518 const TString &functionName = addArrayAssignmentFunction(node->getType());
1519 outputTriplet(visit, (functionName + "(").c_str(), ", ", ")");
Olli Etuahoe79904c2015-03-18 16:56:42 +02001520 }
1521 else
1522 {
1523 outputTriplet(visit, "(", " = ", ")");
1524 }
1525 break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001526 case EOpInitialize:
1527 if (visit == PreVisit)
1528 {
1529 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1530 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1531 // new variable is created before the assignment is evaluated), so we need to convert
1532 // this to "float t = x, x = t;".
1533
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001534 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
Jamie Madill37997142015-01-28 10:06:34 -05001535 ASSERT(symbolNode);
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001536 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001537
Jamie Madill37997142015-01-28 10:06:34 -05001538 // TODO (jmadill): do a 'deep' scan to know if an expression is statically const
1539 if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst)
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001540 {
Jamie Madill37997142015-01-28 10:06:34 -05001541 // For variables which are not constant, defer their real initialization until
Olli Etuahod81ed842015-05-12 12:46:35 +03001542 // after we initialize uniforms.
1543 TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
1544 deferredInit->setLeft(node->getLeft());
1545 deferredInit->setRight(node->getRight());
1546 deferredInit->setType(node->getType());
1547 mDeferredGlobalInitializers.push_back(deferredInit);
Jamie Madill37997142015-01-28 10:06:34 -05001548 const TString &initString = initializer(node->getType());
1549 node->setRight(new TIntermRaw(node->getType(), initString));
1550 }
1551 else if (writeSameSymbolInitializer(out, symbolNode, expression))
1552 {
1553 // Skip initializing the rest of the expression
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001554 return false;
1555 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02001556 else if (writeConstantInitialization(out, symbolNode, expression))
1557 {
1558 return false;
1559 }
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001560 }
1561 else if (visit == InVisit)
1562 {
1563 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001564 }
1565 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001566 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
1567 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
1568 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1569 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1570 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1571 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001572 if (visit == PreVisit)
1573 {
1574 out << "(";
1575 }
1576 else if (visit == InVisit)
1577 {
1578 out << " = mul(";
1579 node->getLeft()->traverse(this);
Jamie Madillf91ce812014-06-13 10:04:34 -04001580 out << ", transpose(";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001581 }
1582 else
1583 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001584 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001585 }
1586 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001587 case EOpMatrixTimesMatrixAssign:
1588 if (visit == PreVisit)
1589 {
1590 out << "(";
1591 }
1592 else if (visit == InVisit)
1593 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001594 out << " = transpose(mul(transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001595 node->getLeft()->traverse(this);
Olli Etuahofc7fab72015-03-06 12:03:18 +02001596 out << "), transpose(";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001597 }
1598 else
1599 {
Olli Etuahofc7fab72015-03-06 12:03:18 +02001600 out << "))))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001601 }
1602 break;
1603 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
Olli Etuahoff805cc2015-02-13 10:59:34 +02001604 case EOpIModAssign: outputTriplet(visit, "(", " %= ", ")"); break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001605 case EOpBitShiftLeftAssign: outputTriplet(visit, "(", " <<= ", ")"); break;
1606 case EOpBitShiftRightAssign: outputTriplet(visit, "(", " >>= ", ")"); break;
1607 case EOpBitwiseAndAssign: outputTriplet(visit, "(", " &= ", ")"); break;
1608 case EOpBitwiseXorAssign: outputTriplet(visit, "(", " ^= ", ")"); break;
1609 case EOpBitwiseOrAssign: outputTriplet(visit, "(", " |= ", ")"); break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001610 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001611 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001612 const TType& leftType = node->getLeft()->getType();
1613 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001614 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001615 if (visit == PreVisit)
1616 {
1617 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1618 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001619 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001620 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001621 return false;
1622 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001623 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001624 else
1625 {
1626 outputTriplet(visit, "", "[", "]");
1627 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001628 }
1629 break;
1630 case EOpIndexIndirect:
1631 // We do not currently support indirect references to interface blocks
1632 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1633 outputTriplet(visit, "", "[", "]");
1634 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001635 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001636 if (visit == InVisit)
1637 {
1638 const TStructure* structure = node->getLeft()->getType().getStruct();
1639 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1640 const TField* field = structure->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001641 out << "." + DecorateField(field->name(), *structure);
Jamie Madill98493dd2013-07-08 14:39:03 -04001642
1643 return false;
1644 }
1645 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001646 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001647 if (visit == InVisit)
1648 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001649 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1650 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1651 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001652 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001653
1654 return false;
1655 }
1656 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001657 case EOpVectorSwizzle:
1658 if (visit == InVisit)
1659 {
1660 out << ".";
1661
1662 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1663
1664 if (swizzle)
1665 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001666 TIntermSequence *sequence = swizzle->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001668 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001669 {
1670 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1671
1672 if (element)
1673 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00001674 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001675
1676 switch (i)
1677 {
1678 case 0: out << "x"; break;
1679 case 1: out << "y"; break;
1680 case 2: out << "z"; break;
1681 case 3: out << "w"; break;
1682 default: UNREACHABLE();
1683 }
1684 }
1685 else UNREACHABLE();
1686 }
1687 }
1688 else UNREACHABLE();
1689
1690 return false; // Fully processed
1691 }
1692 break;
1693 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
1694 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
1695 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
1696 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
Olli Etuahoff805cc2015-02-13 10:59:34 +02001697 case EOpIMod: outputTriplet(visit, "(", " % ", ")"); break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001698 case EOpBitShiftLeft: outputTriplet(visit, "(", " << ", ")"); break;
1699 case EOpBitShiftRight: outputTriplet(visit, "(", " >> ", ")"); break;
1700 case EOpBitwiseAnd: outputTriplet(visit, "(", " & ", ")"); break;
1701 case EOpBitwiseXor: outputTriplet(visit, "(", " ^ ", ")"); break;
1702 case EOpBitwiseOr: outputTriplet(visit, "(", " | ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001703 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001704 case EOpNotEqual:
Olli Etuaho7fb49552015-03-18 17:27:44 +02001705 outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001706 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1708 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1709 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1710 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1711 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001712 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001713 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1714 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001715 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001716 case EOpLogicalOr:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001717 // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
1718 ASSERT(!node->getRight()->hasSideEffects());
1719 outputTriplet(visit, "(", " || ", ")");
1720 return true;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001721 case EOpLogicalXor:
1722 mUsesXor = true;
1723 outputTriplet(visit, "xor(", ", ", ")");
1724 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001725 case EOpLogicalAnd:
Olli Etuahoa6f22092015-05-08 18:31:10 +03001726 // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
1727 ASSERT(!node->getRight()->hasSideEffects());
1728 outputTriplet(visit, "(", " && ", ")");
1729 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001730 default: UNREACHABLE();
1731 }
1732
1733 return true;
1734}
1735
1736bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1737{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001738 switch (node->getOp())
1739 {
Nicolas Capens16004fc2014-06-11 11:29:11 -04001740 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001741 case EOpPositive: outputTriplet(visit, "(+", "", ")"); break;
Nicolas Capens16004fc2014-06-11 11:29:11 -04001742 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1743 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001744 case EOpBitwiseNot: outputTriplet(visit, "(~", "", ")"); break;
Nicolas Capens16004fc2014-06-11 11:29:11 -04001745 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1746 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1747 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1748 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001749 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1750 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1751 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1752 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1753 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1754 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1755 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1756 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02001757 case EOpSinh: outputTriplet(visit, "sinh(", "", ")"); break;
1758 case EOpCosh: outputTriplet(visit, "cosh(", "", ")"); break;
1759 case EOpTanh: outputTriplet(visit, "tanh(", "", ")"); break;
1760 case EOpAsinh:
1761 ASSERT(node->getUseEmulatedFunction());
1762 writeEmulatedFunctionTriplet(visit, "asinh(");
1763 break;
1764 case EOpAcosh:
1765 ASSERT(node->getUseEmulatedFunction());
1766 writeEmulatedFunctionTriplet(visit, "acosh(");
1767 break;
1768 case EOpAtanh:
1769 ASSERT(node->getUseEmulatedFunction());
1770 writeEmulatedFunctionTriplet(visit, "atanh(");
1771 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001772 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1773 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1774 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1775 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1776 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1777 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1778 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1779 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1780 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
Qingqing Deng5dbece52015-02-27 20:35:38 -08001781 case EOpTrunc: outputTriplet(visit, "trunc(", "", ")"); break;
1782 case EOpRound: outputTriplet(visit, "round(", "", ")"); break;
1783 case EOpRoundEven:
1784 ASSERT(node->getUseEmulatedFunction());
1785 writeEmulatedFunctionTriplet(visit, "roundEven(");
1786 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001787 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1788 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
Arun Patole44efa0b2015-03-04 17:11:05 +05301789 case EOpIsNan:
1790 outputTriplet(visit, "isnan(", "", ")");
1791 mRequiresIEEEStrictCompiling = true;
1792 break;
Arun Patole0c1726e2015-02-18 14:35:02 +05301793 case EOpIsInf: outputTriplet(visit, "isinf(", "", ")"); break;
Olli Etuahoe8d2c072015-01-08 16:33:54 +02001794 case EOpFloatBitsToInt: outputTriplet(visit, "asint(", "", ")"); break;
1795 case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break;
1796 case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
1797 case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
Olli Etuaho7700ff62015-01-15 12:16:29 +02001798 case EOpPackSnorm2x16:
1799 ASSERT(node->getUseEmulatedFunction());
1800 writeEmulatedFunctionTriplet(visit, "packSnorm2x16(");
1801 break;
1802 case EOpPackUnorm2x16:
1803 ASSERT(node->getUseEmulatedFunction());
1804 writeEmulatedFunctionTriplet(visit, "packUnorm2x16(");
1805 break;
1806 case EOpPackHalf2x16:
1807 ASSERT(node->getUseEmulatedFunction());
1808 writeEmulatedFunctionTriplet(visit, "packHalf2x16(");
1809 break;
1810 case EOpUnpackSnorm2x16:
1811 ASSERT(node->getUseEmulatedFunction());
1812 writeEmulatedFunctionTriplet(visit, "unpackSnorm2x16(");
1813 break;
1814 case EOpUnpackUnorm2x16:
1815 ASSERT(node->getUseEmulatedFunction());
1816 writeEmulatedFunctionTriplet(visit, "unpackUnorm2x16(");
1817 break;
1818 case EOpUnpackHalf2x16:
1819 ASSERT(node->getUseEmulatedFunction());
1820 writeEmulatedFunctionTriplet(visit, "unpackHalf2x16(");
1821 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001822 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1823 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001824 case EOpDFdx:
1825 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1826 {
1827 outputTriplet(visit, "(", "", ", 0.0)");
1828 }
1829 else
1830 {
1831 outputTriplet(visit, "ddx(", "", ")");
1832 }
1833 break;
1834 case EOpDFdy:
1835 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1836 {
1837 outputTriplet(visit, "(", "", ", 0.0)");
1838 }
1839 else
1840 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001841 outputTriplet(visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001842 }
1843 break;
1844 case EOpFwidth:
1845 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1846 {
1847 outputTriplet(visit, "(", "", ", 0.0)");
1848 }
1849 else
1850 {
1851 outputTriplet(visit, "fwidth(", "", ")");
1852 }
1853 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001854 case EOpTranspose: outputTriplet(visit, "transpose(", "", ")"); break;
1855 case EOpDeterminant: outputTriplet(visit, "determinant(transpose(", "", "))"); break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +02001856 case EOpInverse:
1857 ASSERT(node->getUseEmulatedFunction());
1858 writeEmulatedFunctionTriplet(visit, "inverse(");
1859 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001860
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001861 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1862 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001863 default: UNREACHABLE();
1864 }
1865
1866 return true;
1867}
1868
1869bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1870{
Jamie Madill32aab012015-01-27 14:12:26 -05001871 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001872
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001873 switch (node->getOp())
1874 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001875 case EOpSequence:
1876 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001877 if (mInsideFunction)
1878 {
Jamie Madill075edd82013-07-08 13:30:19 -04001879 outputLineDirective(node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001880 out << "{\n";
1881 }
1882
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001883 for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001884 {
Jamie Madill075edd82013-07-08 13:30:19 -04001885 outputLineDirective((*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001886
Olli Etuahoa6f22092015-05-08 18:31:10 +03001887 (*sit)->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001888
Olli Etuaho05ae50d2015-02-20 10:16:47 +02001889 // Don't output ; after case labels, they're terminated by :
1890 // This is needed especially since outputting a ; after a case statement would turn empty
1891 // case statements into non-empty case statements, disallowing fall-through from them.
Olli Etuaho4785fec2015-05-18 16:09:37 +03001892 // Also no need to output ; after selection (if) statements or sequences. This is done just
1893 // for code clarity.
Olli Etuahoa6f22092015-05-08 18:31:10 +03001894 TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
1895 ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
Olli Etuaho4785fec2015-05-18 16:09:37 +03001896 if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
Olli Etuaho05ae50d2015-02-20 10:16:47 +02001897 out << ";\n";
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001898 }
1899
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001900 if (mInsideFunction)
1901 {
Jamie Madill075edd82013-07-08 13:30:19 -04001902 outputLineDirective(node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001903 out << "}\n";
1904 }
1905
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001906 return false;
1907 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001908 case EOpDeclaration:
1909 if (visit == PreVisit)
1910 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001911 TIntermSequence *sequence = node->getSequence();
1912 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
Olli Etuahoa6f22092015-05-08 18:31:10 +03001913 ASSERT(sequence->size() == 1);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001914
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001915 if (variable &&
1916 (variable->getQualifier() == EvqTemporary ||
1917 variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001918 {
Jamie Madill2e295e22015-04-29 10:41:33 -04001919 ensureStructDefined(variable->getType());
daniel@transgaming.comead23042010-04-29 03:35:36 +00001920
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001921 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001922 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03001923 if (!mInsideFunction)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001924 {
Olli Etuahoa6f22092015-05-08 18:31:10 +03001925 out << "static ";
1926 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04001927
Olli Etuahoa6f22092015-05-08 18:31:10 +03001928 out << TypeString(variable->getType()) + " ";
Nicolas Capensd974db42014-10-07 10:50:19 -04001929
Olli Etuahoa6f22092015-05-08 18:31:10 +03001930 TIntermSymbol *symbol = variable->getAsSymbolNode();
Nicolas Capensd974db42014-10-07 10:50:19 -04001931
Olli Etuahoa6f22092015-05-08 18:31:10 +03001932 if (symbol)
1933 {
1934 symbol->traverse(this);
1935 out << ArrayString(symbol->getType());
1936 out << " = " + initializer(symbol->getType());
1937 }
1938 else
1939 {
1940 variable->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001941 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001942 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001943 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1944 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001945 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001946 }
1947 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001948 }
Jamie Madill033dae62014-06-18 12:56:28 -04001949 else if (variable && IsVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00001950 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001951 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00001952 {
1953 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1954
1955 if (symbol)
1956 {
1957 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
1958 mReferencedVaryings[symbol->getSymbol()] = symbol;
1959 }
1960 else
1961 {
1962 (*sit)->traverse(this);
1963 }
1964 }
1965 }
1966
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001967 return false;
1968 }
1969 else if (visit == InVisit)
1970 {
1971 out << ", ";
1972 }
1973 break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001974 case EOpInvariantDeclaration:
1975 // Do not do any translation
1976 return false;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001977 case EOpPrototype:
1978 if (visit == PreVisit)
1979 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07001980 size_t index = mCallDag.findIndex(node);
1981 // Skip the prototype if it is not implemented (and thus not used)
1982 if (index == CallDAG::InvalidIndex)
1983 {
1984 return false;
1985 }
1986
Olli Etuaho59f9a642015-08-06 20:38:26 +03001987 TString name = DecorateFunctionIfNeeded(node->getNameObj());
1988 out << TypeString(node->getType()) << " " << name
1989 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001990
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001991 TIntermSequence *arguments = node->getSequence();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001992
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001993 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001994 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001995 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001996
1997 if (symbol)
1998 {
1999 out << argumentString(symbol);
2000
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002001 if (i < arguments->size() - 1)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002002 {
2003 out << ", ";
2004 }
2005 }
2006 else UNREACHABLE();
2007 }
2008
2009 out << ");\n";
2010
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002011 // Also prototype the Lod0 variant if needed
Corentin Wallez1239ee92015-03-19 14:38:02 -07002012 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2013 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002014 {
2015 mOutputLod0Function = true;
2016 node->traverse(this);
2017 mOutputLod0Function = false;
2018 }
2019
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002020 return false;
2021 }
2022 break;
daniel@transgaming.comed2180d2012-03-26 17:08:54 +00002023 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002024 case EOpFunction:
2025 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002026 ASSERT(mCurrentFunctionMetadata == nullptr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03002027 TString name = TFunction::unmangleName(node->getNameObj().getString());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002028
Corentin Wallez1239ee92015-03-19 14:38:02 -07002029 size_t index = mCallDag.findIndex(node);
2030 ASSERT(index != CallDAG::InvalidIndex);
2031 mCurrentFunctionMetadata = &mASTMetadataList[index];
2032
Jamie Madill033dae62014-06-18 12:56:28 -04002033 out << TypeString(node->getType()) << " ";
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002034
2035 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002036 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002037 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002038 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002039 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002040 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002041 out << DecorateFunctionIfNeeded(node->getNameObj())
2042 << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002043 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002044
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002045 TIntermSequence *sequence = node->getSequence();
2046 TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002047
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002048 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002049 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002050 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002051
2052 if (symbol)
2053 {
Jamie Madill2e295e22015-04-29 10:41:33 -04002054 ensureStructDefined(symbol->getType());
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002055
2056 out << argumentString(symbol);
2057
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002058 if (i < arguments->size() - 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002059 {
2060 out << ", ";
2061 }
2062 }
2063 else UNREACHABLE();
2064 }
2065
Olli Etuaho4785fec2015-05-18 16:09:37 +03002066 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002067
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002068 if (sequence->size() > 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002069 {
2070 mInsideFunction = true;
Olli Etuaho4785fec2015-05-18 16:09:37 +03002071 TIntermNode *body = (*sequence)[1];
2072 // The function body node will output braces.
2073 ASSERT(IsSequence(body));
2074 body->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002075 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002077 else
2078 {
2079 out << "{}\n";
2080 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002081
Corentin Wallez1239ee92015-03-19 14:38:02 -07002082 mCurrentFunctionMetadata = nullptr;
2083
2084 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2085 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002086 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002087 ASSERT(name != "main");
2088 mOutputLod0Function = true;
2089 node->traverse(this);
2090 mOutputLod0Function = false;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002091 }
2092
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002093 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002094 }
2095 break;
2096 case EOpFunctionCall:
2097 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002098 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002099
Corentin Wallez1239ee92015-03-19 14:38:02 -07002100 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002101 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002102 {
Olli Etuahoa8c414b2015-04-16 15:51:03 +03002103 if (node->isArray())
2104 {
2105 UNIMPLEMENTED();
2106 }
Corentin Wallez1239ee92015-03-19 14:38:02 -07002107 size_t index = mCallDag.findIndex(node);
2108 ASSERT(index != CallDAG::InvalidIndex);
2109 lod0 &= mASTMetadataList[index].mNeedsLod0;
2110
Olli Etuaho59f9a642015-08-06 20:38:26 +03002111 out << DecorateFunctionIfNeeded(node->getNameObj()) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002112 }
2113 else
2114 {
Olli Etuaho59f9a642015-08-06 20:38:26 +03002115 TString name = TFunction::unmangleName(node->getNameObj().getString());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002116 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002117
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002118 TextureFunction textureFunction;
2119 textureFunction.sampler = samplerType;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002120 textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002121 textureFunction.method = TextureFunction::IMPLICIT;
2122 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002123 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002124
2125 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002126 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002127 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002128 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002129 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002130 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002131 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002132 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002133 }
Nicolas Capens46485082014-04-15 13:12:50 -04002134 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
2135 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002136 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002137 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002138 }
Nicolas Capens46485082014-04-15 13:12:50 -04002139 else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002140 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002141 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002142 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002143 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002144 else if (name == "textureSize")
2145 {
2146 textureFunction.method = TextureFunction::SIZE;
2147 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002148 else if (name == "textureOffset")
2149 {
2150 textureFunction.method = TextureFunction::IMPLICIT;
2151 textureFunction.offset = true;
2152 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002153 else if (name == "textureProjOffset")
2154 {
2155 textureFunction.method = TextureFunction::IMPLICIT;
2156 textureFunction.offset = true;
2157 textureFunction.proj = true;
2158 }
2159 else if (name == "textureLodOffset")
2160 {
2161 textureFunction.method = TextureFunction::LOD;
2162 textureFunction.offset = true;
2163 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002164 else if (name == "textureProjLodOffset")
2165 {
2166 textureFunction.method = TextureFunction::LOD;
2167 textureFunction.proj = true;
2168 textureFunction.offset = true;
2169 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002170 else if (name == "texelFetch")
2171 {
2172 textureFunction.method = TextureFunction::FETCH;
2173 }
2174 else if (name == "texelFetchOffset")
2175 {
2176 textureFunction.method = TextureFunction::FETCH;
2177 textureFunction.offset = true;
2178 }
Nicolas Capens46485082014-04-15 13:12:50 -04002179 else if (name == "textureGrad" || name == "texture2DGradEXT")
Nicolas Capensd11d5492014-02-19 17:06:10 -05002180 {
2181 textureFunction.method = TextureFunction::GRAD;
2182 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002183 else if (name == "textureGradOffset")
2184 {
2185 textureFunction.method = TextureFunction::GRAD;
2186 textureFunction.offset = true;
2187 }
Nicolas Capens46485082014-04-15 13:12:50 -04002188 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
Nicolas Capensf7378e32014-02-19 17:29:32 -05002189 {
2190 textureFunction.method = TextureFunction::GRAD;
2191 textureFunction.proj = true;
2192 }
2193 else if (name == "textureProjGradOffset")
2194 {
2195 textureFunction.method = TextureFunction::GRAD;
2196 textureFunction.proj = true;
2197 textureFunction.offset = true;
2198 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002199 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002200
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002201 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002202 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002203 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2204
2205 if (textureFunction.offset)
2206 {
2207 mandatoryArgumentCount++;
2208 }
2209
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002210 bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional
Nicolas Capens84cfa122014-04-14 13:48:45 -04002211
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002212 if (lod0 || mShaderType == GL_VERTEX_SHADER)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002213 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002214 if (bias)
2215 {
2216 textureFunction.method = TextureFunction::LOD0BIAS;
2217 }
2218 else
2219 {
2220 textureFunction.method = TextureFunction::LOD0;
2221 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002222 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002223 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002224 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002225 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002226 }
2227 }
2228
2229 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002230
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002231 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002232 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002233
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002234 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002235 {
2236 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2237 {
2238 out << "texture_";
2239 (*arg)->traverse(this);
2240 out << ", sampler_";
2241 }
2242
2243 (*arg)->traverse(this);
2244
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002245 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002246 {
2247 out << ", ";
2248 }
2249 }
2250
2251 out << ")";
2252
2253 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002254 }
2255 break;
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002256 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002257 case EOpConstructFloat: outputConstructor(visit, node->getType(), "vec1", node->getSequence()); break;
2258 case EOpConstructVec2: outputConstructor(visit, node->getType(), "vec2", node->getSequence()); break;
2259 case EOpConstructVec3: outputConstructor(visit, node->getType(), "vec3", node->getSequence()); break;
2260 case EOpConstructVec4: outputConstructor(visit, node->getType(), "vec4", node->getSequence()); break;
2261 case EOpConstructBool: outputConstructor(visit, node->getType(), "bvec1", node->getSequence()); break;
2262 case EOpConstructBVec2: outputConstructor(visit, node->getType(), "bvec2", node->getSequence()); break;
2263 case EOpConstructBVec3: outputConstructor(visit, node->getType(), "bvec3", node->getSequence()); break;
2264 case EOpConstructBVec4: outputConstructor(visit, node->getType(), "bvec4", node->getSequence()); break;
2265 case EOpConstructInt: outputConstructor(visit, node->getType(), "ivec1", node->getSequence()); break;
2266 case EOpConstructIVec2: outputConstructor(visit, node->getType(), "ivec2", node->getSequence()); break;
2267 case EOpConstructIVec3: outputConstructor(visit, node->getType(), "ivec3", node->getSequence()); break;
2268 case EOpConstructIVec4: outputConstructor(visit, node->getType(), "ivec4", node->getSequence()); break;
2269 case EOpConstructUInt: outputConstructor(visit, node->getType(), "uvec1", node->getSequence()); break;
2270 case EOpConstructUVec2: outputConstructor(visit, node->getType(), "uvec2", node->getSequence()); break;
2271 case EOpConstructUVec3: outputConstructor(visit, node->getType(), "uvec3", node->getSequence()); break;
2272 case EOpConstructUVec4: outputConstructor(visit, node->getType(), "uvec4", node->getSequence()); break;
2273 case EOpConstructMat2: outputConstructor(visit, node->getType(), "mat2", node->getSequence()); break;
Alexis Hetu07e57df2015-06-16 16:55:52 -04002274 case EOpConstructMat2x3: outputConstructor(visit, node->getType(), "mat2x3", node->getSequence()); break;
2275 case EOpConstructMat2x4: outputConstructor(visit, node->getType(), "mat2x4", node->getSequence()); break;
2276 case EOpConstructMat3x2: outputConstructor(visit, node->getType(), "mat3x2", node->getSequence()); break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002277 case EOpConstructMat3: outputConstructor(visit, node->getType(), "mat3", node->getSequence()); break;
Alexis Hetu07e57df2015-06-16 16:55:52 -04002278 case EOpConstructMat3x4: outputConstructor(visit, node->getType(), "mat3x4", node->getSequence()); break;
2279 case EOpConstructMat4x2: outputConstructor(visit, node->getType(), "mat4x2", node->getSequence()); break;
2280 case EOpConstructMat4x3: outputConstructor(visit, node->getType(), "mat4x3", node->getSequence()); break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002281 case EOpConstructMat4: outputConstructor(visit, node->getType(), "mat4", node->getSequence()); break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002282 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04002283 {
Olli Etuahof40319e2015-03-10 14:33:00 +02002284 if (node->getType().isArray())
2285 {
2286 UNIMPLEMENTED();
2287 }
Jamie Madill033dae62014-06-18 12:56:28 -04002288 const TString &structName = StructNameString(*node->getType().getStruct());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002289 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
Daniel Bratell29190082015-02-20 16:42:54 +01002290 outputTriplet(visit, (structName + "_ctor(").c_str(), ", ", ")");
Jamie Madillbfa91f42014-06-05 15:45:18 -04002291 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002292 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002293 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2294 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2295 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2296 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2297 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
2298 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002299 case EOpMod:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002300 ASSERT(node->getUseEmulatedFunction());
2301 writeEmulatedFunctionTriplet(visit, "mod(");
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002302 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02002303 case EOpModf: outputTriplet(visit, "modf(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002304 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002305 case EOpAtan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002306 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
Olli Etuahoe17e3192015-01-02 12:47:59 +02002307 ASSERT(node->getUseEmulatedFunction());
2308 writeEmulatedFunctionTriplet(visit, "atan(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309 break;
2310 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
2311 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
2312 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
Arun Patoled94f6642015-05-18 16:25:12 +05302313 case EOpMix:
2314 {
2315 TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2316 if (lastParamNode->getType().getBasicType() == EbtBool)
2317 {
2318 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
2319 // so use emulated version.
2320 ASSERT(node->getUseEmulatedFunction());
2321 writeEmulatedFunctionTriplet(visit, "mix(");
2322 }
2323 else
2324 {
2325 outputTriplet(visit, "lerp(", ", ", ")");
2326 }
2327 }
2328 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002329 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
2330 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
2331 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
2332 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
2333 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002334 case EOpFaceForward:
Olli Etuahoe17e3192015-01-02 12:47:59 +02002335 ASSERT(node->getUseEmulatedFunction());
2336 writeEmulatedFunctionTriplet(visit, "faceforward(");
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002337 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002338 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
2339 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02002340 case EOpOuterProduct:
2341 ASSERT(node->getUseEmulatedFunction());
2342 writeEmulatedFunctionTriplet(visit, "outerProduct(");
2343 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002344 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002345 default: UNREACHABLE();
2346 }
2347
2348 return true;
2349}
2350
Olli Etuahod81ed842015-05-12 12:46:35 +03002351void OutputHLSL::writeSelection(TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002352{
Jamie Madill32aab012015-01-27 14:12:26 -05002353 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002354
Olli Etuahoa6f22092015-05-08 18:31:10 +03002355 out << "if (";
2356
2357 node->getCondition()->traverse(this);
2358
2359 out << ")\n";
2360
2361 outputLineDirective(node->getLine().first_line);
Olli Etuahoa6f22092015-05-08 18:31:10 +03002362
2363 bool discard = false;
2364
2365 if (node->getTrueBlock())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002366 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002367 // The trueBlock child node will output braces.
2368 ASSERT(IsSequence(node->getTrueBlock()));
2369
Olli Etuahoa6f22092015-05-08 18:31:10 +03002370 node->getTrueBlock()->traverse(this);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002371
Olli Etuahoa6f22092015-05-08 18:31:10 +03002372 // Detect true discard
2373 discard = (discard || FindDiscard::search(node->getTrueBlock()));
2374 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002375 else
2376 {
2377 // TODO(oetuaho): Check if the semicolon inside is necessary.
2378 // It's there as a result of conservative refactoring of the output.
2379 out << "{;}\n";
2380 }
Corentin Wallez80bacde2014-11-10 12:07:37 -08002381
Olli Etuahoa6f22092015-05-08 18:31:10 +03002382 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002383
Olli Etuahoa6f22092015-05-08 18:31:10 +03002384 if (node->getFalseBlock())
2385 {
2386 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002387
Olli Etuahoa6f22092015-05-08 18:31:10 +03002388 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002389
Olli Etuaho4785fec2015-05-18 16:09:37 +03002390 // Either this is "else if" or the falseBlock child node will output braces.
2391 ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr);
2392
Olli Etuahoa6f22092015-05-08 18:31:10 +03002393 node->getFalseBlock()->traverse(this);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002394
Olli Etuahoa6f22092015-05-08 18:31:10 +03002395 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002396
Olli Etuahoa6f22092015-05-08 18:31:10 +03002397 // Detect false discard
2398 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2399 }
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002400
Olli Etuahoa6f22092015-05-08 18:31:10 +03002401 // ANGLE issue 486: Detect problematic conditional discard
Olli Etuahofd3b9be2015-05-18 17:07:36 +03002402 if (discard)
Olli Etuahoa6f22092015-05-08 18:31:10 +03002403 {
2404 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002405 }
Olli Etuahod81ed842015-05-12 12:46:35 +03002406}
2407
2408bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2409{
2410 TInfoSinkBase &out = getInfoSink();
2411
2412 ASSERT(!node->usesTernaryOperator());
2413
2414 if (!mInsideFunction)
2415 {
2416 // This is part of unfolded global initialization.
2417 mDeferredGlobalInitializers.push_back(node);
2418 return false;
2419 }
2420
2421 // D3D errors when there is a gradient operation in a loop in an unflattened if.
Corentin Wallez477b2432015-08-31 10:41:16 -07002422 if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
Olli Etuahod81ed842015-05-12 12:46:35 +03002423 {
2424 out << "FLATTEN ";
2425 }
2426
2427 writeSelection(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428
2429 return false;
2430}
2431
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002432bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002433{
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002434 if (node->getStatementList())
2435 {
Olli Etuaho2cd7a0e2015-02-27 13:57:32 +02002436 node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002437 outputTriplet(visit, "switch (", ") ", "");
2438 // The curly braces get written when visiting the statementList aggregate
2439 }
2440 else
2441 {
2442 // No statementList, so it won't output curly braces
2443 outputTriplet(visit, "switch (", ") {", "}\n");
2444 }
2445 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002446}
2447
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002448bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002449{
Olli Etuaho05ae50d2015-02-20 10:16:47 +02002450 if (node->hasCondition())
2451 {
2452 outputTriplet(visit, "case (", "", "):\n");
2453 return true;
2454 }
2455 else
2456 {
2457 TInfoSinkBase &out = getInfoSink();
2458 out << "default:\n";
2459 return false;
2460 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +02002461}
2462
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002463void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2464{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002465 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002466}
2467
2468bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2469{
Nicolas Capens655fe362014-04-11 13:12:34 -04002470 mNestedLoopDepth++;
2471
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002472 bool wasDiscontinuous = mInsideDiscontinuousLoop;
Corentin Wallez1239ee92015-03-19 14:38:02 -07002473 mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
Corentin Walleza1884f22015-04-29 10:15:16 -07002474 mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002475
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002476 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002477 {
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002478 if (handleExcessiveLoop(node))
2479 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002480 mInsideDiscontinuousLoop = wasDiscontinuous;
2481 mNestedLoopDepth--;
2482
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002483 return false;
2484 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002485 }
2486
Jamie Madill32aab012015-01-27 14:12:26 -05002487 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002488
Corentin Wallez1239ee92015-03-19 14:38:02 -07002489 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
alokp@chromium.org52813552010-11-16 18:36:09 +00002490 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002491 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002492 out << "{" << unroll << " do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002493
Jamie Madill075edd82013-07-08 13:30:19 -04002494 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002495 }
2496 else
2497 {
Corentin Wallez1239ee92015-03-19 14:38:02 -07002498 out << "{" << unroll << " for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002499
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002500 if (node->getInit())
2501 {
2502 node->getInit()->traverse(this);
2503 }
2504
2505 out << "; ";
2506
alokp@chromium.org52813552010-11-16 18:36:09 +00002507 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002508 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002509 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002510 }
2511
2512 out << "; ";
2513
alokp@chromium.org52813552010-11-16 18:36:09 +00002514 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002515 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002516 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002517 }
2518
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002519 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002520
Jamie Madill075edd82013-07-08 13:30:19 -04002521 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002522 }
2523
2524 if (node->getBody())
2525 {
Olli Etuaho4785fec2015-05-18 16:09:37 +03002526 // The loop body node will output braces.
2527 ASSERT(IsSequence(node->getBody()));
Olli Etuahoa6f22092015-05-08 18:31:10 +03002528 node->getBody()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002529 }
Olli Etuaho4785fec2015-05-18 16:09:37 +03002530 else
2531 {
2532 // TODO(oetuaho): Check if the semicolon inside is necessary.
2533 // It's there as a result of conservative refactoring of the output.
2534 out << "{;}\n";
2535 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002536
Jamie Madill075edd82013-07-08 13:30:19 -04002537 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002538
alokp@chromium.org52813552010-11-16 18:36:09 +00002539 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002540 {
Jamie Madill075edd82013-07-08 13:30:19 -04002541 outputLineDirective(node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002542 out << "while(\n";
2543
alokp@chromium.org52813552010-11-16 18:36:09 +00002544 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002545
daniel@transgaming.com73536982012-03-21 20:45:49 +00002546 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002547 }
2548
daniel@transgaming.com73536982012-03-21 20:45:49 +00002549 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002550
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002551 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002552 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002553
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002554 return false;
2555}
2556
2557bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2558{
Jamie Madill32aab012015-01-27 14:12:26 -05002559 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002560
2561 switch (node->getFlowOp())
2562 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002563 case EOpKill:
2564 outputTriplet(visit, "discard;\n", "", "");
2565 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002566 case EOpBreak:
2567 if (visit == PreVisit)
2568 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002569 if (mNestedLoopDepth > 1)
2570 {
2571 mUsesNestedBreak = true;
2572 }
2573
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002574 if (mExcessiveLoopIndex)
2575 {
2576 out << "{Break";
2577 mExcessiveLoopIndex->traverse(this);
2578 out << " = true; break;}\n";
2579 }
2580 else
2581 {
2582 out << "break;\n";
2583 }
2584 }
2585 break;
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00002586 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002587 case EOpReturn:
2588 if (visit == PreVisit)
2589 {
2590 if (node->getExpression())
2591 {
2592 out << "return ";
2593 }
2594 else
2595 {
2596 out << "return;\n";
2597 }
2598 }
2599 else if (visit == PostVisit)
2600 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002601 if (node->getExpression())
2602 {
2603 out << ";\n";
2604 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002605 }
2606 break;
2607 default: UNREACHABLE();
2608 }
2609
2610 return true;
2611}
2612
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002613bool OutputHLSL::isSingleStatement(TIntermNode *node)
2614{
2615 TIntermAggregate *aggregate = node->getAsAggregate();
2616
2617 if (aggregate)
2618 {
2619 if (aggregate->getOp() == EOpSequence)
2620 {
2621 return false;
2622 }
Nicolas Capensfa41aa02014-10-06 17:40:13 -04002623 else if (aggregate->getOp() == EOpDeclaration)
2624 {
2625 // Declaring multiple comma-separated variables must be considered multiple statements
2626 // because each individual declaration has side effects which are visible in the next.
2627 return false;
2628 }
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002629 else
2630 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002631 for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002632 {
2633 if (!isSingleStatement(*sit))
2634 {
2635 return false;
2636 }
2637 }
2638
2639 return true;
2640 }
2641 }
2642
2643 return true;
2644}
2645
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002646// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2647// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002648bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
2649{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002650 const int MAX_LOOP_ITERATIONS = 254;
Jamie Madill32aab012015-01-27 14:12:26 -05002651 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002652
2653 // Parse loops of the form:
2654 // for(int index = initial; index [comparator] limit; index += increment)
2655 TIntermSymbol *index = NULL;
2656 TOperator comparator = EOpNull;
2657 int initial = 0;
2658 int limit = 0;
2659 int increment = 0;
2660
2661 // Parse index name and intial value
2662 if (node->getInit())
2663 {
2664 TIntermAggregate *init = node->getInit()->getAsAggregate();
2665
2666 if (init)
2667 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002668 TIntermSequence *sequence = init->getSequence();
2669 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002670
2671 if (variable && variable->getQualifier() == EvqTemporary)
2672 {
2673 TIntermBinary *assign = variable->getAsBinaryNode();
2674
2675 if (assign->getOp() == EOpInitialize)
2676 {
2677 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2678 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2679
2680 if (symbol && constant)
2681 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002682 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002683 {
2684 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002685 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002686 }
2687 }
2688 }
2689 }
2690 }
2691 }
2692
2693 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002694 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002695 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002696 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002697
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002698 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2699 {
2700 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2701
2702 if (constant)
2703 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002704 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002705 {
2706 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002707 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002708 }
2709 }
2710 }
2711 }
2712
2713 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002714 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002715 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002716 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2717 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002718
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002719 if (binaryTerminal)
2720 {
2721 TOperator op = binaryTerminal->getOp();
2722 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2723
2724 if (constant)
2725 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002726 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002727 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002728 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002729
2730 switch (op)
2731 {
2732 case EOpAddAssign: increment = value; break;
2733 case EOpSubAssign: increment = -value; break;
2734 default: UNIMPLEMENTED();
2735 }
2736 }
2737 }
2738 }
2739 else if (unaryTerminal)
2740 {
2741 TOperator op = unaryTerminal->getOp();
2742
2743 switch (op)
2744 {
2745 case EOpPostIncrement: increment = 1; break;
2746 case EOpPostDecrement: increment = -1; break;
2747 case EOpPreIncrement: increment = 1; break;
2748 case EOpPreDecrement: increment = -1; break;
2749 default: UNIMPLEMENTED();
2750 }
2751 }
2752 }
2753
2754 if (index != NULL && comparator != EOpNull && increment != 0)
2755 {
2756 if (comparator == EOpLessThanEqual)
2757 {
2758 comparator = EOpLessThan;
2759 limit += 1;
2760 }
2761
2762 if (comparator == EOpLessThan)
2763 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002764 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002765
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002766 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002767 {
2768 return false; // Not an excessive loop
2769 }
2770
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002771 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
2772 mExcessiveLoopIndex = index;
2773
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002774 out << "{int ";
2775 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002776 out << ";\n"
2777 "bool Break";
2778 index->traverse(this);
2779 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002780
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002781 bool firstLoopFragment = true;
2782
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002783 while (iterations > 0)
2784 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002785 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002786
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002787 if (!firstLoopFragment)
2788 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002789 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002790 index->traverse(this);
2791 out << ") {\n";
2792 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002793
2794 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
2795 {
2796 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
2797 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002798
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002799 // for(int index = initial; index < clampedLimit; index += increment)
Corentin Wallez1239ee92015-03-19 14:38:02 -07002800 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002801
Corentin Wallez1239ee92015-03-19 14:38:02 -07002802 out << unroll << " for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002803 index->traverse(this);
2804 out << " = ";
2805 out << initial;
2806
2807 out << "; ";
2808 index->traverse(this);
2809 out << " < ";
2810 out << clampedLimit;
2811
2812 out << "; ";
2813 index->traverse(this);
2814 out << " += ";
2815 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002816 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002817
Jamie Madill075edd82013-07-08 13:30:19 -04002818 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002819 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002820
2821 if (node->getBody())
2822 {
2823 node->getBody()->traverse(this);
2824 }
2825
Jamie Madill075edd82013-07-08 13:30:19 -04002826 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002827 out << ";}\n";
2828
2829 if (!firstLoopFragment)
2830 {
2831 out << "}\n";
2832 }
2833
2834 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002835
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002836 initial += MAX_LOOP_ITERATIONS * increment;
2837 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002838 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002839
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002840 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002841
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002842 mExcessiveLoopIndex = restoreIndex;
2843
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002844 return true;
2845 }
2846 else UNIMPLEMENTED();
2847 }
2848
2849 return false; // Not handled as an excessive loop
2850}
2851
Olli Etuaho7fb49552015-03-18 17:27:44 +02002852void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002853{
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002854 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002855 {
2856 out << preString;
2857 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002858 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002859 {
2860 out << inString;
2861 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002862 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002863 {
2864 out << postString;
2865 }
2866}
2867
Olli Etuaho7fb49552015-03-18 17:27:44 +02002868void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
2869{
2870 outputTriplet(visit, preString, inString, postString, getInfoSink());
2871}
2872
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002873void OutputHLSL::outputLineDirective(int line)
2874{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002875 if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002876 {
Jamie Madill32aab012015-01-27 14:12:26 -05002877 TInfoSinkBase &out = getInfoSink();
2878
2879 out << "\n";
2880 out << "#line " << line;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002881
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002882 if (mSourcePath)
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002883 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +02002884 out << " \"" << mSourcePath << "\"";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002885 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002886
Jamie Madill32aab012015-01-27 14:12:26 -05002887 out << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002888 }
2889}
2890
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002891TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2892{
2893 TQualifier qualifier = symbol->getQualifier();
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002894 const TType &type = symbol->getType();
2895 const TName &name = symbol->getName();
2896 TString nameStr;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002897
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002898 if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002899 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002900 nameStr = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002901 }
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002902 else
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002903 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002904 nameStr = DecorateIfNeeded(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002905 }
2906
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002907 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
2908 {
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002909 return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + nameStr +
2910 ArrayString(type) + ", " + QualifierString(qualifier) + " " + SamplerString(type) +
2911 " sampler_" + nameStr + ArrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002912 }
2913
Olli Etuahof5cfc8d2015-08-06 16:36:39 +03002914 return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002915}
2916
2917TString OutputHLSL::initializer(const TType &type)
2918{
2919 TString string;
2920
Jamie Madill94bf7f22013-07-08 13:31:15 -04002921 size_t size = type.getObjectSize();
2922 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002923 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002924 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002925
Jamie Madill94bf7f22013-07-08 13:31:15 -04002926 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002927 {
2928 string += ", ";
2929 }
2930 }
2931
daniel@transgaming.comead23042010-04-29 03:35:36 +00002932 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002933}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002934
Daniel Bratell29190082015-02-20 16:42:54 +01002935void OutputHLSL::outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters)
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002936{
Olli Etuahof40319e2015-03-10 14:33:00 +02002937 if (type.isArray())
2938 {
2939 UNIMPLEMENTED();
2940 }
Jamie Madill32aab012015-01-27 14:12:26 -05002941 TInfoSinkBase &out = getInfoSink();
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002942
2943 if (visit == PreVisit)
2944 {
Jamie Madill8daaba12014-06-13 10:04:33 -04002945 mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002946
Daniel Bratell29190082015-02-20 16:42:54 +01002947 out << name << "(";
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002948 }
2949 else if (visit == InVisit)
2950 {
2951 out << ", ";
2952 }
2953 else if (visit == PostVisit)
2954 {
2955 out << ")";
2956 }
2957}
2958
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002959const TConstantUnion *OutputHLSL::writeConstantUnion(const TType &type,
2960 const TConstantUnion *const constUnion)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002961{
Jamie Madill32aab012015-01-27 14:12:26 -05002962 TInfoSinkBase &out = getInfoSink();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002963
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002964 const TConstantUnion *constUnionIterated = constUnion;
2965
Jamie Madill98493dd2013-07-08 14:39:03 -04002966 const TStructure* structure = type.getStruct();
2967 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002968 {
Jamie Madill033dae62014-06-18 12:56:28 -04002969 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002970
Jamie Madill98493dd2013-07-08 14:39:03 -04002971 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002972
Jamie Madill98493dd2013-07-08 14:39:03 -04002973 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002974 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002975 const TType *fieldType = fields[i]->type();
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002976 constUnionIterated = writeConstantUnion(*fieldType, constUnionIterated);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002977
Jamie Madill98493dd2013-07-08 14:39:03 -04002978 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002979 {
2980 out << ", ";
2981 }
2982 }
2983
2984 out << ")";
2985 }
2986 else
2987 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04002988 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002989 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002990
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002991 if (writeType)
2992 {
Jamie Madill033dae62014-06-18 12:56:28 -04002993 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002994 }
Olli Etuaho18b9deb2015-11-05 12:14:50 +02002995 constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size);
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002996 if (writeType)
2997 {
2998 out << ")";
2999 }
3000 }
3001
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003002 return constUnionIterated;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003003}
3004
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +02003005void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
3006{
3007 TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
3008 outputTriplet(visit, preString.c_str(), ", ", ")");
3009}
3010
Jamie Madill37997142015-01-28 10:06:34 -05003011bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
3012{
3013 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
3014 expression->traverse(&searchSymbol);
3015
3016 if (searchSymbol.foundMatch())
3017 {
3018 // Type already printed
3019 out << "t" + str(mUniqueIndex) + " = ";
3020 expression->traverse(this);
3021 out << ", ";
3022 symbolNode->traverse(this);
3023 out << " = t" + str(mUniqueIndex);
3024
3025 mUniqueIndex++;
3026 return true;
3027 }
3028
3029 return false;
3030}
3031
Olli Etuaho18b9deb2015-11-05 12:14:50 +02003032bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
3033{
3034 // We support writing constant unions and constructors that only take constant unions as
3035 // parameters as HLSL literals.
3036 if (expression->getAsConstantUnion())
3037 {
3038 return true;
3039 }
3040 if (expression->getQualifier() != EvqConst || !expression->getAsAggregate() ||
3041 !expression->getAsAggregate()->isConstructor())
3042 {
3043 return false;
3044 }
3045 TIntermAggregate *constructor = expression->getAsAggregate();
3046 for (TIntermNode *&node : *constructor->getSequence())
3047 {
3048 if (!node->getAsConstantUnion())
3049 return false;
3050 }
3051 return true;
3052}
3053
3054bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3055 TIntermSymbol *symbolNode,
3056 TIntermTyped *expression)
3057{
3058 if (canWriteAsHLSLLiteral(expression))
3059 {
3060 symbolNode->traverse(this);
3061 if (expression->getType().isArray())
3062 {
3063 out << "[" << expression->getType().getArraySize() << "]";
3064 }
3065 out << " = {";
3066 if (expression->getAsConstantUnion())
3067 {
3068 TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
3069 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3070 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3071 }
3072 else
3073 {
3074 TIntermAggregate *constructor = expression->getAsAggregate();
3075 ASSERT(constructor != nullptr);
3076 for (TIntermNode *&node : *constructor->getSequence())
3077 {
3078 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
3079 ASSERT(nodeConst);
3080 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
3081 WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
3082 if (node != constructor->getSequence()->back())
3083 {
3084 out << ", ";
3085 }
3086 }
3087 }
3088 out << "}";
3089 return true;
3090 }
3091 return false;
3092}
3093
Jamie Madill37997142015-01-28 10:06:34 -05003094void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
3095{
3096 out << "#define ANGLE_USES_DEFERRED_INIT\n"
3097 << "\n"
3098 << "void initializeDeferredGlobals()\n"
3099 << "{\n";
3100
3101 for (const auto &deferredGlobal : mDeferredGlobalInitializers)
3102 {
Olli Etuahod81ed842015-05-12 12:46:35 +03003103 TIntermBinary *binary = deferredGlobal->getAsBinaryNode();
3104 TIntermSelection *selection = deferredGlobal->getAsSelectionNode();
3105 if (binary != nullptr)
3106 {
3107 TIntermSymbol *symbol = binary->getLeft()->getAsSymbolNode();
3108 TIntermTyped *expression = binary->getRight();
3109 ASSERT(symbol);
3110 ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
Jamie Madill37997142015-01-28 10:06:34 -05003111
Olli Etuahod81ed842015-05-12 12:46:35 +03003112 out << " " << Decorate(symbol->getSymbol()) << " = ";
Jamie Madill37997142015-01-28 10:06:34 -05003113
Olli Etuahod81ed842015-05-12 12:46:35 +03003114 if (!writeSameSymbolInitializer(out, symbol, expression))
3115 {
3116 ASSERT(mInfoSinkStack.top() == &out);
3117 expression->traverse(this);
3118 }
3119 out << ";\n";
3120 }
3121 else if (selection != nullptr)
Jamie Madill37997142015-01-28 10:06:34 -05003122 {
3123 ASSERT(mInfoSinkStack.top() == &out);
Olli Etuahod81ed842015-05-12 12:46:35 +03003124 writeSelection(selection);
Jamie Madill37997142015-01-28 10:06:34 -05003125 }
Olli Etuahod81ed842015-05-12 12:46:35 +03003126 else
3127 {
3128 UNREACHABLE();
3129 }
Jamie Madill37997142015-01-28 10:06:34 -05003130 }
3131
3132 out << "}\n"
3133 << "\n";
3134}
3135
Jamie Madill55e79e02015-02-09 15:35:00 -05003136TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3137{
3138 const TFieldList &fields = structure.fields();
3139
3140 for (const auto &eqFunction : mStructEqualityFunctions)
3141 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003142 if (eqFunction->structure == &structure)
Jamie Madill55e79e02015-02-09 15:35:00 -05003143 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003144 return eqFunction->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003145 }
3146 }
3147
3148 const TString &structNameString = StructNameString(structure);
3149
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003150 StructEqualityFunction *function = new StructEqualityFunction();
3151 function->structure = &structure;
3152 function->functionName = "angle_eq_" + structNameString;
Jamie Madill55e79e02015-02-09 15:35:00 -05003153
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003154 TInfoSinkBase fnOut;
Jamie Madill55e79e02015-02-09 15:35:00 -05003155
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003156 fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n"
3157 << "{\n"
3158 " return ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003159
3160 for (size_t i = 0; i < fields.size(); i++)
3161 {
3162 const TField *field = fields[i];
3163 const TType *fieldType = field->type();
3164
3165 const TString &fieldNameA = "a." + Decorate(field->name());
3166 const TString &fieldNameB = "b." + Decorate(field->name());
3167
3168 if (i > 0)
3169 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003170 fnOut << " && ";
Jamie Madill55e79e02015-02-09 15:35:00 -05003171 }
3172
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003173 fnOut << "(";
3174 outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3175 fnOut << fieldNameA;
3176 outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3177 fnOut << fieldNameB;
3178 outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3179 fnOut << ")";
Jamie Madill55e79e02015-02-09 15:35:00 -05003180 }
3181
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003182 fnOut << ";\n" << "}\n";
3183
3184 function->functionDefinition = fnOut.c_str();
Jamie Madill55e79e02015-02-09 15:35:00 -05003185
3186 mStructEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003187 mEqualityFunctions.push_back(function);
Jamie Madill55e79e02015-02-09 15:35:00 -05003188
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003189 return function->functionName;
Jamie Madill55e79e02015-02-09 15:35:00 -05003190}
3191
Olli Etuaho7fb49552015-03-18 17:27:44 +02003192TString OutputHLSL::addArrayEqualityFunction(const TType& type)
3193{
3194 for (const auto &eqFunction : mArrayEqualityFunctions)
3195 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003196 if (eqFunction->type == type)
Olli Etuaho7fb49552015-03-18 17:27:44 +02003197 {
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003198 return eqFunction->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003199 }
3200 }
3201
3202 const TString &typeName = TypeString(type);
3203
Olli Etuaho12690762015-03-31 12:55:28 +03003204 ArrayHelperFunction *function = new ArrayHelperFunction();
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003205 function->type = type;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003206
3207 TInfoSinkBase fnNameOut;
3208 fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003209 function->functionName = fnNameOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003210
3211 TType nonArrayType = type;
3212 nonArrayType.clearArrayness();
3213
3214 TInfoSinkBase fnOut;
3215
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003216 fnOut << "bool " << function->functionName << "("
Olli Etuahofc7cfd12015-03-31 14:46:18 +03003217 << typeName << " a[" << type.getArraySize() << "], "
3218 << typeName << " b[" << type.getArraySize() << "])\n"
Olli Etuaho7fb49552015-03-18 17:27:44 +02003219 << "{\n"
3220 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3221 " {\n"
3222 " if (";
3223
3224 outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
3225 fnOut << "a[i]";
3226 outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
3227 fnOut << "b[i]";
3228 outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
3229
3230 fnOut << ") { return false; }\n"
3231 " }\n"
3232 " return true;\n"
3233 "}\n";
3234
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003235 function->functionDefinition = fnOut.c_str();
Olli Etuaho7fb49552015-03-18 17:27:44 +02003236
3237 mArrayEqualityFunctions.push_back(function);
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003238 mEqualityFunctions.push_back(function);
Olli Etuaho7fb49552015-03-18 17:27:44 +02003239
Olli Etuahoae37a5c2015-03-20 16:50:15 +02003240 return function->functionName;
Olli Etuaho7fb49552015-03-18 17:27:44 +02003241}
3242
Olli Etuaho12690762015-03-31 12:55:28 +03003243TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
3244{
3245 for (const auto &assignFunction : mArrayAssignmentFunctions)
3246 {
3247 if (assignFunction.type == type)
3248 {
3249 return assignFunction.functionName;
3250 }
3251 }
3252
3253 const TString &typeName = TypeString(type);
3254
3255 ArrayHelperFunction function;
3256 function.type = type;
3257
3258 TInfoSinkBase fnNameOut;
3259 fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
3260 function.functionName = fnNameOut.c_str();
3261
3262 TInfoSinkBase fnOut;
3263
3264 fnOut << "void " << function.functionName << "(out "
3265 << typeName << " a[" << type.getArraySize() << "], "
3266 << typeName << " b[" << type.getArraySize() << "])\n"
3267 << "{\n"
3268 " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
3269 " {\n"
3270 " a[i] = b[i];\n"
3271 " }\n"
3272 "}\n";
3273
3274 function.functionDefinition = fnOut.c_str();
3275
3276 mArrayAssignmentFunctions.push_back(function);
3277
3278 return function.functionName;
3279}
3280
Olli Etuaho9638c352015-04-01 14:34:52 +03003281TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
3282{
3283 for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3284 {
3285 if (constructIntoFunction.type == type)
3286 {
3287 return constructIntoFunction.functionName;
3288 }
3289 }
3290
3291 const TString &typeName = TypeString(type);
3292
3293 ArrayHelperFunction function;
3294 function.type = type;
3295
3296 TInfoSinkBase fnNameOut;
3297 fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
3298 function.functionName = fnNameOut.c_str();
3299
3300 TInfoSinkBase fnOut;
3301
3302 fnOut << "void " << function.functionName << "(out "
3303 << typeName << " a[" << type.getArraySize() << "]";
3304 for (int i = 0; i < type.getArraySize(); ++i)
3305 {
3306 fnOut << ", " << typeName << " b" << i;
3307 }
3308 fnOut << ")\n"
3309 "{\n";
3310
3311 for (int i = 0; i < type.getArraySize(); ++i)
3312 {
3313 fnOut << " a[" << i << "] = b" << i << ";\n";
3314 }
3315 fnOut << "}\n";
3316
3317 function.functionDefinition = fnOut.c_str();
3318
3319 mArrayConstructIntoFunctions.push_back(function);
3320
3321 return function.functionName;
3322}
3323
Jamie Madill2e295e22015-04-29 10:41:33 -04003324void OutputHLSL::ensureStructDefined(const TType &type)
3325{
3326 TStructure *structure = type.getStruct();
3327
3328 if (structure)
3329 {
3330 mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
3331 }
3332}
3333
3334
Olli Etuaho9638c352015-04-01 14:34:52 +03003335
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003336}