blob: 2e88b52f501d2f64fca1f2ced84ca2ff7348f235 [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"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000023#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000024#include <cfloat>
25#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000026
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027namespace sh
28{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000029
Jamie Madill033dae62014-06-18 12:56:28 -040030class Std140PaddingHelper
Jamie Madill3891fd22014-06-13 10:04:30 -040031{
32 public:
33 explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes)
34 : mPaddingCounter(0),
35 mElementIndex(0),
36 mStructElementIndexes(structElementIndexes)
37 {}
38
39 int elementIndex() const { return mElementIndex; }
40
41 int prePadding(const TType &type)
42 {
43 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
44 {
45 // no padding needed, HLSL will align the field to a new register
46 mElementIndex = 0;
47 return 0;
48 }
49
Jamie Madill033dae62014-06-18 12:56:28 -040050 const GLenum glType = GLVariableType(type);
Jamie Madill3891fd22014-06-13 10:04:30 -040051 const int numComponents = gl::UniformComponentCount(glType);
52
53 if (numComponents >= 4)
54 {
55 // no padding needed, HLSL will align the field to a new register
56 mElementIndex = 0;
57 return 0;
58 }
59
60 if (mElementIndex + numComponents > 4)
61 {
62 // no padding needed, HLSL will align the field to a new register
63 mElementIndex = numComponents;
64 return 0;
65 }
66
67 const int alignment = numComponents == 3 ? 4 : numComponents;
68 const int paddingOffset = (mElementIndex % alignment);
69 const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
70
71 mElementIndex += paddingCount;
72 mElementIndex += numComponents;
73 mElementIndex %= 4;
74
75 return paddingCount;
76 }
77
78 TString prePaddingString(const TType &type)
79 {
80 int paddingCount = prePadding(type);
81
82 TString padding;
83
84 for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
85 {
86 padding += " float pad_" + str(mPaddingCounter++) + ";\n";
87 }
88
89 return padding;
90 }
91
92 TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
93 {
94 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
95 {
96 return "";
97 }
98
99 int numComponents = 0;
100
101 if (type.isMatrix())
102 {
103 // This method can also be called from structureString, which does not use layout qualifiers.
104 // Thus, use the method parameter for determining the matrix packing.
105 //
106 // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
107 // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
108 //
109 const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
Jamie Madill033dae62014-06-18 12:56:28 -0400110 const GLenum glType = GLVariableType(type);
Jamie Madill3891fd22014-06-13 10:04:30 -0400111 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
112 }
113 else if (type.getStruct())
114 {
Jamie Madill033dae62014-06-18 12:56:28 -0400115 const TString &structName = QualifiedStructNameString(*type.getStruct(), useHLSLRowMajorPacking, true);
Jamie Madill3891fd22014-06-13 10:04:30 -0400116 numComponents = mStructElementIndexes.find(structName)->second;
117
118 if (numComponents == 0)
119 {
120 return "";
121 }
122 }
123 else
124 {
Jamie Madill033dae62014-06-18 12:56:28 -0400125 const GLenum glType = GLVariableType(type);
Jamie Madill3891fd22014-06-13 10:04:30 -0400126 numComponents = gl::UniformComponentCount(glType);
127 }
128
129 TString padding;
130 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
131 {
132 padding += " float pad_" + str(mPaddingCounter++) + ";\n";
133 }
134 return padding;
135 }
136
137 private:
138 int mPaddingCounter;
139 int mElementIndex;
140 const std::map<TString, int> &mStructElementIndexes;
141};
142
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400143TString OutputHLSL::TextureFunction::name() const
144{
145 TString name = "gl_texture";
146
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400147 if (IsSampler2D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400148 {
149 name += "2D";
150 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400151 else if (IsSampler3D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400152 {
153 name += "3D";
154 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -0400155 else if (IsSamplerCube(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400156 {
157 name += "Cube";
158 }
159 else UNREACHABLE();
160
161 if (proj)
162 {
163 name += "Proj";
164 }
165
Nicolas Capensb1f45b72013-12-19 17:37:19 -0500166 if (offset)
167 {
168 name += "Offset";
169 }
170
Nicolas Capens75fb4752013-07-10 15:14:47 -0400171 switch(method)
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400172 {
Nicolas Capensfc014542014-02-18 14:47:13 -0500173 case IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400174 case BIAS: break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -0500175 case LOD: name += "Lod"; break;
176 case LOD0: name += "Lod0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400177 case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -0500178 case SIZE: name += "Size"; break;
179 case FETCH: name += "Fetch"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -0500180 case GRAD: name += "Grad"; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400181 default: UNREACHABLE();
182 }
183
184 return name + "(";
185}
186
Jamie Madillc2141fb2013-08-30 13:21:08 -0400187const char *RegisterPrefix(const TType &type)
188{
189 if (IsSampler(type.getBasicType()))
190 {
191 return "s";
192 }
193 else
194 {
195 return "c";
196 }
197}
198
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400199bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
200{
201 if (sampler < rhs.sampler) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400202 if (sampler > rhs.sampler) return false;
203
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400204 if (coords < rhs.coords) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400205 if (coords > rhs.coords) return false;
206
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400207 if (!proj && rhs.proj) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400208 if (proj && !rhs.proj) return false;
209
210 if (!offset && rhs.offset) return true;
211 if (offset && !rhs.offset) return false;
212
Nicolas Capens75fb4752013-07-10 15:14:47 -0400213 if (method < rhs.method) return true;
Nicolas Capens04296f82014-04-14 14:24:38 -0400214 if (method > rhs.method) return false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400215
216 return false;
217}
218
shannon.woods%transgaming.com@gtempaccount.com18b4c4b2013-04-13 03:31:40 +0000219OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000220 : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +0000222 mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000223 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000224
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000225 mUsesFragColor = false;
226 mUsesFragData = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000227 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000228 mUsesFragCoord = false;
229 mUsesPointCoord = false;
230 mUsesFrontFacing = false;
231 mUsesPointSize = false;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400232 mUsesFragDepth = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000233 mUsesXor = false;
234 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000235 mUsesMod2v = false;
236 mUsesMod2f = false;
237 mUsesMod3v = false;
238 mUsesMod3f = false;
239 mUsesMod4v = false;
240 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000241 mUsesFaceforward1 = false;
242 mUsesFaceforward2 = false;
243 mUsesFaceforward3 = false;
244 mUsesFaceforward4 = false;
daniel@transgaming.com35342dc2012-02-28 02:01:22 +0000245 mUsesAtan2_1 = false;
246 mUsesAtan2_2 = false;
247 mUsesAtan2_3 = false;
248 mUsesAtan2_4 = false;
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500249 mUsesDiscardRewriting = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400250 mUsesNestedBreak = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000251
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000252 mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
253
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000254 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000255
256 mContainsLoopDiscontinuity = false;
257 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000258 mInsideDiscontinuousLoop = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400259 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000260
261 mExcessiveLoopIndex = NULL;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000262
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000263 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000264 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000265 if (mContext.shaderType == SH_FRAGMENT_SHADER)
266 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000267 mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000268 }
269 else
270 {
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +0000271 mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000272 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000273 }
274 else
275 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000276 mUniformRegister = 0;
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000277 }
278
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000279 mSamplerRegister = 0;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000280 mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281}
282
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000283OutputHLSL::~OutputHLSL()
284{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +0000285 delete mUnfoldShortCircuit;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000286}
287
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000288void OutputHLSL::output()
289{
shannon.woods@transgaming.come91615c2013-01-25 21:56:03 +0000290 mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400291 const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
292 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000293
Jamie Madille53c98b2014-02-03 11:57:13 -0500294 // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
295 // use a vertex attribute as a condition, and some related computation in the else block.
296 if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER)
297 {
298 RewriteElseBlocks(mContext.treeRoot);
299 }
300
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000301 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 +0000302 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000303
alokp@chromium.org646ea1e2012-06-15 17:36:31 +0000304 mContext.infoSink().obj << mHeader.c_str();
305 mContext.infoSink().obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000306}
307
Jamie Madill570e04d2013-06-21 09:15:33 -0400308void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
309{
310 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
311 {
312 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
313
314 // This will mark the necessary block elements as referenced
315 flaggedNode->traverse(this);
316 TString structName(mBody.c_str());
317 mBody.erase();
318
319 mFlaggedStructOriginalNames[flaggedNode] = structName;
320
321 for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
322 {
323 structName.erase(pos, 1);
324 }
325
326 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
327 }
328}
329
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000330TInfoSinkBase &OutputHLSL::getBodyStream()
331{
332 return mBody;
333}
334
Jamie Madill834e8b72014-04-11 13:33:58 -0400335const std::vector<gl::Uniform> &OutputHLSL::getUniforms()
daniel@transgaming.com043da132012-12-20 21:12:22 +0000336{
337 return mActiveUniforms;
338}
339
Jamie Madill834e8b72014-04-11 13:33:58 -0400340const std::vector<gl::InterfaceBlock> &OutputHLSL::getInterfaceBlocks() const
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000341{
342 return mActiveInterfaceBlocks;
343}
344
Jamie Madill834e8b72014-04-11 13:33:58 -0400345const std::vector<gl::Attribute> &OutputHLSL::getOutputVariables() const
Jamie Madill46131a32013-06-20 11:55:50 -0400346{
347 return mActiveOutputVariables;
348}
349
Jamie Madill834e8b72014-04-11 13:33:58 -0400350const std::vector<gl::Attribute> &OutputHLSL::getAttributes() const
Jamie Madilldefb6742013-06-20 11:55:51 -0400351{
352 return mActiveAttributes;
353}
354
Jamie Madill834e8b72014-04-11 13:33:58 -0400355const std::vector<gl::Varying> &OutputHLSL::getVaryings() const
Jamie Madill47fdd132013-08-30 13:21:04 -0400356{
357 return mActiveVaryings;
358}
359
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000360int OutputHLSL::vectorSize(const TType &type) const
361{
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000362 int elementSize = type.isMatrix() ? type.getCols() : 1;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000363 int arraySize = type.isArray() ? type.getArraySize() : 1;
364
365 return elementSize * arraySize;
366}
367
Jamie Madill98493dd2013-07-08 14:39:03 -0400368TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field)
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000369{
Jamie Madill98493dd2013-07-08 14:39:03 -0400370 if (interfaceBlock.hasInstanceName())
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000371 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400372 return interfaceBlock.name() + "." + field.name();
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000373 }
374 else
375 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400376 return field.name();
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000377 }
378}
379
Jamie Madill98493dd2013-07-08 14:39:03 -0400380TString OutputHLSL::interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlock)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000381{
Jamie Madill033dae62014-06-18 12:56:28 -0400382 return DecoratePrivate(interfaceBlock.name()) + "_type";
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000383}
384
Jamie Madill98493dd2013-07-08 14:39:03 -0400385TString OutputHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000386{
Jamie Madill98493dd2013-07-08 14:39:03 -0400387 if (!interfaceBlock.hasInstanceName())
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000388 {
389 return "";
390 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400391 else if (interfaceBlock.isArray())
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000392 {
Jamie Madill033dae62014-06-18 12:56:28 -0400393 return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000394 }
395 else
396 {
Jamie Madill033dae62014-06-18 12:56:28 -0400397 return Decorate(interfaceBlock.instanceName());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000398 }
399}
400
Jamie Madill98493dd2013-07-08 14:39:03 -0400401TString OutputHLSL::interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000402{
Jamie Madill98493dd2013-07-08 14:39:03 -0400403 const TType &fieldType = *field.type();
404 const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
Jamie Madill529077d2013-06-20 11:55:54 -0400405 ASSERT(matrixPacking != EmpUnspecified);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000406
Jamie Madill98493dd2013-07-08 14:39:03 -0400407 if (fieldType.isMatrix())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000408 {
Jamie Madill9cf6c072013-06-20 11:55:53 -0400409 // Use HLSL row-major packing for GLSL column-major matrices
Jamie Madill529077d2013-06-20 11:55:54 -0400410 const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
Jamie Madill033dae62014-06-18 12:56:28 -0400411 return matrixPackString + " " + TypeString(fieldType);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000412 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400413 else if (fieldType.getStruct())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000414 {
Jamie Madill9cf6c072013-06-20 11:55:53 -0400415 // Use HLSL row-major packing for GLSL column-major matrices
Jamie Madill033dae62014-06-18 12:56:28 -0400416 return QualifiedStructNameString(*fieldType.getStruct(), matrixPacking == EmpColumnMajor,
417 blockStorage == EbsStd140);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000418 }
419 else
420 {
Jamie Madill033dae62014-06-18 12:56:28 -0400421 return TypeString(fieldType);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000422 }
423}
424
Jamie Madill98493dd2013-07-08 14:39:03 -0400425TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
426{
427 TString hlsl;
428
Jamie Madill3891fd22014-06-13 10:04:30 -0400429 Std140PaddingHelper padHelper(mStd140StructElementIndexes);
Jamie Madill98493dd2013-07-08 14:39:03 -0400430
431 for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
432 {
433 const TField &field = *interfaceBlock.fields()[typeIndex];
434 const TType &fieldType = *field.type();
435
436 if (blockStorage == EbsStd140)
437 {
438 // 2 and 3 component vector types in some cases need pre-padding
Jamie Madill3891fd22014-06-13 10:04:30 -0400439 hlsl += padHelper.prePaddingString(fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -0400440 }
441
442 hlsl += " " + interfaceBlockFieldTypeString(field, blockStorage) +
Jamie Madill033dae62014-06-18 12:56:28 -0400443 " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400444
445 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
446 if (blockStorage == EbsStd140)
447 {
448 const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
Jamie Madill3891fd22014-06-13 10:04:30 -0400449 hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
Jamie Madill98493dd2013-07-08 14:39:03 -0400450 }
451 }
452
453 return hlsl;
454}
455
456TString OutputHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
457{
458 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
459
460 return "struct " + interfaceBlockStructNameString(interfaceBlock) + "\n"
461 "{\n" +
462 interfaceBlockFieldString(interfaceBlock, blockStorage) +
463 "};\n\n";
464}
465
466TString OutputHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
467{
Jamie Madill033dae62014-06-18 12:56:28 -0400468 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
Jamie Madill98493dd2013-07-08 14:39:03 -0400469 const TString &blockName = interfaceBlock.name() + arrayIndexString;
470 TString hlsl;
471
472 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
473 "{\n";
474
475 if (interfaceBlock.hasInstanceName())
476 {
477 hlsl += " " + interfaceBlockStructNameString(interfaceBlock) + " " + interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
478 }
479 else
480 {
481 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
482 hlsl += interfaceBlockFieldString(interfaceBlock, blockStorage);
483 }
484
485 hlsl += "};\n\n";
486
487 return hlsl;
488}
489
Jamie Madill440dc742013-06-20 11:55:55 -0400490// Use the same layout for packed and shared
Jamie Madill834e8b72014-04-11 13:33:58 -0400491void setBlockLayout(gl::InterfaceBlock *interfaceBlock, gl::BlockLayoutType newLayout)
Jamie Madill440dc742013-06-20 11:55:55 -0400492{
493 interfaceBlock->layout = newLayout;
494 interfaceBlock->blockInfo.clear();
495
496 switch (newLayout)
497 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400498 case gl::BLOCKLAYOUT_SHARED:
499 case gl::BLOCKLAYOUT_PACKED:
Jamie Madill440dc742013-06-20 11:55:55 -0400500 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -0400501 gl::HLSLBlockEncoder hlslEncoder(&interfaceBlock->blockInfo, gl::HLSLBlockEncoder::ENCODE_PACKED);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400502 hlslEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
Jamie Madill440dc742013-06-20 11:55:55 -0400503 interfaceBlock->dataSize = hlslEncoder.getBlockSize();
504 }
505 break;
506
Jamie Madill834e8b72014-04-11 13:33:58 -0400507 case gl::BLOCKLAYOUT_STANDARD:
Jamie Madill440dc742013-06-20 11:55:55 -0400508 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400509 gl::Std140BlockEncoder stdEncoder(&interfaceBlock->blockInfo);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400510 stdEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
Jamie Madill440dc742013-06-20 11:55:55 -0400511 interfaceBlock->dataSize = stdEncoder.getBlockSize();
512 }
513 break;
514
515 default:
516 UNREACHABLE();
517 break;
518 }
519}
520
Jamie Madill834e8b72014-04-11 13:33:58 -0400521gl::BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage)
Jamie Madill574d9dd2013-06-20 11:55:56 -0400522{
523 switch (blockStorage)
524 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400525 case EbsPacked: return gl::BLOCKLAYOUT_PACKED;
526 case EbsShared: return gl::BLOCKLAYOUT_SHARED;
527 case EbsStd140: return gl::BLOCKLAYOUT_STANDARD;
528 default: UNREACHABLE(); return gl::BLOCKLAYOUT_SHARED;
Jamie Madill574d9dd2013-06-20 11:55:56 -0400529 }
530}
531
Jamie Madill98493dd2013-07-08 14:39:03 -0400532TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
Jamie Madill570e04d2013-06-21 09:15:33 -0400533{
534 TString init;
535
536 TString preIndentString;
537 TString fullIndentString;
538
539 for (int spaces = 0; spaces < (indent * 4); spaces++)
540 {
541 preIndentString += ' ';
542 }
543
544 for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
545 {
546 fullIndentString += ' ';
547 }
548
549 init += preIndentString + "{\n";
550
Jamie Madill98493dd2013-07-08 14:39:03 -0400551 const TFieldList &fields = structure.fields();
552 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400553 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400554 const TField &field = *fields[fieldIndex];
Jamie Madill033dae62014-06-18 12:56:28 -0400555 const TString &fieldName = rhsStructName + "." + Decorate(field.name());
Jamie Madill98493dd2013-07-08 14:39:03 -0400556 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400557
Jamie Madill98493dd2013-07-08 14:39:03 -0400558 if (fieldType.getStruct())
Jamie Madill570e04d2013-06-21 09:15:33 -0400559 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400560 init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400561 }
562 else
563 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400564 init += fullIndentString + fieldName + ",\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400565 }
566 }
567
568 init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
569
570 return init;
571}
572
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000573void OutputHLSL::header()
574{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000575 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000577 TString uniforms;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000578 TString interfaceBlocks;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000579 TString varyings;
580 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400581 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000582
Jamie Madillc2141fb2013-08-30 13:21:08 -0400583 for (ReferencedSymbols::const_iterator uniformIt = mReferencedUniforms.begin(); uniformIt != mReferencedUniforms.end(); uniformIt++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000584 {
Jamie Madillc2141fb2013-08-30 13:21:08 -0400585 const TIntermSymbol &uniform = *uniformIt->second;
586 const TType &type = uniform.getType();
587 const TString &name = uniform.getSymbol();
588
589 int registerIndex = declareUniformAndAssignRegister(type, name);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000590
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000591 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
592 {
Jamie Madill033dae62014-06-18 12:56:28 -0400593 uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) +
Jamie Madillc2141fb2013-08-30 13:21:08 -0400594 " : register(s" + str(registerIndex) + ");\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000595
Jamie Madill033dae62014-06-18 12:56:28 -0400596 uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) +
Jamie Madillc2141fb2013-08-30 13:21:08 -0400597 " : register(t" + str(registerIndex) + ");\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000598 }
599 else
600 {
Jamie Madillc2141fb2013-08-30 13:21:08 -0400601 const TStructure *structure = type.getStruct();
Jamie Madill033dae62014-06-18 12:56:28 -0400602 const TString &typeName = (structure ? QualifiedStructNameString(*structure, false, false) : TypeString(type));
Jamie Madillc2141fb2013-08-30 13:21:08 -0400603
604 const TString &registerString = TString("register(") + RegisterPrefix(type) + str(registerIndex) + ")";
605
Jamie Madill033dae62014-06-18 12:56:28 -0400606 uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000607 }
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000608 }
609
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000610 for (ReferencedSymbols::const_iterator interfaceBlockIt = mReferencedInterfaceBlocks.begin(); interfaceBlockIt != mReferencedInterfaceBlocks.end(); interfaceBlockIt++)
611 {
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000612 const TType &nodeType = interfaceBlockIt->second->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -0400613 const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
614 const TFieldList &fieldList = interfaceBlock.fields();
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000615
Jamie Madill98493dd2013-07-08 14:39:03 -0400616 unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
Jamie Madill834e8b72014-04-11 13:33:58 -0400617 gl::InterfaceBlock activeBlock(interfaceBlock.name().c_str(), arraySize, mInterfaceBlockRegister);
Jamie Madill98493dd2013-07-08 14:39:03 -0400618 for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000619 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400620 const TField &field = *fieldList[typeIndex];
621 const TString &fullUniformName = interfaceBlockFieldString(interfaceBlock, field);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400622 declareInterfaceBlockField(*field.type(), fullUniformName, activeBlock.fields);
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000623 }
624
Jamie Madill98493dd2013-07-08 14:39:03 -0400625 mInterfaceBlockRegister += std::max(1u, arraySize);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000626
Jamie Madill834e8b72014-04-11 13:33:58 -0400627 gl::BlockLayoutType blockLayoutType = convertBlockLayoutType(interfaceBlock.blockStorage());
Jamie Madill98493dd2013-07-08 14:39:03 -0400628 setBlockLayout(&activeBlock, blockLayoutType);
Jamie Madill9060a4e2013-08-12 16:22:57 -0700629
630 if (interfaceBlock.matrixPacking() == EmpRowMajor)
631 {
632 activeBlock.isRowMajorLayout = true;
633 }
634
Jamie Madill98493dd2013-07-08 14:39:03 -0400635 mActiveInterfaceBlocks.push_back(activeBlock);
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000636
Jamie Madill98493dd2013-07-08 14:39:03 -0400637 if (interfaceBlock.hasInstanceName())
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000638 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400639 interfaceBlocks += interfaceBlockStructString(interfaceBlock);
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000640 }
641
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000642 if (arraySize > 0)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000643 {
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000644 for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
645 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400646 interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex + arrayIndex, arrayIndex);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000647 }
648 }
649 else
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000650 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400651 interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex, GL_INVALID_INDEX);
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000652 }
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000653 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000654
Jamie Madill829f59e2013-11-13 19:40:54 -0500655 for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400656 {
657 TIntermTyped *structNode = flaggedStructIt->first;
658 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400659 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400660 const TString &originalName = mFlaggedStructOriginalNames[structNode];
661
Jamie Madill033dae62014-06-18 12:56:28 -0400662 flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
Jamie Madill98493dd2013-07-08 14:39:03 -0400663 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400664 flaggedStructs += "\n";
665 }
666
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000667 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
668 {
669 const TType &type = varying->second->getType();
670 const TString &name = varying->second->getSymbol();
671
672 // Program linking depends on this exact format
Jamie Madill033dae62014-06-18 12:56:28 -0400673 varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
674 Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madill47fdd132013-08-30 13:21:04 -0400675
Jamie Madill94599662013-08-30 13:21:10 -0400676 declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000677 }
678
679 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
680 {
681 const TType &type = attribute->second->getType();
682 const TString &name = attribute->second->getSymbol();
683
Jamie Madill033dae62014-06-18 12:56:28 -0400684 attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madilldefb6742013-06-20 11:55:51 -0400685
Jamie Madill033dae62014-06-18 12:56:28 -0400686 gl::Attribute attributeVar(GLVariableType(type), GLVariablePrecision(type), name.c_str(),
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400687 (unsigned int)type.getArraySize(), type.getLayoutQualifier().location);
688 mActiveAttributes.push_back(attributeVar);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000689 }
690
Jamie Madill529077d2013-06-20 11:55:54 -0400691 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
692 {
693 out << *structDeclaration;
694 }
695
696 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
697 {
698 out << *constructor;
699 }
700
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500701 if (mUsesDiscardRewriting)
702 {
703 out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
704 }
705
Nicolas Capens655fe362014-04-11 13:12:34 -0400706 if (mUsesNestedBreak)
707 {
708 out << "#define ANGLE_USES_NESTED_BREAK" << "\n";
709 }
710
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400711 if (mContext.shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000712 {
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000713 TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
shannon.woods%transgaming.com@gtempaccount.com99ab6eb2013-04-13 03:42:00 +0000714 const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000715
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000716 out << "// Varyings\n";
717 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400718 out << "\n";
719
720 if (mContext.getShaderVersion() >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000721 {
Jamie Madill829f59e2013-11-13 19:40:54 -0500722 for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000723 {
Jamie Madill46131a32013-06-20 11:55:50 -0400724 const TString &variableName = outputVariableIt->first;
725 const TType &variableType = outputVariableIt->second->getType();
726 const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier();
727
Jamie Madill033dae62014-06-18 12:56:28 -0400728 out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
Jamie Madill46131a32013-06-20 11:55:50 -0400729 " = " + initializer(variableType) + ";\n";
730
Jamie Madill033dae62014-06-18 12:56:28 -0400731 gl::Attribute outputVar(GLVariableType(variableType), GLVariablePrecision(variableType), variableName.c_str(),
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400732 (unsigned int)variableType.getArraySize(), layoutQualifier.location);
Jamie Madill46131a32013-06-20 11:55:50 -0400733 mActiveOutputVariables.push_back(outputVar);
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000734 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000735 }
Jamie Madill46131a32013-06-20 11:55:50 -0400736 else
737 {
738 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
739
740 out << "static float4 gl_Color[" << numColorValues << "] =\n"
741 "{\n";
742 for (unsigned int i = 0; i < numColorValues; i++)
743 {
744 out << " float4(0, 0, 0, 0)";
745 if (i + 1 != numColorValues)
746 {
747 out << ",";
748 }
749 out << "\n";
750 }
751
752 out << "};\n";
753 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000754
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400755 if (mUsesFragDepth)
756 {
757 out << "static float gl_Depth = 0.0;\n";
758 }
759
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000760 if (mUsesFragCoord)
761 {
762 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
763 }
764
765 if (mUsesPointCoord)
766 {
767 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
768 }
769
770 if (mUsesFrontFacing)
771 {
772 out << "static bool gl_FrontFacing = false;\n";
773 }
774
775 out << "\n";
776
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000777 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000778 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000779 out << "struct gl_DepthRangeParameters\n"
780 "{\n"
781 " float near;\n"
782 " float far;\n"
783 " float diff;\n"
784 "};\n"
785 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000786 }
787
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000788 if (mOutputType == SH_HLSL11_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000789 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000790 out << "cbuffer DriverConstants : register(b1)\n"
791 "{\n";
792
793 if (mUsesDepthRange)
794 {
795 out << " float3 dx_DepthRange : packoffset(c0);\n";
796 }
797
798 if (mUsesFragCoord)
799 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000800 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000801 }
802
803 if (mUsesFragCoord || mUsesFrontFacing)
804 {
805 out << " float3 dx_DepthFront : packoffset(c2);\n";
806 }
807
808 out << "};\n";
809 }
810 else
811 {
812 if (mUsesDepthRange)
813 {
814 out << "uniform float3 dx_DepthRange : register(c0);";
815 }
816
817 if (mUsesFragCoord)
818 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000819 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000820 }
821
822 if (mUsesFragCoord || mUsesFrontFacing)
823 {
824 out << "uniform float3 dx_DepthFront : register(c2);\n";
825 }
826 }
827
828 out << "\n";
829
830 if (mUsesDepthRange)
831 {
832 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
833 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000834 }
835
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000837 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000838
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000839 if (!interfaceBlocks.empty())
840 {
841 out << interfaceBlocks;
842 out << "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400843
844 if (!flaggedStructs.empty())
845 {
846 out << "// Std140 Structures accessed by value\n";
847 out << "\n";
848 out << flaggedStructs;
849 out << "\n";
850 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000851 }
852
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000853 if (usingMRTExtension && mNumRenderTargets > 1)
854 {
855 out << "#define GL_USES_MRT\n";
856 }
857
858 if (mUsesFragColor)
859 {
860 out << "#define GL_USES_FRAG_COLOR\n";
861 }
862
863 if (mUsesFragData)
864 {
865 out << "#define GL_USES_FRAG_DATA\n";
866 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000867 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000868 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000869 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000870 out << "// Attributes\n";
871 out << attributes;
872 out << "\n"
873 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
874
875 if (mUsesPointSize)
876 {
877 out << "static float gl_PointSize = float(1);\n";
878 }
879
880 out << "\n"
881 "// Varyings\n";
882 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000883 out << "\n";
884
885 if (mUsesDepthRange)
886 {
887 out << "struct gl_DepthRangeParameters\n"
888 "{\n"
889 " float near;\n"
890 " float far;\n"
891 " float diff;\n"
892 "};\n"
893 "\n";
894 }
895
896 if (mOutputType == SH_HLSL11_OUTPUT)
897 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000898 if (mUsesDepthRange)
899 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000900 out << "cbuffer DriverConstants : register(b1)\n"
901 "{\n"
902 " float3 dx_DepthRange : packoffset(c0);\n"
903 "};\n"
904 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000905 }
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000906 }
907 else
908 {
909 if (mUsesDepthRange)
910 {
911 out << "uniform float3 dx_DepthRange : register(c0);\n";
912 }
913
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +0000914 out << "uniform float4 dx_ViewAdjust : register(c1);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000915 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000916 }
917
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000918 if (mUsesDepthRange)
919 {
920 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
921 "\n";
922 }
923
924 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000925 out << "\n";
daniel@transgaming.com15795192011-05-11 15:36:20 +0000926
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000927 if (!interfaceBlocks.empty())
928 {
929 out << interfaceBlocks;
930 out << "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400931
932 if (!flaggedStructs.empty())
933 {
934 out << "// Std140 Structures accessed by value\n";
935 out << "\n";
936 out << flaggedStructs;
937 out << "\n";
938 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000939 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400940 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000941
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400942 for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
943 {
944 // Return type
Nicolas Capens75fb4752013-07-10 15:14:47 -0400945 if (textureFunction->method == TextureFunction::SIZE)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000946 {
Nicolas Capens75fb4752013-07-10 15:14:47 -0400947 switch(textureFunction->sampler)
948 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400949 case EbtSampler2D: out << "int2 "; break;
950 case EbtSampler3D: out << "int3 "; break;
951 case EbtSamplerCube: out << "int2 "; break;
952 case EbtSampler2DArray: out << "int3 "; break;
953 case EbtISampler2D: out << "int2 "; break;
954 case EbtISampler3D: out << "int3 "; break;
955 case EbtISamplerCube: out << "int2 "; break;
956 case EbtISampler2DArray: out << "int3 "; break;
957 case EbtUSampler2D: out << "int2 "; break;
958 case EbtUSampler3D: out << "int3 "; break;
959 case EbtUSamplerCube: out << "int2 "; break;
960 case EbtUSampler2DArray: out << "int3 "; break;
961 case EbtSampler2DShadow: out << "int2 "; break;
962 case EbtSamplerCubeShadow: out << "int2 "; break;
963 case EbtSampler2DArrayShadow: out << "int3 "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400964 default: UNREACHABLE();
965 }
966 }
967 else // Sampling function
968 {
969 switch(textureFunction->sampler)
970 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400971 case EbtSampler2D: out << "float4 "; break;
972 case EbtSampler3D: out << "float4 "; break;
973 case EbtSamplerCube: out << "float4 "; break;
974 case EbtSampler2DArray: out << "float4 "; break;
975 case EbtISampler2D: out << "int4 "; break;
976 case EbtISampler3D: out << "int4 "; break;
977 case EbtISamplerCube: out << "int4 "; break;
978 case EbtISampler2DArray: out << "int4 "; break;
979 case EbtUSampler2D: out << "uint4 "; break;
980 case EbtUSampler3D: out << "uint4 "; break;
981 case EbtUSamplerCube: out << "uint4 "; break;
982 case EbtUSampler2DArray: out << "uint4 "; break;
983 case EbtSampler2DShadow: out << "float "; break;
984 case EbtSamplerCubeShadow: out << "float "; break;
985 case EbtSampler2DArrayShadow: out << "float "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400986 default: UNREACHABLE();
987 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000988 }
989
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400990 // Function name
991 out << textureFunction->name();
992
993 // Argument list
994 int hlslCoords = 4;
995
996 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000997 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400998 switch(textureFunction->sampler)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000999 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001000 case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
1001 case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
1002 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00001003 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001004
Nicolas Capens75fb4752013-07-10 15:14:47 -04001005 switch(textureFunction->method)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00001006 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001007 case TextureFunction::IMPLICIT: break;
1008 case TextureFunction::BIAS: hlslCoords = 4; break;
1009 case TextureFunction::LOD: hlslCoords = 4; break;
1010 case TextureFunction::LOD0: hlslCoords = 4; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001011 case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001012 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00001013 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001014 }
1015 else if (mOutputType == SH_HLSL11_OUTPUT)
1016 {
1017 switch(textureFunction->sampler)
1018 {
Nicolas Capenscb127d32013-07-15 17:26:18 -04001019 case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
1020 case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
1021 case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
1022 case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
1023 case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
1024 case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001025 case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001026 case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
1027 case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
1028 case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001029 case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001030 case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
1031 case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
1032 case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
1033 case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001034 default: UNREACHABLE();
1035 }
1036 }
1037 else UNREACHABLE();
1038
Nicolas Capensfc014542014-02-18 14:47:13 -05001039 if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001040 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001041 switch(textureFunction->coords)
1042 {
1043 case 2: out << ", int2 t"; break;
1044 case 3: out << ", int3 t"; break;
1045 default: UNREACHABLE();
1046 }
1047 }
1048 else // Floating-point coordinates (except textureSize)
1049 {
1050 switch(textureFunction->coords)
1051 {
1052 case 1: out << ", int lod"; break; // textureSize()
1053 case 2: out << ", float2 t"; break;
1054 case 3: out << ", float3 t"; break;
1055 case 4: out << ", float4 t"; break;
1056 default: UNREACHABLE();
1057 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001058 }
1059
Nicolas Capensd11d5492014-02-19 17:06:10 -05001060 if (textureFunction->method == TextureFunction::GRAD)
1061 {
1062 switch(textureFunction->sampler)
1063 {
1064 case EbtSampler2D:
1065 case EbtISampler2D:
1066 case EbtUSampler2D:
1067 case EbtSampler2DArray:
1068 case EbtISampler2DArray:
1069 case EbtUSampler2DArray:
1070 case EbtSampler2DShadow:
1071 case EbtSampler2DArrayShadow:
1072 out << ", float2 ddx, float2 ddy";
1073 break;
1074 case EbtSampler3D:
1075 case EbtISampler3D:
1076 case EbtUSampler3D:
1077 case EbtSamplerCube:
1078 case EbtISamplerCube:
1079 case EbtUSamplerCube:
1080 case EbtSamplerCubeShadow:
1081 out << ", float3 ddx, float3 ddy";
1082 break;
1083 default: UNREACHABLE();
1084 }
1085 }
1086
Nicolas Capens75fb4752013-07-10 15:14:47 -04001087 switch(textureFunction->method)
daniel@transgaming.com15795192011-05-11 15:36:20 +00001088 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001089 case TextureFunction::IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001090 case TextureFunction::BIAS: break; // Comes after the offset parameter
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001091 case TextureFunction::LOD: out << ", float lod"; break;
1092 case TextureFunction::LOD0: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001093 case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
Nicolas Capens75fb4752013-07-10 15:14:47 -04001094 case TextureFunction::SIZE: break;
Nicolas Capensfc014542014-02-18 14:47:13 -05001095 case TextureFunction::FETCH: out << ", int mip"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -05001096 case TextureFunction::GRAD: break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001097 default: UNREACHABLE();
daniel@transgaming.com15795192011-05-11 15:36:20 +00001098 }
1099
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001100 if (textureFunction->offset)
1101 {
1102 switch(textureFunction->sampler)
1103 {
1104 case EbtSampler2D: out << ", int2 offset"; break;
1105 case EbtSampler3D: out << ", int3 offset"; break;
1106 case EbtSampler2DArray: out << ", int2 offset"; break;
1107 case EbtISampler2D: out << ", int2 offset"; break;
1108 case EbtISampler3D: out << ", int3 offset"; break;
1109 case EbtISampler2DArray: out << ", int2 offset"; break;
1110 case EbtUSampler2D: out << ", int2 offset"; break;
1111 case EbtUSampler3D: out << ", int3 offset"; break;
1112 case EbtUSampler2DArray: out << ", int2 offset"; break;
1113 case EbtSampler2DShadow: out << ", int2 offset"; break;
Nicolas Capensbf7db102014-02-19 17:20:28 -05001114 case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001115 default: UNREACHABLE();
1116 }
1117 }
1118
Nicolas Capens84cfa122014-04-14 13:48:45 -04001119 if (textureFunction->method == TextureFunction::BIAS ||
1120 textureFunction->method == TextureFunction::LOD0BIAS)
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001121 {
1122 out << ", float bias";
1123 }
1124
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001125 out << ")\n"
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001126 "{\n";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001127
Nicolas Capens75fb4752013-07-10 15:14:47 -04001128 if (textureFunction->method == TextureFunction::SIZE)
1129 {
1130 if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
1131 {
1132 if (IsSamplerArray(textureFunction->sampler))
1133 {
1134 out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
1135 " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
1136 }
1137 else
1138 {
1139 out << " uint width; uint height; uint numberOfLevels;\n"
1140 " x.GetDimensions(lod, width, height, numberOfLevels);\n";
1141 }
1142 }
1143 else if (IsSampler3D(textureFunction->sampler))
1144 {
1145 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
1146 " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
1147 }
1148 else UNREACHABLE();
1149
1150 switch(textureFunction->sampler)
1151 {
Nicolas Capenscb127d32013-07-15 17:26:18 -04001152 case EbtSampler2D: out << " return int2(width, height);"; break;
1153 case EbtSampler3D: out << " return int3(width, height, depth);"; break;
1154 case EbtSamplerCube: out << " return int2(width, height);"; break;
1155 case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
1156 case EbtISampler2D: out << " return int2(width, height);"; break;
1157 case EbtISampler3D: out << " return int3(width, height, depth);"; break;
1158 case EbtISamplerCube: out << " return int2(width, height);"; break;
1159 case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
1160 case EbtUSampler2D: out << " return int2(width, height);"; break;
1161 case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
1162 case EbtUSamplerCube: out << " return int2(width, height);"; break;
1163 case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
1164 case EbtSampler2DShadow: out << " return int2(width, height);"; break;
1165 case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
1166 case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -04001167 default: UNREACHABLE();
1168 }
1169 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001170 else
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001171 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001172 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1173 {
1174 out << " float width; float height; float layers; float levels;\n";
1175
1176 out << " uint mip = 0;\n";
1177
1178 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
1179
1180 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
1181 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
1182 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
1183 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
1184
1185 // FACE_POSITIVE_X = 000b
1186 // FACE_NEGATIVE_X = 001b
1187 // FACE_POSITIVE_Y = 010b
1188 // FACE_NEGATIVE_Y = 011b
1189 // FACE_POSITIVE_Z = 100b
1190 // FACE_NEGATIVE_Z = 101b
1191 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
1192
1193 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
1194 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
1195 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
1196
1197 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
1198 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
1199 }
1200 else if (IsIntegerSampler(textureFunction->sampler) &&
1201 textureFunction->method != TextureFunction::FETCH)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001202 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001203 if (IsSampler2D(textureFunction->sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001204 {
Nicolas Capens93e50de2013-07-09 13:46:28 -04001205 if (IsSamplerArray(textureFunction->sampler))
1206 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001207 out << " float width; float height; float layers; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001208
Nicolas Capens9edebd62013-08-06 10:59:10 -04001209 if (textureFunction->method == TextureFunction::LOD0)
1210 {
1211 out << " uint mip = 0;\n";
1212 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001213 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1214 {
1215 out << " uint mip = bias;\n";
1216 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001217 else
1218 {
1219 if (textureFunction->method == TextureFunction::IMPLICIT ||
1220 textureFunction->method == TextureFunction::BIAS)
1221 {
1222 out << " x.GetDimensions(0, width, height, layers, levels);\n"
1223 " float2 tSized = float2(t.x * width, t.y * height);\n"
1224 " float dx = length(ddx(tSized));\n"
1225 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001226 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001227
1228 if (textureFunction->method == TextureFunction::BIAS)
1229 {
1230 out << " lod += bias;\n";
1231 }
1232 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001233 else if (textureFunction->method == TextureFunction::GRAD)
1234 {
1235 out << " x.GetDimensions(0, width, height, layers, levels);\n"
1236 " float lod = log2(max(length(ddx), length(ddy)));\n";
1237 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001238
1239 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1240 }
1241
1242 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001243 }
1244 else
1245 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001246 out << " float width; float height; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001247
Nicolas Capens9edebd62013-08-06 10:59:10 -04001248 if (textureFunction->method == TextureFunction::LOD0)
1249 {
1250 out << " uint mip = 0;\n";
1251 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001252 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1253 {
1254 out << " uint mip = bias;\n";
1255 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001256 else
1257 {
1258 if (textureFunction->method == TextureFunction::IMPLICIT ||
1259 textureFunction->method == TextureFunction::BIAS)
1260 {
1261 out << " x.GetDimensions(0, width, height, levels);\n"
1262 " float2 tSized = float2(t.x * width, t.y * height);\n"
1263 " float dx = length(ddx(tSized));\n"
1264 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001265 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001266
1267 if (textureFunction->method == TextureFunction::BIAS)
1268 {
1269 out << " lod += bias;\n";
1270 }
1271 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05001272 else if (textureFunction->method == TextureFunction::LOD)
1273 {
1274 out << " x.GetDimensions(0, width, height, levels);\n";
1275 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001276 else if (textureFunction->method == TextureFunction::GRAD)
1277 {
1278 out << " x.GetDimensions(0, width, height, levels);\n"
1279 " float lod = log2(max(length(ddx), length(ddy)));\n";
1280 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001281
1282 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1283 }
1284
1285 out << " x.GetDimensions(mip, width, height, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001286 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001287 }
1288 else if (IsSampler3D(textureFunction->sampler))
1289 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001290 out << " float width; float height; float depth; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001291
Nicolas Capens9edebd62013-08-06 10:59:10 -04001292 if (textureFunction->method == TextureFunction::LOD0)
1293 {
1294 out << " uint mip = 0;\n";
1295 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001296 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1297 {
1298 out << " uint mip = bias;\n";
1299 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001300 else
1301 {
1302 if (textureFunction->method == TextureFunction::IMPLICIT ||
1303 textureFunction->method == TextureFunction::BIAS)
1304 {
1305 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1306 " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
1307 " float dx = length(ddx(tSized));\n"
1308 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001309 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001310
1311 if (textureFunction->method == TextureFunction::BIAS)
1312 {
1313 out << " lod += bias;\n";
1314 }
1315 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001316 else if (textureFunction->method == TextureFunction::GRAD)
1317 {
1318 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1319 " float lod = log2(max(length(ddx), length(ddy)));\n";
1320 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001321
1322 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1323 }
1324
1325 out << " x.GetDimensions(mip, width, height, depth, levels);\n";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001326 }
1327 else UNREACHABLE();
1328 }
1329
1330 out << " return ";
1331
1332 // HLSL intrinsic
1333 if (mOutputType == SH_HLSL9_OUTPUT)
1334 {
1335 switch(textureFunction->sampler)
1336 {
1337 case EbtSampler2D: out << "tex2D"; break;
1338 case EbtSamplerCube: out << "texCUBE"; break;
1339 default: UNREACHABLE();
1340 }
1341
Nicolas Capens75fb4752013-07-10 15:14:47 -04001342 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001343 {
1344 case TextureFunction::IMPLICIT: out << "(s, "; break;
1345 case TextureFunction::BIAS: out << "bias(s, "; break;
1346 case TextureFunction::LOD: out << "lod(s, "; break;
1347 case TextureFunction::LOD0: out << "lod(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001348 case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001349 default: UNREACHABLE();
1350 }
1351 }
1352 else if (mOutputType == SH_HLSL11_OUTPUT)
1353 {
Nicolas Capensd11d5492014-02-19 17:06:10 -05001354 if (textureFunction->method == TextureFunction::GRAD)
1355 {
1356 if (IsIntegerSampler(textureFunction->sampler))
1357 {
1358 out << "x.Load(";
1359 }
1360 else if (IsShadowSampler(textureFunction->sampler))
1361 {
1362 out << "x.SampleCmpLevelZero(s, ";
1363 }
1364 else
1365 {
1366 out << "x.SampleGrad(s, ";
1367 }
1368 }
1369 else if (IsIntegerSampler(textureFunction->sampler) ||
1370 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001371 {
1372 out << "x.Load(";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001373 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001374 else if (IsShadowSampler(textureFunction->sampler))
1375 {
1376 out << "x.SampleCmp(s, ";
1377 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001378 else
1379 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001380 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001381 {
1382 case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
1383 case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
1384 case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
1385 case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001386 case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001387 default: UNREACHABLE();
1388 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001389 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001390 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001391 else UNREACHABLE();
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001392
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001393 // Integer sampling requires integer addresses
1394 TString addressx = "";
1395 TString addressy = "";
1396 TString addressz = "";
1397 TString close = "";
1398
Nicolas Capensfc014542014-02-18 14:47:13 -05001399 if (IsIntegerSampler(textureFunction->sampler) ||
1400 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001401 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001402 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001403 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001404 case 2: out << "int3("; break;
1405 case 3: out << "int4("; break;
1406 default: UNREACHABLE();
1407 }
1408
Nicolas Capensfc014542014-02-18 14:47:13 -05001409 // Convert from normalized floating-point to integer
1410 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001411 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001412 addressx = "int(floor(width * frac((";
1413 addressy = "int(floor(height * frac((";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001414
Nicolas Capensfc014542014-02-18 14:47:13 -05001415 if (IsSamplerArray(textureFunction->sampler))
1416 {
1417 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
1418 }
Nicolas Capens0027fa92014-02-20 14:26:42 -05001419 else if (IsSamplerCube(textureFunction->sampler))
1420 {
1421 addressz = "((((";
1422 }
Nicolas Capensfc014542014-02-18 14:47:13 -05001423 else
1424 {
1425 addressz = "int(floor(depth * frac((";
1426 }
1427
1428 close = "))))";
1429 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001430 }
1431 else
1432 {
1433 switch(hlslCoords)
1434 {
1435 case 2: out << "float2("; break;
1436 case 3: out << "float3("; break;
1437 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001438 default: UNREACHABLE();
1439 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001440 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001441
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001442 TString proj = ""; // Only used for projected textures
1443
1444 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001445 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001446 switch(textureFunction->coords)
1447 {
1448 case 3: proj = " / t.z"; break;
1449 case 4: proj = " / t.w"; break;
1450 default: UNREACHABLE();
1451 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001452 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001453
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001454 out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001455
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001456 if (mOutputType == SH_HLSL9_OUTPUT)
1457 {
1458 if (hlslCoords >= 3)
1459 {
1460 if (textureFunction->coords < 3)
1461 {
1462 out << ", 0";
1463 }
1464 else
1465 {
1466 out << ", t.z" + proj;
1467 }
1468 }
1469
1470 if (hlslCoords == 4)
1471 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001472 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001473 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001474 case TextureFunction::BIAS: out << ", bias"; break;
1475 case TextureFunction::LOD: out << ", lod"; break;
1476 case TextureFunction::LOD0: out << ", 0"; break;
1477 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001478 default: UNREACHABLE();
1479 }
1480 }
1481
1482 out << "));\n";
1483 }
1484 else if (mOutputType == SH_HLSL11_OUTPUT)
1485 {
1486 if (hlslCoords >= 3)
1487 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001488 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1489 {
1490 out << ", face";
1491 }
1492 else
1493 {
1494 out << ", " + addressz + ("t.z" + proj) + close;
1495 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001496 }
1497
Nicolas Capensd11d5492014-02-19 17:06:10 -05001498 if (textureFunction->method == TextureFunction::GRAD)
1499 {
1500 if (IsIntegerSampler(textureFunction->sampler))
1501 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001502 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001503 }
1504 else if (IsShadowSampler(textureFunction->sampler))
1505 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001506 // Compare value
Nicolas Capensd11d5492014-02-19 17:06:10 -05001507 switch(textureFunction->coords)
1508 {
1509 case 3: out << "), t.z"; break;
1510 case 4: out << "), t.w"; break;
1511 default: UNREACHABLE();
1512 }
1513 }
1514 else
1515 {
1516 out << "), ddx, ddy";
1517 }
1518 }
1519 else if (IsIntegerSampler(textureFunction->sampler) ||
1520 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001521 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001522 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001523 }
1524 else if (IsShadowSampler(textureFunction->sampler))
1525 {
1526 // Compare value
1527 switch(textureFunction->coords)
1528 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001529 case 3: out << "), t.z"; break;
1530 case 4: out << "), t.w"; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001531 default: UNREACHABLE();
1532 }
1533 }
1534 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001535 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001536 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001537 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001538 case TextureFunction::IMPLICIT: out << ")"; break;
1539 case TextureFunction::BIAS: out << "), bias"; break;
1540 case TextureFunction::LOD: out << "), lod"; break;
1541 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001542 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001543 default: UNREACHABLE();
1544 }
1545 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001546
1547 if (textureFunction->offset)
1548 {
1549 out << ", offset";
1550 }
1551
1552 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001553 }
1554 else UNREACHABLE();
1555 }
1556
1557 out << "\n"
1558 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001559 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001560 }
1561
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001562 if (mUsesFragCoord)
1563 {
1564 out << "#define GL_USES_FRAG_COORD\n";
1565 }
1566
1567 if (mUsesPointCoord)
1568 {
1569 out << "#define GL_USES_POINT_COORD\n";
1570 }
1571
1572 if (mUsesFrontFacing)
1573 {
1574 out << "#define GL_USES_FRONT_FACING\n";
1575 }
1576
1577 if (mUsesPointSize)
1578 {
1579 out << "#define GL_USES_POINT_SIZE\n";
1580 }
1581
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001582 if (mUsesFragDepth)
1583 {
1584 out << "#define GL_USES_FRAG_DEPTH\n";
1585 }
1586
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001587 if (mUsesDepthRange)
1588 {
1589 out << "#define GL_USES_DEPTH_RANGE\n";
1590 }
1591
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001592 if (mUsesXor)
1593 {
1594 out << "bool xor(bool p, bool q)\n"
1595 "{\n"
1596 " return (p || q) && !(p && q);\n"
1597 "}\n"
1598 "\n";
1599 }
1600
1601 if (mUsesMod1)
1602 {
1603 out << "float mod(float x, float y)\n"
1604 "{\n"
1605 " return x - y * floor(x / y);\n"
1606 "}\n"
1607 "\n";
1608 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001609
1610 if (mUsesMod2v)
1611 {
1612 out << "float2 mod(float2 x, float2 y)\n"
1613 "{\n"
1614 " return x - y * floor(x / y);\n"
1615 "}\n"
1616 "\n";
1617 }
1618
1619 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001620 {
1621 out << "float2 mod(float2 x, float y)\n"
1622 "{\n"
1623 " return x - y * floor(x / y);\n"
1624 "}\n"
1625 "\n";
1626 }
1627
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001628 if (mUsesMod3v)
1629 {
1630 out << "float3 mod(float3 x, float3 y)\n"
1631 "{\n"
1632 " return x - y * floor(x / y);\n"
1633 "}\n"
1634 "\n";
1635 }
1636
1637 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001638 {
1639 out << "float3 mod(float3 x, float y)\n"
1640 "{\n"
1641 " return x - y * floor(x / y);\n"
1642 "}\n"
1643 "\n";
1644 }
1645
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001646 if (mUsesMod4v)
1647 {
1648 out << "float4 mod(float4 x, float4 y)\n"
1649 "{\n"
1650 " return x - y * floor(x / y);\n"
1651 "}\n"
1652 "\n";
1653 }
1654
1655 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001656 {
1657 out << "float4 mod(float4 x, float y)\n"
1658 "{\n"
1659 " return x - y * floor(x / y);\n"
1660 "}\n"
1661 "\n";
1662 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001663
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001664 if (mUsesFaceforward1)
1665 {
1666 out << "float faceforward(float N, float I, float Nref)\n"
1667 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001668 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001669 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001670 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001671 " }\n"
1672 " else\n"
1673 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001674 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001675 " }\n"
1676 "}\n"
1677 "\n";
1678 }
1679
1680 if (mUsesFaceforward2)
1681 {
1682 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
1683 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001684 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001685 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001686 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001687 " }\n"
1688 " else\n"
1689 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001690 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001691 " }\n"
1692 "}\n"
1693 "\n";
1694 }
1695
1696 if (mUsesFaceforward3)
1697 {
1698 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
1699 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001700 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001701 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001702 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001703 " }\n"
1704 " else\n"
1705 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001706 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001707 " }\n"
1708 "}\n"
1709 "\n";
1710 }
1711
1712 if (mUsesFaceforward4)
1713 {
1714 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
1715 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001716 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001717 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001718 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001719 " }\n"
1720 " else\n"
1721 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001722 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001723 " }\n"
1724 "}\n"
1725 "\n";
1726 }
1727
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001728 if (mUsesAtan2_1)
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001729 {
1730 out << "float atanyx(float y, float x)\n"
1731 "{\n"
1732 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
1733 " return atan2(y, x);\n"
1734 "}\n";
1735 }
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001736
1737 if (mUsesAtan2_2)
1738 {
1739 out << "float2 atanyx(float2 y, float2 x)\n"
1740 "{\n"
1741 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1742 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1743 " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
1744 "}\n";
1745 }
1746
1747 if (mUsesAtan2_3)
1748 {
1749 out << "float3 atanyx(float3 y, float3 x)\n"
1750 "{\n"
1751 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1752 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1753 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1754 " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
1755 "}\n";
1756 }
1757
1758 if (mUsesAtan2_4)
1759 {
1760 out << "float4 atanyx(float4 y, float4 x)\n"
1761 "{\n"
1762 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1763 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1764 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1765 " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
1766 " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
1767 "}\n";
1768 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001769}
1770
1771void OutputHLSL::visitSymbol(TIntermSymbol *node)
1772{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001773 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001774
Jamie Madill570e04d2013-06-21 09:15:33 -04001775 // Handle accessing std140 structs by value
1776 if (mFlaggedStructMappedNames.count(node) > 0)
1777 {
1778 out << mFlaggedStructMappedNames[node];
1779 return;
1780 }
1781
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001782 TString name = node->getSymbol();
1783
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001784 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001785 {
1786 mUsesDepthRange = true;
1787 out << name;
1788 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789 else
1790 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001791 TQualifier qualifier = node->getQualifier();
1792
1793 if (qualifier == EvqUniform)
1794 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001795 const TType& nodeType = node->getType();
1796 const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock();
1797
1798 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001799 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001800 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001801 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001802 else
1803 {
1804 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001805 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001806
Jamie Madill033dae62014-06-18 12:56:28 -04001807 out << DecorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001808 }
Jamie Madill19571812013-08-12 15:26:34 -07001809 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001810 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001811 mReferencedAttributes[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001812 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001813 }
Jamie Madill033dae62014-06-18 12:56:28 -04001814 else if (IsVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001815 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001816 mReferencedVaryings[name] = node;
Jamie Madill033dae62014-06-18 12:56:28 -04001817 out << Decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001818 }
Jamie Madill19571812013-08-12 15:26:34 -07001819 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001820 {
1821 mReferencedOutputVariables[name] = node;
1822 out << "out_" << name;
1823 }
1824 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001825 {
1826 out << "gl_Color[0]";
1827 mUsesFragColor = true;
1828 }
1829 else if (qualifier == EvqFragData)
1830 {
1831 out << "gl_Color";
1832 mUsesFragData = true;
1833 }
1834 else if (qualifier == EvqFragCoord)
1835 {
1836 mUsesFragCoord = true;
1837 out << name;
1838 }
1839 else if (qualifier == EvqPointCoord)
1840 {
1841 mUsesPointCoord = true;
1842 out << name;
1843 }
1844 else if (qualifier == EvqFrontFacing)
1845 {
1846 mUsesFrontFacing = true;
1847 out << name;
1848 }
1849 else if (qualifier == EvqPointSize)
1850 {
1851 mUsesPointSize = true;
1852 out << name;
1853 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001854 else if (name == "gl_FragDepthEXT")
1855 {
1856 mUsesFragDepth = true;
1857 out << "gl_Depth";
1858 }
Jamie Madille53c98b2014-02-03 11:57:13 -05001859 else if (qualifier == EvqInternal)
1860 {
1861 out << name;
1862 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001863 else
1864 {
Jamie Madill033dae62014-06-18 12:56:28 -04001865 out << Decorate(name);
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001866 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001867 }
1868}
1869
1870bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1871{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001872 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001873
Jamie Madill570e04d2013-06-21 09:15:33 -04001874 // Handle accessing std140 structs by value
1875 if (mFlaggedStructMappedNames.count(node) > 0)
1876 {
1877 out << mFlaggedStructMappedNames[node];
1878 return false;
1879 }
1880
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001881 switch (node->getOp())
1882 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001883 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001884 case EOpInitialize:
1885 if (visit == PreVisit)
1886 {
1887 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1888 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1889 // new variable is created before the assignment is evaluated), so we need to convert
1890 // this to "float t = x, x = t;".
1891
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001892 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1893 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001894
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001895 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
1896 expression->traverse(&searchSymbol);
1897 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001898
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001899 if (sameSymbol)
1900 {
1901 // Type already printed
1902 out << "t" + str(mUniqueIndex) + " = ";
1903 expression->traverse(this);
1904 out << ", ";
1905 symbolNode->traverse(this);
1906 out << " = t" + str(mUniqueIndex);
1907
1908 mUniqueIndex++;
1909 return false;
1910 }
1911 }
1912 else if (visit == InVisit)
1913 {
1914 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001915 }
1916 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001917 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
1918 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
1919 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1920 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1921 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1922 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001923 if (visit == PreVisit)
1924 {
1925 out << "(";
1926 }
1927 else if (visit == InVisit)
1928 {
1929 out << " = mul(";
1930 node->getLeft()->traverse(this);
1931 out << ", transpose(";
1932 }
1933 else
1934 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001935 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001936 }
1937 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001938 case EOpMatrixTimesMatrixAssign:
1939 if (visit == PreVisit)
1940 {
1941 out << "(";
1942 }
1943 else if (visit == InVisit)
1944 {
1945 out << " = mul(";
1946 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001947 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001948 }
1949 else
1950 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001951 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001952 }
1953 break;
1954 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001955 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001956 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001957 const TType& leftType = node->getLeft()->getType();
1958 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001959 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001960 if (visit == PreVisit)
1961 {
1962 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1963 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
1964
1965 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
1966 out << interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
1967
1968 return false;
1969 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001970 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001971 else
1972 {
1973 outputTriplet(visit, "", "[", "]");
1974 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001975 }
1976 break;
1977 case EOpIndexIndirect:
1978 // We do not currently support indirect references to interface blocks
1979 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1980 outputTriplet(visit, "", "[", "]");
1981 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001982 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001983 if (visit == InVisit)
1984 {
1985 const TStructure* structure = node->getLeft()->getType().getStruct();
1986 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1987 const TField* field = structure->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001988 out << "." + DecorateField(field->name(), *structure);
Jamie Madill98493dd2013-07-08 14:39:03 -04001989
1990 return false;
1991 }
1992 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001993 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001994 if (visit == InVisit)
1995 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001996 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1997 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1998 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
Jamie Madill033dae62014-06-18 12:56:28 -04001999 out << "." + Decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002000
2001 return false;
2002 }
2003 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002004 case EOpVectorSwizzle:
2005 if (visit == InVisit)
2006 {
2007 out << ".";
2008
2009 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
2010
2011 if (swizzle)
2012 {
2013 TIntermSequence &sequence = swizzle->getSequence();
2014
2015 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
2016 {
2017 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
2018
2019 if (element)
2020 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002021 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002022
2023 switch (i)
2024 {
2025 case 0: out << "x"; break;
2026 case 1: out << "y"; break;
2027 case 2: out << "z"; break;
2028 case 3: out << "w"; break;
2029 default: UNREACHABLE();
2030 }
2031 }
2032 else UNREACHABLE();
2033 }
2034 }
2035 else UNREACHABLE();
2036
2037 return false; // Fully processed
2038 }
2039 break;
2040 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
2041 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
2042 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
2043 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002044 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002045 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002046 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002047 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002048 if (node->getOp() == EOpEqual)
2049 {
2050 outputTriplet(visit, "(", " == ", ")");
2051 }
2052 else
2053 {
2054 outputTriplet(visit, "(", " != ", ")");
2055 }
2056 }
2057 else if (node->getLeft()->getBasicType() == EbtStruct)
2058 {
2059 if (node->getOp() == EOpEqual)
2060 {
2061 out << "(";
2062 }
2063 else
2064 {
2065 out << "!(";
2066 }
2067
Jamie Madill98493dd2013-07-08 14:39:03 -04002068 const TStructure &structure = *node->getLeft()->getType().getStruct();
2069 const TFieldList &fields = structure.fields();
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002070
Jamie Madill98493dd2013-07-08 14:39:03 -04002071 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002072 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002073 const TField *field = fields[i];
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002074
2075 node->getLeft()->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04002076 out << "." + DecorateField(field->name(), structure) + " == ";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002077 node->getRight()->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04002078 out << "." + DecorateField(field->name(), structure);
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002079
Jamie Madill98493dd2013-07-08 14:39:03 -04002080 if (i < fields.size() - 1)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002081 {
2082 out << " && ";
2083 }
2084 }
2085
2086 out << ")";
2087
2088 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002089 }
2090 else
2091 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002092 ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002093
2094 if (node->getOp() == EOpEqual)
2095 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002096 outputTriplet(visit, "all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002097 }
2098 else
2099 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002100 outputTriplet(visit, "!all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002101 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002102 }
2103 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002104 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2105 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2106 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2107 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2108 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00002109 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00002110 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
2111 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00002112 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00002113 case EOpLogicalOr:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002114 if (node->getRight()->hasSideEffects())
2115 {
2116 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
2117 return false;
2118 }
2119 else
2120 {
2121 outputTriplet(visit, "(", " || ", ")");
2122 return true;
2123 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002124 case EOpLogicalXor:
2125 mUsesXor = true;
2126 outputTriplet(visit, "xor(", ", ", ")");
2127 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00002128 case EOpLogicalAnd:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002129 if (node->getRight()->hasSideEffects())
2130 {
2131 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
2132 return false;
2133 }
2134 else
2135 {
2136 outputTriplet(visit, "(", " && ", ")");
2137 return true;
2138 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002139 default: UNREACHABLE();
2140 }
2141
2142 return true;
2143}
2144
2145bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
2146{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002147 switch (node->getOp())
2148 {
Nicolas Capens16004fc2014-06-11 11:29:11 -04002149 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
2150 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
2151 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
2152 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
2153 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
2154 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
2155 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002156 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
2157 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
2158 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
2159 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
2160 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
2161 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
2162 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
2163 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
2164 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
2165 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
2166 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
2167 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
2168 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
2169 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
2170 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
2171 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
2172 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
2173 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
2174 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
2175 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
2176 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002177 case EOpDFdx:
2178 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2179 {
2180 outputTriplet(visit, "(", "", ", 0.0)");
2181 }
2182 else
2183 {
2184 outputTriplet(visit, "ddx(", "", ")");
2185 }
2186 break;
2187 case EOpDFdy:
2188 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2189 {
2190 outputTriplet(visit, "(", "", ", 0.0)");
2191 }
2192 else
2193 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00002194 outputTriplet(visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002195 }
2196 break;
2197 case EOpFwidth:
2198 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2199 {
2200 outputTriplet(visit, "(", "", ", 0.0)");
2201 }
2202 else
2203 {
2204 outputTriplet(visit, "fwidth(", "", ")");
2205 }
2206 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002207 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
2208 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002209 default: UNREACHABLE();
2210 }
2211
2212 return true;
2213}
2214
2215bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2216{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002217 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002218
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002219 switch (node->getOp())
2220 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002221 case EOpSequence:
2222 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002223 if (mInsideFunction)
2224 {
Jamie Madill075edd82013-07-08 13:30:19 -04002225 outputLineDirective(node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002226 out << "{\n";
2227 }
2228
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002229 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
2230 {
Jamie Madill075edd82013-07-08 13:30:19 -04002231 outputLineDirective((*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002232
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002233 traverseStatements(*sit);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002234
2235 out << ";\n";
2236 }
2237
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002238 if (mInsideFunction)
2239 {
Jamie Madill075edd82013-07-08 13:30:19 -04002240 outputLineDirective(node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002241 out << "}\n";
2242 }
2243
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002244 return false;
2245 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002246 case EOpDeclaration:
2247 if (visit == PreVisit)
2248 {
2249 TIntermSequence &sequence = node->getSequence();
2250 TIntermTyped *variable = sequence[0]->getAsTyped();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002251
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00002252 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002253 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002254 if (variable->getType().getStruct())
2255 {
Jamie Madill033dae62014-06-18 12:56:28 -04002256 addConstructor(variable->getType(), StructNameString(*variable->getType().getStruct()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00002257 }
2258
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002259 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00002261 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002262 {
2263 out << "static ";
2264 }
2265
Jamie Madill033dae62014-06-18 12:56:28 -04002266 out << TypeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002268 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002269 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002270 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002271
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002272 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002273 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002274 symbol->traverse(this);
Jamie Madill033dae62014-06-18 12:56:28 -04002275 out << ArrayString(symbol->getType());
Jamie Madill79bb0d92013-12-09 16:20:28 -05002276 out << " = " + initializer(symbol->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002277 }
2278 else
2279 {
2280 (*sit)->traverse(this);
2281 }
2282
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002283 if (*sit != sequence.back())
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002284 {
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002285 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002286 }
2287 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002288 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002289 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
2290 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002291 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002292 }
2293 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002294 }
Jamie Madill033dae62014-06-18 12:56:28 -04002295 else if (variable && IsVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002296 {
2297 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
2298 {
2299 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
2300
2301 if (symbol)
2302 {
2303 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
2304 mReferencedVaryings[symbol->getSymbol()] = symbol;
2305 }
2306 else
2307 {
2308 (*sit)->traverse(this);
2309 }
2310 }
2311 }
2312
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002313 return false;
2314 }
2315 else if (visit == InVisit)
2316 {
2317 out << ", ";
2318 }
2319 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002320 case EOpPrototype:
2321 if (visit == PreVisit)
2322 {
Jamie Madill033dae62014-06-18 12:56:28 -04002323 out << TypeString(node->getType()) << " " << Decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002324
2325 TIntermSequence &arguments = node->getSequence();
2326
2327 for (unsigned int i = 0; i < arguments.size(); i++)
2328 {
2329 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
2330
2331 if (symbol)
2332 {
2333 out << argumentString(symbol);
2334
2335 if (i < arguments.size() - 1)
2336 {
2337 out << ", ";
2338 }
2339 }
2340 else UNREACHABLE();
2341 }
2342
2343 out << ");\n";
2344
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002345 // Also prototype the Lod0 variant if needed
2346 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
2347 {
2348 mOutputLod0Function = true;
2349 node->traverse(this);
2350 mOutputLod0Function = false;
2351 }
2352
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002353 return false;
2354 }
2355 break;
daniel@transgaming.comed2180d2012-03-26 17:08:54 +00002356 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002357 case EOpFunction:
2358 {
alokp@chromium.org43884872010-03-30 00:08:52 +00002359 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002360
Jamie Madill033dae62014-06-18 12:56:28 -04002361 out << TypeString(node->getType()) << " ";
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002362
2363 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002364 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002365 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002366 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002367 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002368 {
Jamie Madill033dae62014-06-18 12:56:28 -04002369 out << Decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002370 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002371
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002372 TIntermSequence &sequence = node->getSequence();
2373 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
2374
2375 for (unsigned int i = 0; i < arguments.size(); i++)
2376 {
2377 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
2378
2379 if (symbol)
2380 {
2381 if (symbol->getType().getStruct())
2382 {
Jamie Madill033dae62014-06-18 12:56:28 -04002383 addConstructor(symbol->getType(), StructNameString(*symbol->getType().getStruct()), NULL);
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002384 }
2385
2386 out << argumentString(symbol);
2387
2388 if (i < arguments.size() - 1)
2389 {
2390 out << ", ";
2391 }
2392 }
2393 else UNREACHABLE();
2394 }
2395
2396 out << ")\n"
2397 "{\n";
2398
2399 if (sequence.size() > 1)
2400 {
2401 mInsideFunction = true;
2402 sequence[1]->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002403 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002405
2406 out << "}\n";
2407
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002408 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
2409 {
daniel@transgaming.comecdf44a2012-06-01 01:45:15 +00002410 if (name != "main")
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002411 {
2412 mOutputLod0Function = true;
2413 node->traverse(this);
2414 mOutputLod0Function = false;
2415 }
2416 }
2417
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002418 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002419 }
2420 break;
2421 case EOpFunctionCall:
2422 {
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002423 TString name = TFunction::unmangleName(node->getName());
2424 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002425 TIntermSequence &arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002426
2427 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428 {
Jamie Madill033dae62014-06-18 12:56:28 -04002429 out << Decorate(name) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002430 }
2431 else
2432 {
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002433 TBasicType samplerType = arguments[0]->getAsTyped()->getType().getBasicType();
2434
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002435 TextureFunction textureFunction;
2436 textureFunction.sampler = samplerType;
2437 textureFunction.coords = arguments[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002438 textureFunction.method = TextureFunction::IMPLICIT;
2439 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002440 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002441
2442 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002443 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002444 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002445 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002446 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002447 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002448 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002449 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002450 }
Nicolas Capens46485082014-04-15 13:12:50 -04002451 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
2452 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002453 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002454 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002455 }
Nicolas Capens46485082014-04-15 13:12:50 -04002456 else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002457 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002458 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002459 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002460 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002461 else if (name == "textureSize")
2462 {
2463 textureFunction.method = TextureFunction::SIZE;
2464 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002465 else if (name == "textureOffset")
2466 {
2467 textureFunction.method = TextureFunction::IMPLICIT;
2468 textureFunction.offset = true;
2469 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002470 else if (name == "textureProjOffset")
2471 {
2472 textureFunction.method = TextureFunction::IMPLICIT;
2473 textureFunction.offset = true;
2474 textureFunction.proj = true;
2475 }
2476 else if (name == "textureLodOffset")
2477 {
2478 textureFunction.method = TextureFunction::LOD;
2479 textureFunction.offset = true;
2480 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002481 else if (name == "textureProjLodOffset")
2482 {
2483 textureFunction.method = TextureFunction::LOD;
2484 textureFunction.proj = true;
2485 textureFunction.offset = true;
2486 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002487 else if (name == "texelFetch")
2488 {
2489 textureFunction.method = TextureFunction::FETCH;
2490 }
2491 else if (name == "texelFetchOffset")
2492 {
2493 textureFunction.method = TextureFunction::FETCH;
2494 textureFunction.offset = true;
2495 }
Nicolas Capens46485082014-04-15 13:12:50 -04002496 else if (name == "textureGrad" || name == "texture2DGradEXT")
Nicolas Capensd11d5492014-02-19 17:06:10 -05002497 {
2498 textureFunction.method = TextureFunction::GRAD;
2499 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002500 else if (name == "textureGradOffset")
2501 {
2502 textureFunction.method = TextureFunction::GRAD;
2503 textureFunction.offset = true;
2504 }
Nicolas Capens46485082014-04-15 13:12:50 -04002505 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
Nicolas Capensf7378e32014-02-19 17:29:32 -05002506 {
2507 textureFunction.method = TextureFunction::GRAD;
2508 textureFunction.proj = true;
2509 }
2510 else if (name == "textureProjGradOffset")
2511 {
2512 textureFunction.method = TextureFunction::GRAD;
2513 textureFunction.proj = true;
2514 textureFunction.offset = true;
2515 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002516 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002517
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002518 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002519 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002520 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2521
2522 if (textureFunction.offset)
2523 {
2524 mandatoryArgumentCount++;
2525 }
2526
2527 bool bias = (arguments.size() > mandatoryArgumentCount); // Bias argument is optional
2528
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002529 if (lod0 || mContext.shaderType == SH_VERTEX_SHADER)
2530 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002531 if (bias)
2532 {
2533 textureFunction.method = TextureFunction::LOD0BIAS;
2534 }
2535 else
2536 {
2537 textureFunction.method = TextureFunction::LOD0;
2538 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002539 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002540 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002541 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002542 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002543 }
2544 }
2545
2546 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002547
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002548 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002549 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002550
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002551 for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
2552 {
2553 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2554 {
2555 out << "texture_";
2556 (*arg)->traverse(this);
2557 out << ", sampler_";
2558 }
2559
2560 (*arg)->traverse(this);
2561
2562 if (arg < arguments.end() - 1)
2563 {
2564 out << ", ";
2565 }
2566 }
2567
2568 out << ")";
2569
2570 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002571 }
2572 break;
Nicolas Capens1af18dc2014-06-11 11:07:32 -04002573 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
2574 case EOpConstructFloat: outputConstructor(visit, node->getType(), "vec1", &node->getSequence()); break;
2575 case EOpConstructVec2: outputConstructor(visit, node->getType(), "vec2", &node->getSequence()); break;
2576 case EOpConstructVec3: outputConstructor(visit, node->getType(), "vec3", &node->getSequence()); break;
2577 case EOpConstructVec4: outputConstructor(visit, node->getType(), "vec4", &node->getSequence()); break;
2578 case EOpConstructBool: outputConstructor(visit, node->getType(), "bvec1", &node->getSequence()); break;
2579 case EOpConstructBVec2: outputConstructor(visit, node->getType(), "bvec2", &node->getSequence()); break;
2580 case EOpConstructBVec3: outputConstructor(visit, node->getType(), "bvec3", &node->getSequence()); break;
2581 case EOpConstructBVec4: outputConstructor(visit, node->getType(), "bvec4", &node->getSequence()); break;
2582 case EOpConstructInt: outputConstructor(visit, node->getType(), "ivec1", &node->getSequence()); break;
2583 case EOpConstructIVec2: outputConstructor(visit, node->getType(), "ivec2", &node->getSequence()); break;
2584 case EOpConstructIVec3: outputConstructor(visit, node->getType(), "ivec3", &node->getSequence()); break;
2585 case EOpConstructIVec4: outputConstructor(visit, node->getType(), "ivec4", &node->getSequence()); break;
2586 case EOpConstructUInt: outputConstructor(visit, node->getType(), "uvec1", &node->getSequence()); break;
2587 case EOpConstructUVec2: outputConstructor(visit, node->getType(), "uvec2", &node->getSequence()); break;
2588 case EOpConstructUVec3: outputConstructor(visit, node->getType(), "uvec3", &node->getSequence()); break;
2589 case EOpConstructUVec4: outputConstructor(visit, node->getType(), "uvec4", &node->getSequence()); break;
2590 case EOpConstructMat2: outputConstructor(visit, node->getType(), "mat2", &node->getSequence()); break;
2591 case EOpConstructMat3: outputConstructor(visit, node->getType(), "mat3", &node->getSequence()); break;
2592 case EOpConstructMat4: outputConstructor(visit, node->getType(), "mat4", &node->getSequence()); break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002593 case EOpConstructStruct:
Jamie Madillbfa91f42014-06-05 15:45:18 -04002594 {
Jamie Madill033dae62014-06-18 12:56:28 -04002595 const TString &structName = StructNameString(*node->getType().getStruct());
Jamie Madillbfa91f42014-06-05 15:45:18 -04002596 addConstructor(node->getType(), structName, &node->getSequence());
2597 outputTriplet(visit, structName + "_ctor(", ", ", ")");
2598 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002599 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002600 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2601 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2602 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2603 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2604 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
2605 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002606 case EOpMod:
2607 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002608 // We need to look at the number of components in both arguments
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002609 const int modValue = node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
2610 + node->getSequence()[1]->getAsTyped()->getNominalSize();
2611 switch (modValue)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002612 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002613 case 11: mUsesMod1 = true; break;
2614 case 22: mUsesMod2v = true; break;
2615 case 21: mUsesMod2f = true; break;
2616 case 33: mUsesMod3v = true; break;
2617 case 31: mUsesMod3f = true; break;
2618 case 44: mUsesMod4v = true; break;
2619 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002620 default: UNREACHABLE();
2621 }
2622
2623 outputTriplet(visit, "mod(", ", ", ")");
2624 }
2625 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002626 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002627 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00002628 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00002629 switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
2630 {
2631 case 1: mUsesAtan2_1 = true; break;
2632 case 2: mUsesAtan2_2 = true; break;
2633 case 3: mUsesAtan2_3 = true; break;
2634 case 4: mUsesAtan2_4 = true; break;
2635 default: UNREACHABLE();
2636 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +00002637 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002638 break;
2639 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
2640 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
2641 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
2642 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
2643 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
2644 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
2645 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
2646 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
2647 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002648 case EOpFaceForward:
2649 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00002650 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002651 {
2652 case 1: mUsesFaceforward1 = true; break;
2653 case 2: mUsesFaceforward2 = true; break;
2654 case 3: mUsesFaceforward3 = true; break;
2655 case 4: mUsesFaceforward4 = true; break;
2656 default: UNREACHABLE();
2657 }
2658
2659 outputTriplet(visit, "faceforward(", ", ", ")");
2660 }
2661 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002662 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
2663 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
2664 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002665 default: UNREACHABLE();
2666 }
2667
2668 return true;
2669}
2670
2671bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2672{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002673 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002674
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002675 if (node->usesTernaryOperator())
2676 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002677 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002678 }
2679 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002680 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002681 mUnfoldShortCircuit->traverse(node->getCondition());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002682
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002683 out << "if (";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002684
2685 node->getCondition()->traverse(this);
2686
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002687 out << ")\n";
2688
Jamie Madill075edd82013-07-08 13:30:19 -04002689 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002690 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002691
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002692 bool discard = false;
2693
daniel@transgaming.combb885322010-04-15 20:45:24 +00002694 if (node->getTrueBlock())
2695 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002696 traverseStatements(node->getTrueBlock());
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002697
2698 // Detect true discard
2699 discard = (discard || FindDiscard::search(node->getTrueBlock()));
daniel@transgaming.combb885322010-04-15 20:45:24 +00002700 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002701
Jamie Madill075edd82013-07-08 13:30:19 -04002702 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002703 out << ";\n}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002704
2705 if (node->getFalseBlock())
2706 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002707 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002708
Jamie Madill075edd82013-07-08 13:30:19 -04002709 outputLineDirective(node->getFalseBlock()->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002710 out << "{\n";
2711
Jamie Madill075edd82013-07-08 13:30:19 -04002712 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002713 traverseStatements(node->getFalseBlock());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002714
Jamie Madill075edd82013-07-08 13:30:19 -04002715 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002716 out << ";\n}\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002717
2718 // Detect false discard
2719 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2720 }
2721
2722 // ANGLE issue 486: Detect problematic conditional discard
2723 if (discard && FindSideEffectRewriting::search(node))
2724 {
2725 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002726 }
2727 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002728
2729 return false;
2730}
2731
2732void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2733{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002734 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002735}
2736
2737bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2738{
Nicolas Capens655fe362014-04-11 13:12:34 -04002739 mNestedLoopDepth++;
2740
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002741 bool wasDiscontinuous = mInsideDiscontinuousLoop;
2742
shannon.woods@transgaming.come91615c2013-01-25 21:56:03 +00002743 if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002744 {
2745 mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
2746 }
2747
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002748 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002749 {
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002750 if (handleExcessiveLoop(node))
2751 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002752 mInsideDiscontinuousLoop = wasDiscontinuous;
2753 mNestedLoopDepth--;
2754
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002755 return false;
2756 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002757 }
2758
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002759 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002760
alokp@chromium.org52813552010-11-16 18:36:09 +00002761 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002762 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002763 out << "{do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002764
Jamie Madill075edd82013-07-08 13:30:19 -04002765 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002766 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002767 }
2768 else
2769 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002770 out << "{for(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002771
2772 if (node->getInit())
2773 {
2774 node->getInit()->traverse(this);
2775 }
2776
2777 out << "; ";
2778
alokp@chromium.org52813552010-11-16 18:36:09 +00002779 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002780 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002781 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002782 }
2783
2784 out << "; ";
2785
alokp@chromium.org52813552010-11-16 18:36:09 +00002786 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002787 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002788 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002789 }
2790
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002791 out << ")\n";
2792
Jamie Madill075edd82013-07-08 13:30:19 -04002793 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002794 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002795 }
2796
2797 if (node->getBody())
2798 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002799 traverseStatements(node->getBody());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002800 }
2801
Jamie Madill075edd82013-07-08 13:30:19 -04002802 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00002803 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002804
alokp@chromium.org52813552010-11-16 18:36:09 +00002805 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002806 {
Jamie Madill075edd82013-07-08 13:30:19 -04002807 outputLineDirective(node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002808 out << "while(\n";
2809
alokp@chromium.org52813552010-11-16 18:36:09 +00002810 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002811
daniel@transgaming.com73536982012-03-21 20:45:49 +00002812 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002813 }
2814
daniel@transgaming.com73536982012-03-21 20:45:49 +00002815 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002816
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002817 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002818 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002819
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002820 return false;
2821}
2822
2823bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2824{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002825 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002826
2827 switch (node->getFlowOp())
2828 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002829 case EOpKill:
2830 outputTriplet(visit, "discard;\n", "", "");
2831 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002832 case EOpBreak:
2833 if (visit == PreVisit)
2834 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002835 if (mNestedLoopDepth > 1)
2836 {
2837 mUsesNestedBreak = true;
2838 }
2839
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002840 if (mExcessiveLoopIndex)
2841 {
2842 out << "{Break";
2843 mExcessiveLoopIndex->traverse(this);
2844 out << " = true; break;}\n";
2845 }
2846 else
2847 {
2848 out << "break;\n";
2849 }
2850 }
2851 break;
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00002852 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002853 case EOpReturn:
2854 if (visit == PreVisit)
2855 {
2856 if (node->getExpression())
2857 {
2858 out << "return ";
2859 }
2860 else
2861 {
2862 out << "return;\n";
2863 }
2864 }
2865 else if (visit == PostVisit)
2866 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002867 if (node->getExpression())
2868 {
2869 out << ";\n";
2870 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002871 }
2872 break;
2873 default: UNREACHABLE();
2874 }
2875
2876 return true;
2877}
2878
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002879void OutputHLSL::traverseStatements(TIntermNode *node)
2880{
2881 if (isSingleStatement(node))
2882 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002883 mUnfoldShortCircuit->traverse(node);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002884 }
2885
2886 node->traverse(this);
2887}
2888
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002889bool OutputHLSL::isSingleStatement(TIntermNode *node)
2890{
2891 TIntermAggregate *aggregate = node->getAsAggregate();
2892
2893 if (aggregate)
2894 {
2895 if (aggregate->getOp() == EOpSequence)
2896 {
2897 return false;
2898 }
2899 else
2900 {
2901 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
2902 {
2903 if (!isSingleStatement(*sit))
2904 {
2905 return false;
2906 }
2907 }
2908
2909 return true;
2910 }
2911 }
2912
2913 return true;
2914}
2915
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002916// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2917// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002918bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
2919{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002920 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002921 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002922
2923 // Parse loops of the form:
2924 // for(int index = initial; index [comparator] limit; index += increment)
2925 TIntermSymbol *index = NULL;
2926 TOperator comparator = EOpNull;
2927 int initial = 0;
2928 int limit = 0;
2929 int increment = 0;
2930
2931 // Parse index name and intial value
2932 if (node->getInit())
2933 {
2934 TIntermAggregate *init = node->getInit()->getAsAggregate();
2935
2936 if (init)
2937 {
2938 TIntermSequence &sequence = init->getSequence();
2939 TIntermTyped *variable = sequence[0]->getAsTyped();
2940
2941 if (variable && variable->getQualifier() == EvqTemporary)
2942 {
2943 TIntermBinary *assign = variable->getAsBinaryNode();
2944
2945 if (assign->getOp() == EOpInitialize)
2946 {
2947 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2948 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2949
2950 if (symbol && constant)
2951 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002952 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002953 {
2954 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002955 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002956 }
2957 }
2958 }
2959 }
2960 }
2961 }
2962
2963 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00002964 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002965 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002966 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002967
2968 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2969 {
2970 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2971
2972 if (constant)
2973 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002974 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002975 {
2976 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002977 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002978 }
2979 }
2980 }
2981 }
2982
2983 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00002984 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002985 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002986 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2987 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002988
2989 if (binaryTerminal)
2990 {
2991 TOperator op = binaryTerminal->getOp();
2992 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2993
2994 if (constant)
2995 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002996 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002997 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00002998 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002999
3000 switch (op)
3001 {
3002 case EOpAddAssign: increment = value; break;
3003 case EOpSubAssign: increment = -value; break;
3004 default: UNIMPLEMENTED();
3005 }
3006 }
3007 }
3008 }
3009 else if (unaryTerminal)
3010 {
3011 TOperator op = unaryTerminal->getOp();
3012
3013 switch (op)
3014 {
3015 case EOpPostIncrement: increment = 1; break;
3016 case EOpPostDecrement: increment = -1; break;
3017 case EOpPreIncrement: increment = 1; break;
3018 case EOpPreDecrement: increment = -1; break;
3019 default: UNIMPLEMENTED();
3020 }
3021 }
3022 }
3023
3024 if (index != NULL && comparator != EOpNull && increment != 0)
3025 {
3026 if (comparator == EOpLessThanEqual)
3027 {
3028 comparator = EOpLessThan;
3029 limit += 1;
3030 }
3031
3032 if (comparator == EOpLessThan)
3033 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00003034 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003035
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003036 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003037 {
3038 return false; // Not an excessive loop
3039 }
3040
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003041 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
3042 mExcessiveLoopIndex = index;
3043
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003044 out << "{int ";
3045 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003046 out << ";\n"
3047 "bool Break";
3048 index->traverse(this);
3049 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003050
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003051 bool firstLoopFragment = true;
3052
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003053 while (iterations > 0)
3054 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003055 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003056
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003057 if (!firstLoopFragment)
3058 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05003059 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003060 index->traverse(this);
3061 out << ") {\n";
3062 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00003063
3064 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
3065 {
3066 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
3067 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003068
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003069 // for(int index = initial; index < clampedLimit; index += increment)
3070
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003071 out << "for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003072 index->traverse(this);
3073 out << " = ";
3074 out << initial;
3075
3076 out << "; ";
3077 index->traverse(this);
3078 out << " < ";
3079 out << clampedLimit;
3080
3081 out << "; ";
3082 index->traverse(this);
3083 out << " += ";
3084 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003085 out << ")\n";
3086
Jamie Madill075edd82013-07-08 13:30:19 -04003087 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003088 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003089
3090 if (node->getBody())
3091 {
3092 node->getBody()->traverse(this);
3093 }
3094
Jamie Madill075edd82013-07-08 13:30:19 -04003095 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003096 out << ";}\n";
3097
3098 if (!firstLoopFragment)
3099 {
3100 out << "}\n";
3101 }
3102
3103 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003104
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003105 initial += MAX_LOOP_ITERATIONS * increment;
3106 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003107 }
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003108
3109 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003110
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003111 mExcessiveLoopIndex = restoreIndex;
3112
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003113 return true;
3114 }
3115 else UNIMPLEMENTED();
3116 }
3117
3118 return false; // Not handled as an excessive loop
3119}
3120
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003121void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003122{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00003123 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003124
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003125 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003126 {
3127 out << preString;
3128 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003129 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003130 {
3131 out << inString;
3132 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003133 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003134 {
3135 out << postString;
3136 }
3137}
3138
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003139void OutputHLSL::outputLineDirective(int line)
3140{
3141 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
3142 {
baustin@google.com8ab69842011-06-02 21:53:45 +00003143 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003144 mBody << "#line " << line;
3145
3146 if (mContext.sourcePath)
3147 {
3148 mBody << " \"" << mContext.sourcePath << "\"";
3149 }
3150
3151 mBody << "\n";
3152 }
3153}
3154
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003155TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
3156{
3157 TQualifier qualifier = symbol->getQualifier();
3158 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003159 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003160
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003161 if (name.empty()) // HLSL demands named arguments, also for prototypes
3162 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00003163 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003164 }
3165 else
3166 {
Jamie Madill033dae62014-06-18 12:56:28 -04003167 name = Decorate(name);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003168 }
3169
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003170 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
3171 {
Jamie Madill033dae62014-06-18 12:56:28 -04003172 return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + name + ArrayString(type) + ", " +
3173 QualifierString(qualifier) + " " + SamplerString(type) + " sampler_" + name + ArrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003174 }
3175
Jamie Madill033dae62014-06-18 12:56:28 -04003176 return QualifierString(qualifier) + " " + TypeString(type) + " " + name + ArrayString(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003177}
3178
3179TString OutputHLSL::initializer(const TType &type)
3180{
3181 TString string;
3182
Jamie Madill94bf7f22013-07-08 13:31:15 -04003183 size_t size = type.getObjectSize();
3184 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003185 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00003186 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003187
Jamie Madill94bf7f22013-07-08 13:31:15 -04003188 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003189 {
3190 string += ", ";
3191 }
3192 }
3193
daniel@transgaming.comead23042010-04-29 03:35:36 +00003194 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003195}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003196
Jamie Madill033dae62014-06-18 12:56:28 -04003197TString OutputHLSL::defineNamelessStruct(const TStructure &structure)
3198{
3199 return defineStruct(structure, false, false, NULL);
3200}
3201
3202TString OutputHLSL::defineQualifiedStruct(const TStructure &structure, bool useHLSLRowMajorPacking,
3203 bool useStd140Packing)
3204{
3205 if (useStd140Packing)
3206 {
3207 Std140PaddingHelper padHelper(mStd140StructElementIndexes);
3208 return defineStruct(structure, useHLSLRowMajorPacking, true, &padHelper);
3209 }
3210 else
3211 {
3212 return defineStruct(structure, useHLSLRowMajorPacking, false, NULL);
3213 }
3214}
3215
3216TString OutputHLSL::defineStruct(const TStructure &structure, bool useHLSLRowMajorPacking,
3217 bool useStd140Packing, Std140PaddingHelper *padHelper)
Jamie Madill9cf6c072013-06-20 11:55:53 -04003218{
Jamie Madill98493dd2013-07-08 14:39:03 -04003219 const TFieldList &fields = structure.fields();
3220 const bool isNameless = (structure.name() == "");
Jamie Madill033dae62014-06-18 12:56:28 -04003221 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
Jamie Madill9cf6c072013-06-20 11:55:53 -04003222 const TString declareString = (isNameless ? "struct" : "struct " + structName);
3223
Jamie Madill98493dd2013-07-08 14:39:03 -04003224 TString string;
3225 string += declareString + "\n"
3226 "{\n";
Jamie Madill9cf6c072013-06-20 11:55:53 -04003227
3228 for (unsigned int i = 0; i < fields.size(); i++)
3229 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003230 const TField &field = *fields[i];
3231 const TType &fieldType = *field.type();
3232 const TStructure *fieldStruct = fieldType.getStruct();
Jamie Madill3891fd22014-06-13 10:04:30 -04003233 const TString &fieldTypeString = fieldStruct ?
Jamie Madill033dae62014-06-18 12:56:28 -04003234 QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
3235 useStd140Packing) :
3236 TypeString(fieldType);
Jamie Madill9cf6c072013-06-20 11:55:53 -04003237
Jamie Madill033dae62014-06-18 12:56:28 -04003238 if (padHelper)
Jamie Madillc835df62013-06-21 09:15:32 -04003239 {
Jamie Madill033dae62014-06-18 12:56:28 -04003240 string += padHelper->prePaddingString(fieldType);
Jamie Madillc835df62013-06-21 09:15:32 -04003241 }
3242
Jamie Madill033dae62014-06-18 12:56:28 -04003243 string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
Jamie Madillc835df62013-06-21 09:15:32 -04003244
Jamie Madill033dae62014-06-18 12:56:28 -04003245 if (padHelper)
Jamie Madillc835df62013-06-21 09:15:32 -04003246 {
Jamie Madill033dae62014-06-18 12:56:28 -04003247 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
Jamie Madillc835df62013-06-21 09:15:32 -04003248 }
Jamie Madill9cf6c072013-06-20 11:55:53 -04003249 }
3250
3251 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
Jamie Madill98493dd2013-07-08 14:39:03 -04003252 string += (isNameless ? "} " : "};\n");
Jamie Madill9cf6c072013-06-20 11:55:53 -04003253
Jamie Madill98493dd2013-07-08 14:39:03 -04003254 return string;
Jamie Madill9cf6c072013-06-20 11:55:53 -04003255}
3256
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003257void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters)
3258{
3259 TInfoSinkBase &out = mBody;
3260
3261 if (visit == PreVisit)
3262 {
3263 addConstructor(type, name, parameters);
3264
3265 out << name + "(";
3266 }
3267 else if (visit == InVisit)
3268 {
3269 out << ", ";
3270 }
3271 else if (visit == PostVisit)
3272 {
3273 out << ")";
3274 }
3275}
3276
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003277void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00003278{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003279 if (name == "")
3280 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00003281 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003282 }
3283
Jamie Madill96509e42014-05-29 14:33:27 -04003284 if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
daniel@transgaming.com43eecdc2012-03-20 20:10:33 +00003285 {
3286 return; // Already added
3287 }
3288
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003289 TType ctorType = type;
3290 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00003291 ctorType.setPrecision(EbpHigh);
3292 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00003293
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003294 typedef std::vector<TType> ParameterArray;
3295 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00003296
Jamie Madill98493dd2013-07-08 14:39:03 -04003297 const TStructure* structure = type.getStruct();
3298 if (structure)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003299 {
Jamie Madill96509e42014-05-29 14:33:27 -04003300 mStructNames.insert(name);
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003301
Jamie Madill80ebce52014-06-06 11:54:12 -04003302 // Add element index
3303 storeStd140ElementIndex(*structure, false);
3304 storeStd140ElementIndex(*structure, true);
3305
Jamie Madill033dae62014-06-18 12:56:28 -04003306 const TString &structString = defineQualifiedStruct(*structure, false, false);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003307
Jamie Madill98493dd2013-07-08 14:39:03 -04003308 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003309 {
Jamie Madill9cf6c072013-06-20 11:55:53 -04003310 // Add row-major packed struct for interface blocks
3311 TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
Jamie Madill033dae62014-06-18 12:56:28 -04003312 defineQualifiedStruct(*structure, true, false) +
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00003313 "#pragma pack_matrix(column_major)\n";
3314
Jamie Madill033dae62014-06-18 12:56:28 -04003315 TString std140String = defineQualifiedStruct(*structure, false, true);
Jamie Madillc835df62013-06-21 09:15:32 -04003316 TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
Jamie Madill033dae62014-06-18 12:56:28 -04003317 defineQualifiedStruct(*structure, true, true) +
Jamie Madillc835df62013-06-21 09:15:32 -04003318 "#pragma pack_matrix(column_major)\n";
3319
Jamie Madill98493dd2013-07-08 14:39:03 -04003320 mStructDeclarations.push_back(structString);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00003321 mStructDeclarations.push_back(rowMajorString);
Jamie Madillc835df62013-06-21 09:15:32 -04003322 mStructDeclarations.push_back(std140String);
3323 mStructDeclarations.push_back(std140RowMajorString);
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003324 }
3325
Jamie Madill98493dd2013-07-08 14:39:03 -04003326 const TFieldList &fields = structure->fields();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003327 for (unsigned int i = 0; i < fields.size(); i++)
3328 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003329 ctorParameters.push_back(*fields[i]->type());
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003330 }
3331 }
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00003332 else if (parameters)
3333 {
3334 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
3335 {
3336 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
3337 }
3338 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003339 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00003340
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003341 TString constructor;
3342
3343 if (ctorType.getStruct())
3344 {
Jamie Madill96509e42014-05-29 14:33:27 -04003345 constructor += name + " " + name + "_ctor(";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003346 }
3347 else // Built-in type
3348 {
Jamie Madill033dae62014-06-18 12:56:28 -04003349 constructor += TypeString(ctorType) + " " + name + "(";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003350 }
3351
3352 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
3353 {
3354 const TType &type = ctorParameters[parameter];
3355
Jamie Madill033dae62014-06-18 12:56:28 -04003356 constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003357
3358 if (parameter < ctorParameters.size() - 1)
3359 {
3360 constructor += ", ";
3361 }
3362 }
3363
3364 constructor += ")\n"
3365 "{\n";
3366
3367 if (ctorType.getStruct())
3368 {
Jamie Madill96509e42014-05-29 14:33:27 -04003369 constructor += " " + name + " structure = {";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003370 }
3371 else
3372 {
Jamie Madill033dae62014-06-18 12:56:28 -04003373 constructor += " return " + TypeString(ctorType) + "(";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003374 }
3375
3376 if (ctorType.isMatrix() && ctorParameters.size() == 1)
3377 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003378 int rows = ctorType.getRows();
3379 int cols = ctorType.getCols();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003380 const TType &parameter = ctorParameters[0];
3381
3382 if (parameter.isScalar())
3383 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003384 for (int row = 0; row < rows; row++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003385 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003386 for (int col = 0; col < cols; col++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003387 {
3388 constructor += TString((row == col) ? "x0" : "0.0");
3389
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003390 if (row < rows - 1 || col < cols - 1)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003391 {
3392 constructor += ", ";
3393 }
3394 }
3395 }
3396 }
3397 else if (parameter.isMatrix())
3398 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003399 for (int row = 0; row < rows; row++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003400 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003401 for (int col = 0; col < cols; col++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003402 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003403 if (row < parameter.getRows() && col < parameter.getCols())
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003404 {
Nicolas Capens1af18dc2014-06-11 11:07:32 -04003405 constructor += TString("x0") + "[" + str(row) + "][" + str(col) + "]";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003406 }
3407 else
3408 {
3409 constructor += TString((row == col) ? "1.0" : "0.0");
3410 }
3411
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003412 if (row < rows - 1 || col < cols - 1)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003413 {
3414 constructor += ", ";
3415 }
3416 }
3417 }
3418 }
Nicolas Capens2a592922014-06-11 16:22:57 -04003419 else
3420 {
3421 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
3422
3423 constructor += "x0";
3424 }
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003425 }
3426 else
3427 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003428 size_t remainingComponents = ctorType.getObjectSize();
3429 size_t parameterIndex = 0;
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003430
3431 while (remainingComponents > 0)
3432 {
3433 const TType &parameter = ctorParameters[parameterIndex];
Jamie Madill94bf7f22013-07-08 13:31:15 -04003434 const size_t parameterSize = parameter.getObjectSize();
3435 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003436
3437 constructor += "x" + str(parameterIndex);
3438
Nicolas Capensf7f76162014-06-06 15:48:21 -04003439 if (ctorType.getStruct())
3440 {
3441 ASSERT(remainingComponents == parameterSize || moreParameters);
3442 ASSERT(parameterSize <= remainingComponents);
3443
3444 remainingComponents -= parameterSize;
3445 }
3446 else if (parameter.isScalar())
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003447 {
3448 remainingComponents -= parameter.getObjectSize();
3449 }
3450 else if (parameter.isVector())
3451 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003452 if (remainingComponents == parameterSize || moreParameters)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003453 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003454 ASSERT(parameterSize <= remainingComponents);
3455 remainingComponents -= parameterSize;
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003456 }
Jamie Madill94bf7f22013-07-08 13:31:15 -04003457 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003458 {
3459 switch (remainingComponents)
3460 {
3461 case 1: constructor += ".x"; break;
3462 case 2: constructor += ".xy"; break;
3463 case 3: constructor += ".xyz"; break;
3464 case 4: constructor += ".xyzw"; break;
3465 default: UNREACHABLE();
3466 }
3467
3468 remainingComponents = 0;
3469 }
3470 else UNREACHABLE();
3471 }
Nicolas Capensf7f76162014-06-06 15:48:21 -04003472 else if (parameter.isMatrix())
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003473 {
Nicolas Capensf7f76162014-06-06 15:48:21 -04003474 int column = 0;
3475 while (remainingComponents > 0 && column < parameter.getCols())
3476 {
3477 constructor += "[" + str(column) + "]";
3478
3479 if (remainingComponents < static_cast<size_t>(parameter.getRows()))
3480 {
3481 switch (remainingComponents)
3482 {
3483 case 1: constructor += ".x"; break;
3484 case 2: constructor += ".xy"; break;
3485 case 3: constructor += ".xyz"; break;
3486 default: UNREACHABLE();
3487 }
3488
3489 remainingComponents = 0;
3490 }
3491 else
3492 {
3493 remainingComponents -= parameter.getRows();
3494
3495 if (remainingComponents > 0)
3496 {
3497 constructor += ", x" + str(parameterIndex);
3498 }
3499 }
3500
3501 column++;
3502 }
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003503 }
3504 else UNREACHABLE();
3505
3506 if (moreParameters)
3507 {
3508 parameterIndex++;
3509 }
3510
3511 if (remainingComponents)
3512 {
3513 constructor += ", ";
3514 }
3515 }
3516 }
3517
3518 if (ctorType.getStruct())
3519 {
3520 constructor += "};\n"
3521 " return structure;\n"
3522 "}\n";
3523 }
3524 else
3525 {
3526 constructor += ");\n"
3527 "}\n";
3528 }
3529
daniel@transgaming.com63691862010-04-29 03:32:42 +00003530 mConstructors.insert(constructor);
3531}
3532
Jamie Madill80ebce52014-06-06 11:54:12 -04003533void OutputHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
3534{
Jamie Madill3891fd22014-06-13 10:04:30 -04003535 Std140PaddingHelper padHelper(mStd140StructElementIndexes);
Jamie Madill80ebce52014-06-06 11:54:12 -04003536 const TFieldList &fields = structure.fields();
3537
3538 for (unsigned int i = 0; i < fields.size(); i++)
3539 {
Jamie Madill3891fd22014-06-13 10:04:30 -04003540 padHelper.prePadding(*fields[i]->type());
Jamie Madill80ebce52014-06-06 11:54:12 -04003541 }
3542
3543 // Add remaining element index to the global map, for use with nested structs in standard layouts
Jamie Madill033dae62014-06-18 12:56:28 -04003544 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
Jamie Madill3891fd22014-06-13 10:04:30 -04003545 mStd140StructElementIndexes[structName] = padHelper.elementIndex();
Jamie Madill80ebce52014-06-06 11:54:12 -04003546}
3547
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003548const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
3549{
3550 TInfoSinkBase &out = mBody;
3551
Jamie Madill98493dd2013-07-08 14:39:03 -04003552 const TStructure* structure = type.getStruct();
3553 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003554 {
Jamie Madill033dae62014-06-18 12:56:28 -04003555 out << StructNameString(*structure) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003556
Jamie Madill98493dd2013-07-08 14:39:03 -04003557 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003558
Jamie Madill98493dd2013-07-08 14:39:03 -04003559 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003560 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003561 const TType *fieldType = fields[i]->type();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003562
3563 constUnion = writeConstantUnion(*fieldType, constUnion);
3564
Jamie Madill98493dd2013-07-08 14:39:03 -04003565 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003566 {
3567 out << ", ";
3568 }
3569 }
3570
3571 out << ")";
3572 }
3573 else
3574 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003575 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003576 bool writeType = size > 1;
3577
3578 if (writeType)
3579 {
Jamie Madill033dae62014-06-18 12:56:28 -04003580 out << TypeString(type) << "(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003581 }
3582
Jamie Madill94bf7f22013-07-08 13:31:15 -04003583 for (size_t i = 0; i < size; i++, constUnion++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003584 {
3585 switch (constUnion->getType())
3586 {
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +00003587 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003588 case EbtInt: out << constUnion->getIConst(); break;
Nicolas Capensc0f7c612013-06-05 11:46:09 -04003589 case EbtUInt: out << constUnion->getUConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00003590 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003591 default: UNREACHABLE();
3592 }
3593
3594 if (i != size - 1)
3595 {
3596 out << ", ";
3597 }
3598 }
3599
3600 if (writeType)
3601 {
3602 out << ")";
3603 }
3604 }
3605
3606 return constUnion;
3607}
3608
Jamie Madill834e8b72014-04-11 13:33:58 -04003609void OutputHLSL::declareInterfaceBlockField(const TType &type, const TString &name, std::vector<gl::InterfaceBlockField>& output)
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003610{
Jamie Madill98493dd2013-07-08 14:39:03 -04003611 const TStructure *structure = type.getStruct();
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003612
3613 if (!structure)
3614 {
Jamie Madill010fffa2013-06-20 11:55:53 -04003615 const bool isRowMajorMatrix = (type.isMatrix() && type.getLayoutQualifier().matrixPacking == EmpRowMajor);
Jamie Madill033dae62014-06-18 12:56:28 -04003616 gl::InterfaceBlockField field(GLVariableType(type), GLVariablePrecision(type), name.c_str(),
Jamie Madill834e8b72014-04-11 13:33:58 -04003617 (unsigned int)type.getArraySize(), isRowMajorMatrix);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003618 output.push_back(field);
3619 }
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003620 else
3621 {
Jamie Madill834e8b72014-04-11 13:33:58 -04003622 gl::InterfaceBlockField structField(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), false);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003623
3624 const TFieldList &fields = structure->fields();
3625
3626 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
3627 {
3628 TField *field = fields[fieldIndex];
3629 TType *fieldType = field->type();
3630
3631 // make sure to copy matrix packing information
3632 fieldType->setLayoutQualifier(type.getLayoutQualifier());
3633
3634 declareInterfaceBlockField(*fieldType, field->name(), structField.fields);
3635 }
3636
3637 output.push_back(structField);
3638 }
3639}
3640
Jamie Madill834e8b72014-04-11 13:33:58 -04003641gl::Uniform OutputHLSL::declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<gl::Uniform>& output)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003642{
3643 const TStructure *structure = type.getStruct();
3644
3645 if (!structure)
3646 {
Jamie Madill033dae62014-06-18 12:56:28 -04003647 gl::Uniform uniform(GLVariableType(type), GLVariablePrecision(type), name.c_str(),
Jamie Madill834e8b72014-04-11 13:33:58 -04003648 (unsigned int)type.getArraySize(), (unsigned int)registerIndex, 0);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003649 output.push_back(uniform);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003650
3651 return uniform;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003652 }
3653 else
3654 {
Jamie Madill834e8b72014-04-11 13:33:58 -04003655 gl::Uniform structUniform(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(),
3656 (unsigned int)registerIndex, GL_INVALID_INDEX);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003657
Jamie Madill98493dd2013-07-08 14:39:03 -04003658 const TFieldList &fields = structure->fields();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003659
Jamie Madill98493dd2013-07-08 14:39:03 -04003660 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003661 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003662 TField *field = fields[fieldIndex];
3663 TType *fieldType = field->type();
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003664
Jamie Madill56093782013-08-30 13:21:11 -04003665 declareUniformToList(*fieldType, field->name(), GL_INVALID_INDEX, structUniform.fields);
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003666 }
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003667
Jamie Madill56093782013-08-30 13:21:11 -04003668 // assign register offset information -- this will override the information in any sub-structures.
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -04003669 HLSLVariableGetRegisterInfo(registerIndex, &structUniform, mOutputType);
Jamie Madill56093782013-08-30 13:21:11 -04003670
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003671 output.push_back(structUniform);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003672
3673 return structUniform;
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003674 }
3675}
3676
Jamie Madill834e8b72014-04-11 13:33:58 -04003677void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<gl::Varying>& fieldsOut)
Jamie Madill47fdd132013-08-30 13:21:04 -04003678{
3679 const TStructure *structure = type.getStruct();
3680
Jamie Madill033dae62014-06-18 12:56:28 -04003681 gl::InterpolationType interpolation = GetInterpolationType(baseTypeQualifier);
Jamie Madill47fdd132013-08-30 13:21:04 -04003682 if (!structure)
3683 {
Jamie Madill033dae62014-06-18 12:56:28 -04003684 gl::Varying varying(GLVariableType(type), GLVariablePrecision(type), name.c_str(), (unsigned int)type.getArraySize(), interpolation);
Jamie Madill47fdd132013-08-30 13:21:04 -04003685 fieldsOut.push_back(varying);
3686 }
3687 else
3688 {
Jamie Madill834e8b72014-04-11 13:33:58 -04003689 gl::Varying structVarying(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), interpolation);
Jamie Madill47fdd132013-08-30 13:21:04 -04003690 const TFieldList &fields = structure->fields();
3691
Jamie Madill28167c62013-08-30 13:21:10 -04003692 structVarying.structName = structure->name().c_str();
3693
Jamie Madill47fdd132013-08-30 13:21:04 -04003694 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
3695 {
3696 const TField &field = *fields[fieldIndex];
Jamie Madill94599662013-08-30 13:21:10 -04003697 declareVaryingToList(*field.type(), baseTypeQualifier, field.name(), structVarying.fields);
Jamie Madill47fdd132013-08-30 13:21:04 -04003698 }
3699
3700 fieldsOut.push_back(structVarying);
3701 }
3702}
3703
Jamie Madillc2141fb2013-08-30 13:21:08 -04003704int OutputHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003705{
Jamie Madillc2141fb2013-08-30 13:21:08 -04003706 int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
3707
Jamie Madill834e8b72014-04-11 13:33:58 -04003708 const gl::Uniform &uniform = declareUniformToList(type, name, registerIndex, mActiveUniforms);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003709
3710 if (IsSampler(type.getBasicType()))
3711 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -04003712 mSamplerRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003713 }
3714 else
3715 {
Vladimir Vukicevic24d8d672014-05-27 12:07:51 -04003716 mUniformRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003717 }
3718
3719 return registerIndex;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003720}
3721
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003722}