blob: defb34a272b8a0aac37ebefcf85530364334d295 [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
alokp@chromium.org79fb1012012-04-26 21:07:39 +00009#include "common/angleutils.h"
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +000010#include "common/utilities.h"
Jamie Madill834e8b72014-04-11 13:33:58 -040011#include "common/blocklayout.h"
Geoff Lang17732822013-08-29 13:46:49 -040012#include "compiler/translator/compilerdebug.h"
13#include "compiler/translator/InfoSink.h"
14#include "compiler/translator/DetectDiscontinuity.h"
15#include "compiler/translator/SearchSymbol.h"
16#include "compiler/translator/UnfoldShortCircuit.h"
Geoff Lang17732822013-08-29 13:46:49 -040017#include "compiler/translator/FlagStd140Structs.h"
Jamie Madill3c9eeb92013-11-04 11:09:26 -050018#include "compiler/translator/NodeSearch.h"
Jamie Madille53c98b2014-02-03 11:57:13 -050019#include "compiler/translator/RewriteElseBlocks.h"
Jamie Madill033dae62014-06-18 12:56:28 -040020#include "compiler/translator/UtilsHLSL.h"
21#include "compiler/translator/util.h"
Jamie Madillf91ce812014-06-13 10:04:34 -040022#include "compiler/translator/UniformHLSL.h"
Jamie Madill8daaba12014-06-13 10:04:33 -040023#include "compiler/translator/StructureHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000025#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000026#include <cfloat>
27#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000028
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000029namespace sh
30{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000031
Jamie Madilla3fe2b42014-07-18 10:33:13 -040032static sh::Attribute MakeAttributeFromType(const TType &type, const TString &name)
33{
34 sh::Attribute attributeVar;
35 attributeVar.type = GLVariableType(type);
36 attributeVar.precision = GLVariablePrecision(type);
37 attributeVar.name = name.c_str();
38 attributeVar.arraySize = static_cast<unsigned int>(type.getArraySize());
39 attributeVar.location = type.getLayoutQualifier().location;
40
41 return attributeVar;
42}
43
Nicolas Capense0ba27a2013-06-24 16:10:52 -040044TString OutputHLSL::TextureFunction::name() const
45{
46 TString name = "gl_texture";
47
Nicolas Capens6d232bb2013-07-08 15:56:38 -040048 if (IsSampler2D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040049 {
50 name += "2D";
51 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040052 else if (IsSampler3D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040053 {
54 name += "3D";
55 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040056 else if (IsSamplerCube(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040057 {
58 name += "Cube";
59 }
60 else UNREACHABLE();
61
62 if (proj)
63 {
64 name += "Proj";
65 }
66
Nicolas Capensb1f45b72013-12-19 17:37:19 -050067 if (offset)
68 {
69 name += "Offset";
70 }
71
Nicolas Capens75fb4752013-07-10 15:14:47 -040072 switch(method)
Nicolas Capense0ba27a2013-06-24 16:10:52 -040073 {
Nicolas Capensfc014542014-02-18 14:47:13 -050074 case IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -040075 case BIAS: break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -050076 case LOD: name += "Lod"; break;
77 case LOD0: name += "Lod0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -040078 case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -050079 case SIZE: name += "Size"; break;
80 case FETCH: name += "Fetch"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -050081 case GRAD: name += "Grad"; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -040082 default: UNREACHABLE();
83 }
84
85 return name + "(";
86}
87
88bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
89{
90 if (sampler < rhs.sampler) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -040091 if (sampler > rhs.sampler) return false;
92
Nicolas Capense0ba27a2013-06-24 16:10:52 -040093 if (coords < rhs.coords) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -040094 if (coords > rhs.coords) return false;
95
Nicolas Capense0ba27a2013-06-24 16:10:52 -040096 if (!proj && rhs.proj) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -040097 if (proj && !rhs.proj) return false;
98
99 if (!offset && rhs.offset) return true;
100 if (offset && !rhs.offset) return false;
101
Nicolas Capens75fb4752013-07-10 15:14:47 -0400102 if (method < rhs.method) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400103 if (method > rhs.method) return false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400104
105 return false;
106}
107
shannon.woods%transgaming.com@gtempaccount.com18b4c4b2013-04-13 03:31:40 +0000108OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000109 : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +0000111 mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000112 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000113
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000114 mUsesFragColor = false;
115 mUsesFragData = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000116 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000117 mUsesFragCoord = false;
118 mUsesPointCoord = false;
119 mUsesFrontFacing = false;
120 mUsesPointSize = false;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400121 mUsesFragDepth = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000122 mUsesXor = false;
123 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000124 mUsesMod2v = false;
125 mUsesMod2f = false;
126 mUsesMod3v = false;
127 mUsesMod3f = false;
128 mUsesMod4v = false;
129 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000130 mUsesFaceforward1 = false;
131 mUsesFaceforward2 = false;
132 mUsesFaceforward3 = false;
133 mUsesFaceforward4 = false;
daniel@transgaming.com35342dc2012-02-28 02:01:22 +0000134 mUsesAtan2_1 = false;
135 mUsesAtan2_2 = false;
136 mUsesAtan2_3 = false;
137 mUsesAtan2_4 = false;
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500138 mUsesDiscardRewriting = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400139 mUsesNestedBreak = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000140
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000141 mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
142
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000143 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000144
145 mContainsLoopDiscontinuity = false;
146 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000147 mInsideDiscontinuousLoop = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400148 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000149
150 mExcessiveLoopIndex = NULL;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000151
Jamie Madill8daaba12014-06-13 10:04:33 -0400152 mStructureHLSL = new StructureHLSL;
Jamie Madillf91ce812014-06-13 10:04:34 -0400153 mUniformHLSL = new UniformHLSL(mStructureHLSL, mOutputType);
Jamie Madill8daaba12014-06-13 10:04:33 -0400154
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000155 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000156 {
Jamie Madill183bde52014-07-02 15:31:19 -0400157 if (mContext.shaderType == GL_FRAGMENT_SHADER)
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000158 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400159 // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
160 mUniformHLSL->reserveUniformRegisters(3);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000161 }
162 else
163 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400164 // Reserve registers for dx_DepthRange and dx_ViewAdjust
165 mUniformHLSL->reserveUniformRegisters(2);
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000166 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000167 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000168
Jamie Madillf91ce812014-06-13 10:04:34 -0400169 // Reserve registers for the default uniform block and driver constants
170 mUniformHLSL->reserveInterfaceBlockRegisters(2);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171}
172
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000173OutputHLSL::~OutputHLSL()
174{
Jamie Madill8daaba12014-06-13 10:04:33 -0400175 SafeDelete(mUnfoldShortCircuit);
176 SafeDelete(mStructureHLSL);
Jamie Madillf91ce812014-06-13 10:04:34 -0400177 SafeDelete(mUniformHLSL);
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000178}
179
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000180void OutputHLSL::output()
181{
Jamie Madill183bde52014-07-02 15:31:19 -0400182 mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400183 const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
184 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000185
Jamie Madille53c98b2014-02-03 11:57:13 -0500186 // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
187 // use a vertex attribute as a condition, and some related computation in the else block.
Jamie Madill183bde52014-07-02 15:31:19 -0400188 if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == GL_VERTEX_SHADER)
Jamie Madille53c98b2014-02-03 11:57:13 -0500189 {
190 RewriteElseBlocks(mContext.treeRoot);
191 }
192
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000193 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000194 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000195
alokp@chromium.org646ea1e2012-06-15 17:36:31 +0000196 mContext.infoSink().obj << mHeader.c_str();
197 mContext.infoSink().obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000198}
199
Jamie Madill570e04d2013-06-21 09:15:33 -0400200void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
201{
202 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
203 {
204 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
205
206 // This will mark the necessary block elements as referenced
207 flaggedNode->traverse(this);
208 TString structName(mBody.c_str());
209 mBody.erase();
210
211 mFlaggedStructOriginalNames[flaggedNode] = structName;
212
213 for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
214 {
215 structName.erase(pos, 1);
216 }
217
218 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
219 }
220}
221
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000222TInfoSinkBase &OutputHLSL::getBodyStream()
223{
224 return mBody;
225}
226
Jamie Madillf2575982014-06-25 16:04:54 -0400227const std::vector<sh::Uniform> &OutputHLSL::getUniforms()
daniel@transgaming.com043da132012-12-20 21:12:22 +0000228{
Jamie Madillf91ce812014-06-13 10:04:34 -0400229 return mUniformHLSL->getUniforms();
daniel@transgaming.com043da132012-12-20 21:12:22 +0000230}
231
Jamie Madillf2575982014-06-25 16:04:54 -0400232const std::vector<sh::InterfaceBlock> &OutputHLSL::getInterfaceBlocks() const
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000233{
Jamie Madillf91ce812014-06-13 10:04:34 -0400234 return mUniformHLSL->getInterfaceBlocks();
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000235}
236
Jamie Madillf2575982014-06-25 16:04:54 -0400237const std::vector<sh::Attribute> &OutputHLSL::getOutputVariables() const
Jamie Madill46131a32013-06-20 11:55:50 -0400238{
239 return mActiveOutputVariables;
240}
241
Jamie Madillf2575982014-06-25 16:04:54 -0400242const std::vector<sh::Attribute> &OutputHLSL::getAttributes() const
Jamie Madilldefb6742013-06-20 11:55:51 -0400243{
244 return mActiveAttributes;
245}
246
Jamie Madillf2575982014-06-25 16:04:54 -0400247const std::vector<sh::Varying> &OutputHLSL::getVaryings() const
Jamie Madill47fdd132013-08-30 13:21:04 -0400248{
249 return mActiveVaryings;
250}
251
Jamie Madill4e1fd412014-07-10 17:50:10 -0400252const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
253{
254 return mUniformHLSL->getInterfaceBlockRegisterMap();
255}
256
Jamie Madill9fe25e92014-07-18 10:33:08 -0400257const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
258{
259 return mUniformHLSL->getUniformRegisterMap();
260}
261
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000262int OutputHLSL::vectorSize(const TType &type) const
263{
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000264 int elementSize = type.isMatrix() ? type.getCols() : 1;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000265 int arraySize = type.isArray() ? type.getArraySize() : 1;
266
267 return elementSize * arraySize;
268}
269
Jamie Madill98493dd2013-07-08 14:39:03 -0400270TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
Jamie Madill570e04d2013-06-21 09:15:33 -0400271{
272 TString init;
273
274 TString preIndentString;
275 TString fullIndentString;
276
277 for (int spaces = 0; spaces < (indent * 4); spaces++)
278 {
279 preIndentString += ' ';
280 }
281
282 for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
283 {
284 fullIndentString += ' ';
285 }
286
287 init += preIndentString + "{\n";
288
Jamie Madill98493dd2013-07-08 14:39:03 -0400289 const TFieldList &fields = structure.fields();
290 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400292 const TField &field = *fields[fieldIndex];
Jamie Madill033dae62014-06-18 12:56:28 -0400293 const TString &fieldName = rhsStructName + "." + Decorate(field.name());
Jamie Madill98493dd2013-07-08 14:39:03 -0400294 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400295
Jamie Madill98493dd2013-07-08 14:39:03 -0400296 if (fieldType.getStruct())
Jamie Madill570e04d2013-06-21 09:15:33 -0400297 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400298 init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400299 }
300 else
301 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400302 init += fullIndentString + fieldName + ",\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400303 }
304 }
305
306 init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
307
308 return init;
309}
310
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311void OutputHLSL::header()
312{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000313 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000315 TString varyings;
316 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400317 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000318
Jamie Madill829f59e2013-11-13 19:40:54 -0500319 for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400320 {
321 TIntermTyped *structNode = flaggedStructIt->first;
322 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400323 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400324 const TString &originalName = mFlaggedStructOriginalNames[structNode];
325
Jamie Madill033dae62014-06-18 12:56:28 -0400326 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400327 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400328 flaggedStructs += "\n";
329 }
330
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000331 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
332 {
333 const TType &type = varying->second->getType();
334 const TString &name = varying->second->getSymbol();
335
336 // Program linking depends on this exact format
Jamie Madill033dae62014-06-18 12:56:28 -0400337 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
338 Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madill47fdd132013-08-30 13:21:04 -0400339
Jamie Madill94599662013-08-30 13:21:10 -0400340 declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000341 }
342
343 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
344 {
345 const TType &type = attribute->second->getType();
346 const TString &name = attribute->second->getSymbol();
347
Jamie Madill033dae62014-06-18 12:56:28 -0400348 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madilldefb6742013-06-20 11:55:51 -0400349
Jamie Madilla3fe2b42014-07-18 10:33:13 -0400350 sh::Attribute attributeVar = MakeAttributeFromType(type, name);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400351 mActiveAttributes.push_back(attributeVar);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000352 }
353
Jamie Madill8daaba12014-06-13 10:04:33 -0400354 out << mStructureHLSL->structsHeader();
Jamie Madill529077d2013-06-20 11:55:54 -0400355
Jamie Madillf91ce812014-06-13 10:04:34 -0400356 out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms);
357 out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
358
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500359 if (mUsesDiscardRewriting)
360 {
361 out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
362 }
363
Nicolas Capens655fe362014-04-11 13:12:34 -0400364 if (mUsesNestedBreak)
365 {
366 out << "#define ANGLE_USES_NESTED_BREAK" << "\n";
367 }
368
Jamie Madill183bde52014-07-02 15:31:19 -0400369 if (mContext.shaderType == GL_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370 {
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000371 TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
shannon.woods%transgaming.com@gtempaccount.com99ab6eb2013-04-13 03:42:00 +0000372 const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000373
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000374 out << "// Varyings\n";
375 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400376 out << "\n";
377
378 if (mContext.getShaderVersion() >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000379 {
Jamie Madill829f59e2013-11-13 19:40:54 -0500380 for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000381 {
Jamie Madill46131a32013-06-20 11:55:50 -0400382 const TString &variableName = outputVariableIt->first;
383 const TType &variableType = outputVariableIt->second->getType();
Jamie Madill46131a32013-06-20 11:55:50 -0400384
Jamie Madill033dae62014-06-18 12:56:28 -0400385 out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
Jamie Madill46131a32013-06-20 11:55:50 -0400386 " = " + initializer(variableType) + ";\n";
387
Jamie Madilla3fe2b42014-07-18 10:33:13 -0400388 sh::Attribute outputVar = MakeAttributeFromType(variableType, variableName);
Jamie Madill46131a32013-06-20 11:55:50 -0400389 mActiveOutputVariables.push_back(outputVar);
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000390 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000391 }
Jamie Madill46131a32013-06-20 11:55:50 -0400392 else
393 {
394 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
395
396 out << "static float4 gl_Color[" << numColorValues << "] =\n"
397 "{\n";
398 for (unsigned int i = 0; i < numColorValues; i++)
399 {
400 out << " float4(0, 0, 0, 0)";
401 if (i + 1 != numColorValues)
402 {
403 out << ",";
404 }
405 out << "\n";
406 }
407
408 out << "};\n";
409 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000410
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400411 if (mUsesFragDepth)
412 {
413 out << "static float gl_Depth = 0.0;\n";
414 }
415
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000416 if (mUsesFragCoord)
417 {
418 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
419 }
420
421 if (mUsesPointCoord)
422 {
423 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
424 }
425
426 if (mUsesFrontFacing)
427 {
428 out << "static bool gl_FrontFacing = false;\n";
429 }
430
431 out << "\n";
432
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000433 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000434 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000435 out << "struct gl_DepthRangeParameters\n"
436 "{\n"
437 " float near;\n"
438 " float far;\n"
439 " float diff;\n"
440 "};\n"
441 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000442 }
443
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000444 if (mOutputType == SH_HLSL11_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000445 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000446 out << "cbuffer DriverConstants : register(b1)\n"
447 "{\n";
448
449 if (mUsesDepthRange)
450 {
451 out << " float3 dx_DepthRange : packoffset(c0);\n";
452 }
453
454 if (mUsesFragCoord)
455 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000456 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000457 }
458
459 if (mUsesFragCoord || mUsesFrontFacing)
460 {
461 out << " float3 dx_DepthFront : packoffset(c2);\n";
462 }
463
464 out << "};\n";
465 }
466 else
467 {
468 if (mUsesDepthRange)
469 {
470 out << "uniform float3 dx_DepthRange : register(c0);";
471 }
472
473 if (mUsesFragCoord)
474 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000475 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000476 }
477
478 if (mUsesFragCoord || mUsesFrontFacing)
479 {
480 out << "uniform float3 dx_DepthFront : register(c2);\n";
481 }
482 }
483
484 out << "\n";
485
486 if (mUsesDepthRange)
487 {
488 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
489 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000490 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000491
Jamie Madillf91ce812014-06-13 10:04:34 -0400492 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000493 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400494 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000495 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400496 out << flaggedStructs;
497 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000498 }
499
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000500 if (usingMRTExtension && mNumRenderTargets > 1)
501 {
502 out << "#define GL_USES_MRT\n";
503 }
504
505 if (mUsesFragColor)
506 {
507 out << "#define GL_USES_FRAG_COLOR\n";
508 }
509
510 if (mUsesFragData)
511 {
512 out << "#define GL_USES_FRAG_DATA\n";
513 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000515 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000517 out << "// Attributes\n";
518 out << attributes;
519 out << "\n"
520 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400521
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000522 if (mUsesPointSize)
523 {
524 out << "static float gl_PointSize = float(1);\n";
525 }
526
527 out << "\n"
528 "// Varyings\n";
529 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000530 out << "\n";
531
532 if (mUsesDepthRange)
533 {
534 out << "struct gl_DepthRangeParameters\n"
535 "{\n"
536 " float near;\n"
537 " float far;\n"
538 " float diff;\n"
539 "};\n"
540 "\n";
541 }
542
543 if (mOutputType == SH_HLSL11_OUTPUT)
544 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000545 if (mUsesDepthRange)
546 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000547 out << "cbuffer DriverConstants : register(b1)\n"
548 "{\n"
549 " float3 dx_DepthRange : packoffset(c0);\n"
550 "};\n"
551 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000552 }
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000553 }
554 else
555 {
556 if (mUsesDepthRange)
557 {
558 out << "uniform float3 dx_DepthRange : register(c0);\n";
559 }
560
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +0000561 out << "uniform float4 dx_ViewAdjust : register(c1);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000562 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000563 }
564
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000565 if (mUsesDepthRange)
566 {
567 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
568 "\n";
569 }
570
Jamie Madillf91ce812014-06-13 10:04:34 -0400571 if (!flaggedStructs.empty())
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000572 {
Jamie Madillf91ce812014-06-13 10:04:34 -0400573 out << "// Std140 Structures accessed by value\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000574 out << "\n";
Jamie Madillf91ce812014-06-13 10:04:34 -0400575 out << flaggedStructs;
576 out << "\n";
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000577 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400578 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000579
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400580 for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
581 {
582 // Return type
Nicolas Capens75fb4752013-07-10 15:14:47 -0400583 if (textureFunction->method == TextureFunction::SIZE)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000584 {
Nicolas Capens75fb4752013-07-10 15:14:47 -0400585 switch(textureFunction->sampler)
586 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400587 case EbtSampler2D: out << "int2 "; break;
588 case EbtSampler3D: out << "int3 "; break;
589 case EbtSamplerCube: out << "int2 "; break;
590 case EbtSampler2DArray: out << "int3 "; break;
591 case EbtISampler2D: out << "int2 "; break;
592 case EbtISampler3D: out << "int3 "; break;
593 case EbtISamplerCube: out << "int2 "; break;
594 case EbtISampler2DArray: out << "int3 "; break;
595 case EbtUSampler2D: out << "int2 "; break;
596 case EbtUSampler3D: out << "int3 "; break;
597 case EbtUSamplerCube: out << "int2 "; break;
598 case EbtUSampler2DArray: out << "int3 "; break;
599 case EbtSampler2DShadow: out << "int2 "; break;
600 case EbtSamplerCubeShadow: out << "int2 "; break;
601 case EbtSampler2DArrayShadow: out << "int3 "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400602 default: UNREACHABLE();
603 }
604 }
605 else // Sampling function
606 {
607 switch(textureFunction->sampler)
608 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400609 case EbtSampler2D: out << "float4 "; break;
610 case EbtSampler3D: out << "float4 "; break;
611 case EbtSamplerCube: out << "float4 "; break;
612 case EbtSampler2DArray: out << "float4 "; break;
613 case EbtISampler2D: out << "int4 "; break;
614 case EbtISampler3D: out << "int4 "; break;
615 case EbtISamplerCube: out << "int4 "; break;
616 case EbtISampler2DArray: out << "int4 "; break;
617 case EbtUSampler2D: out << "uint4 "; break;
618 case EbtUSampler3D: out << "uint4 "; break;
619 case EbtUSamplerCube: out << "uint4 "; break;
620 case EbtUSampler2DArray: out << "uint4 "; break;
621 case EbtSampler2DShadow: out << "float "; break;
622 case EbtSamplerCubeShadow: out << "float "; break;
623 case EbtSampler2DArrayShadow: out << "float "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400624 default: UNREACHABLE();
625 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000626 }
627
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400628 // Function name
629 out << textureFunction->name();
630
631 // Argument list
632 int hlslCoords = 4;
633
634 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000635 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400636 switch(textureFunction->sampler)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000637 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400638 case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
639 case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
640 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000641 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400642
Nicolas Capens75fb4752013-07-10 15:14:47 -0400643 switch(textureFunction->method)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000644 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400645 case TextureFunction::IMPLICIT: break;
646 case TextureFunction::BIAS: hlslCoords = 4; break;
647 case TextureFunction::LOD: hlslCoords = 4; break;
648 case TextureFunction::LOD0: hlslCoords = 4; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400649 case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400650 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000651 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400652 }
653 else if (mOutputType == SH_HLSL11_OUTPUT)
654 {
655 switch(textureFunction->sampler)
656 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400657 case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
658 case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
659 case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
660 case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
661 case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
662 case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500663 case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400664 case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
665 case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
666 case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -0500667 case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -0400668 case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
669 case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
670 case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
671 case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400672 default: UNREACHABLE();
673 }
674 }
675 else UNREACHABLE();
676
Nicolas Capensfc014542014-02-18 14:47:13 -0500677 if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400678 {
Nicolas Capensfc014542014-02-18 14:47:13 -0500679 switch(textureFunction->coords)
680 {
681 case 2: out << ", int2 t"; break;
682 case 3: out << ", int3 t"; break;
683 default: UNREACHABLE();
684 }
685 }
686 else // Floating-point coordinates (except textureSize)
687 {
688 switch(textureFunction->coords)
689 {
690 case 1: out << ", int lod"; break; // textureSize()
691 case 2: out << ", float2 t"; break;
692 case 3: out << ", float3 t"; break;
693 case 4: out << ", float4 t"; break;
694 default: UNREACHABLE();
695 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000696 }
697
Nicolas Capensd11d5492014-02-19 17:06:10 -0500698 if (textureFunction->method == TextureFunction::GRAD)
699 {
700 switch(textureFunction->sampler)
701 {
702 case EbtSampler2D:
703 case EbtISampler2D:
704 case EbtUSampler2D:
705 case EbtSampler2DArray:
706 case EbtISampler2DArray:
707 case EbtUSampler2DArray:
708 case EbtSampler2DShadow:
709 case EbtSampler2DArrayShadow:
710 out << ", float2 ddx, float2 ddy";
711 break;
712 case EbtSampler3D:
713 case EbtISampler3D:
714 case EbtUSampler3D:
715 case EbtSamplerCube:
716 case EbtISamplerCube:
717 case EbtUSamplerCube:
718 case EbtSamplerCubeShadow:
719 out << ", float3 ddx, float3 ddy";
720 break;
721 default: UNREACHABLE();
722 }
723 }
724
Nicolas Capens75fb4752013-07-10 15:14:47 -0400725 switch(textureFunction->method)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000726 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400727 case TextureFunction::IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400728 case TextureFunction::BIAS: break; // Comes after the offset parameter
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400729 case TextureFunction::LOD: out << ", float lod"; break;
730 case TextureFunction::LOD0: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400731 case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
Nicolas Capens75fb4752013-07-10 15:14:47 -0400732 case TextureFunction::SIZE: break;
Nicolas Capensfc014542014-02-18 14:47:13 -0500733 case TextureFunction::FETCH: out << ", int mip"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -0500734 case TextureFunction::GRAD: break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400735 default: UNREACHABLE();
daniel@transgaming.com15795192011-05-11 15:36:20 +0000736 }
737
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500738 if (textureFunction->offset)
739 {
740 switch(textureFunction->sampler)
741 {
742 case EbtSampler2D: out << ", int2 offset"; break;
743 case EbtSampler3D: out << ", int3 offset"; break;
744 case EbtSampler2DArray: out << ", int2 offset"; break;
745 case EbtISampler2D: out << ", int2 offset"; break;
746 case EbtISampler3D: out << ", int3 offset"; break;
747 case EbtISampler2DArray: out << ", int2 offset"; break;
748 case EbtUSampler2D: out << ", int2 offset"; break;
749 case EbtUSampler3D: out << ", int3 offset"; break;
750 case EbtUSampler2DArray: out << ", int2 offset"; break;
751 case EbtSampler2DShadow: out << ", int2 offset"; break;
Nicolas Capensbf7db102014-02-19 17:20:28 -0500752 case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500753 default: UNREACHABLE();
754 }
755 }
756
Nicolas Capens84cfa122014-04-14 13:48:45 -0400757 if (textureFunction->method == TextureFunction::BIAS ||
758 textureFunction->method == TextureFunction::LOD0BIAS)
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500759 {
760 out << ", float bias";
761 }
762
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400763 out << ")\n"
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400764 "{\n";
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400765
Nicolas Capens75fb4752013-07-10 15:14:47 -0400766 if (textureFunction->method == TextureFunction::SIZE)
767 {
768 if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
769 {
770 if (IsSamplerArray(textureFunction->sampler))
771 {
772 out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
773 " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
774 }
775 else
776 {
777 out << " uint width; uint height; uint numberOfLevels;\n"
778 " x.GetDimensions(lod, width, height, numberOfLevels);\n";
779 }
780 }
781 else if (IsSampler3D(textureFunction->sampler))
782 {
783 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
784 " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
785 }
786 else UNREACHABLE();
787
788 switch(textureFunction->sampler)
789 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400790 case EbtSampler2D: out << " return int2(width, height);"; break;
791 case EbtSampler3D: out << " return int3(width, height, depth);"; break;
792 case EbtSamplerCube: out << " return int2(width, height);"; break;
793 case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
794 case EbtISampler2D: out << " return int2(width, height);"; break;
795 case EbtISampler3D: out << " return int3(width, height, depth);"; break;
796 case EbtISamplerCube: out << " return int2(width, height);"; break;
797 case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
798 case EbtUSampler2D: out << " return int2(width, height);"; break;
799 case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
800 case EbtUSamplerCube: out << " return int2(width, height);"; break;
801 case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
802 case EbtSampler2DShadow: out << " return int2(width, height);"; break;
803 case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
804 case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400805 default: UNREACHABLE();
806 }
807 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400808 else
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400809 {
Nicolas Capens0027fa92014-02-20 14:26:42 -0500810 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
811 {
812 out << " float width; float height; float layers; float levels;\n";
813
814 out << " uint mip = 0;\n";
815
816 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
817
818 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
819 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
820 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
821 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
822
823 // FACE_POSITIVE_X = 000b
824 // FACE_NEGATIVE_X = 001b
825 // FACE_POSITIVE_Y = 010b
826 // FACE_NEGATIVE_Y = 011b
827 // FACE_POSITIVE_Z = 100b
828 // FACE_NEGATIVE_Z = 101b
829 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
830
831 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
832 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
833 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
834
835 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
836 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
837 }
838 else if (IsIntegerSampler(textureFunction->sampler) &&
839 textureFunction->method != TextureFunction::FETCH)
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400840 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400841 if (IsSampler2D(textureFunction->sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400842 {
Nicolas Capens93e50de2013-07-09 13:46:28 -0400843 if (IsSamplerArray(textureFunction->sampler))
844 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400845 out << " float width; float height; float layers; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400846
Nicolas Capens9edebd62013-08-06 10:59:10 -0400847 if (textureFunction->method == TextureFunction::LOD0)
848 {
849 out << " uint mip = 0;\n";
850 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400851 else if (textureFunction->method == TextureFunction::LOD0BIAS)
852 {
853 out << " uint mip = bias;\n";
854 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400855 else
856 {
857 if (textureFunction->method == TextureFunction::IMPLICIT ||
858 textureFunction->method == TextureFunction::BIAS)
859 {
860 out << " x.GetDimensions(0, width, height, layers, levels);\n"
861 " float2 tSized = float2(t.x * width, t.y * height);\n"
862 " float dx = length(ddx(tSized));\n"
863 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500864 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400865
866 if (textureFunction->method == TextureFunction::BIAS)
867 {
868 out << " lod += bias;\n";
869 }
870 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500871 else if (textureFunction->method == TextureFunction::GRAD)
872 {
873 out << " x.GetDimensions(0, width, height, layers, levels);\n"
874 " float lod = log2(max(length(ddx), length(ddy)));\n";
875 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400876
877 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
878 }
879
880 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400881 }
882 else
883 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400884 out << " float width; float height; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400885
Nicolas Capens9edebd62013-08-06 10:59:10 -0400886 if (textureFunction->method == TextureFunction::LOD0)
887 {
888 out << " uint mip = 0;\n";
889 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400890 else if (textureFunction->method == TextureFunction::LOD0BIAS)
891 {
892 out << " uint mip = bias;\n";
893 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400894 else
895 {
896 if (textureFunction->method == TextureFunction::IMPLICIT ||
897 textureFunction->method == TextureFunction::BIAS)
898 {
899 out << " x.GetDimensions(0, width, height, levels);\n"
900 " float2 tSized = float2(t.x * width, t.y * height);\n"
901 " float dx = length(ddx(tSized));\n"
902 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500903 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400904
905 if (textureFunction->method == TextureFunction::BIAS)
906 {
907 out << " lod += bias;\n";
908 }
909 }
Nicolas Capens2adc2562014-02-14 23:50:59 -0500910 else if (textureFunction->method == TextureFunction::LOD)
911 {
912 out << " x.GetDimensions(0, width, height, levels);\n";
913 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500914 else if (textureFunction->method == TextureFunction::GRAD)
915 {
916 out << " x.GetDimensions(0, width, height, levels);\n"
917 " float lod = log2(max(length(ddx), length(ddy)));\n";
918 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400919
920 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
921 }
922
923 out << " x.GetDimensions(mip, width, height, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -0400924 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400925 }
926 else if (IsSampler3D(textureFunction->sampler))
927 {
Nicolas Capens9edebd62013-08-06 10:59:10 -0400928 out << " float width; float height; float depth; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -0400929
Nicolas Capens9edebd62013-08-06 10:59:10 -0400930 if (textureFunction->method == TextureFunction::LOD0)
931 {
932 out << " uint mip = 0;\n";
933 }
Nicolas Capens84cfa122014-04-14 13:48:45 -0400934 else if (textureFunction->method == TextureFunction::LOD0BIAS)
935 {
936 out << " uint mip = bias;\n";
937 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400938 else
939 {
940 if (textureFunction->method == TextureFunction::IMPLICIT ||
941 textureFunction->method == TextureFunction::BIAS)
942 {
943 out << " x.GetDimensions(0, width, height, depth, levels);\n"
944 " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
945 " float dx = length(ddx(tSized));\n"
946 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -0500947 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -0400948
949 if (textureFunction->method == TextureFunction::BIAS)
950 {
951 out << " lod += bias;\n";
952 }
953 }
Nicolas Capensd11d5492014-02-19 17:06:10 -0500954 else if (textureFunction->method == TextureFunction::GRAD)
955 {
956 out << " x.GetDimensions(0, width, height, depth, levels);\n"
957 " float lod = log2(max(length(ddx), length(ddy)));\n";
958 }
Nicolas Capens9edebd62013-08-06 10:59:10 -0400959
960 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
961 }
962
963 out << " x.GetDimensions(mip, width, height, depth, levels);\n";
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400964 }
965 else UNREACHABLE();
966 }
967
968 out << " return ";
969
970 // HLSL intrinsic
971 if (mOutputType == SH_HLSL9_OUTPUT)
972 {
973 switch(textureFunction->sampler)
974 {
975 case EbtSampler2D: out << "tex2D"; break;
976 case EbtSamplerCube: out << "texCUBE"; break;
977 default: UNREACHABLE();
978 }
979
Nicolas Capens75fb4752013-07-10 15:14:47 -0400980 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400981 {
982 case TextureFunction::IMPLICIT: out << "(s, "; break;
983 case TextureFunction::BIAS: out << "bias(s, "; break;
984 case TextureFunction::LOD: out << "lod(s, "; break;
985 case TextureFunction::LOD0: out << "lod(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400986 case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400987 default: UNREACHABLE();
988 }
989 }
990 else if (mOutputType == SH_HLSL11_OUTPUT)
991 {
Nicolas Capensd11d5492014-02-19 17:06:10 -0500992 if (textureFunction->method == TextureFunction::GRAD)
993 {
994 if (IsIntegerSampler(textureFunction->sampler))
995 {
996 out << "x.Load(";
997 }
998 else if (IsShadowSampler(textureFunction->sampler))
999 {
1000 out << "x.SampleCmpLevelZero(s, ";
1001 }
1002 else
1003 {
1004 out << "x.SampleGrad(s, ";
1005 }
1006 }
1007 else if (IsIntegerSampler(textureFunction->sampler) ||
1008 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001009 {
1010 out << "x.Load(";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001011 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001012 else if (IsShadowSampler(textureFunction->sampler))
1013 {
1014 out << "x.SampleCmp(s, ";
1015 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001016 else
1017 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001018 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001019 {
1020 case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
1021 case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
1022 case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
1023 case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001024 case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001025 default: UNREACHABLE();
1026 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001027 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001028 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001029 else UNREACHABLE();
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001030
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001031 // Integer sampling requires integer addresses
1032 TString addressx = "";
1033 TString addressy = "";
1034 TString addressz = "";
1035 TString close = "";
1036
Nicolas Capensfc014542014-02-18 14:47:13 -05001037 if (IsIntegerSampler(textureFunction->sampler) ||
1038 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001039 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001040 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001041 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001042 case 2: out << "int3("; break;
1043 case 3: out << "int4("; break;
1044 default: UNREACHABLE();
1045 }
Jamie Madillf91ce812014-06-13 10:04:34 -04001046
Nicolas Capensfc014542014-02-18 14:47:13 -05001047 // Convert from normalized floating-point to integer
1048 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001049 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001050 addressx = "int(floor(width * frac((";
1051 addressy = "int(floor(height * frac((";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001052
Nicolas Capensfc014542014-02-18 14:47:13 -05001053 if (IsSamplerArray(textureFunction->sampler))
1054 {
1055 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
1056 }
Nicolas Capens0027fa92014-02-20 14:26:42 -05001057 else if (IsSamplerCube(textureFunction->sampler))
1058 {
1059 addressz = "((((";
1060 }
Nicolas Capensfc014542014-02-18 14:47:13 -05001061 else
1062 {
1063 addressz = "int(floor(depth * frac((";
1064 }
1065
1066 close = "))))";
1067 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001068 }
1069 else
1070 {
1071 switch(hlslCoords)
1072 {
1073 case 2: out << "float2("; break;
1074 case 3: out << "float3("; break;
1075 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001076 default: UNREACHABLE();
1077 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001078 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001079
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001080 TString proj = ""; // Only used for projected textures
Jamie Madillf91ce812014-06-13 10:04:34 -04001081
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001082 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001083 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001084 switch(textureFunction->coords)
1085 {
1086 case 3: proj = " / t.z"; break;
1087 case 4: proj = " / t.w"; break;
1088 default: UNREACHABLE();
1089 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001090 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001091
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001092 out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001093
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001094 if (mOutputType == SH_HLSL9_OUTPUT)
1095 {
1096 if (hlslCoords >= 3)
1097 {
1098 if (textureFunction->coords < 3)
1099 {
1100 out << ", 0";
1101 }
1102 else
1103 {
1104 out << ", t.z" + proj;
1105 }
1106 }
1107
1108 if (hlslCoords == 4)
1109 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001110 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001111 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001112 case TextureFunction::BIAS: out << ", bias"; break;
1113 case TextureFunction::LOD: out << ", lod"; break;
1114 case TextureFunction::LOD0: out << ", 0"; break;
1115 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001116 default: UNREACHABLE();
1117 }
1118 }
1119
1120 out << "));\n";
1121 }
1122 else if (mOutputType == SH_HLSL11_OUTPUT)
1123 {
1124 if (hlslCoords >= 3)
1125 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001126 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1127 {
1128 out << ", face";
1129 }
1130 else
1131 {
1132 out << ", " + addressz + ("t.z" + proj) + close;
1133 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001134 }
1135
Nicolas Capensd11d5492014-02-19 17:06:10 -05001136 if (textureFunction->method == TextureFunction::GRAD)
1137 {
1138 if (IsIntegerSampler(textureFunction->sampler))
1139 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001140 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001141 }
1142 else if (IsShadowSampler(textureFunction->sampler))
1143 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001144 // Compare value
Nicolas Capensd11d5492014-02-19 17:06:10 -05001145 switch(textureFunction->coords)
1146 {
1147 case 3: out << "), t.z"; break;
1148 case 4: out << "), t.w"; break;
1149 default: UNREACHABLE();
1150 }
1151 }
1152 else
1153 {
1154 out << "), ddx, ddy";
1155 }
1156 }
1157 else if (IsIntegerSampler(textureFunction->sampler) ||
1158 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001159 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001160 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001161 }
1162 else if (IsShadowSampler(textureFunction->sampler))
1163 {
1164 // Compare value
1165 switch(textureFunction->coords)
1166 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001167 case 3: out << "), t.z"; break;
1168 case 4: out << "), t.w"; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001169 default: UNREACHABLE();
1170 }
1171 }
1172 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001173 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001174 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001175 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001176 case TextureFunction::IMPLICIT: out << ")"; break;
1177 case TextureFunction::BIAS: out << "), bias"; break;
1178 case TextureFunction::LOD: out << "), lod"; break;
1179 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001180 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001181 default: UNREACHABLE();
1182 }
1183 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001184
1185 if (textureFunction->offset)
1186 {
1187 out << ", offset";
1188 }
1189
1190 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001191 }
1192 else UNREACHABLE();
1193 }
1194
1195 out << "\n"
1196 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001197 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001198 }
1199
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001200 if (mUsesFragCoord)
1201 {
1202 out << "#define GL_USES_FRAG_COORD\n";
1203 }
1204
1205 if (mUsesPointCoord)
1206 {
1207 out << "#define GL_USES_POINT_COORD\n";
1208 }
1209
1210 if (mUsesFrontFacing)
1211 {
1212 out << "#define GL_USES_FRONT_FACING\n";
1213 }
1214
1215 if (mUsesPointSize)
1216 {
1217 out << "#define GL_USES_POINT_SIZE\n";
1218 }
1219
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001220 if (mUsesFragDepth)
1221 {
1222 out << "#define GL_USES_FRAG_DEPTH\n";
1223 }
1224
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001225 if (mUsesDepthRange)
1226 {
1227 out << "#define GL_USES_DEPTH_RANGE\n";
1228 }
1229
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001230 if (mUsesXor)
1231 {
1232 out << "bool xor(bool p, bool q)\n"
1233 "{\n"
1234 " return (p || q) && !(p && q);\n"
1235 "}\n"
1236 "\n";
1237 }
1238
1239 if (mUsesMod1)
1240 {
1241 out << "float mod(float x, float y)\n"
1242 "{\n"
1243 " return x - y * floor(x / y);\n"
1244 "}\n"
1245 "\n";
1246 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001247
1248 if (mUsesMod2v)
1249 {
1250 out << "float2 mod(float2 x, float2 y)\n"
1251 "{\n"
1252 " return x - y * floor(x / y);\n"
1253 "}\n"
1254 "\n";
1255 }
1256
1257 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001258 {
1259 out << "float2 mod(float2 x, float y)\n"
1260 "{\n"
1261 " return x - y * floor(x / y);\n"
1262 "}\n"
1263 "\n";
1264 }
Jamie Madillf91ce812014-06-13 10:04:34 -04001265
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001266 if (mUsesMod3v)
1267 {
1268 out << "float3 mod(float3 x, float3 y)\n"
1269 "{\n"
1270 " return x - y * floor(x / y);\n"
1271 "}\n"
1272 "\n";
1273 }
1274
1275 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001276 {
1277 out << "float3 mod(float3 x, float y)\n"
1278 "{\n"
1279 " return x - y * floor(x / y);\n"
1280 "}\n"
1281 "\n";
1282 }
1283
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001284 if (mUsesMod4v)
1285 {
1286 out << "float4 mod(float4 x, float4 y)\n"
1287 "{\n"
1288 " return x - y * floor(x / y);\n"
1289 "}\n"
1290 "\n";
1291 }
1292
1293 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001294 {
1295 out << "float4 mod(float4 x, float y)\n"
1296 "{\n"
1297 " return x - y * floor(x / y);\n"
1298 "}\n"
1299 "\n";
1300 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001301
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001302 if (mUsesFaceforward1)
1303 {
1304 out << "float faceforward(float N, float I, float Nref)\n"
1305 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001306 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001307 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001308 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001309 " }\n"
1310 " else\n"
1311 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001312 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001313 " }\n"
1314 "}\n"
1315 "\n";
1316 }
1317
1318 if (mUsesFaceforward2)
1319 {
1320 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
1321 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001322 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001323 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001324 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001325 " }\n"
1326 " else\n"
1327 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001328 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001329 " }\n"
1330 "}\n"
1331 "\n";
1332 }
1333
1334 if (mUsesFaceforward3)
1335 {
1336 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
1337 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001338 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001339 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001340 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001341 " }\n"
1342 " else\n"
1343 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001344 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001345 " }\n"
1346 "}\n"
1347 "\n";
1348 }
1349
1350 if (mUsesFaceforward4)
1351 {
1352 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
1353 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001354 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001355 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001356 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001357 " }\n"
1358 " else\n"
1359 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001360 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001361 " }\n"
1362 "}\n"
1363 "\n";
1364 }
1365
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001366 if (mUsesAtan2_1)
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001367 {
1368 out << "float atanyx(float y, float x)\n"
1369 "{\n"
1370 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
1371 " return atan2(y, x);\n"
1372 "}\n";
1373 }
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001374
1375 if (mUsesAtan2_2)
1376 {
1377 out << "float2 atanyx(float2 y, float2 x)\n"
1378 "{\n"
1379 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1380 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1381 " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
1382 "}\n";
1383 }
1384
1385 if (mUsesAtan2_3)
1386 {
1387 out << "float3 atanyx(float3 y, float3 x)\n"
1388 "{\n"
1389 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1390 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1391 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1392 " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
1393 "}\n";
1394 }
1395
1396 if (mUsesAtan2_4)
1397 {
1398 out << "float4 atanyx(float4 y, float4 x)\n"
1399 "{\n"
1400 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1401 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1402 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1403 " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
1404 " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
1405 "}\n";
1406 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001407}
1408
1409void OutputHLSL::visitSymbol(TIntermSymbol *node)
1410{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001411 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001412
Jamie Madill570e04d2013-06-21 09:15:33 -04001413 // Handle accessing std140 structs by value
1414 if (mFlaggedStructMappedNames.count(node) > 0)
1415 {
1416 out << mFlaggedStructMappedNames[node];
1417 return;
1418 }
1419
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001420 TString name = node->getSymbol();
1421
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001422 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001423 {
1424 mUsesDepthRange = true;
1425 out << name;
1426 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001427 else
1428 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001429 TQualifier qualifier = node->getQualifier();
1430
1431 if (qualifier == EvqUniform)
1432 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001433 const TType& nodeType = node->getType();
1434 const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock();
1435
1436 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001437 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001438 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001439 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001440 else
1441 {
1442 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001443 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001444
Jamie Madill033dae62014-06-18 12:56:28 -04001445 out << DecorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001446 }
Jamie Madill19571812013-08-12 15:26:34 -07001447 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001448 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001449 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001450 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001451 }
Jamie Madill033dae62014-06-18 12:56:28 -04001452 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001453 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001454 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001455 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001456 }
Jamie Madill19571812013-08-12 15:26:34 -07001457 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001458 {
1459 mReferencedOutputVariables[name] = node;
1460 out << "out_" << name;
1461 }
1462 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001463 {
1464 out << "gl_Color[0]";
1465 mUsesFragColor = true;
1466 }
1467 else if (qualifier == EvqFragData)
1468 {
1469 out << "gl_Color";
1470 mUsesFragData = true;
1471 }
1472 else if (qualifier == EvqFragCoord)
1473 {
1474 mUsesFragCoord = true;
1475 out << name;
1476 }
1477 else if (qualifier == EvqPointCoord)
1478 {
1479 mUsesPointCoord = true;
1480 out << name;
1481 }
1482 else if (qualifier == EvqFrontFacing)
1483 {
1484 mUsesFrontFacing = true;
1485 out << name;
1486 }
1487 else if (qualifier == EvqPointSize)
1488 {
1489 mUsesPointSize = true;
1490 out << name;
1491 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001492 else if (name == "gl_FragDepthEXT")
1493 {
1494 mUsesFragDepth = true;
1495 out << "gl_Depth";
1496 }
Jamie Madille53c98b2014-02-03 11:57:13 -05001497 else if (qualifier == EvqInternal)
1498 {
1499 out << name;
1500 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001501 else
1502 {
Jamie Madill033dae62014-06-18 12:56:28 -04001503 out << Decorate(name);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001504 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001505 }
1506}
1507
Jamie Madill4cfb1e82014-07-07 12:49:23 -04001508void OutputHLSL::visitRaw(TIntermRaw *node)
1509{
1510 mBody << node->getRawText();
1511}
1512
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001513bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1514{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001515 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001516
Jamie Madill570e04d2013-06-21 09:15:33 -04001517 // Handle accessing std140 structs by value
1518 if (mFlaggedStructMappedNames.count(node) > 0)
1519 {
1520 out << mFlaggedStructMappedNames[node];
1521 return false;
1522 }
1523
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001524 switch (node->getOp())
1525 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001526 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001527 case EOpInitialize:
1528 if (visit == PreVisit)
1529 {
1530 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1531 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1532 // new variable is created before the assignment is evaluated), so we need to convert
1533 // this to "float t = x, x = t;".
1534
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001535 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1536 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001537
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001538 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
1539 expression->traverse(&searchSymbol);
1540 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001541
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001542 if (sameSymbol)
1543 {
1544 // Type already printed
1545 out << "t" + str(mUniqueIndex) + " = ";
1546 expression->traverse(this);
1547 out << ", ";
1548 symbolNode->traverse(this);
1549 out << " = t" + str(mUniqueIndex);
1550
1551 mUniqueIndex++;
1552 return false;
1553 }
1554 }
1555 else if (visit == InVisit)
1556 {
1557 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001558 }
1559 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001560 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
1561 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
1562 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1563 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1564 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1565 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001566 if (visit == PreVisit)
1567 {
1568 out << "(";
1569 }
1570 else if (visit == InVisit)
1571 {
1572 out << " = mul(";
1573 node->getLeft()->traverse(this);
Jamie Madillf91ce812014-06-13 10:04:34 -04001574 out << ", transpose(";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001575 }
1576 else
1577 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001578 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001579 }
1580 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001581 case EOpMatrixTimesMatrixAssign:
1582 if (visit == PreVisit)
1583 {
1584 out << "(";
1585 }
1586 else if (visit == InVisit)
1587 {
1588 out << " = mul(";
1589 node->getLeft()->traverse(this);
Jamie Madillf91ce812014-06-13 10:04:34 -04001590 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001591 }
1592 else
1593 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001594 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001595 }
1596 break;
1597 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001598 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001599 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001600 const TType& leftType = node->getLeft()->getType();
1601 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001602 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001603 if (visit == PreVisit)
1604 {
1605 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1606 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001607 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04001608 out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
Jamie Madill98493dd2013-07-08 14:39:03 -04001609 return false;
1610 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001611 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001612 else
1613 {
1614 outputTriplet(visit, "", "[", "]");
1615 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001616 }
1617 break;
1618 case EOpIndexIndirect:
1619 // We do not currently support indirect references to interface blocks
1620 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1621 outputTriplet(visit, "", "[", "]");
1622 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001623 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001624 if (visit == InVisit)
1625 {
1626 const TStructure* structure = node->getLeft()->getType().getStruct();
1627 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1628 const TField* field = structure->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001629 out << "." + DecorateField(field->name(), *structure);
Jamie Madill98493dd2013-07-08 14:39:03 -04001630
1631 return false;
1632 }
1633 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001634 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001635 if (visit == InVisit)
1636 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001637 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1638 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1639 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001640 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001641
1642 return false;
1643 }
1644 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645 case EOpVectorSwizzle:
1646 if (visit == InVisit)
1647 {
1648 out << ".";
1649
1650 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1651
1652 if (swizzle)
1653 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001654 TIntermSequence *sequence = swizzle->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001656 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001657 {
1658 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1659
1660 if (element)
1661 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00001662 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663
1664 switch (i)
1665 {
1666 case 0: out << "x"; break;
1667 case 1: out << "y"; break;
1668 case 2: out << "z"; break;
1669 case 3: out << "w"; break;
1670 default: UNREACHABLE();
1671 }
1672 }
1673 else UNREACHABLE();
1674 }
1675 }
1676 else UNREACHABLE();
1677
1678 return false; // Fully processed
1679 }
1680 break;
1681 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
1682 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
1683 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
1684 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001685 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001686 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001687 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001688 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001689 if (node->getOp() == EOpEqual)
1690 {
1691 outputTriplet(visit, "(", " == ", ")");
1692 }
1693 else
1694 {
1695 outputTriplet(visit, "(", " != ", ")");
1696 }
1697 }
1698 else if (node->getLeft()->getBasicType() == EbtStruct)
1699 {
1700 if (node->getOp() == EOpEqual)
1701 {
1702 out << "(";
1703 }
1704 else
1705 {
1706 out << "!(";
1707 }
1708
Jamie Madill98493dd2013-07-08 14:39:03 -04001709 const TStructure &structure = *node->getLeft()->getType().getStruct();
1710 const TFieldList &fields = structure.fields();
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001711
Jamie Madill98493dd2013-07-08 14:39:03 -04001712 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001713 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001714 const TField *field = fields[i];
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001715
1716 node->getLeft()->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04001717 out << "." + DecorateField(field->name(), structure) + " == ";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001718 node->getRight()->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04001719 out << "." + DecorateField(field->name(), structure);
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001720
Jamie Madill98493dd2013-07-08 14:39:03 -04001721 if (i < fields.size() - 1)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001722 {
1723 out << " && ";
1724 }
1725 }
1726
1727 out << ")";
1728
1729 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001730 }
1731 else
1732 {
Jamie Madill0b20c942013-07-19 16:36:56 -04001733 ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001734
1735 if (node->getOp() == EOpEqual)
1736 {
Jamie Madill0b20c942013-07-19 16:36:56 -04001737 outputTriplet(visit, "all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001738 }
1739 else
1740 {
Jamie Madill0b20c942013-07-19 16:36:56 -04001741 outputTriplet(visit, "!all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001742 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001743 }
1744 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001745 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1746 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1747 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1748 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1749 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001750 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001751 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1752 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001753 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001754 case EOpLogicalOr:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05001755 if (node->getRight()->hasSideEffects())
1756 {
1757 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
1758 return false;
1759 }
1760 else
1761 {
1762 outputTriplet(visit, "(", " || ", ")");
1763 return true;
1764 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001765 case EOpLogicalXor:
1766 mUsesXor = true;
1767 outputTriplet(visit, "xor(", ", ", ")");
1768 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001769 case EOpLogicalAnd:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05001770 if (node->getRight()->hasSideEffects())
1771 {
1772 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
1773 return false;
1774 }
1775 else
1776 {
1777 outputTriplet(visit, "(", " && ", ")");
1778 return true;
1779 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001780 default: UNREACHABLE();
1781 }
1782
1783 return true;
1784}
1785
1786bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1787{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001788 switch (node->getOp())
1789 {
Nicolas Capens16004fc2014-06-11 11:29:11 -04001790 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
1791 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1792 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1793 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1794 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1795 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1796 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001797 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1798 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1799 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1800 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1801 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1802 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1803 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1804 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
1805 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1806 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1807 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1808 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1809 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1810 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1811 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1812 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1813 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
1814 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1815 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
1816 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1817 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001818 case EOpDFdx:
1819 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1820 {
1821 outputTriplet(visit, "(", "", ", 0.0)");
1822 }
1823 else
1824 {
1825 outputTriplet(visit, "ddx(", "", ")");
1826 }
1827 break;
1828 case EOpDFdy:
1829 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1830 {
1831 outputTriplet(visit, "(", "", ", 0.0)");
1832 }
1833 else
1834 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001835 outputTriplet(visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001836 }
1837 break;
1838 case EOpFwidth:
1839 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1840 {
1841 outputTriplet(visit, "(", "", ", 0.0)");
1842 }
1843 else
1844 {
1845 outputTriplet(visit, "fwidth(", "", ")");
1846 }
1847 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001848 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1849 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001850 default: UNREACHABLE();
1851 }
1852
1853 return true;
1854}
1855
1856bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1857{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001858 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001860 switch (node->getOp())
1861 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001862 case EOpSequence:
1863 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001864 if (mInsideFunction)
1865 {
Jamie Madill075edd82013-07-08 13:30:19 -04001866 outputLineDirective(node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001867 out << "{\n";
1868 }
1869
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001870 for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001871 {
Jamie Madill075edd82013-07-08 13:30:19 -04001872 outputLineDirective((*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001873
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001874 traverseStatements(*sit);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001875
1876 out << ";\n";
1877 }
1878
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001879 if (mInsideFunction)
1880 {
Jamie Madill075edd82013-07-08 13:30:19 -04001881 outputLineDirective(node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001882 out << "}\n";
1883 }
1884
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001885 return false;
1886 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001887 case EOpDeclaration:
1888 if (visit == PreVisit)
1889 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001890 TIntermSequence *sequence = node->getSequence();
1891 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001892
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001893 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001894 {
Jamie Madill8daaba12014-06-13 10:04:33 -04001895 TStructure *structure = variable->getType().getStruct();
1896
1897 if (structure)
daniel@transgaming.comead23042010-04-29 03:35:36 +00001898 {
Jamie Madill8daaba12014-06-13 10:04:33 -04001899 mStructureHLSL->addConstructor(variable->getType(), StructNameString(*structure), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001900 }
1901
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001902 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001903 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001904 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001905 {
1906 out << "static ";
1907 }
1908
Jamie Madill033dae62014-06-18 12:56:28 -04001909 out << TypeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001910
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001911 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001912 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001913 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001914
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001915 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001916 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001917 symbol->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04001918 out << ArrayString(symbol->getType());
Jamie Madill79bb0d92013-12-09 16:20:28 -05001919 out << " = " + initializer(symbol->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001920 }
1921 else
1922 {
1923 (*sit)->traverse(this);
1924 }
1925
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001926 if (*sit != sequence->back())
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001927 {
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00001928 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001929 }
1930 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001931 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001932 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1933 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001934 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001935 }
1936 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001937 }
Jamie Madill033dae62014-06-18 12:56:28 -04001938 else if (variable && IsVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00001939 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001940 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00001941 {
1942 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1943
1944 if (symbol)
1945 {
1946 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
1947 mReferencedVaryings[symbol->getSymbol()] = symbol;
1948 }
1949 else
1950 {
1951 (*sit)->traverse(this);
1952 }
1953 }
1954 }
1955
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001956 return false;
1957 }
1958 else if (visit == InVisit)
1959 {
1960 out << ", ";
1961 }
1962 break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001963 case EOpInvariantDeclaration:
1964 // Do not do any translation
1965 return false;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001966 case EOpPrototype:
1967 if (visit == PreVisit)
1968 {
Jamie Madill033dae62014-06-18 12:56:28 -04001969 out << TypeString(node->getType()) << " " << Decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001970
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001971 TIntermSequence *arguments = node->getSequence();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001972
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001973 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001974 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001975 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001976
1977 if (symbol)
1978 {
1979 out << argumentString(symbol);
1980
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001981 if (i < arguments->size() - 1)
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001982 {
1983 out << ", ";
1984 }
1985 }
1986 else UNREACHABLE();
1987 }
1988
1989 out << ");\n";
1990
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00001991 // Also prototype the Lod0 variant if needed
1992 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
1993 {
1994 mOutputLod0Function = true;
1995 node->traverse(this);
1996 mOutputLod0Function = false;
1997 }
1998
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001999 return false;
2000 }
2001 break;
daniel@transgaming.comed2180d2012-03-26 17:08:54 +00002002 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002003 case EOpFunction:
2004 {
alokp@chromium.org43884872010-03-30 00:08:52 +00002005 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002006
Jamie Madill033dae62014-06-18 12:56:28 -04002007 out << TypeString(node->getType()) << " ";
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002008
2009 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002010 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002011 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002012 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002013 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002014 {
Jamie Madill033dae62014-06-18 12:56:28 -04002015 out << Decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002016 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002017
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002018 TIntermSequence *sequence = node->getSequence();
2019 TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002020
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002021 for (unsigned int i = 0; i < arguments->size(); i++)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002022 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002023 TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002024
2025 if (symbol)
2026 {
Jamie Madill8daaba12014-06-13 10:04:33 -04002027 TStructure *structure = symbol->getType().getStruct();
2028
2029 if (structure)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002030 {
Jamie Madill8daaba12014-06-13 10:04:33 -04002031 mStructureHLSL->addConstructor(symbol->getType(), StructNameString(*structure), NULL);
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002032 }
2033
2034 out << argumentString(symbol);
2035
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002036 if (i < arguments->size() - 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002037 {
2038 out << ", ";
2039 }
2040 }
2041 else UNREACHABLE();
2042 }
2043
2044 out << ")\n"
2045 "{\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002046
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002047 if (sequence->size() > 1)
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002048 {
2049 mInsideFunction = true;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002050 (*sequence)[1]->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002051 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002052 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002053
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002054 out << "}\n";
2055
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002056 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
2057 {
daniel@transgaming.comecdf44a2012-06-01 01:45:15 +00002058 if (name != "main")
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002059 {
2060 mOutputLod0Function = true;
2061 node->traverse(this);
2062 mOutputLod0Function = false;
2063 }
2064 }
2065
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002066 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002067 }
2068 break;
2069 case EOpFunctionCall:
2070 {
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002071 TString name = TFunction::unmangleName(node->getName());
2072 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002073 TIntermSequence *arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002074
2075 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002076 {
Jamie Madill033dae62014-06-18 12:56:28 -04002077 out << Decorate(name) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002078 }
2079 else
2080 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002081 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002082
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002083 TextureFunction textureFunction;
2084 textureFunction.sampler = samplerType;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002085 textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002086 textureFunction.method = TextureFunction::IMPLICIT;
2087 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002088 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002089
2090 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002091 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002092 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002093 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002094 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002095 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002096 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002097 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002098 }
Nicolas Capens46485082014-04-15 13:12:50 -04002099 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
2100 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002101 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002102 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002103 }
Nicolas Capens46485082014-04-15 13:12:50 -04002104 else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002105 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002106 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002107 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002108 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002109 else if (name == "textureSize")
2110 {
2111 textureFunction.method = TextureFunction::SIZE;
2112 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002113 else if (name == "textureOffset")
2114 {
2115 textureFunction.method = TextureFunction::IMPLICIT;
2116 textureFunction.offset = true;
2117 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002118 else if (name == "textureProjOffset")
2119 {
2120 textureFunction.method = TextureFunction::IMPLICIT;
2121 textureFunction.offset = true;
2122 textureFunction.proj = true;
2123 }
2124 else if (name == "textureLodOffset")
2125 {
2126 textureFunction.method = TextureFunction::LOD;
2127 textureFunction.offset = true;
2128 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002129 else if (name == "textureProjLodOffset")
2130 {
2131 textureFunction.method = TextureFunction::LOD;
2132 textureFunction.proj = true;
2133 textureFunction.offset = true;
2134 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002135 else if (name == "texelFetch")
2136 {
2137 textureFunction.method = TextureFunction::FETCH;
2138 }
2139 else if (name == "texelFetchOffset")
2140 {
2141 textureFunction.method = TextureFunction::FETCH;
2142 textureFunction.offset = true;
2143 }
Nicolas Capens46485082014-04-15 13:12:50 -04002144 else if (name == "textureGrad" || name == "texture2DGradEXT")
Nicolas Capensd11d5492014-02-19 17:06:10 -05002145 {
2146 textureFunction.method = TextureFunction::GRAD;
2147 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002148 else if (name == "textureGradOffset")
2149 {
2150 textureFunction.method = TextureFunction::GRAD;
2151 textureFunction.offset = true;
2152 }
Nicolas Capens46485082014-04-15 13:12:50 -04002153 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
Nicolas Capensf7378e32014-02-19 17:29:32 -05002154 {
2155 textureFunction.method = TextureFunction::GRAD;
2156 textureFunction.proj = true;
2157 }
2158 else if (name == "textureProjGradOffset")
2159 {
2160 textureFunction.method = TextureFunction::GRAD;
2161 textureFunction.proj = true;
2162 textureFunction.offset = true;
2163 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002164 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002165
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002166 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002167 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002168 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2169
2170 if (textureFunction.offset)
2171 {
2172 mandatoryArgumentCount++;
2173 }
2174
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002175 bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional
Nicolas Capens84cfa122014-04-14 13:48:45 -04002176
Jamie Madill183bde52014-07-02 15:31:19 -04002177 if (lod0 || mContext.shaderType == GL_VERTEX_SHADER)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002178 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002179 if (bias)
2180 {
2181 textureFunction.method = TextureFunction::LOD0BIAS;
2182 }
2183 else
2184 {
2185 textureFunction.method = TextureFunction::LOD0;
2186 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002187 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002188 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002189 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002190 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002191 }
2192 }
2193
2194 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002195
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002196 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002197 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002198
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002199 for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002200 {
2201 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2202 {
2203 out << "texture_";
2204 (*arg)->traverse(this);
2205 out << ", sampler_";
2206 }
2207
2208 (*arg)->traverse(this);
2209
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002210 if (arg < arguments->end() - 1)
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002211 {
2212 out << ", ";
2213 }
2214 }
2215
2216 out << ")";
2217
2218 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 }
2220 break;
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002221 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002222 case EOpConstructFloat: outputConstructor(visit, node->getType(), "vec1", node->getSequence()); break;
2223 case EOpConstructVec2: outputConstructor(visit, node->getType(), "vec2", node->getSequence()); break;
2224 case EOpConstructVec3: outputConstructor(visit, node->getType(), "vec3", node->getSequence()); break;
2225 case EOpConstructVec4: outputConstructor(visit, node->getType(), "vec4", node->getSequence()); break;
2226 case EOpConstructBool: outputConstructor(visit, node->getType(), "bvec1", node->getSequence()); break;
2227 case EOpConstructBVec2: outputConstructor(visit, node->getType(), "bvec2", node->getSequence()); break;
2228 case EOpConstructBVec3: outputConstructor(visit, node->getType(), "bvec3", node->getSequence()); break;
2229 case EOpConstructBVec4: outputConstructor(visit, node->getType(), "bvec4", node->getSequence()); break;
2230 case EOpConstructInt: outputConstructor(visit, node->getType(), "ivec1", node->getSequence()); break;
2231 case EOpConstructIVec2: outputConstructor(visit, node->getType(), "ivec2", node->getSequence()); break;
2232 case EOpConstructIVec3: outputConstructor(visit, node->getType(), "ivec3", node->getSequence()); break;
2233 case EOpConstructIVec4: outputConstructor(visit, node->getType(), "ivec4", node->getSequence()); break;
2234 case EOpConstructUInt: outputConstructor(visit, node->getType(), "uvec1", node->getSequence()); break;
2235 case EOpConstructUVec2: outputConstructor(visit, node->getType(), "uvec2", node->getSequence()); break;
2236 case EOpConstructUVec3: outputConstructor(visit, node->getType(), "uvec3", node->getSequence()); break;
2237 case EOpConstructUVec4: outputConstructor(visit, node->getType(), "uvec4", node->getSequence()); break;
2238 case EOpConstructMat2: outputConstructor(visit, node->getType(), "mat2", node->getSequence()); break;
2239 case EOpConstructMat3: outputConstructor(visit, node->getType(), "mat3", node->getSequence()); break;
2240 case EOpConstructMat4: outputConstructor(visit, node->getType(), "mat4", node->getSequence()); break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002241 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04002242 {
Jamie Madill033dae62014-06-18 12:56:28 -04002243 const TString &structName = StructNameString(*node->getType().getStruct());
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002244 mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
Jamie Madillbfa91f42014-06-05 15:45:18 -04002245 outputTriplet(visit, structName + "_ctor(", ", ", ")");
2246 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002247 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002248 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2249 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2250 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2251 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2252 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
2253 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002254 case EOpMod:
2255 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002256 // We need to look at the number of components in both arguments
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002257 const int modValue = (*node->getSequence())[0]->getAsTyped()->getNominalSize() * 10 +
2258 (*node->getSequence())[1]->getAsTyped()->getNominalSize();
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002259 switch (modValue)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002260 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002261 case 11: mUsesMod1 = true; break;
2262 case 22: mUsesMod2v = true; break;
2263 case 21: mUsesMod2f = true; break;
2264 case 33: mUsesMod3v = true; break;
2265 case 31: mUsesMod3f = true; break;
2266 case 44: mUsesMod4v = true; break;
2267 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002268 default: UNREACHABLE();
2269 }
2270
2271 outputTriplet(visit, "mod(", ", ", ")");
2272 }
2273 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002274 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002275 case EOpAtan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002276 ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
2277 switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize())
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00002278 {
2279 case 1: mUsesAtan2_1 = true; break;
2280 case 2: mUsesAtan2_2 = true; break;
2281 case 3: mUsesAtan2_3 = true; break;
2282 case 4: mUsesAtan2_4 = true; break;
2283 default: UNREACHABLE();
2284 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +00002285 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002286 break;
2287 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
2288 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
2289 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
2290 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
2291 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
2292 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
2293 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
2294 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
2295 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002296 case EOpFaceForward:
2297 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002298 switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002299 {
2300 case 1: mUsesFaceforward1 = true; break;
2301 case 2: mUsesFaceforward2 = true; break;
2302 case 3: mUsesFaceforward3 = true; break;
2303 case 4: mUsesFaceforward4 = true; break;
2304 default: UNREACHABLE();
2305 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002306
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002307 outputTriplet(visit, "faceforward(", ", ", ")");
2308 }
2309 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002310 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
2311 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
2312 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002313 default: UNREACHABLE();
2314 }
2315
2316 return true;
2317}
2318
2319bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2320{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002321 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002322
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002323 if (node->usesTernaryOperator())
2324 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002325 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002326 }
2327 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002328 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002329 mUnfoldShortCircuit->traverse(node->getCondition());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002330
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002331 out << "if (";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002332
2333 node->getCondition()->traverse(this);
2334
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002335 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002336
Jamie Madill075edd82013-07-08 13:30:19 -04002337 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002338 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002339
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002340 bool discard = false;
2341
daniel@transgaming.combb885322010-04-15 20:45:24 +00002342 if (node->getTrueBlock())
2343 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002344 traverseStatements(node->getTrueBlock());
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002345
2346 // Detect true discard
2347 discard = (discard || FindDiscard::search(node->getTrueBlock()));
daniel@transgaming.combb885322010-04-15 20:45:24 +00002348 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002349
Jamie Madill075edd82013-07-08 13:30:19 -04002350 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002351 out << ";\n}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002352
2353 if (node->getFalseBlock())
2354 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002355 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002356
Jamie Madill075edd82013-07-08 13:30:19 -04002357 outputLineDirective(node->getFalseBlock()->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002358 out << "{\n";
2359
Jamie Madill075edd82013-07-08 13:30:19 -04002360 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002361 traverseStatements(node->getFalseBlock());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002362
Jamie Madill075edd82013-07-08 13:30:19 -04002363 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002364 out << ";\n}\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002365
2366 // Detect false discard
2367 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2368 }
2369
2370 // ANGLE issue 486: Detect problematic conditional discard
2371 if (discard && FindSideEffectRewriting::search(node))
2372 {
2373 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002374 }
2375 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002376
2377 return false;
2378}
2379
2380void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2381{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002382 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002383}
2384
2385bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2386{
Nicolas Capens655fe362014-04-11 13:12:34 -04002387 mNestedLoopDepth++;
2388
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002389 bool wasDiscontinuous = mInsideDiscontinuousLoop;
2390
shannon.woods@transgaming.come91615c2013-01-25 21:56:03 +00002391 if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002392 {
2393 mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
2394 }
2395
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002396 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002397 {
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002398 if (handleExcessiveLoop(node))
2399 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002400 mInsideDiscontinuousLoop = wasDiscontinuous;
2401 mNestedLoopDepth--;
2402
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002403 return false;
2404 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002405 }
2406
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002407 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002408
alokp@chromium.org52813552010-11-16 18:36:09 +00002409 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002410 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002411 out << "{do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002412
Jamie Madill075edd82013-07-08 13:30:19 -04002413 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002414 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002415 }
2416 else
2417 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002418 out << "{for(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002419
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002420 if (node->getInit())
2421 {
2422 node->getInit()->traverse(this);
2423 }
2424
2425 out << "; ";
2426
alokp@chromium.org52813552010-11-16 18:36:09 +00002427 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002429 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002430 }
2431
2432 out << "; ";
2433
alokp@chromium.org52813552010-11-16 18:36:09 +00002434 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002435 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002436 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002437 }
2438
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002439 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002440
Jamie Madill075edd82013-07-08 13:30:19 -04002441 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002442 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002443 }
2444
2445 if (node->getBody())
2446 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002447 traverseStatements(node->getBody());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002448 }
2449
Jamie Madill075edd82013-07-08 13:30:19 -04002450 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00002451 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002452
alokp@chromium.org52813552010-11-16 18:36:09 +00002453 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002454 {
Jamie Madill075edd82013-07-08 13:30:19 -04002455 outputLineDirective(node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002456 out << "while(\n";
2457
alokp@chromium.org52813552010-11-16 18:36:09 +00002458 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002459
daniel@transgaming.com73536982012-03-21 20:45:49 +00002460 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002461 }
2462
daniel@transgaming.com73536982012-03-21 20:45:49 +00002463 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002464
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002465 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002466 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002467
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002468 return false;
2469}
2470
2471bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2472{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002473 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002474
2475 switch (node->getFlowOp())
2476 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002477 case EOpKill:
2478 outputTriplet(visit, "discard;\n", "", "");
2479 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002480 case EOpBreak:
2481 if (visit == PreVisit)
2482 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002483 if (mNestedLoopDepth > 1)
2484 {
2485 mUsesNestedBreak = true;
2486 }
2487
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002488 if (mExcessiveLoopIndex)
2489 {
2490 out << "{Break";
2491 mExcessiveLoopIndex->traverse(this);
2492 out << " = true; break;}\n";
2493 }
2494 else
2495 {
2496 out << "break;\n";
2497 }
2498 }
2499 break;
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00002500 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002501 case EOpReturn:
2502 if (visit == PreVisit)
2503 {
2504 if (node->getExpression())
2505 {
2506 out << "return ";
2507 }
2508 else
2509 {
2510 out << "return;\n";
2511 }
2512 }
2513 else if (visit == PostVisit)
2514 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002515 if (node->getExpression())
2516 {
2517 out << ";\n";
2518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002519 }
2520 break;
2521 default: UNREACHABLE();
2522 }
2523
2524 return true;
2525}
2526
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002527void OutputHLSL::traverseStatements(TIntermNode *node)
2528{
2529 if (isSingleStatement(node))
2530 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002531 mUnfoldShortCircuit->traverse(node);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002532 }
2533
2534 node->traverse(this);
2535}
2536
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002537bool OutputHLSL::isSingleStatement(TIntermNode *node)
2538{
2539 TIntermAggregate *aggregate = node->getAsAggregate();
2540
2541 if (aggregate)
2542 {
2543 if (aggregate->getOp() == EOpSequence)
2544 {
2545 return false;
2546 }
2547 else
2548 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002549 for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++)
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002550 {
2551 if (!isSingleStatement(*sit))
2552 {
2553 return false;
2554 }
2555 }
2556
2557 return true;
2558 }
2559 }
2560
2561 return true;
2562}
2563
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002564// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2565// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002566bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
2567{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002568 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002569 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002570
2571 // Parse loops of the form:
2572 // for(int index = initial; index [comparator] limit; index += increment)
2573 TIntermSymbol *index = NULL;
2574 TOperator comparator = EOpNull;
2575 int initial = 0;
2576 int limit = 0;
2577 int increment = 0;
2578
2579 // Parse index name and intial value
2580 if (node->getInit())
2581 {
2582 TIntermAggregate *init = node->getInit()->getAsAggregate();
2583
2584 if (init)
2585 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002586 TIntermSequence *sequence = init->getSequence();
2587 TIntermTyped *variable = (*sequence)[0]->getAsTyped();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002588
2589 if (variable && variable->getQualifier() == EvqTemporary)
2590 {
2591 TIntermBinary *assign = variable->getAsBinaryNode();
2592
2593 if (assign->getOp() == EOpInitialize)
2594 {
2595 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2596 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2597
2598 if (symbol && constant)
2599 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002600 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002601 {
2602 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002603 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002604 }
2605 }
2606 }
2607 }
2608 }
2609 }
2610
2611 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002612 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002613 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002614 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002615
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002616 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2617 {
2618 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2619
2620 if (constant)
2621 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002622 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002623 {
2624 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002625 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002626 }
2627 }
2628 }
2629 }
2630
2631 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002632 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002633 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002634 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2635 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
Jamie Madillf91ce812014-06-13 10:04:34 -04002636
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002637 if (binaryTerminal)
2638 {
2639 TOperator op = binaryTerminal->getOp();
2640 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2641
2642 if (constant)
2643 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002644 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002645 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002646 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002647
2648 switch (op)
2649 {
2650 case EOpAddAssign: increment = value; break;
2651 case EOpSubAssign: increment = -value; break;
2652 default: UNIMPLEMENTED();
2653 }
2654 }
2655 }
2656 }
2657 else if (unaryTerminal)
2658 {
2659 TOperator op = unaryTerminal->getOp();
2660
2661 switch (op)
2662 {
2663 case EOpPostIncrement: increment = 1; break;
2664 case EOpPostDecrement: increment = -1; break;
2665 case EOpPreIncrement: increment = 1; break;
2666 case EOpPreDecrement: increment = -1; break;
2667 default: UNIMPLEMENTED();
2668 }
2669 }
2670 }
2671
2672 if (index != NULL && comparator != EOpNull && increment != 0)
2673 {
2674 if (comparator == EOpLessThanEqual)
2675 {
2676 comparator = EOpLessThan;
2677 limit += 1;
2678 }
2679
2680 if (comparator == EOpLessThan)
2681 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00002682 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002683
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002684 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002685 {
2686 return false; // Not an excessive loop
2687 }
2688
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002689 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
2690 mExcessiveLoopIndex = index;
2691
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002692 out << "{int ";
2693 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002694 out << ";\n"
2695 "bool Break";
2696 index->traverse(this);
2697 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002698
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002699 bool firstLoopFragment = true;
2700
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002701 while (iterations > 0)
2702 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002703 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002704
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002705 if (!firstLoopFragment)
2706 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002707 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002708 index->traverse(this);
2709 out << ") {\n";
2710 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002711
2712 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
2713 {
2714 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
2715 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002716
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002717 // for(int index = initial; index < clampedLimit; index += increment)
2718
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002719 out << "for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002720 index->traverse(this);
2721 out << " = ";
2722 out << initial;
2723
2724 out << "; ";
2725 index->traverse(this);
2726 out << " < ";
2727 out << clampedLimit;
2728
2729 out << "; ";
2730 index->traverse(this);
2731 out << " += ";
2732 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002733 out << ")\n";
Jamie Madillf91ce812014-06-13 10:04:34 -04002734
Jamie Madill075edd82013-07-08 13:30:19 -04002735 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002736 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002737
2738 if (node->getBody())
2739 {
2740 node->getBody()->traverse(this);
2741 }
2742
Jamie Madill075edd82013-07-08 13:30:19 -04002743 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002744 out << ";}\n";
2745
2746 if (!firstLoopFragment)
2747 {
2748 out << "}\n";
2749 }
2750
2751 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002752
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002753 initial += MAX_LOOP_ITERATIONS * increment;
2754 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002755 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002756
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002757 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002758
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002759 mExcessiveLoopIndex = restoreIndex;
2760
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002761 return true;
2762 }
2763 else UNIMPLEMENTED();
2764 }
2765
2766 return false; // Not handled as an excessive loop
2767}
2768
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002769void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002770{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002771 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002772
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002773 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002774 {
2775 out << preString;
2776 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002777 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002778 {
2779 out << inString;
2780 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002781 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002782 {
2783 out << postString;
2784 }
2785}
2786
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002787void OutputHLSL::outputLineDirective(int line)
2788{
2789 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
2790 {
baustin@google.com8ab69842011-06-02 21:53:45 +00002791 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002792 mBody << "#line " << line;
2793
2794 if (mContext.sourcePath)
2795 {
2796 mBody << " \"" << mContext.sourcePath << "\"";
2797 }
Jamie Madillf91ce812014-06-13 10:04:34 -04002798
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002799 mBody << "\n";
2800 }
2801}
2802
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002803TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2804{
2805 TQualifier qualifier = symbol->getQualifier();
2806 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002807 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002808
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002809 if (name.empty()) // HLSL demands named arguments, also for prototypes
2810 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00002811 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002812 }
2813 else
2814 {
Jamie Madill033dae62014-06-18 12:56:28 -04002815 name = Decorate(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002816 }
2817
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002818 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
2819 {
Jamie Madill033dae62014-06-18 12:56:28 -04002820 return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + name + ArrayString(type) + ", " +
Jamie Madillf91ce812014-06-13 10:04:34 -04002821 QualifierString(qualifier) + " " + SamplerString(type) + " sampler_" + name + ArrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002822 }
2823
Jamie Madill033dae62014-06-18 12:56:28 -04002824 return QualifierString(qualifier) + " " + TypeString(type) + " " + name + ArrayString(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002825}
2826
2827TString OutputHLSL::initializer(const TType &type)
2828{
2829 TString string;
2830
Jamie Madill94bf7f22013-07-08 13:31:15 -04002831 size_t size = type.getObjectSize();
2832 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002833 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002834 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002835
Jamie Madill94bf7f22013-07-08 13:31:15 -04002836 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002837 {
2838 string += ", ";
2839 }
2840 }
2841
daniel@transgaming.comead23042010-04-29 03:35:36 +00002842 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002843}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002844
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002845void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters)
2846{
2847 TInfoSinkBase &out = mBody;
2848
2849 if (visit == PreVisit)
2850 {
Jamie Madill8daaba12014-06-13 10:04:33 -04002851 mStructureHLSL->addConstructor(type, name, parameters);
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002852
2853 out << name + "(";
2854 }
2855 else if (visit == InVisit)
2856 {
2857 out << ", ";
2858 }
2859 else if (visit == PostVisit)
2860 {
2861 out << ")";
2862 }
2863}
2864
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002865const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2866{
2867 TInfoSinkBase &out = mBody;
2868
Jamie Madill98493dd2013-07-08 14:39:03 -04002869 const TStructure* structure = type.getStruct();
2870 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002871 {
Jamie Madill033dae62014-06-18 12:56:28 -04002872 out << StructNameString(*structure) + "_ctor(";
Jamie Madillf91ce812014-06-13 10:04:34 -04002873
Jamie Madill98493dd2013-07-08 14:39:03 -04002874 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002875
Jamie Madill98493dd2013-07-08 14:39:03 -04002876 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002877 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002878 const TType *fieldType = fields[i]->type();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002879 constUnion = writeConstantUnion(*fieldType, constUnion);
2880
Jamie Madill98493dd2013-07-08 14:39:03 -04002881 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002882 {
2883 out << ", ";
2884 }
2885 }
2886
2887 out << ")";
2888 }
2889 else
2890 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04002891 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002892 bool writeType = size > 1;
Jamie Madillf91ce812014-06-13 10:04:34 -04002893
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002894 if (writeType)
2895 {
Jamie Madill033dae62014-06-18 12:56:28 -04002896 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002897 }
2898
Jamie Madill94bf7f22013-07-08 13:31:15 -04002899 for (size_t i = 0; i < size; i++, constUnion++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002900 {
2901 switch (constUnion->getType())
2902 {
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +00002903 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002904 case EbtInt: out << constUnion->getIConst(); break;
Nicolas Capensc0f7c612013-06-05 11:46:09 -04002905 case EbtUInt: out << constUnion->getUConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002906 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002907 default: UNREACHABLE();
2908 }
2909
2910 if (i != size - 1)
2911 {
2912 out << ", ";
2913 }
2914 }
2915
2916 if (writeType)
2917 {
2918 out << ")";
2919 }
2920 }
2921
2922 return constUnion;
2923}
2924
Jamie Madill77f74852014-07-08 15:02:34 -04002925void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier,
2926 const TString &name, std::vector<Varying> &fieldsOut)
2927{
Jamie Madill42bcf322014-08-25 16:20:46 -04002928 GetVariableTraverser traverser;
2929 traverser.traverse(type, name, &fieldsOut);
2930 fieldsOut.back().interpolation = GetInterpolationType(baseTypeQualifier);
Jamie Madill47fdd132013-08-30 13:21:04 -04002931}
2932
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002933}