blob: b05e6b6b2185c883dca7b9fd8ccf3ed36ae52b01 [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"
Geoff Lang17732822013-08-29 13:46:49 -040011#include "compiler/translator/compilerdebug.h"
12#include "compiler/translator/InfoSink.h"
13#include "compiler/translator/DetectDiscontinuity.h"
14#include "compiler/translator/SearchSymbol.h"
15#include "compiler/translator/UnfoldShortCircuit.h"
16#include "compiler/translator/HLSLLayoutEncoder.h"
17#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"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000021#include <algorithm>
shannon.woods@transgaming.comfff89b32013-02-28 23:20:15 +000022#include <cfloat>
23#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025namespace sh
26{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000027
Nicolas Capense0ba27a2013-06-24 16:10:52 -040028TString OutputHLSL::TextureFunction::name() const
29{
30 TString name = "gl_texture";
31
Nicolas Capens6d232bb2013-07-08 15:56:38 -040032 if (IsSampler2D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040033 {
34 name += "2D";
35 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040036 else if (IsSampler3D(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040037 {
38 name += "3D";
39 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -040040 else if (IsSamplerCube(sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -040041 {
42 name += "Cube";
43 }
44 else UNREACHABLE();
45
46 if (proj)
47 {
48 name += "Proj";
49 }
50
Nicolas Capensb1f45b72013-12-19 17:37:19 -050051 if (offset)
52 {
53 name += "Offset";
54 }
55
Nicolas Capens75fb4752013-07-10 15:14:47 -040056 switch(method)
Nicolas Capense0ba27a2013-06-24 16:10:52 -040057 {
Nicolas Capensfc014542014-02-18 14:47:13 -050058 case IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -040059 case BIAS: break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -050060 case LOD: name += "Lod"; break;
61 case LOD0: name += "Lod0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -040062 case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique
Nicolas Capensfc014542014-02-18 14:47:13 -050063 case SIZE: name += "Size"; break;
64 case FETCH: name += "Fetch"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -050065 case GRAD: name += "Grad"; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -040066 default: UNREACHABLE();
67 }
68
69 return name + "(";
70}
71
Jamie Madillc2141fb2013-08-30 13:21:08 -040072const char *RegisterPrefix(const TType &type)
73{
74 if (IsSampler(type.getBasicType()))
75 {
76 return "s";
77 }
78 else
79 {
80 return "c";
81 }
82}
83
Nicolas Capense0ba27a2013-06-24 16:10:52 -040084bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
85{
86 if (sampler < rhs.sampler) return true;
87 if (coords < rhs.coords) return true;
88 if (!proj && rhs.proj) return true;
Nicolas Capens75fb4752013-07-10 15:14:47 -040089 if (method < rhs.method) return true;
Nicolas Capense0ba27a2013-06-24 16:10:52 -040090
91 return false;
92}
93
shannon.woods%transgaming.com@gtempaccount.com18b4c4b2013-04-13 03:31:40 +000094OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +000095 : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +000097 mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000098 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000099
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000100 mUsesFragColor = false;
101 mUsesFragData = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000102 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000103 mUsesFragCoord = false;
104 mUsesPointCoord = false;
105 mUsesFrontFacing = false;
106 mUsesPointSize = false;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400107 mUsesFragDepth = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000108 mUsesXor = false;
109 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000110 mUsesMod2v = false;
111 mUsesMod2f = false;
112 mUsesMod3v = false;
113 mUsesMod3f = false;
114 mUsesMod4v = false;
115 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000116 mUsesFaceforward1 = false;
117 mUsesFaceforward2 = false;
118 mUsesFaceforward3 = false;
119 mUsesFaceforward4 = false;
daniel@transgaming.com35342dc2012-02-28 02:01:22 +0000120 mUsesAtan2_1 = false;
121 mUsesAtan2_2 = false;
122 mUsesAtan2_3 = false;
123 mUsesAtan2_4 = false;
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500124 mUsesDiscardRewriting = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400125 mUsesNestedBreak = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000126
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000127 mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
128
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000129 mScopeDepth = 0;
130
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000131 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000132
133 mContainsLoopDiscontinuity = false;
134 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +0000135 mInsideDiscontinuousLoop = false;
Nicolas Capens655fe362014-04-11 13:12:34 -0400136 mNestedLoopDepth = 0;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +0000137
138 mExcessiveLoopIndex = NULL;
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000139
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000140 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000141 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000142 if (mContext.shaderType == SH_FRAGMENT_SHADER)
143 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000144 mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000145 }
146 else
147 {
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +0000148 mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000149 }
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000150 }
151 else
152 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000153 mUniformRegister = 0;
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +0000154 }
155
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000156 mSamplerRegister = 0;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000157 mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants
Jamie Madill574d9dd2013-06-20 11:55:56 -0400158 mPaddingCounter = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159}
160
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000161OutputHLSL::~OutputHLSL()
162{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +0000163 delete mUnfoldShortCircuit;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000164}
165
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000166void OutputHLSL::output()
167{
shannon.woods@transgaming.come91615c2013-01-25 21:56:03 +0000168 mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
Jamie Madill570e04d2013-06-21 09:15:33 -0400169 const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
170 makeFlaggedStructMaps(flaggedStructs);
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000171
Jamie Madille53c98b2014-02-03 11:57:13 -0500172 // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
173 // use a vertex attribute as a condition, and some related computation in the else block.
174 if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER)
175 {
176 RewriteElseBlocks(mContext.treeRoot);
177 }
178
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000179 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 +0000180 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000181
alokp@chromium.org646ea1e2012-06-15 17:36:31 +0000182 mContext.infoSink().obj << mHeader.c_str();
183 mContext.infoSink().obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000184}
185
Jamie Madill570e04d2013-06-21 09:15:33 -0400186void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
187{
188 for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
189 {
190 TIntermTyped *flaggedNode = flaggedStructs[structIndex];
191
192 // This will mark the necessary block elements as referenced
193 flaggedNode->traverse(this);
194 TString structName(mBody.c_str());
195 mBody.erase();
196
197 mFlaggedStructOriginalNames[flaggedNode] = structName;
198
199 for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
200 {
201 structName.erase(pos, 1);
202 }
203
204 mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
205 }
206}
207
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000208TInfoSinkBase &OutputHLSL::getBodyStream()
209{
210 return mBody;
211}
212
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400213const std::vector<Uniform> &OutputHLSL::getUniforms()
daniel@transgaming.com043da132012-12-20 21:12:22 +0000214{
215 return mActiveUniforms;
216}
217
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000218const ActiveInterfaceBlocks &OutputHLSL::getInterfaceBlocks() const
219{
220 return mActiveInterfaceBlocks;
221}
222
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400223const std::vector<Attribute> &OutputHLSL::getOutputVariables() const
Jamie Madill46131a32013-06-20 11:55:50 -0400224{
225 return mActiveOutputVariables;
226}
227
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400228const std::vector<Attribute> &OutputHLSL::getAttributes() const
Jamie Madilldefb6742013-06-20 11:55:51 -0400229{
230 return mActiveAttributes;
231}
232
Jamie Madill47fdd132013-08-30 13:21:04 -0400233const std::vector<Varying> &OutputHLSL::getVaryings() const
234{
235 return mActiveVaryings;
236}
237
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000238int OutputHLSL::vectorSize(const TType &type) const
239{
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000240 int elementSize = type.isMatrix() ? type.getCols() : 1;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000241 int arraySize = type.isArray() ? type.getArraySize() : 1;
242
243 return elementSize * arraySize;
244}
245
Jamie Madill98493dd2013-07-08 14:39:03 -0400246TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field)
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000247{
Jamie Madill98493dd2013-07-08 14:39:03 -0400248 if (interfaceBlock.hasInstanceName())
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000249 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400250 return interfaceBlock.name() + "." + field.name();
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000251 }
252 else
253 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400254 return field.name();
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000255 }
256}
257
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000258TString OutputHLSL::decoratePrivate(const TString &privateText)
259{
260 return "dx_" + privateText;
261}
262
Jamie Madill98493dd2013-07-08 14:39:03 -0400263TString OutputHLSL::interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlock)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000264{
Jamie Madill98493dd2013-07-08 14:39:03 -0400265 return decoratePrivate(interfaceBlock.name()) + "_type";
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000266}
267
Jamie Madill98493dd2013-07-08 14:39:03 -0400268TString OutputHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000269{
Jamie Madill98493dd2013-07-08 14:39:03 -0400270 if (!interfaceBlock.hasInstanceName())
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000271 {
272 return "";
273 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400274 else if (interfaceBlock.isArray())
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000275 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400276 return decoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000277 }
278 else
279 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400280 return decorate(interfaceBlock.instanceName());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000281 }
282}
283
Jamie Madill98493dd2013-07-08 14:39:03 -0400284TString OutputHLSL::interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000285{
Jamie Madill98493dd2013-07-08 14:39:03 -0400286 const TType &fieldType = *field.type();
287 const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
Jamie Madill529077d2013-06-20 11:55:54 -0400288 ASSERT(matrixPacking != EmpUnspecified);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000289
Jamie Madill98493dd2013-07-08 14:39:03 -0400290 if (fieldType.isMatrix())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000291 {
Jamie Madill9cf6c072013-06-20 11:55:53 -0400292 // Use HLSL row-major packing for GLSL column-major matrices
Jamie Madill529077d2013-06-20 11:55:54 -0400293 const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
Jamie Madill98493dd2013-07-08 14:39:03 -0400294 return matrixPackString + " " + typeString(fieldType);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000295 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400296 else if (fieldType.getStruct())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000297 {
Jamie Madill9cf6c072013-06-20 11:55:53 -0400298 // Use HLSL row-major packing for GLSL column-major matrices
Jamie Madill98493dd2013-07-08 14:39:03 -0400299 return structureTypeName(*fieldType.getStruct(), matrixPacking == EmpColumnMajor, blockStorage == EbsStd140);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000300 }
301 else
302 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400303 return typeString(fieldType);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +0000304 }
305}
306
Jamie Madill98493dd2013-07-08 14:39:03 -0400307TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
308{
309 TString hlsl;
310
311 int elementIndex = 0;
312
313 for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
314 {
315 const TField &field = *interfaceBlock.fields()[typeIndex];
316 const TType &fieldType = *field.type();
317
318 if (blockStorage == EbsStd140)
319 {
320 // 2 and 3 component vector types in some cases need pre-padding
321 hlsl += std140PrePaddingString(fieldType, &elementIndex);
322 }
323
324 hlsl += " " + interfaceBlockFieldTypeString(field, blockStorage) +
325 " " + decorate(field.name()) + arrayString(fieldType) + ";\n";
326
327 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
328 if (blockStorage == EbsStd140)
329 {
330 const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
331 hlsl += std140PostPaddingString(fieldType, useHLSLRowMajorPacking);
332 }
333 }
334
335 return hlsl;
336}
337
338TString OutputHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
339{
340 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
341
342 return "struct " + interfaceBlockStructNameString(interfaceBlock) + "\n"
343 "{\n" +
344 interfaceBlockFieldString(interfaceBlock, blockStorage) +
345 "};\n\n";
346}
347
348TString OutputHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
349{
350 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? decorate(str(arrayIndex)) : "");
351 const TString &blockName = interfaceBlock.name() + arrayIndexString;
352 TString hlsl;
353
354 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
355 "{\n";
356
357 if (interfaceBlock.hasInstanceName())
358 {
359 hlsl += " " + interfaceBlockStructNameString(interfaceBlock) + " " + interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
360 }
361 else
362 {
363 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
364 hlsl += interfaceBlockFieldString(interfaceBlock, blockStorage);
365 }
366
367 hlsl += "};\n\n";
368
369 return hlsl;
370}
371
Jamie Madill574d9dd2013-06-20 11:55:56 -0400372TString OutputHLSL::std140PrePaddingString(const TType &type, int *elementIndex)
373{
374 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
375 {
376 // no padding needed, HLSL will align the field to a new register
377 *elementIndex = 0;
378 return "";
379 }
380
381 const GLenum glType = glVariableType(type);
382 const int numComponents = gl::UniformComponentCount(glType);
383
384 if (numComponents >= 4)
385 {
386 // no padding needed, HLSL will align the field to a new register
387 *elementIndex = 0;
388 return "";
389 }
390
391 if (*elementIndex + numComponents > 4)
392 {
393 // no padding needed, HLSL will align the field to a new register
394 *elementIndex = numComponents;
395 return "";
396 }
397
398 TString padding;
399
400 const int alignment = numComponents == 3 ? 4 : numComponents;
401 const int paddingOffset = (*elementIndex % alignment);
402
403 if (paddingOffset != 0)
404 {
405 // padding is neccessary
406 for (int paddingIndex = paddingOffset; paddingIndex < alignment; paddingIndex++)
407 {
408 padding += " float pad_" + str(mPaddingCounter++) + ";\n";
409 }
410
411 *elementIndex += (alignment - paddingOffset);
412 }
413
414 *elementIndex += numComponents;
415 *elementIndex %= 4;
416
417 return padding;
418}
419
Jamie Madille4075c92013-06-21 09:15:32 -0400420TString OutputHLSL::std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking)
Jamie Madill574d9dd2013-06-20 11:55:56 -0400421{
Jamie Madillc835df62013-06-21 09:15:32 -0400422 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
Jamie Madill574d9dd2013-06-20 11:55:56 -0400423 {
424 return "";
425 }
426
Jamie Madill574d9dd2013-06-20 11:55:56 -0400427 int numComponents = 0;
428
429 if (type.isMatrix())
430 {
Jamie Madille4075c92013-06-21 09:15:32 -0400431 // This method can also be called from structureString, which does not use layout qualifiers.
432 // Thus, use the method parameter for determining the matrix packing.
433 //
434 // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
435 // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
436 //
437 const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
Jamie Madillc835df62013-06-21 09:15:32 -0400438 const GLenum glType = glVariableType(type);
Jamie Madill574d9dd2013-06-20 11:55:56 -0400439 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
440 }
Jamie Madill98493dd2013-07-08 14:39:03 -0400441 else if (type.getStruct())
Jamie Madillc835df62013-06-21 09:15:32 -0400442 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400443 const TString &structName = structureTypeName(*type.getStruct(), useHLSLRowMajorPacking, true);
Jamie Madille4075c92013-06-21 09:15:32 -0400444 numComponents = mStd140StructElementIndexes[structName];
445
446 if (numComponents == 0)
447 {
448 return "";
449 }
Jamie Madillc835df62013-06-21 09:15:32 -0400450 }
Jamie Madill574d9dd2013-06-20 11:55:56 -0400451 else
452 {
Jamie Madillc835df62013-06-21 09:15:32 -0400453 const GLenum glType = glVariableType(type);
Jamie Madill574d9dd2013-06-20 11:55:56 -0400454 numComponents = gl::UniformComponentCount(glType);
455 }
456
457 TString padding;
458 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
459 {
460 padding += " float pad_" + str(mPaddingCounter++) + ";\n";
461 }
462 return padding;
463}
464
Jamie Madill440dc742013-06-20 11:55:55 -0400465// Use the same layout for packed and shared
466void setBlockLayout(InterfaceBlock *interfaceBlock, BlockLayoutType newLayout)
467{
468 interfaceBlock->layout = newLayout;
469 interfaceBlock->blockInfo.clear();
470
471 switch (newLayout)
472 {
473 case BLOCKLAYOUT_SHARED:
474 case BLOCKLAYOUT_PACKED:
475 {
476 HLSLBlockEncoder hlslEncoder(&interfaceBlock->blockInfo);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400477 hlslEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
Jamie Madill440dc742013-06-20 11:55:55 -0400478 interfaceBlock->dataSize = hlslEncoder.getBlockSize();
479 }
480 break;
481
482 case BLOCKLAYOUT_STANDARD:
483 {
484 Std140BlockEncoder stdEncoder(&interfaceBlock->blockInfo);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400485 stdEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
Jamie Madill440dc742013-06-20 11:55:55 -0400486 interfaceBlock->dataSize = stdEncoder.getBlockSize();
487 }
488 break;
489
490 default:
491 UNREACHABLE();
492 break;
493 }
494}
495
Jamie Madill574d9dd2013-06-20 11:55:56 -0400496BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage)
497{
498 switch (blockStorage)
499 {
500 case EbsPacked: return BLOCKLAYOUT_PACKED;
501 case EbsShared: return BLOCKLAYOUT_SHARED;
502 case EbsStd140: return BLOCKLAYOUT_STANDARD;
503 default: UNREACHABLE(); return BLOCKLAYOUT_SHARED;
504 }
505}
506
Jamie Madill98493dd2013-07-08 14:39:03 -0400507TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
Jamie Madill570e04d2013-06-21 09:15:33 -0400508{
509 TString init;
510
511 TString preIndentString;
512 TString fullIndentString;
513
514 for (int spaces = 0; spaces < (indent * 4); spaces++)
515 {
516 preIndentString += ' ';
517 }
518
519 for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
520 {
521 fullIndentString += ' ';
522 }
523
524 init += preIndentString + "{\n";
525
Jamie Madill98493dd2013-07-08 14:39:03 -0400526 const TFieldList &fields = structure.fields();
527 for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400528 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400529 const TField &field = *fields[fieldIndex];
530 const TString &fieldName = rhsStructName + "." + decorate(field.name());
531 const TType &fieldType = *field.type();
Jamie Madill570e04d2013-06-21 09:15:33 -0400532
Jamie Madill98493dd2013-07-08 14:39:03 -0400533 if (fieldType.getStruct())
Jamie Madill570e04d2013-06-21 09:15:33 -0400534 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400535 init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400536 }
537 else
538 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400539 init += fullIndentString + fieldName + ",\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400540 }
541 }
542
543 init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
544
545 return init;
546}
547
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548void OutputHLSL::header()
549{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000550 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000551
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000552 TString uniforms;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000553 TString interfaceBlocks;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000554 TString varyings;
555 TString attributes;
Jamie Madill570e04d2013-06-21 09:15:33 -0400556 TString flaggedStructs;
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000557
Jamie Madillc2141fb2013-08-30 13:21:08 -0400558 for (ReferencedSymbols::const_iterator uniformIt = mReferencedUniforms.begin(); uniformIt != mReferencedUniforms.end(); uniformIt++)
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000559 {
Jamie Madillc2141fb2013-08-30 13:21:08 -0400560 const TIntermSymbol &uniform = *uniformIt->second;
561 const TType &type = uniform.getType();
562 const TString &name = uniform.getSymbol();
563
564 int registerIndex = declareUniformAndAssignRegister(type, name);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000565
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000566 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
567 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400568 uniforms += "uniform " + samplerString(type) + " sampler_" + decorateUniform(name, type) + arrayString(type) +
Jamie Madillc2141fb2013-08-30 13:21:08 -0400569 " : register(s" + str(registerIndex) + ");\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000570
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000571 uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) +
Jamie Madillc2141fb2013-08-30 13:21:08 -0400572 " : register(t" + str(registerIndex) + ");\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000573 }
574 else
575 {
Jamie Madillc2141fb2013-08-30 13:21:08 -0400576 const TStructure *structure = type.getStruct();
577 const TString &typeName = (structure ? structureTypeName(*structure, false, false) : typeString(type));
578
579 const TString &registerString = TString("register(") + RegisterPrefix(type) + str(registerIndex) + ")";
580
581 uniforms += "uniform " + typeName + " " + decorateUniform(name, type) + arrayString(type) + " : " + registerString + ";\n";
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000582 }
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000583 }
584
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000585 for (ReferencedSymbols::const_iterator interfaceBlockIt = mReferencedInterfaceBlocks.begin(); interfaceBlockIt != mReferencedInterfaceBlocks.end(); interfaceBlockIt++)
586 {
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000587 const TType &nodeType = interfaceBlockIt->second->getType();
Jamie Madill98493dd2013-07-08 14:39:03 -0400588 const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
589 const TFieldList &fieldList = interfaceBlock.fields();
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000590
Jamie Madill98493dd2013-07-08 14:39:03 -0400591 unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
592 sh::InterfaceBlock activeBlock(interfaceBlock.name().c_str(), arraySize, mInterfaceBlockRegister);
593 for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000594 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400595 const TField &field = *fieldList[typeIndex];
596 const TString &fullUniformName = interfaceBlockFieldString(interfaceBlock, field);
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400597 declareInterfaceBlockField(*field.type(), fullUniformName, activeBlock.fields);
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000598 }
599
Jamie Madill98493dd2013-07-08 14:39:03 -0400600 mInterfaceBlockRegister += std::max(1u, arraySize);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000601
Jamie Madill98493dd2013-07-08 14:39:03 -0400602 BlockLayoutType blockLayoutType = convertBlockLayoutType(interfaceBlock.blockStorage());
603 setBlockLayout(&activeBlock, blockLayoutType);
Jamie Madill9060a4e2013-08-12 16:22:57 -0700604
605 if (interfaceBlock.matrixPacking() == EmpRowMajor)
606 {
607 activeBlock.isRowMajorLayout = true;
608 }
609
Jamie Madill98493dd2013-07-08 14:39:03 -0400610 mActiveInterfaceBlocks.push_back(activeBlock);
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000611
Jamie Madill98493dd2013-07-08 14:39:03 -0400612 if (interfaceBlock.hasInstanceName())
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000613 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400614 interfaceBlocks += interfaceBlockStructString(interfaceBlock);
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000615 }
616
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000617 if (arraySize > 0)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000618 {
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000619 for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
620 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400621 interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex + arrayIndex, arrayIndex);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000622 }
623 }
624 else
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000625 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400626 interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex, GL_INVALID_INDEX);
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000627 }
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +0000628 }
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000629
Jamie Madill829f59e2013-11-13 19:40:54 -0500630 for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
Jamie Madill570e04d2013-06-21 09:15:33 -0400631 {
632 TIntermTyped *structNode = flaggedStructIt->first;
633 const TString &mappedName = flaggedStructIt->second;
Jamie Madill98493dd2013-07-08 14:39:03 -0400634 const TStructure &structure = *structNode->getType().getStruct();
Jamie Madill570e04d2013-06-21 09:15:33 -0400635 const TString &originalName = mFlaggedStructOriginalNames[structNode];
636
Jamie Madill98493dd2013-07-08 14:39:03 -0400637 flaggedStructs += "static " + decorate(structure.name()) + " " + mappedName + " =\n";
638 flaggedStructs += structInitializerString(0, structure, originalName);
Jamie Madill570e04d2013-06-21 09:15:33 -0400639 flaggedStructs += "\n";
640 }
641
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000642 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
643 {
644 const TType &type = varying->second->getType();
645 const TString &name = varying->second->getSymbol();
646
647 // Program linking depends on this exact format
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000648 varyings += "static " + interpolationString(type.getQualifier()) + " " + typeString(type) + " " +
649 decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madill47fdd132013-08-30 13:21:04 -0400650
Jamie Madill94599662013-08-30 13:21:10 -0400651 declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000652 }
653
654 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
655 {
656 const TType &type = attribute->second->getType();
657 const TString &name = attribute->second->getSymbol();
658
659 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
Jamie Madilldefb6742013-06-20 11:55:51 -0400660
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400661 Attribute attributeVar(glVariableType(type), glVariablePrecision(type), name.c_str(),
662 (unsigned int)type.getArraySize(), type.getLayoutQualifier().location);
663 mActiveAttributes.push_back(attributeVar);
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000664 }
665
Jamie Madill529077d2013-06-20 11:55:54 -0400666 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
667 {
668 out << *structDeclaration;
669 }
670
671 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
672 {
673 out << *constructor;
674 }
675
Jamie Madill3c9eeb92013-11-04 11:09:26 -0500676 if (mUsesDiscardRewriting)
677 {
678 out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
679 }
680
Nicolas Capens655fe362014-04-11 13:12:34 -0400681 if (mUsesNestedBreak)
682 {
683 out << "#define ANGLE_USES_NESTED_BREAK" << "\n";
684 }
685
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400686 if (mContext.shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687 {
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000688 TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
shannon.woods%transgaming.com@gtempaccount.com99ab6eb2013-04-13 03:42:00 +0000689 const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000690
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000691 out << "// Varyings\n";
692 out << varyings;
Jamie Madill46131a32013-06-20 11:55:50 -0400693 out << "\n";
694
695 if (mContext.getShaderVersion() >= 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000696 {
Jamie Madill829f59e2013-11-13 19:40:54 -0500697 for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000698 {
Jamie Madill46131a32013-06-20 11:55:50 -0400699 const TString &variableName = outputVariableIt->first;
700 const TType &variableType = outputVariableIt->second->getType();
701 const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier();
702
703 out << "static " + typeString(variableType) + " out_" + variableName + arrayString(variableType) +
704 " = " + initializer(variableType) + ";\n";
705
Jamie Madill9d2ffb12013-08-30 13:21:04 -0400706 Attribute outputVar(glVariableType(variableType), glVariablePrecision(variableType), variableName.c_str(),
707 (unsigned int)variableType.getArraySize(), layoutQualifier.location);
Jamie Madill46131a32013-06-20 11:55:50 -0400708 mActiveOutputVariables.push_back(outputVar);
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000709 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +0000710 }
Jamie Madill46131a32013-06-20 11:55:50 -0400711 else
712 {
713 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
714
715 out << "static float4 gl_Color[" << numColorValues << "] =\n"
716 "{\n";
717 for (unsigned int i = 0; i < numColorValues; i++)
718 {
719 out << " float4(0, 0, 0, 0)";
720 if (i + 1 != numColorValues)
721 {
722 out << ",";
723 }
724 out << "\n";
725 }
726
727 out << "};\n";
728 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000729
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400730 if (mUsesFragDepth)
731 {
732 out << "static float gl_Depth = 0.0;\n";
733 }
734
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000735 if (mUsesFragCoord)
736 {
737 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
738 }
739
740 if (mUsesPointCoord)
741 {
742 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
743 }
744
745 if (mUsesFrontFacing)
746 {
747 out << "static bool gl_FrontFacing = false;\n";
748 }
749
750 out << "\n";
751
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000752 if (mUsesDepthRange)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000753 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000754 out << "struct gl_DepthRangeParameters\n"
755 "{\n"
756 " float near;\n"
757 " float far;\n"
758 " float diff;\n"
759 "};\n"
760 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000761 }
762
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000763 if (mOutputType == SH_HLSL11_OUTPUT)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000764 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000765 out << "cbuffer DriverConstants : register(b1)\n"
766 "{\n";
767
768 if (mUsesDepthRange)
769 {
770 out << " float3 dx_DepthRange : packoffset(c0);\n";
771 }
772
773 if (mUsesFragCoord)
774 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000775 out << " float4 dx_ViewCoords : packoffset(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000776 }
777
778 if (mUsesFragCoord || mUsesFrontFacing)
779 {
780 out << " float3 dx_DepthFront : packoffset(c2);\n";
781 }
782
783 out << "};\n";
784 }
785 else
786 {
787 if (mUsesDepthRange)
788 {
789 out << "uniform float3 dx_DepthRange : register(c0);";
790 }
791
792 if (mUsesFragCoord)
793 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000794 out << "uniform float4 dx_ViewCoords : register(c1);\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000795 }
796
797 if (mUsesFragCoord || mUsesFrontFacing)
798 {
799 out << "uniform float3 dx_DepthFront : register(c2);\n";
800 }
801 }
802
803 out << "\n";
804
805 if (mUsesDepthRange)
806 {
807 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
808 "\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000809 }
810
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000812 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000813
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000814 if (!interfaceBlocks.empty())
815 {
816 out << interfaceBlocks;
817 out << "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400818
819 if (!flaggedStructs.empty())
820 {
821 out << "// Std140 Structures accessed by value\n";
822 out << "\n";
823 out << flaggedStructs;
824 out << "\n";
825 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000826 }
827
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000828 if (usingMRTExtension && mNumRenderTargets > 1)
829 {
830 out << "#define GL_USES_MRT\n";
831 }
832
833 if (mUsesFragColor)
834 {
835 out << "#define GL_USES_FRAG_COLOR\n";
836 }
837
838 if (mUsesFragData)
839 {
840 out << "#define GL_USES_FRAG_DATA\n";
841 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000842 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000843 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000845 out << "// Attributes\n";
846 out << attributes;
847 out << "\n"
848 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
849
850 if (mUsesPointSize)
851 {
852 out << "static float gl_PointSize = float(1);\n";
853 }
854
855 out << "\n"
856 "// Varyings\n";
857 out << varyings;
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000858 out << "\n";
859
860 if (mUsesDepthRange)
861 {
862 out << "struct gl_DepthRangeParameters\n"
863 "{\n"
864 " float near;\n"
865 " float far;\n"
866 " float diff;\n"
867 "};\n"
868 "\n";
869 }
870
871 if (mOutputType == SH_HLSL11_OUTPUT)
872 {
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000873 if (mUsesDepthRange)
874 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000875 out << "cbuffer DriverConstants : register(b1)\n"
876 "{\n"
877 " float3 dx_DepthRange : packoffset(c0);\n"
878 "};\n"
879 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000880 }
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000881 }
882 else
883 {
884 if (mUsesDepthRange)
885 {
886 out << "uniform float3 dx_DepthRange : register(c0);\n";
887 }
888
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +0000889 out << "uniform float4 dx_ViewAdjust : register(c1);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +0000890 "\n";
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000891 }
892
shannon.woods@transgaming.com46a5b872013-01-25 21:52:57 +0000893 if (mUsesDepthRange)
894 {
895 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
896 "\n";
897 }
898
899 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000900 out << "\n";
daniel@transgaming.com15795192011-05-11 15:36:20 +0000901
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000902 if (!interfaceBlocks.empty())
903 {
904 out << interfaceBlocks;
905 out << "\n";
Jamie Madill570e04d2013-06-21 09:15:33 -0400906
907 if (!flaggedStructs.empty())
908 {
909 out << "// Std140 Structures accessed by value\n";
910 out << "\n";
911 out << flaggedStructs;
912 out << "\n";
913 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000914 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400915 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +0000916
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400917 for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
918 {
919 // Return type
Nicolas Capens75fb4752013-07-10 15:14:47 -0400920 if (textureFunction->method == TextureFunction::SIZE)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000921 {
Nicolas Capens75fb4752013-07-10 15:14:47 -0400922 switch(textureFunction->sampler)
923 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400924 case EbtSampler2D: out << "int2 "; break;
925 case EbtSampler3D: out << "int3 "; break;
926 case EbtSamplerCube: out << "int2 "; break;
927 case EbtSampler2DArray: out << "int3 "; break;
928 case EbtISampler2D: out << "int2 "; break;
929 case EbtISampler3D: out << "int3 "; break;
930 case EbtISamplerCube: out << "int2 "; break;
931 case EbtISampler2DArray: out << "int3 "; break;
932 case EbtUSampler2D: out << "int2 "; break;
933 case EbtUSampler3D: out << "int3 "; break;
934 case EbtUSamplerCube: out << "int2 "; break;
935 case EbtUSampler2DArray: out << "int3 "; break;
936 case EbtSampler2DShadow: out << "int2 "; break;
937 case EbtSamplerCubeShadow: out << "int2 "; break;
938 case EbtSampler2DArrayShadow: out << "int3 "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400939 default: UNREACHABLE();
940 }
941 }
942 else // Sampling function
943 {
944 switch(textureFunction->sampler)
945 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400946 case EbtSampler2D: out << "float4 "; break;
947 case EbtSampler3D: out << "float4 "; break;
948 case EbtSamplerCube: out << "float4 "; break;
949 case EbtSampler2DArray: out << "float4 "; break;
950 case EbtISampler2D: out << "int4 "; break;
951 case EbtISampler3D: out << "int4 "; break;
952 case EbtISamplerCube: out << "int4 "; break;
953 case EbtISampler2DArray: out << "int4 "; break;
954 case EbtUSampler2D: out << "uint4 "; break;
955 case EbtUSampler3D: out << "uint4 "; break;
956 case EbtUSamplerCube: out << "uint4 "; break;
957 case EbtUSampler2DArray: out << "uint4 "; break;
958 case EbtSampler2DShadow: out << "float "; break;
959 case EbtSamplerCubeShadow: out << "float "; break;
960 case EbtSampler2DArrayShadow: out << "float "; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -0400961 default: UNREACHABLE();
962 }
daniel@transgaming.com15795192011-05-11 15:36:20 +0000963 }
964
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400965 // Function name
966 out << textureFunction->name();
967
968 // Argument list
969 int hlslCoords = 4;
970
971 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com15795192011-05-11 15:36:20 +0000972 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400973 switch(textureFunction->sampler)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000974 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400975 case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
976 case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
977 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000978 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400979
Nicolas Capens75fb4752013-07-10 15:14:47 -0400980 switch(textureFunction->method)
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000981 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400982 case TextureFunction::IMPLICIT: break;
983 case TextureFunction::BIAS: hlslCoords = 4; break;
984 case TextureFunction::LOD: hlslCoords = 4; break;
985 case TextureFunction::LOD0: hlslCoords = 4; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -0400986 case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400987 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +0000988 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -0400989 }
990 else if (mOutputType == SH_HLSL11_OUTPUT)
991 {
992 switch(textureFunction->sampler)
993 {
Nicolas Capenscb127d32013-07-15 17:26:18 -0400994 case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
995 case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
996 case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
997 case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
998 case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
999 case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001000 case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001001 case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
1002 case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
1003 case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capens0027fa92014-02-20 14:26:42 -05001004 case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001005 case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
1006 case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
1007 case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
1008 case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001009 default: UNREACHABLE();
1010 }
1011 }
1012 else UNREACHABLE();
1013
Nicolas Capensfc014542014-02-18 14:47:13 -05001014 if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001015 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001016 switch(textureFunction->coords)
1017 {
1018 case 2: out << ", int2 t"; break;
1019 case 3: out << ", int3 t"; break;
1020 default: UNREACHABLE();
1021 }
1022 }
1023 else // Floating-point coordinates (except textureSize)
1024 {
1025 switch(textureFunction->coords)
1026 {
1027 case 1: out << ", int lod"; break; // textureSize()
1028 case 2: out << ", float2 t"; break;
1029 case 3: out << ", float3 t"; break;
1030 case 4: out << ", float4 t"; break;
1031 default: UNREACHABLE();
1032 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001033 }
1034
Nicolas Capensd11d5492014-02-19 17:06:10 -05001035 if (textureFunction->method == TextureFunction::GRAD)
1036 {
1037 switch(textureFunction->sampler)
1038 {
1039 case EbtSampler2D:
1040 case EbtISampler2D:
1041 case EbtUSampler2D:
1042 case EbtSampler2DArray:
1043 case EbtISampler2DArray:
1044 case EbtUSampler2DArray:
1045 case EbtSampler2DShadow:
1046 case EbtSampler2DArrayShadow:
1047 out << ", float2 ddx, float2 ddy";
1048 break;
1049 case EbtSampler3D:
1050 case EbtISampler3D:
1051 case EbtUSampler3D:
1052 case EbtSamplerCube:
1053 case EbtISamplerCube:
1054 case EbtUSamplerCube:
1055 case EbtSamplerCubeShadow:
1056 out << ", float3 ddx, float3 ddy";
1057 break;
1058 default: UNREACHABLE();
1059 }
1060 }
1061
Nicolas Capens75fb4752013-07-10 15:14:47 -04001062 switch(textureFunction->method)
daniel@transgaming.com15795192011-05-11 15:36:20 +00001063 {
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001064 case TextureFunction::IMPLICIT: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001065 case TextureFunction::BIAS: break; // Comes after the offset parameter
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001066 case TextureFunction::LOD: out << ", float lod"; break;
1067 case TextureFunction::LOD0: break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001068 case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
Nicolas Capens75fb4752013-07-10 15:14:47 -04001069 case TextureFunction::SIZE: break;
Nicolas Capensfc014542014-02-18 14:47:13 -05001070 case TextureFunction::FETCH: out << ", int mip"; break;
Nicolas Capensd11d5492014-02-19 17:06:10 -05001071 case TextureFunction::GRAD: break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001072 default: UNREACHABLE();
daniel@transgaming.com15795192011-05-11 15:36:20 +00001073 }
1074
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001075 if (textureFunction->offset)
1076 {
1077 switch(textureFunction->sampler)
1078 {
1079 case EbtSampler2D: out << ", int2 offset"; break;
1080 case EbtSampler3D: out << ", int3 offset"; break;
1081 case EbtSampler2DArray: out << ", int2 offset"; break;
1082 case EbtISampler2D: out << ", int2 offset"; break;
1083 case EbtISampler3D: out << ", int3 offset"; break;
1084 case EbtISampler2DArray: out << ", int2 offset"; break;
1085 case EbtUSampler2D: out << ", int2 offset"; break;
1086 case EbtUSampler3D: out << ", int3 offset"; break;
1087 case EbtUSampler2DArray: out << ", int2 offset"; break;
1088 case EbtSampler2DShadow: out << ", int2 offset"; break;
Nicolas Capensbf7db102014-02-19 17:20:28 -05001089 case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001090 default: UNREACHABLE();
1091 }
1092 }
1093
Nicolas Capens84cfa122014-04-14 13:48:45 -04001094 if (textureFunction->method == TextureFunction::BIAS ||
1095 textureFunction->method == TextureFunction::LOD0BIAS)
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001096 {
1097 out << ", float bias";
1098 }
1099
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001100 out << ")\n"
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001101 "{\n";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001102
Nicolas Capens75fb4752013-07-10 15:14:47 -04001103 if (textureFunction->method == TextureFunction::SIZE)
1104 {
1105 if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
1106 {
1107 if (IsSamplerArray(textureFunction->sampler))
1108 {
1109 out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
1110 " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
1111 }
1112 else
1113 {
1114 out << " uint width; uint height; uint numberOfLevels;\n"
1115 " x.GetDimensions(lod, width, height, numberOfLevels);\n";
1116 }
1117 }
1118 else if (IsSampler3D(textureFunction->sampler))
1119 {
1120 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
1121 " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
1122 }
1123 else UNREACHABLE();
1124
1125 switch(textureFunction->sampler)
1126 {
Nicolas Capenscb127d32013-07-15 17:26:18 -04001127 case EbtSampler2D: out << " return int2(width, height);"; break;
1128 case EbtSampler3D: out << " return int3(width, height, depth);"; break;
1129 case EbtSamplerCube: out << " return int2(width, height);"; break;
1130 case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
1131 case EbtISampler2D: out << " return int2(width, height);"; break;
1132 case EbtISampler3D: out << " return int3(width, height, depth);"; break;
1133 case EbtISamplerCube: out << " return int2(width, height);"; break;
1134 case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
1135 case EbtUSampler2D: out << " return int2(width, height);"; break;
1136 case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
1137 case EbtUSamplerCube: out << " return int2(width, height);"; break;
1138 case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
1139 case EbtSampler2DShadow: out << " return int2(width, height);"; break;
1140 case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
1141 case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
Nicolas Capens75fb4752013-07-10 15:14:47 -04001142 default: UNREACHABLE();
1143 }
1144 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001145 else
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001146 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001147 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1148 {
1149 out << " float width; float height; float layers; float levels;\n";
1150
1151 out << " uint mip = 0;\n";
1152
1153 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
1154
1155 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
1156 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
1157 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
1158 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
1159
1160 // FACE_POSITIVE_X = 000b
1161 // FACE_NEGATIVE_X = 001b
1162 // FACE_POSITIVE_Y = 010b
1163 // FACE_NEGATIVE_Y = 011b
1164 // FACE_POSITIVE_Z = 100b
1165 // FACE_NEGATIVE_Z = 101b
1166 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
1167
1168 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
1169 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
1170 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
1171
1172 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
1173 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
1174 }
1175 else if (IsIntegerSampler(textureFunction->sampler) &&
1176 textureFunction->method != TextureFunction::FETCH)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001177 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001178 if (IsSampler2D(textureFunction->sampler))
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001179 {
Nicolas Capens93e50de2013-07-09 13:46:28 -04001180 if (IsSamplerArray(textureFunction->sampler))
1181 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001182 out << " float width; float height; float layers; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001183
Nicolas Capens9edebd62013-08-06 10:59:10 -04001184 if (textureFunction->method == TextureFunction::LOD0)
1185 {
1186 out << " uint mip = 0;\n";
1187 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001188 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1189 {
1190 out << " uint mip = bias;\n";
1191 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001192 else
1193 {
1194 if (textureFunction->method == TextureFunction::IMPLICIT ||
1195 textureFunction->method == TextureFunction::BIAS)
1196 {
1197 out << " x.GetDimensions(0, width, height, layers, levels);\n"
1198 " float2 tSized = float2(t.x * width, t.y * height);\n"
1199 " float dx = length(ddx(tSized));\n"
1200 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001201 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001202
1203 if (textureFunction->method == TextureFunction::BIAS)
1204 {
1205 out << " lod += bias;\n";
1206 }
1207 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001208 else if (textureFunction->method == TextureFunction::GRAD)
1209 {
1210 out << " x.GetDimensions(0, width, height, layers, levels);\n"
1211 " float lod = log2(max(length(ddx), length(ddy)));\n";
1212 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001213
1214 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1215 }
1216
1217 out << " x.GetDimensions(mip, width, height, layers, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001218 }
1219 else
1220 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001221 out << " float width; float height; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001222
Nicolas Capens9edebd62013-08-06 10:59:10 -04001223 if (textureFunction->method == TextureFunction::LOD0)
1224 {
1225 out << " uint mip = 0;\n";
1226 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001227 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1228 {
1229 out << " uint mip = bias;\n";
1230 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001231 else
1232 {
1233 if (textureFunction->method == TextureFunction::IMPLICIT ||
1234 textureFunction->method == TextureFunction::BIAS)
1235 {
1236 out << " x.GetDimensions(0, width, height, levels);\n"
1237 " float2 tSized = float2(t.x * width, t.y * height);\n"
1238 " float dx = length(ddx(tSized));\n"
1239 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001240 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001241
1242 if (textureFunction->method == TextureFunction::BIAS)
1243 {
1244 out << " lod += bias;\n";
1245 }
1246 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05001247 else if (textureFunction->method == TextureFunction::LOD)
1248 {
1249 out << " x.GetDimensions(0, width, height, levels);\n";
1250 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001251 else if (textureFunction->method == TextureFunction::GRAD)
1252 {
1253 out << " x.GetDimensions(0, width, height, levels);\n"
1254 " float lod = log2(max(length(ddx), length(ddy)));\n";
1255 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001256
1257 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1258 }
1259
1260 out << " x.GetDimensions(mip, width, height, levels);\n";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001261 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001262 }
1263 else if (IsSampler3D(textureFunction->sampler))
1264 {
Nicolas Capens9edebd62013-08-06 10:59:10 -04001265 out << " float width; float height; float depth; float levels;\n";
Nicolas Capens84cfa122014-04-14 13:48:45 -04001266
Nicolas Capens9edebd62013-08-06 10:59:10 -04001267 if (textureFunction->method == TextureFunction::LOD0)
1268 {
1269 out << " uint mip = 0;\n";
1270 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04001271 else if (textureFunction->method == TextureFunction::LOD0BIAS)
1272 {
1273 out << " uint mip = bias;\n";
1274 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001275 else
1276 {
1277 if (textureFunction->method == TextureFunction::IMPLICIT ||
1278 textureFunction->method == TextureFunction::BIAS)
1279 {
1280 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1281 " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
1282 " float dx = length(ddx(tSized));\n"
1283 " float dy = length(ddy(tSized));\n"
Jamie Madill03847b62013-11-13 19:42:39 -05001284 " float lod = log2(max(dx, dy));\n";
Nicolas Capens9edebd62013-08-06 10:59:10 -04001285
1286 if (textureFunction->method == TextureFunction::BIAS)
1287 {
1288 out << " lod += bias;\n";
1289 }
1290 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05001291 else if (textureFunction->method == TextureFunction::GRAD)
1292 {
1293 out << " x.GetDimensions(0, width, height, depth, levels);\n"
1294 " float lod = log2(max(length(ddx), length(ddy)));\n";
1295 }
Nicolas Capens9edebd62013-08-06 10:59:10 -04001296
1297 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
1298 }
1299
1300 out << " x.GetDimensions(mip, width, height, depth, levels);\n";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001301 }
1302 else UNREACHABLE();
1303 }
1304
1305 out << " return ";
1306
1307 // HLSL intrinsic
1308 if (mOutputType == SH_HLSL9_OUTPUT)
1309 {
1310 switch(textureFunction->sampler)
1311 {
1312 case EbtSampler2D: out << "tex2D"; break;
1313 case EbtSamplerCube: out << "texCUBE"; break;
1314 default: UNREACHABLE();
1315 }
1316
Nicolas Capens75fb4752013-07-10 15:14:47 -04001317 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001318 {
1319 case TextureFunction::IMPLICIT: out << "(s, "; break;
1320 case TextureFunction::BIAS: out << "bias(s, "; break;
1321 case TextureFunction::LOD: out << "lod(s, "; break;
1322 case TextureFunction::LOD0: out << "lod(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001323 case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001324 default: UNREACHABLE();
1325 }
1326 }
1327 else if (mOutputType == SH_HLSL11_OUTPUT)
1328 {
Nicolas Capensd11d5492014-02-19 17:06:10 -05001329 if (textureFunction->method == TextureFunction::GRAD)
1330 {
1331 if (IsIntegerSampler(textureFunction->sampler))
1332 {
1333 out << "x.Load(";
1334 }
1335 else if (IsShadowSampler(textureFunction->sampler))
1336 {
1337 out << "x.SampleCmpLevelZero(s, ";
1338 }
1339 else
1340 {
1341 out << "x.SampleGrad(s, ";
1342 }
1343 }
1344 else if (IsIntegerSampler(textureFunction->sampler) ||
1345 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001346 {
1347 out << "x.Load(";
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001348 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04001349 else if (IsShadowSampler(textureFunction->sampler))
1350 {
1351 out << "x.SampleCmp(s, ";
1352 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001353 else
1354 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001355 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001356 {
1357 case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
1358 case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
1359 case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
1360 case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001361 case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001362 default: UNREACHABLE();
1363 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001364 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001365 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001366 else UNREACHABLE();
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001367
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001368 // Integer sampling requires integer addresses
1369 TString addressx = "";
1370 TString addressy = "";
1371 TString addressz = "";
1372 TString close = "";
1373
Nicolas Capensfc014542014-02-18 14:47:13 -05001374 if (IsIntegerSampler(textureFunction->sampler) ||
1375 textureFunction->method == TextureFunction::FETCH)
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001376 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001377 switch(hlslCoords)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001378 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001379 case 2: out << "int3("; break;
1380 case 3: out << "int4("; break;
1381 default: UNREACHABLE();
1382 }
1383
Nicolas Capensfc014542014-02-18 14:47:13 -05001384 // Convert from normalized floating-point to integer
1385 if (textureFunction->method != TextureFunction::FETCH)
Nicolas Capens93e50de2013-07-09 13:46:28 -04001386 {
Nicolas Capensfc014542014-02-18 14:47:13 -05001387 addressx = "int(floor(width * frac((";
1388 addressy = "int(floor(height * frac((";
Nicolas Capens93e50de2013-07-09 13:46:28 -04001389
Nicolas Capensfc014542014-02-18 14:47:13 -05001390 if (IsSamplerArray(textureFunction->sampler))
1391 {
1392 addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
1393 }
Nicolas Capens0027fa92014-02-20 14:26:42 -05001394 else if (IsSamplerCube(textureFunction->sampler))
1395 {
1396 addressz = "((((";
1397 }
Nicolas Capensfc014542014-02-18 14:47:13 -05001398 else
1399 {
1400 addressz = "int(floor(depth * frac((";
1401 }
1402
1403 close = "))))";
1404 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001405 }
1406 else
1407 {
1408 switch(hlslCoords)
1409 {
1410 case 2: out << "float2("; break;
1411 case 3: out << "float3("; break;
1412 case 4: out << "float4("; break;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001413 default: UNREACHABLE();
1414 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001415 }
Nicolas Capens9fe6f982013-06-24 16:05:25 -04001416
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001417 TString proj = ""; // Only used for projected textures
1418
1419 if (textureFunction->proj)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001420 {
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001421 switch(textureFunction->coords)
1422 {
1423 case 3: proj = " / t.z"; break;
1424 case 4: proj = " / t.w"; break;
1425 default: UNREACHABLE();
1426 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001427 }
daniel@transgaming.com15795192011-05-11 15:36:20 +00001428
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001429 out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001430
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001431 if (mOutputType == SH_HLSL9_OUTPUT)
1432 {
1433 if (hlslCoords >= 3)
1434 {
1435 if (textureFunction->coords < 3)
1436 {
1437 out << ", 0";
1438 }
1439 else
1440 {
1441 out << ", t.z" + proj;
1442 }
1443 }
1444
1445 if (hlslCoords == 4)
1446 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001447 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001448 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04001449 case TextureFunction::BIAS: out << ", bias"; break;
1450 case TextureFunction::LOD: out << ", lod"; break;
1451 case TextureFunction::LOD0: out << ", 0"; break;
1452 case TextureFunction::LOD0BIAS: out << ", bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001453 default: UNREACHABLE();
1454 }
1455 }
1456
1457 out << "));\n";
1458 }
1459 else if (mOutputType == SH_HLSL11_OUTPUT)
1460 {
1461 if (hlslCoords >= 3)
1462 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001463 if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
1464 {
1465 out << ", face";
1466 }
1467 else
1468 {
1469 out << ", " + addressz + ("t.z" + proj) + close;
1470 }
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001471 }
1472
Nicolas Capensd11d5492014-02-19 17:06:10 -05001473 if (textureFunction->method == TextureFunction::GRAD)
1474 {
1475 if (IsIntegerSampler(textureFunction->sampler))
1476 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001477 out << ", mip)";
Nicolas Capensd11d5492014-02-19 17:06:10 -05001478 }
1479 else if (IsShadowSampler(textureFunction->sampler))
1480 {
Nicolas Capens0027fa92014-02-20 14:26:42 -05001481 // Compare value
Nicolas Capensd11d5492014-02-19 17:06:10 -05001482 switch(textureFunction->coords)
1483 {
1484 case 3: out << "), t.z"; break;
1485 case 4: out << "), t.w"; break;
1486 default: UNREACHABLE();
1487 }
1488 }
1489 else
1490 {
1491 out << "), ddx, ddy";
1492 }
1493 }
1494 else if (IsIntegerSampler(textureFunction->sampler) ||
1495 textureFunction->method == TextureFunction::FETCH)
Nicolas Capenscb127d32013-07-15 17:26:18 -04001496 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001497 out << ", mip)";
Nicolas Capenscb127d32013-07-15 17:26:18 -04001498 }
1499 else if (IsShadowSampler(textureFunction->sampler))
1500 {
1501 // Compare value
1502 switch(textureFunction->coords)
1503 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001504 case 3: out << "), t.z"; break;
1505 case 4: out << "), t.w"; break;
Nicolas Capenscb127d32013-07-15 17:26:18 -04001506 default: UNREACHABLE();
1507 }
1508 }
1509 else
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001510 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04001511 switch(textureFunction->method)
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001512 {
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001513 case TextureFunction::IMPLICIT: out << ")"; break;
1514 case TextureFunction::BIAS: out << "), bias"; break;
1515 case TextureFunction::LOD: out << "), lod"; break;
1516 case TextureFunction::LOD0: out << "), 0"; break;
Nicolas Capens84cfa122014-04-14 13:48:45 -04001517 case TextureFunction::LOD0BIAS: out << "), bias"; break;
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001518 default: UNREACHABLE();
1519 }
1520 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05001521
1522 if (textureFunction->offset)
1523 {
1524 out << ", offset";
1525 }
1526
1527 out << ");";
Nicolas Capens6d232bb2013-07-08 15:56:38 -04001528 }
1529 else UNREACHABLE();
1530 }
1531
1532 out << "\n"
1533 "}\n"
Nicolas Capense0ba27a2013-06-24 16:10:52 -04001534 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001535 }
1536
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +00001537 if (mUsesFragCoord)
1538 {
1539 out << "#define GL_USES_FRAG_COORD\n";
1540 }
1541
1542 if (mUsesPointCoord)
1543 {
1544 out << "#define GL_USES_POINT_COORD\n";
1545 }
1546
1547 if (mUsesFrontFacing)
1548 {
1549 out << "#define GL_USES_FRONT_FACING\n";
1550 }
1551
1552 if (mUsesPointSize)
1553 {
1554 out << "#define GL_USES_POINT_SIZE\n";
1555 }
1556
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001557 if (mUsesFragDepth)
1558 {
1559 out << "#define GL_USES_FRAG_DEPTH\n";
1560 }
1561
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001562 if (mUsesDepthRange)
1563 {
1564 out << "#define GL_USES_DEPTH_RANGE\n";
1565 }
1566
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001567 if (mUsesXor)
1568 {
1569 out << "bool xor(bool p, bool q)\n"
1570 "{\n"
1571 " return (p || q) && !(p && q);\n"
1572 "}\n"
1573 "\n";
1574 }
1575
1576 if (mUsesMod1)
1577 {
1578 out << "float mod(float x, float y)\n"
1579 "{\n"
1580 " return x - y * floor(x / y);\n"
1581 "}\n"
1582 "\n";
1583 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001584
1585 if (mUsesMod2v)
1586 {
1587 out << "float2 mod(float2 x, float2 y)\n"
1588 "{\n"
1589 " return x - y * floor(x / y);\n"
1590 "}\n"
1591 "\n";
1592 }
1593
1594 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001595 {
1596 out << "float2 mod(float2 x, float y)\n"
1597 "{\n"
1598 " return x - y * floor(x / y);\n"
1599 "}\n"
1600 "\n";
1601 }
1602
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001603 if (mUsesMod3v)
1604 {
1605 out << "float3 mod(float3 x, float3 y)\n"
1606 "{\n"
1607 " return x - y * floor(x / y);\n"
1608 "}\n"
1609 "\n";
1610 }
1611
1612 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001613 {
1614 out << "float3 mod(float3 x, float y)\n"
1615 "{\n"
1616 " return x - y * floor(x / y);\n"
1617 "}\n"
1618 "\n";
1619 }
1620
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001621 if (mUsesMod4v)
1622 {
1623 out << "float4 mod(float4 x, float4 y)\n"
1624 "{\n"
1625 " return x - y * floor(x / y);\n"
1626 "}\n"
1627 "\n";
1628 }
1629
1630 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001631 {
1632 out << "float4 mod(float4 x, float y)\n"
1633 "{\n"
1634 " return x - y * floor(x / y);\n"
1635 "}\n"
1636 "\n";
1637 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001638
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001639 if (mUsesFaceforward1)
1640 {
1641 out << "float faceforward(float N, float I, float Nref)\n"
1642 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001643 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001644 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001645 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001646 " }\n"
1647 " else\n"
1648 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001649 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001650 " }\n"
1651 "}\n"
1652 "\n";
1653 }
1654
1655 if (mUsesFaceforward2)
1656 {
1657 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
1658 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001659 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001660 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001661 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001662 " }\n"
1663 " else\n"
1664 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001665 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001666 " }\n"
1667 "}\n"
1668 "\n";
1669 }
1670
1671 if (mUsesFaceforward3)
1672 {
1673 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
1674 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001675 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001676 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001677 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001678 " }\n"
1679 " else\n"
1680 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001681 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001682 " }\n"
1683 "}\n"
1684 "\n";
1685 }
1686
1687 if (mUsesFaceforward4)
1688 {
1689 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
1690 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001691 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001692 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001693 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001694 " }\n"
1695 " else\n"
1696 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +00001697 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001698 " }\n"
1699 "}\n"
1700 "\n";
1701 }
1702
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001703 if (mUsesAtan2_1)
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001704 {
1705 out << "float atanyx(float y, float x)\n"
1706 "{\n"
1707 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
1708 " return atan2(y, x);\n"
1709 "}\n";
1710 }
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001711
1712 if (mUsesAtan2_2)
1713 {
1714 out << "float2 atanyx(float2 y, float2 x)\n"
1715 "{\n"
1716 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1717 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1718 " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
1719 "}\n";
1720 }
1721
1722 if (mUsesAtan2_3)
1723 {
1724 out << "float3 atanyx(float3 y, float3 x)\n"
1725 "{\n"
1726 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1727 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1728 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1729 " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
1730 "}\n";
1731 }
1732
1733 if (mUsesAtan2_4)
1734 {
1735 out << "float4 atanyx(float4 y, float4 x)\n"
1736 "{\n"
1737 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
1738 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
1739 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
1740 " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
1741 " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
1742 "}\n";
1743 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001744}
1745
1746void OutputHLSL::visitSymbol(TIntermSymbol *node)
1747{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001748 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749
Jamie Madill570e04d2013-06-21 09:15:33 -04001750 // Handle accessing std140 structs by value
1751 if (mFlaggedStructMappedNames.count(node) > 0)
1752 {
1753 out << mFlaggedStructMappedNames[node];
1754 return;
1755 }
1756
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001757 TString name = node->getSymbol();
1758
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001759 if (name == "gl_DepthRange")
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001760 {
1761 mUsesDepthRange = true;
1762 out << name;
1763 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001764 else
1765 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001766 TQualifier qualifier = node->getQualifier();
1767
1768 if (qualifier == EvqUniform)
1769 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001770 const TType& nodeType = node->getType();
1771 const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock();
1772
1773 if (interfaceBlock)
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001774 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001775 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001776 }
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001777 else
1778 {
1779 mReferencedUniforms[name] = node;
shannonwoods@chromium.org4a643ae2013-05-30 00:12:27 +00001780 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001781
1782 out << decorateUniform(name, nodeType);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001783 }
Jamie Madill19571812013-08-12 15:26:34 -07001784 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001785 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001786 mReferencedAttributes[name] = node;
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001787 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001788 }
shannon.woods%transgaming.com@gtempaccount.com6f273e32013-04-13 03:41:15 +00001789 else if (isVarying(qualifier))
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001790 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +00001791 mReferencedVaryings[name] = node;
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001792 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +00001793 }
Jamie Madill19571812013-08-12 15:26:34 -07001794 else if (qualifier == EvqFragmentOut)
Jamie Madill46131a32013-06-20 11:55:50 -04001795 {
1796 mReferencedOutputVariables[name] = node;
1797 out << "out_" << name;
1798 }
1799 else if (qualifier == EvqFragColor)
shannon.woods%transgaming.com@gtempaccount.come7d4a242013-04-13 03:38:33 +00001800 {
1801 out << "gl_Color[0]";
1802 mUsesFragColor = true;
1803 }
1804 else if (qualifier == EvqFragData)
1805 {
1806 out << "gl_Color";
1807 mUsesFragData = true;
1808 }
1809 else if (qualifier == EvqFragCoord)
1810 {
1811 mUsesFragCoord = true;
1812 out << name;
1813 }
1814 else if (qualifier == EvqPointCoord)
1815 {
1816 mUsesPointCoord = true;
1817 out << name;
1818 }
1819 else if (qualifier == EvqFrontFacing)
1820 {
1821 mUsesFrontFacing = true;
1822 out << name;
1823 }
1824 else if (qualifier == EvqPointSize)
1825 {
1826 mUsesPointSize = true;
1827 out << name;
1828 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001829 else if (name == "gl_FragDepthEXT")
1830 {
1831 mUsesFragDepth = true;
1832 out << "gl_Depth";
1833 }
Jamie Madille53c98b2014-02-03 11:57:13 -05001834 else if (qualifier == EvqInternal)
1835 {
1836 out << name;
1837 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00001838 else
1839 {
1840 out << decorate(name);
1841 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001842 }
1843}
1844
1845bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1846{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001847 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001848
Jamie Madill570e04d2013-06-21 09:15:33 -04001849 // Handle accessing std140 structs by value
1850 if (mFlaggedStructMappedNames.count(node) > 0)
1851 {
1852 out << mFlaggedStructMappedNames[node];
1853 return false;
1854 }
1855
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001856 switch (node->getOp())
1857 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001858 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001859 case EOpInitialize:
1860 if (visit == PreVisit)
1861 {
1862 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1863 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1864 // new variable is created before the assignment is evaluated), so we need to convert
1865 // this to "float t = x, x = t;".
1866
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001867 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1868 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001869
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001870 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
1871 expression->traverse(&searchSymbol);
1872 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001873
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +00001874 if (sameSymbol)
1875 {
1876 // Type already printed
1877 out << "t" + str(mUniqueIndex) + " = ";
1878 expression->traverse(this);
1879 out << ", ";
1880 symbolNode->traverse(this);
1881 out << " = t" + str(mUniqueIndex);
1882
1883 mUniqueIndex++;
1884 return false;
1885 }
1886 }
1887 else if (visit == InVisit)
1888 {
1889 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001890 }
1891 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001892 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
1893 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
1894 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1895 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1896 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
1897 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001898 if (visit == PreVisit)
1899 {
1900 out << "(";
1901 }
1902 else if (visit == InVisit)
1903 {
1904 out << " = mul(";
1905 node->getLeft()->traverse(this);
1906 out << ", transpose(";
1907 }
1908 else
1909 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001910 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001911 }
1912 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001913 case EOpMatrixTimesMatrixAssign:
1914 if (visit == PreVisit)
1915 {
1916 out << "(";
1917 }
1918 else if (visit == InVisit)
1919 {
1920 out << " = mul(";
1921 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001922 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001923 }
1924 else
1925 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +00001926 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001927 }
1928 break;
1929 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
Jamie Madillb4e664b2013-06-20 11:55:54 -04001930 case EOpIndexDirect:
Jamie Madillb4e664b2013-06-20 11:55:54 -04001931 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001932 const TType& leftType = node->getLeft()->getType();
1933 if (leftType.isInterfaceBlock())
Jamie Madillb4e664b2013-06-20 11:55:54 -04001934 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001935 if (visit == PreVisit)
1936 {
1937 TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
1938 const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
1939
1940 mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
1941 out << interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
1942
1943 return false;
1944 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001945 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001946 else
1947 {
1948 outputTriplet(visit, "", "[", "]");
1949 }
Jamie Madillb4e664b2013-06-20 11:55:54 -04001950 }
1951 break;
1952 case EOpIndexIndirect:
1953 // We do not currently support indirect references to interface blocks
1954 ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1955 outputTriplet(visit, "", "[", "]");
1956 break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001957 case EOpIndexDirectStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04001958 if (visit == InVisit)
1959 {
1960 const TStructure* structure = node->getLeft()->getType().getStruct();
1961 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1962 const TField* field = structure->fields()[index->getIConst(0)];
1963 out << "." + decorateField(field->name(), *structure);
1964
1965 return false;
1966 }
1967 break;
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +00001968 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001969 if (visit == InVisit)
1970 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001971 const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
1972 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1973 const TField* field = interfaceBlock->fields()[index->getIConst(0)];
1974 out << "." + decorate(field->name());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001975
1976 return false;
1977 }
1978 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001979 case EOpVectorSwizzle:
1980 if (visit == InVisit)
1981 {
1982 out << ".";
1983
1984 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1985
1986 if (swizzle)
1987 {
1988 TIntermSequence &sequence = swizzle->getSequence();
1989
1990 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
1991 {
1992 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1993
1994 if (element)
1995 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00001996 int i = element->getIConst(0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001997
1998 switch (i)
1999 {
2000 case 0: out << "x"; break;
2001 case 1: out << "y"; break;
2002 case 2: out << "z"; break;
2003 case 3: out << "w"; break;
2004 default: UNREACHABLE();
2005 }
2006 }
2007 else UNREACHABLE();
2008 }
2009 }
2010 else UNREACHABLE();
2011
2012 return false; // Fully processed
2013 }
2014 break;
2015 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
2016 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
2017 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
2018 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002019 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002020 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002021 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002022 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002023 if (node->getOp() == EOpEqual)
2024 {
2025 outputTriplet(visit, "(", " == ", ")");
2026 }
2027 else
2028 {
2029 outputTriplet(visit, "(", " != ", ")");
2030 }
2031 }
2032 else if (node->getLeft()->getBasicType() == EbtStruct)
2033 {
2034 if (node->getOp() == EOpEqual)
2035 {
2036 out << "(";
2037 }
2038 else
2039 {
2040 out << "!(";
2041 }
2042
Jamie Madill98493dd2013-07-08 14:39:03 -04002043 const TStructure &structure = *node->getLeft()->getType().getStruct();
2044 const TFieldList &fields = structure.fields();
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002045
Jamie Madill98493dd2013-07-08 14:39:03 -04002046 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002047 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002048 const TField *field = fields[i];
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002049
2050 node->getLeft()->traverse(this);
Jamie Madill98493dd2013-07-08 14:39:03 -04002051 out << "." + decorateField(field->name(), structure) + " == ";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002052 node->getRight()->traverse(this);
Jamie Madill98493dd2013-07-08 14:39:03 -04002053 out << "." + decorateField(field->name(), structure);
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002054
Jamie Madill98493dd2013-07-08 14:39:03 -04002055 if (i < fields.size() - 1)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002056 {
2057 out << " && ";
2058 }
2059 }
2060
2061 out << ")";
2062
2063 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002064 }
2065 else
2066 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002067 ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002068
2069 if (node->getOp() == EOpEqual)
2070 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002071 outputTriplet(visit, "all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002072 }
2073 else
2074 {
Jamie Madill0b20c942013-07-19 16:36:56 -04002075 outputTriplet(visit, "!all(", " == ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002076 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00002077 }
2078 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002079 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2080 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2081 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2082 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2083 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00002084 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00002085 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
2086 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00002087 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00002088 case EOpLogicalOr:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002089 if (node->getRight()->hasSideEffects())
2090 {
2091 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
2092 return false;
2093 }
2094 else
2095 {
2096 outputTriplet(visit, "(", " || ", ")");
2097 return true;
2098 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002099 case EOpLogicalXor:
2100 mUsesXor = true;
2101 outputTriplet(visit, "xor(", ", ", ")");
2102 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00002103 case EOpLogicalAnd:
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002104 if (node->getRight()->hasSideEffects())
2105 {
2106 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
2107 return false;
2108 }
2109 else
2110 {
2111 outputTriplet(visit, "(", " && ", ")");
2112 return true;
2113 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002114 default: UNREACHABLE();
2115 }
2116
2117 return true;
2118}
2119
2120bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
2121{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002122 switch (node->getOp())
2123 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002124 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
2125 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
2126 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
2127 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
2128 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
2129 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
2130 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002131 case EOpConvIntToBool:
Nicolas Capensab60b932013-06-05 10:31:21 -04002132 case EOpConvUIntToBool:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002133 case EOpConvFloatToBool:
2134 switch (node->getOperand()->getType().getNominalSize())
2135 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002136 case 1: outputTriplet(visit, "bool(", "", ")"); break;
2137 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
2138 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
2139 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002140 default: UNREACHABLE();
2141 }
2142 break;
2143 case EOpConvBoolToFloat:
2144 case EOpConvIntToFloat:
Nicolas Capensab60b932013-06-05 10:31:21 -04002145 case EOpConvUIntToFloat:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002146 switch (node->getOperand()->getType().getNominalSize())
2147 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002148 case 1: outputTriplet(visit, "float(", "", ")"); break;
2149 case 2: outputTriplet(visit, "float2(", "", ")"); break;
2150 case 3: outputTriplet(visit, "float3(", "", ")"); break;
2151 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002152 default: UNREACHABLE();
2153 }
2154 break;
2155 case EOpConvFloatToInt:
2156 case EOpConvBoolToInt:
Nicolas Capensab60b932013-06-05 10:31:21 -04002157 case EOpConvUIntToInt:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002158 switch (node->getOperand()->getType().getNominalSize())
2159 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002160 case 1: outputTriplet(visit, "int(", "", ")"); break;
2161 case 2: outputTriplet(visit, "int2(", "", ")"); break;
2162 case 3: outputTriplet(visit, "int3(", "", ")"); break;
2163 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002164 default: UNREACHABLE();
2165 }
2166 break;
Nicolas Capensab60b932013-06-05 10:31:21 -04002167 case EOpConvFloatToUInt:
2168 case EOpConvBoolToUInt:
2169 case EOpConvIntToUInt:
Jamie Madilla16f1672013-07-03 15:15:17 -04002170 switch (node->getOperand()->getType().getNominalSize())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002171 {
2172 case 1: outputTriplet(visit, "uint(", "", ")"); break;
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +00002173 case 2: outputTriplet(visit, "uint2(", "", ")"); break;
2174 case 3: outputTriplet(visit, "uint3(", "", ")"); break;
2175 case 4: outputTriplet(visit, "uint4(", "", ")"); break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002176 default: UNREACHABLE();
2177 }
2178 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002179 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
2180 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
2181 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
2182 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
2183 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
2184 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
2185 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
2186 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
2187 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
2188 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
2189 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
2190 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
2191 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
2192 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
2193 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
2194 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
2195 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
2196 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
2197 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
2198 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
2199 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002200 case EOpDFdx:
2201 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2202 {
2203 outputTriplet(visit, "(", "", ", 0.0)");
2204 }
2205 else
2206 {
2207 outputTriplet(visit, "ddx(", "", ")");
2208 }
2209 break;
2210 case EOpDFdy:
2211 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2212 {
2213 outputTriplet(visit, "(", "", ", 0.0)");
2214 }
2215 else
2216 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00002217 outputTriplet(visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00002218 }
2219 break;
2220 case EOpFwidth:
2221 if(mInsideDiscontinuousLoop || mOutputLod0Function)
2222 {
2223 outputTriplet(visit, "(", "", ", 0.0)");
2224 }
2225 else
2226 {
2227 outputTriplet(visit, "fwidth(", "", ")");
2228 }
2229 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002230 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
2231 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002232 default: UNREACHABLE();
2233 }
2234
2235 return true;
2236}
2237
2238bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2239{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002240 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002242 switch (node->getOp())
2243 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002244 case EOpSequence:
2245 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002246 if (mInsideFunction)
2247 {
Jamie Madill075edd82013-07-08 13:30:19 -04002248 outputLineDirective(node->getLine().first_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002249 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002250
2251 mScopeDepth++;
2252
2253 if (mScopeBracket.size() < mScopeDepth)
2254 {
2255 mScopeBracket.push_back(0); // New scope level
2256 }
2257 else
2258 {
2259 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
2260 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002261 }
2262
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002263 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
2264 {
Jamie Madill075edd82013-07-08 13:30:19 -04002265 outputLineDirective((*sit)->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002266
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002267 traverseStatements(*sit);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002268
2269 out << ";\n";
2270 }
2271
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002272 if (mInsideFunction)
2273 {
Jamie Madill075edd82013-07-08 13:30:19 -04002274 outputLineDirective(node->getLine().last_line);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002275 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002276
2277 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002278 }
2279
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002280 return false;
2281 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002282 case EOpDeclaration:
2283 if (visit == PreVisit)
2284 {
2285 TIntermSequence &sequence = node->getSequence();
2286 TIntermTyped *variable = sequence[0]->getAsTyped();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002287
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00002288 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002289 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002290 if (variable->getType().getStruct())
2291 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002292 addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00002293 }
2294
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002295 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002296 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00002297 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00002298 {
2299 out << "static ";
2300 }
2301
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002302 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002303
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002304 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002305 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002306 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002307
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002308 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002310 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002311 out << arrayString(symbol->getType());
Jamie Madill79bb0d92013-12-09 16:20:28 -05002312 out << " = " + initializer(symbol->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002313 }
2314 else
2315 {
2316 (*sit)->traverse(this);
2317 }
2318
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002319 if (*sit != sequence.back())
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002320 {
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002321 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002322 }
2323 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002324 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002325 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
2326 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002327 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002328 }
2329 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002330 }
shannon.woods%transgaming.com@gtempaccount.com6f273e32013-04-13 03:41:15 +00002331 else if (variable && isVaryingOut(variable->getQualifier()))
shannon.woods@transgaming.comcb332ab2013-02-28 23:12:18 +00002332 {
2333 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
2334 {
2335 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
2336
2337 if (symbol)
2338 {
2339 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
2340 mReferencedVaryings[symbol->getSymbol()] = symbol;
2341 }
2342 else
2343 {
2344 (*sit)->traverse(this);
2345 }
2346 }
2347 }
2348
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002349 return false;
2350 }
2351 else if (visit == InVisit)
2352 {
2353 out << ", ";
2354 }
2355 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002356 case EOpPrototype:
2357 if (visit == PreVisit)
2358 {
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002359 out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002360
2361 TIntermSequence &arguments = node->getSequence();
2362
2363 for (unsigned int i = 0; i < arguments.size(); i++)
2364 {
2365 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
2366
2367 if (symbol)
2368 {
2369 out << argumentString(symbol);
2370
2371 if (i < arguments.size() - 1)
2372 {
2373 out << ", ";
2374 }
2375 }
2376 else UNREACHABLE();
2377 }
2378
2379 out << ");\n";
2380
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00002381 // Also prototype the Lod0 variant if needed
2382 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
2383 {
2384 mOutputLod0Function = true;
2385 node->traverse(this);
2386 mOutputLod0Function = false;
2387 }
2388
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002389 return false;
2390 }
2391 break;
daniel@transgaming.comed2180d2012-03-26 17:08:54 +00002392 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002393 case EOpFunction:
2394 {
alokp@chromium.org43884872010-03-30 00:08:52 +00002395 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002396
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002397 out << typeString(node->getType()) << " ";
2398
2399 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002400 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002401 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002402 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002403 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002404 {
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002405 out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002406 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002407
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002408 TIntermSequence &sequence = node->getSequence();
2409 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
2410
2411 for (unsigned int i = 0; i < arguments.size(); i++)
2412 {
2413 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
2414
2415 if (symbol)
2416 {
2417 if (symbol->getType().getStruct())
2418 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002419 addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL);
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002420 }
2421
2422 out << argumentString(symbol);
2423
2424 if (i < arguments.size() - 1)
2425 {
2426 out << ", ";
2427 }
2428 }
2429 else UNREACHABLE();
2430 }
2431
2432 out << ")\n"
2433 "{\n";
2434
2435 if (sequence.size() > 1)
2436 {
2437 mInsideFunction = true;
2438 sequence[1]->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00002439 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002440 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002441
2442 out << "}\n";
2443
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002444 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
2445 {
daniel@transgaming.comecdf44a2012-06-01 01:45:15 +00002446 if (name != "main")
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00002447 {
2448 mOutputLod0Function = true;
2449 node->traverse(this);
2450 mOutputLod0Function = false;
2451 }
2452 }
2453
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00002454 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002455 }
2456 break;
2457 case EOpFunctionCall:
2458 {
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002459 TString name = TFunction::unmangleName(node->getName());
2460 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002461 TIntermSequence &arguments = node->getSequence();
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002462
2463 if (node->isUserDefined())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002464 {
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002465 out << decorate(name) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002466 }
2467 else
2468 {
shannonwoods@chromium.orgc6ac65f2013-05-30 00:02:50 +00002469 TBasicType samplerType = arguments[0]->getAsTyped()->getType().getBasicType();
2470
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002471 TextureFunction textureFunction;
2472 textureFunction.sampler = samplerType;
2473 textureFunction.coords = arguments[1]->getAsTyped()->getNominalSize();
Nicolas Capens75fb4752013-07-10 15:14:47 -04002474 textureFunction.method = TextureFunction::IMPLICIT;
2475 textureFunction.proj = false;
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002476 textureFunction.offset = false;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002477
2478 if (name == "texture2D" || name == "textureCube" || name == "texture")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002479 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002480 textureFunction.method = TextureFunction::IMPLICIT;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002481 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002482 else if (name == "texture2DProj" || name == "textureProj")
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002483 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002484 textureFunction.method = TextureFunction::IMPLICIT;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002485 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002486 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002487 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002488 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002489 textureFunction.method = TextureFunction::LOD;
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002490 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002491 else if (name == "texture2DProjLod" || name == "textureProjLod")
Nicolas Capens9fe6f982013-06-24 16:05:25 -04002492 {
Nicolas Capens75fb4752013-07-10 15:14:47 -04002493 textureFunction.method = TextureFunction::LOD;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002494 textureFunction.proj = true;
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002495 }
Nicolas Capens75fb4752013-07-10 15:14:47 -04002496 else if (name == "textureSize")
2497 {
2498 textureFunction.method = TextureFunction::SIZE;
2499 }
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002500 else if (name == "textureOffset")
2501 {
2502 textureFunction.method = TextureFunction::IMPLICIT;
2503 textureFunction.offset = true;
2504 }
Nicolas Capensdf86c6b2014-02-14 20:09:17 -05002505 else if (name == "textureProjOffset")
2506 {
2507 textureFunction.method = TextureFunction::IMPLICIT;
2508 textureFunction.offset = true;
2509 textureFunction.proj = true;
2510 }
2511 else if (name == "textureLodOffset")
2512 {
2513 textureFunction.method = TextureFunction::LOD;
2514 textureFunction.offset = true;
2515 }
Nicolas Capens2adc2562014-02-14 23:50:59 -05002516 else if (name == "textureProjLod")
2517 {
2518 textureFunction.method = TextureFunction::LOD;
2519 textureFunction.proj = true;
2520 }
2521 else if (name == "textureProjLodOffset")
2522 {
2523 textureFunction.method = TextureFunction::LOD;
2524 textureFunction.proj = true;
2525 textureFunction.offset = true;
2526 }
Nicolas Capensfc014542014-02-18 14:47:13 -05002527 else if (name == "texelFetch")
2528 {
2529 textureFunction.method = TextureFunction::FETCH;
2530 }
2531 else if (name == "texelFetchOffset")
2532 {
2533 textureFunction.method = TextureFunction::FETCH;
2534 textureFunction.offset = true;
2535 }
Nicolas Capensd11d5492014-02-19 17:06:10 -05002536 else if (name == "textureGrad")
2537 {
2538 textureFunction.method = TextureFunction::GRAD;
2539 }
Nicolas Capensbf7db102014-02-19 17:20:28 -05002540 else if (name == "textureGradOffset")
2541 {
2542 textureFunction.method = TextureFunction::GRAD;
2543 textureFunction.offset = true;
2544 }
Nicolas Capensf7378e32014-02-19 17:29:32 -05002545 else if (name == "textureProjGrad")
2546 {
2547 textureFunction.method = TextureFunction::GRAD;
2548 textureFunction.proj = true;
2549 }
2550 else if (name == "textureProjGradOffset")
2551 {
2552 textureFunction.method = TextureFunction::GRAD;
2553 textureFunction.proj = true;
2554 textureFunction.offset = true;
2555 }
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002556 else UNREACHABLE();
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002557
Nicolas Capensb1f45b72013-12-19 17:37:19 -05002558 if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002559 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002560 unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
2561
2562 if (textureFunction.offset)
2563 {
2564 mandatoryArgumentCount++;
2565 }
2566
2567 bool bias = (arguments.size() > mandatoryArgumentCount); // Bias argument is optional
2568
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002569 if (lod0 || mContext.shaderType == SH_VERTEX_SHADER)
2570 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002571 if (bias)
2572 {
2573 textureFunction.method = TextureFunction::LOD0BIAS;
2574 }
2575 else
2576 {
2577 textureFunction.method = TextureFunction::LOD0;
2578 }
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002579 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002580 else if (bias)
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002581 {
Nicolas Capens84cfa122014-04-14 13:48:45 -04002582 textureFunction.method = TextureFunction::BIAS;
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002583 }
2584 }
2585
2586 mUsesTexture.insert(textureFunction);
Nicolas Capens84cfa122014-04-14 13:48:45 -04002587
Nicolas Capense0ba27a2013-06-24 16:10:52 -04002588 out << textureFunction.name();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002589 }
Nicolas Capens84cfa122014-04-14 13:48:45 -04002590
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00002591 for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
2592 {
2593 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
2594 {
2595 out << "texture_";
2596 (*arg)->traverse(this);
2597 out << ", sampler_";
2598 }
2599
2600 (*arg)->traverse(this);
2601
2602 if (arg < arguments.end() - 1)
2603 {
2604 out << ", ";
2605 }
2606 }
2607
2608 out << ")";
2609
2610 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002611 }
2612 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002613 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002614 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002615 addConstructor(node->getType(), "vec1", &node->getSequence());
2616 outputTriplet(visit, "vec1(", "", ")");
2617 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002618 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002619 addConstructor(node->getType(), "vec2", &node->getSequence());
2620 outputTriplet(visit, "vec2(", ", ", ")");
2621 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002622 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002623 addConstructor(node->getType(), "vec3", &node->getSequence());
2624 outputTriplet(visit, "vec3(", ", ", ")");
2625 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002626 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002627 addConstructor(node->getType(), "vec4", &node->getSequence());
2628 outputTriplet(visit, "vec4(", ", ", ")");
2629 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002630 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002631 addConstructor(node->getType(), "bvec1", &node->getSequence());
2632 outputTriplet(visit, "bvec1(", "", ")");
2633 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002634 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002635 addConstructor(node->getType(), "bvec2", &node->getSequence());
2636 outputTriplet(visit, "bvec2(", ", ", ")");
2637 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002638 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002639 addConstructor(node->getType(), "bvec3", &node->getSequence());
2640 outputTriplet(visit, "bvec3(", ", ", ")");
2641 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002642 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002643 addConstructor(node->getType(), "bvec4", &node->getSequence());
2644 outputTriplet(visit, "bvec4(", ", ", ")");
2645 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002646 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002647 addConstructor(node->getType(), "ivec1", &node->getSequence());
2648 outputTriplet(visit, "ivec1(", "", ")");
2649 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002650 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002651 addConstructor(node->getType(), "ivec2", &node->getSequence());
2652 outputTriplet(visit, "ivec2(", ", ", ")");
2653 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002654 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002655 addConstructor(node->getType(), "ivec3", &node->getSequence());
2656 outputTriplet(visit, "ivec3(", ", ", ")");
2657 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002658 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002659 addConstructor(node->getType(), "ivec4", &node->getSequence());
2660 outputTriplet(visit, "ivec4(", ", ", ")");
2661 break;
Nicolas Capensab60b932013-06-05 10:31:21 -04002662 case EOpConstructUInt:
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002663 addConstructor(node->getType(), "uvec1", &node->getSequence());
2664 outputTriplet(visit, "uvec1(", "", ")");
2665 break;
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +00002666 case EOpConstructUVec2:
2667 addConstructor(node->getType(), "uvec2", &node->getSequence());
2668 outputTriplet(visit, "uvec2(", ", ", ")");
2669 break;
2670 case EOpConstructUVec3:
2671 addConstructor(node->getType(), "uvec3", &node->getSequence());
2672 outputTriplet(visit, "uvec3(", ", ", ")");
2673 break;
2674 case EOpConstructUVec4:
2675 addConstructor(node->getType(), "uvec4", &node->getSequence());
2676 outputTriplet(visit, "uvec4(", ", ", ")");
2677 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002678 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002679 addConstructor(node->getType(), "mat2", &node->getSequence());
2680 outputTriplet(visit, "mat2(", ", ", ")");
2681 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002682 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002683 addConstructor(node->getType(), "mat3", &node->getSequence());
2684 outputTriplet(visit, "mat3(", ", ", ")");
2685 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002686 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002687 addConstructor(node->getType(), "mat4", &node->getSequence());
2688 outputTriplet(visit, "mat4(", ", ", ")");
2689 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002690 case EOpConstructStruct:
Jamie Madill98493dd2013-07-08 14:39:03 -04002691 addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence());
2692 outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002693 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002694 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
2695 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
2696 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
2697 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
2698 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
2699 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002700 case EOpMod:
2701 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002702 // We need to look at the number of components in both arguments
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002703 const int modValue = node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
2704 + node->getSequence()[1]->getAsTyped()->getNominalSize();
2705 switch (modValue)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002706 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00002707 case 11: mUsesMod1 = true; break;
2708 case 22: mUsesMod2v = true; break;
2709 case 21: mUsesMod2f = true; break;
2710 case 33: mUsesMod3v = true; break;
2711 case 31: mUsesMod3f = true; break;
2712 case 44: mUsesMod4v = true; break;
2713 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00002714 default: UNREACHABLE();
2715 }
2716
2717 outputTriplet(visit, "mod(", ", ", ")");
2718 }
2719 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002720 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002721 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00002722 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00002723 switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
2724 {
2725 case 1: mUsesAtan2_1 = true; break;
2726 case 2: mUsesAtan2_2 = true; break;
2727 case 3: mUsesAtan2_3 = true; break;
2728 case 4: mUsesAtan2_4 = true; break;
2729 default: UNREACHABLE();
2730 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +00002731 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002732 break;
2733 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
2734 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
2735 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
2736 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
2737 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
2738 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
2739 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
2740 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
2741 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002742 case EOpFaceForward:
2743 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00002744 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00002745 {
2746 case 1: mUsesFaceforward1 = true; break;
2747 case 2: mUsesFaceforward2 = true; break;
2748 case 3: mUsesFaceforward3 = true; break;
2749 case 4: mUsesFaceforward4 = true; break;
2750 default: UNREACHABLE();
2751 }
2752
2753 outputTriplet(visit, "faceforward(", ", ", ")");
2754 }
2755 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002756 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
2757 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
2758 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002759 default: UNREACHABLE();
2760 }
2761
2762 return true;
2763}
2764
2765bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
2766{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002767 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002768
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002769 if (node->usesTernaryOperator())
2770 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002771 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00002772 }
2773 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002774 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002775 mUnfoldShortCircuit->traverse(node->getCondition());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002776
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002777 out << "if (";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002778
2779 node->getCondition()->traverse(this);
2780
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002781 out << ")\n";
2782
Jamie Madill075edd82013-07-08 13:30:19 -04002783 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002784 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002785
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002786 bool discard = false;
2787
daniel@transgaming.combb885322010-04-15 20:45:24 +00002788 if (node->getTrueBlock())
2789 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002790 traverseStatements(node->getTrueBlock());
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002791
2792 // Detect true discard
2793 discard = (discard || FindDiscard::search(node->getTrueBlock()));
daniel@transgaming.combb885322010-04-15 20:45:24 +00002794 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002795
Jamie Madill075edd82013-07-08 13:30:19 -04002796 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002797 out << ";\n}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002798
2799 if (node->getFalseBlock())
2800 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002801 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002802
Jamie Madill075edd82013-07-08 13:30:19 -04002803 outputLineDirective(node->getFalseBlock()->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002804 out << "{\n";
2805
Jamie Madill075edd82013-07-08 13:30:19 -04002806 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002807 traverseStatements(node->getFalseBlock());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002808
Jamie Madill075edd82013-07-08 13:30:19 -04002809 outputLineDirective(node->getFalseBlock()->getLine().first_line);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002810 out << ";\n}\n";
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002811
2812 // Detect false discard
2813 discard = (discard || FindDiscard::search(node->getFalseBlock()));
2814 }
2815
2816 // ANGLE issue 486: Detect problematic conditional discard
2817 if (discard && FindSideEffectRewriting::search(node))
2818 {
2819 mUsesDiscardRewriting = true;
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00002820 }
2821 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002822
2823 return false;
2824}
2825
2826void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2827{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002828 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002829}
2830
2831bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2832{
Nicolas Capens655fe362014-04-11 13:12:34 -04002833 mNestedLoopDepth++;
2834
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002835 bool wasDiscontinuous = mInsideDiscontinuousLoop;
2836
shannon.woods@transgaming.come91615c2013-01-25 21:56:03 +00002837 if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002838 {
2839 mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
2840 }
2841
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002842 if (mOutputType == SH_HLSL9_OUTPUT)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002843 {
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002844 if (handleExcessiveLoop(node))
2845 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002846 mInsideDiscontinuousLoop = wasDiscontinuous;
2847 mNestedLoopDepth--;
2848
shannon.woods@transgaming.com9cbce922013-02-28 23:14:24 +00002849 return false;
2850 }
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002851 }
2852
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002853 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002854
alokp@chromium.org52813552010-11-16 18:36:09 +00002855 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002856 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002857 out << "{do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002858
Jamie Madill075edd82013-07-08 13:30:19 -04002859 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002860 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002861 }
2862 else
2863 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00002864 out << "{for(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002865
2866 if (node->getInit())
2867 {
2868 node->getInit()->traverse(this);
2869 }
2870
2871 out << "; ";
2872
alokp@chromium.org52813552010-11-16 18:36:09 +00002873 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002874 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002875 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002876 }
2877
2878 out << "; ";
2879
alokp@chromium.org52813552010-11-16 18:36:09 +00002880 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002881 {
alokp@chromium.org52813552010-11-16 18:36:09 +00002882 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002883 }
2884
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002885 out << ")\n";
2886
Jamie Madill075edd82013-07-08 13:30:19 -04002887 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002888 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002889 }
2890
2891 if (node->getBody())
2892 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002893 traverseStatements(node->getBody());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002894 }
2895
Jamie Madill075edd82013-07-08 13:30:19 -04002896 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00002897 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002898
alokp@chromium.org52813552010-11-16 18:36:09 +00002899 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002900 {
Jamie Madill075edd82013-07-08 13:30:19 -04002901 outputLineDirective(node->getCondition()->getLine().first_line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002902 out << "while(\n";
2903
alokp@chromium.org52813552010-11-16 18:36:09 +00002904 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002905
daniel@transgaming.com73536982012-03-21 20:45:49 +00002906 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002907 }
2908
daniel@transgaming.com73536982012-03-21 20:45:49 +00002909 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002910
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002911 mInsideDiscontinuousLoop = wasDiscontinuous;
Nicolas Capens655fe362014-04-11 13:12:34 -04002912 mNestedLoopDepth--;
daniel@transgaming.come11100c2012-05-31 01:20:32 +00002913
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002914 return false;
2915}
2916
2917bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2918{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002919 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002920
2921 switch (node->getFlowOp())
2922 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05002923 case EOpKill:
2924 outputTriplet(visit, "discard;\n", "", "");
2925 break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002926 case EOpBreak:
2927 if (visit == PreVisit)
2928 {
Nicolas Capens655fe362014-04-11 13:12:34 -04002929 if (mNestedLoopDepth > 1)
2930 {
2931 mUsesNestedBreak = true;
2932 }
2933
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002934 if (mExcessiveLoopIndex)
2935 {
2936 out << "{Break";
2937 mExcessiveLoopIndex->traverse(this);
2938 out << " = true; break;}\n";
2939 }
2940 else
2941 {
2942 out << "break;\n";
2943 }
2944 }
2945 break;
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00002946 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002947 case EOpReturn:
2948 if (visit == PreVisit)
2949 {
2950 if (node->getExpression())
2951 {
2952 out << "return ";
2953 }
2954 else
2955 {
2956 out << "return;\n";
2957 }
2958 }
2959 else if (visit == PostVisit)
2960 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002961 if (node->getExpression())
2962 {
2963 out << ";\n";
2964 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002965 }
2966 break;
2967 default: UNREACHABLE();
2968 }
2969
2970 return true;
2971}
2972
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002973void OutputHLSL::traverseStatements(TIntermNode *node)
2974{
2975 if (isSingleStatement(node))
2976 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00002977 mUnfoldShortCircuit->traverse(node);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00002978 }
2979
2980 node->traverse(this);
2981}
2982
daniel@transgaming.comb5875982010-04-15 20:44:53 +00002983bool OutputHLSL::isSingleStatement(TIntermNode *node)
2984{
2985 TIntermAggregate *aggregate = node->getAsAggregate();
2986
2987 if (aggregate)
2988 {
2989 if (aggregate->getOp() == EOpSequence)
2990 {
2991 return false;
2992 }
2993 else
2994 {
2995 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
2996 {
2997 if (!isSingleStatement(*sit))
2998 {
2999 return false;
3000 }
3001 }
3002
3003 return true;
3004 }
3005 }
3006
3007 return true;
3008}
3009
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003010// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
3011// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003012bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
3013{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003014 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com950f9932010-04-13 03:26:14 +00003015 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003016
3017 // Parse loops of the form:
3018 // for(int index = initial; index [comparator] limit; index += increment)
3019 TIntermSymbol *index = NULL;
3020 TOperator comparator = EOpNull;
3021 int initial = 0;
3022 int limit = 0;
3023 int increment = 0;
3024
3025 // Parse index name and intial value
3026 if (node->getInit())
3027 {
3028 TIntermAggregate *init = node->getInit()->getAsAggregate();
3029
3030 if (init)
3031 {
3032 TIntermSequence &sequence = init->getSequence();
3033 TIntermTyped *variable = sequence[0]->getAsTyped();
3034
3035 if (variable && variable->getQualifier() == EvqTemporary)
3036 {
3037 TIntermBinary *assign = variable->getAsBinaryNode();
3038
3039 if (assign->getOp() == EOpInitialize)
3040 {
3041 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
3042 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
3043
3044 if (symbol && constant)
3045 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003046 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003047 {
3048 index = symbol;
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00003049 initial = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003050 }
3051 }
3052 }
3053 }
3054 }
3055 }
3056
3057 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00003058 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003059 {
alokp@chromium.org52813552010-11-16 18:36:09 +00003060 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003061
3062 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
3063 {
3064 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
3065
3066 if (constant)
3067 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003068 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003069 {
3070 comparator = test->getOp();
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00003071 limit = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003072 }
3073 }
3074 }
3075 }
3076
3077 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00003078 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003079 {
alokp@chromium.org52813552010-11-16 18:36:09 +00003080 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
3081 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003082
3083 if (binaryTerminal)
3084 {
3085 TOperator op = binaryTerminal->getOp();
3086 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
3087
3088 if (constant)
3089 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003090 if (constant->getBasicType() == EbtInt && constant->isScalar())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003091 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +00003092 int value = constant->getIConst(0);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003093
3094 switch (op)
3095 {
3096 case EOpAddAssign: increment = value; break;
3097 case EOpSubAssign: increment = -value; break;
3098 default: UNIMPLEMENTED();
3099 }
3100 }
3101 }
3102 }
3103 else if (unaryTerminal)
3104 {
3105 TOperator op = unaryTerminal->getOp();
3106
3107 switch (op)
3108 {
3109 case EOpPostIncrement: increment = 1; break;
3110 case EOpPostDecrement: increment = -1; break;
3111 case EOpPreIncrement: increment = 1; break;
3112 case EOpPreDecrement: increment = -1; break;
3113 default: UNIMPLEMENTED();
3114 }
3115 }
3116 }
3117
3118 if (index != NULL && comparator != EOpNull && increment != 0)
3119 {
3120 if (comparator == EOpLessThanEqual)
3121 {
3122 comparator = EOpLessThan;
3123 limit += 1;
3124 }
3125
3126 if (comparator == EOpLessThan)
3127 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00003128 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003129
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003130 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003131 {
3132 return false; // Not an excessive loop
3133 }
3134
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003135 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
3136 mExcessiveLoopIndex = index;
3137
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003138 out << "{int ";
3139 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003140 out << ";\n"
3141 "bool Break";
3142 index->traverse(this);
3143 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003144
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003145 bool firstLoopFragment = true;
3146
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003147 while (iterations > 0)
3148 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003149 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003150
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003151 if (!firstLoopFragment)
3152 {
Jamie Madill3c9eeb92013-11-04 11:09:26 -05003153 out << "if (!Break";
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003154 index->traverse(this);
3155 out << ") {\n";
3156 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00003157
3158 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
3159 {
3160 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
3161 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00003162
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003163 // for(int index = initial; index < clampedLimit; index += increment)
3164
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00003165 out << "for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003166 index->traverse(this);
3167 out << " = ";
3168 out << initial;
3169
3170 out << "; ";
3171 index->traverse(this);
3172 out << " < ";
3173 out << clampedLimit;
3174
3175 out << "; ";
3176 index->traverse(this);
3177 out << " += ";
3178 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003179 out << ")\n";
3180
Jamie Madill075edd82013-07-08 13:30:19 -04003181 outputLineDirective(node->getLine().first_line);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003182 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003183
3184 if (node->getBody())
3185 {
3186 node->getBody()->traverse(this);
3187 }
3188
Jamie Madill075edd82013-07-08 13:30:19 -04003189 outputLineDirective(node->getLine().first_line);
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00003190 out << ";}\n";
3191
3192 if (!firstLoopFragment)
3193 {
3194 out << "}\n";
3195 }
3196
3197 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003198
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00003199 initial += MAX_LOOP_ITERATIONS * increment;
3200 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003201 }
daniel@transgaming.comc264de42012-07-11 20:37:25 +00003202
3203 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003204
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00003205 mExcessiveLoopIndex = restoreIndex;
3206
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00003207 return true;
3208 }
3209 else UNIMPLEMENTED();
3210 }
3211
3212 return false; // Not handled as an excessive loop
3213}
3214
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003215void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003216{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00003217 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003218
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003219 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003220 {
3221 out << preString;
3222 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003223 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003224 {
3225 out << inString;
3226 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003227 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003228 {
3229 out << postString;
3230 }
3231}
3232
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003233void OutputHLSL::outputLineDirective(int line)
3234{
3235 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
3236 {
baustin@google.com8ab69842011-06-02 21:53:45 +00003237 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00003238 mBody << "#line " << line;
3239
3240 if (mContext.sourcePath)
3241 {
3242 mBody << " \"" << mContext.sourcePath << "\"";
3243 }
3244
3245 mBody << "\n";
3246 }
3247}
3248
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003249TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
3250{
3251 TQualifier qualifier = symbol->getQualifier();
3252 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003253 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003254
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003255 if (name.empty()) // HLSL demands named arguments, also for prototypes
3256 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00003257 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003258 }
3259 else
3260 {
3261 name = decorate(name);
3262 }
3263
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003264 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
3265 {
Nicolas Capenscb127d32013-07-15 17:26:18 -04003266 return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " +
3267 qualifierString(qualifier) + " " + samplerString(type) + " sampler_" + name + arrayString(type);
shannon.woods@transgaming.com01a5cf92013-02-28 23:13:51 +00003268 }
3269
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003270 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003271}
3272
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00003273TString OutputHLSL::interpolationString(TQualifier qualifier)
3274{
3275 switch(qualifier)
3276 {
3277 case EvqVaryingIn: return "";
Jamie Madill19571812013-08-12 15:26:34 -07003278 case EvqFragmentIn: return "";
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00003279 case EvqInvariantVaryingIn: return "";
3280 case EvqSmoothIn: return "linear";
3281 case EvqFlatIn: return "nointerpolation";
3282 case EvqCentroidIn: return "centroid";
3283 case EvqVaryingOut: return "";
Jamie Madill19571812013-08-12 15:26:34 -07003284 case EvqVertexOut: return "";
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00003285 case EvqInvariantVaryingOut: return "";
3286 case EvqSmoothOut: return "linear";
3287 case EvqFlatOut: return "nointerpolation";
3288 case EvqCentroidOut: return "centroid";
3289 default: UNREACHABLE();
3290 }
3291
3292 return "";
3293}
3294
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00003295TString OutputHLSL::qualifierString(TQualifier qualifier)
3296{
3297 switch(qualifier)
3298 {
3299 case EvqIn: return "in";
3300 case EvqOut: return "out";
3301 case EvqInOut: return "inout";
3302 case EvqConstReadOnly: return "const";
3303 default: UNREACHABLE();
3304 }
3305
3306 return "";
3307}
3308
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003309TString OutputHLSL::typeString(const TType &type)
3310{
Jamie Madill98493dd2013-07-08 14:39:03 -04003311 const TStructure* structure = type.getStruct();
3312 if (structure)
daniel@transgaming.comfe565152010-04-10 05:29:07 +00003313 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003314 const TString& typeName = structure->name();
3315 if (typeName != "")
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003316 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003317 return structLookup(typeName);
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003318 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00003319 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003320 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003321 return structureString(*structure, false, false);
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003322 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00003323 }
3324 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003325 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00003326 int cols = type.getCols();
3327 int rows = type.getRows();
3328 return "float" + str(cols) + "x" + str(rows);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003329 }
3330 else
3331 {
3332 switch (type.getBasicType())
3333 {
3334 case EbtFloat:
3335 switch (type.getNominalSize())
3336 {
3337 case 1: return "float";
3338 case 2: return "float2";
3339 case 3: return "float3";
3340 case 4: return "float4";
3341 }
3342 case EbtInt:
3343 switch (type.getNominalSize())
3344 {
3345 case 1: return "int";
3346 case 2: return "int2";
3347 case 3: return "int3";
3348 case 4: return "int4";
3349 }
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00003350 case EbtUInt:
Jamie Madill22d63da2013-06-07 12:45:12 -04003351 switch (type.getNominalSize())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00003352 {
3353 case 1: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +00003354 case 2: return "uint2";
3355 case 3: return "uint3";
3356 case 4: return "uint4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00003357 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003358 case EbtBool:
3359 switch (type.getNominalSize())
3360 {
3361 case 1: return "bool";
3362 case 2: return "bool2";
3363 case 3: return "bool3";
3364 case 4: return "bool4";
3365 }
3366 case EbtVoid:
3367 return "void";
3368 case EbtSampler2D:
Nicolas Capens1f1a8332013-06-24 15:42:27 -04003369 case EbtISampler2D:
Nicolas Capens075368e2013-06-24 15:58:30 -04003370 case EbtUSampler2D:
Nicolas Capensfb50dff2013-06-24 16:16:23 -04003371 case EbtSampler2DArray:
3372 case EbtISampler2DArray:
3373 case EbtUSampler2DArray:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003374 return "sampler2D";
3375 case EbtSamplerCube:
Nicolas Capens1f1a8332013-06-24 15:42:27 -04003376 case EbtISamplerCube:
Nicolas Capens075368e2013-06-24 15:58:30 -04003377 case EbtUSamplerCube:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003378 return "samplerCUBE";
apatrick@chromium.org65756022012-01-17 21:45:38 +00003379 case EbtSamplerExternalOES:
3380 return "sampler2D";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00003381 default:
3382 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003383 }
3384 }
3385
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00003386 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003387 return "<unknown type>";
3388}
3389
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00003390TString OutputHLSL::textureString(const TType &type)
3391{
3392 switch (type.getBasicType())
3393 {
Nicolas Capenscb127d32013-07-15 17:26:18 -04003394 case EbtSampler2D: return "Texture2D";
3395 case EbtSamplerCube: return "TextureCube";
3396 case EbtSamplerExternalOES: return "Texture2D";
3397 case EbtSampler2DArray: return "Texture2DArray";
3398 case EbtSampler3D: return "Texture3D";
3399 case EbtISampler2D: return "Texture2D<int4>";
3400 case EbtISampler3D: return "Texture3D<int4>";
Nicolas Capens0027fa92014-02-20 14:26:42 -05003401 case EbtISamplerCube: return "Texture2DArray<int4>";
Nicolas Capenscb127d32013-07-15 17:26:18 -04003402 case EbtISampler2DArray: return "Texture2DArray<int4>";
3403 case EbtUSampler2D: return "Texture2D<uint4>";
3404 case EbtUSampler3D: return "Texture3D<uint4>";
Nicolas Capens0027fa92014-02-20 14:26:42 -05003405 case EbtUSamplerCube: return "Texture2DArray<uint4>";
Nicolas Capenscb127d32013-07-15 17:26:18 -04003406 case EbtUSampler2DArray: return "Texture2DArray<uint4>";
3407 case EbtSampler2DShadow: return "Texture2D";
3408 case EbtSamplerCubeShadow: return "TextureCube";
3409 case EbtSampler2DArrayShadow: return "Texture2DArray";
3410 default: UNREACHABLE();
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00003411 }
Nicolas Capenscb127d32013-07-15 17:26:18 -04003412
shannon.woods@transgaming.comfb256be2013-01-25 21:49:25 +00003413 return "<unknown texture type>";
3414}
3415
Nicolas Capenscb127d32013-07-15 17:26:18 -04003416TString OutputHLSL::samplerString(const TType &type)
3417{
3418 if (IsShadowSampler(type.getBasicType()))
3419 {
3420 return "SamplerComparisonState";
3421 }
3422 else
3423 {
3424 return "SamplerState";
3425 }
3426}
3427
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003428TString OutputHLSL::arrayString(const TType &type)
3429{
3430 if (!type.isArray())
3431 {
3432 return "";
3433 }
3434
daniel@transgaming.com005c7392010-04-15 20:45:27 +00003435 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003436}
3437
3438TString OutputHLSL::initializer(const TType &type)
3439{
3440 TString string;
3441
Jamie Madill94bf7f22013-07-08 13:31:15 -04003442 size_t size = type.getObjectSize();
3443 for (size_t component = 0; component < size; component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003444 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00003445 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003446
Jamie Madill94bf7f22013-07-08 13:31:15 -04003447 if (component + 1 < size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003448 {
3449 string += ", ";
3450 }
3451 }
3452
daniel@transgaming.comead23042010-04-29 03:35:36 +00003453 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003454}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003455
Jamie Madill98493dd2013-07-08 14:39:03 -04003456TString OutputHLSL::structureString(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
Jamie Madill9cf6c072013-06-20 11:55:53 -04003457{
Jamie Madill98493dd2013-07-08 14:39:03 -04003458 const TFieldList &fields = structure.fields();
3459 const bool isNameless = (structure.name() == "");
3460 const TString &structName = structureTypeName(structure, useHLSLRowMajorPacking, useStd140Packing);
Jamie Madill9cf6c072013-06-20 11:55:53 -04003461 const TString declareString = (isNameless ? "struct" : "struct " + structName);
3462
Jamie Madill98493dd2013-07-08 14:39:03 -04003463 TString string;
3464 string += declareString + "\n"
3465 "{\n";
Jamie Madill9cf6c072013-06-20 11:55:53 -04003466
Jamie Madillc835df62013-06-21 09:15:32 -04003467 int elementIndex = 0;
3468
Jamie Madill9cf6c072013-06-20 11:55:53 -04003469 for (unsigned int i = 0; i < fields.size(); i++)
3470 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003471 const TField &field = *fields[i];
3472 const TType &fieldType = *field.type();
3473 const TStructure *fieldStruct = fieldType.getStruct();
3474 const TString &fieldTypeString = fieldStruct ? structureTypeName(*fieldStruct, useHLSLRowMajorPacking, useStd140Packing) : typeString(fieldType);
Jamie Madill9cf6c072013-06-20 11:55:53 -04003475
Jamie Madillc835df62013-06-21 09:15:32 -04003476 if (useStd140Packing)
3477 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003478 string += std140PrePaddingString(*field.type(), &elementIndex);
Jamie Madillc835df62013-06-21 09:15:32 -04003479 }
3480
Jamie Madill98493dd2013-07-08 14:39:03 -04003481 string += " " + fieldTypeString + " " + decorateField(field.name(), structure) + arrayString(fieldType) + ";\n";
Jamie Madillc835df62013-06-21 09:15:32 -04003482
3483 if (useStd140Packing)
3484 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003485 string += std140PostPaddingString(*field.type(), useHLSLRowMajorPacking);
Jamie Madillc835df62013-06-21 09:15:32 -04003486 }
Jamie Madill9cf6c072013-06-20 11:55:53 -04003487 }
3488
3489 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
Jamie Madill98493dd2013-07-08 14:39:03 -04003490 string += (isNameless ? "} " : "};\n");
Jamie Madill9cf6c072013-06-20 11:55:53 -04003491
Jamie Madille4075c92013-06-21 09:15:32 -04003492 // Add remaining element index to the global map, for use with nested structs in standard layouts
3493 if (useStd140Packing)
3494 {
3495 mStd140StructElementIndexes[structName] = elementIndex;
3496 }
3497
Jamie Madill98493dd2013-07-08 14:39:03 -04003498 return string;
Jamie Madill9cf6c072013-06-20 11:55:53 -04003499}
3500
Jamie Madill98493dd2013-07-08 14:39:03 -04003501TString OutputHLSL::structureTypeName(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
Jamie Madill9cf6c072013-06-20 11:55:53 -04003502{
Jamie Madill98493dd2013-07-08 14:39:03 -04003503 if (structure.name() == "")
Jamie Madill9cf6c072013-06-20 11:55:53 -04003504 {
3505 return "";
3506 }
3507
3508 TString prefix = "";
3509
3510 // Structs packed with row-major matrices in HLSL are prefixed with "rm"
3511 // GLSL column-major maps to HLSL row-major, and the converse is true
Jamie Madillc835df62013-06-21 09:15:32 -04003512
3513 if (useStd140Packing)
3514 {
3515 prefix += "std";
3516 }
3517
Jamie Madill9cf6c072013-06-20 11:55:53 -04003518 if (useHLSLRowMajorPacking)
3519 {
Jamie Madillc835df62013-06-21 09:15:32 -04003520 if (prefix != "") prefix += "_";
Jamie Madill9cf6c072013-06-20 11:55:53 -04003521 prefix += "rm";
3522 }
3523
Jamie Madill98493dd2013-07-08 14:39:03 -04003524 return prefix + structLookup(structure.name());
Jamie Madill9cf6c072013-06-20 11:55:53 -04003525}
3526
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00003527void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00003528{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003529 if (name == "")
3530 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00003531 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00003532 }
3533
daniel@transgaming.com43eecdc2012-03-20 20:10:33 +00003534 if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
3535 {
3536 return; // Already added
3537 }
3538
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003539 TType ctorType = type;
3540 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00003541 ctorType.setPrecision(EbpHigh);
3542 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00003543
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003544 TString ctorName = type.getStruct() ? decorate(name) : name;
3545
3546 typedef std::vector<TType> ParameterArray;
3547 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00003548
Jamie Madill98493dd2013-07-08 14:39:03 -04003549 const TStructure* structure = type.getStruct();
3550 if (structure)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003551 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003552 mStructNames.insert(decorate(name));
3553
Jamie Madill98493dd2013-07-08 14:39:03 -04003554 const TString &structString = structureString(*structure, false, false);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003555
Jamie Madill98493dd2013-07-08 14:39:03 -04003556 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003557 {
Jamie Madill9cf6c072013-06-20 11:55:53 -04003558 // Add row-major packed struct for interface blocks
3559 TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
Jamie Madill98493dd2013-07-08 14:39:03 -04003560 structureString(*structure, true, false) +
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00003561 "#pragma pack_matrix(column_major)\n";
3562
Jamie Madill98493dd2013-07-08 14:39:03 -04003563 TString std140String = structureString(*structure, false, true);
Jamie Madillc835df62013-06-21 09:15:32 -04003564 TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
Jamie Madill98493dd2013-07-08 14:39:03 -04003565 structureString(*structure, true, true) +
Jamie Madillc835df62013-06-21 09:15:32 -04003566 "#pragma pack_matrix(column_major)\n";
3567
Jamie Madill98493dd2013-07-08 14:39:03 -04003568 mStructDeclarations.push_back(structString);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00003569 mStructDeclarations.push_back(rowMajorString);
Jamie Madillc835df62013-06-21 09:15:32 -04003570 mStructDeclarations.push_back(std140String);
3571 mStructDeclarations.push_back(std140RowMajorString);
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003572 }
3573
Jamie Madill98493dd2013-07-08 14:39:03 -04003574 const TFieldList &fields = structure->fields();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003575 for (unsigned int i = 0; i < fields.size(); i++)
3576 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003577 ctorParameters.push_back(*fields[i]->type());
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003578 }
3579 }
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00003580 else if (parameters)
3581 {
3582 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
3583 {
3584 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
3585 }
3586 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00003587 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00003588
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003589 TString constructor;
3590
3591 if (ctorType.getStruct())
3592 {
3593 constructor += ctorName + " " + ctorName + "_ctor(";
3594 }
3595 else // Built-in type
3596 {
3597 constructor += typeString(ctorType) + " " + ctorName + "(";
3598 }
3599
3600 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
3601 {
3602 const TType &type = ctorParameters[parameter];
3603
3604 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
3605
3606 if (parameter < ctorParameters.size() - 1)
3607 {
3608 constructor += ", ";
3609 }
3610 }
3611
3612 constructor += ")\n"
3613 "{\n";
3614
3615 if (ctorType.getStruct())
3616 {
3617 constructor += " " + ctorName + " structure = {";
3618 }
3619 else
3620 {
3621 constructor += " return " + typeString(ctorType) + "(";
3622 }
3623
3624 if (ctorType.isMatrix() && ctorParameters.size() == 1)
3625 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003626 int rows = ctorType.getRows();
3627 int cols = ctorType.getCols();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003628 const TType &parameter = ctorParameters[0];
3629
3630 if (parameter.isScalar())
3631 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003632 for (int row = 0; row < rows; row++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003633 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003634 for (int col = 0; col < cols; col++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003635 {
3636 constructor += TString((row == col) ? "x0" : "0.0");
3637
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003638 if (row < rows - 1 || col < cols - 1)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003639 {
3640 constructor += ", ";
3641 }
3642 }
3643 }
3644 }
3645 else if (parameter.isMatrix())
3646 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003647 for (int row = 0; row < rows; row++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003648 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003649 for (int col = 0; col < cols; col++)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003650 {
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003651 if (row < parameter.getRows() && col < parameter.getCols())
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003652 {
3653 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
3654 }
3655 else
3656 {
3657 constructor += TString((row == col) ? "1.0" : "0.0");
3658 }
3659
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003660 if (row < rows - 1 || col < cols - 1)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003661 {
3662 constructor += ", ";
3663 }
3664 }
3665 }
3666 }
3667 else UNREACHABLE();
3668 }
3669 else
3670 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003671 size_t remainingComponents = ctorType.getObjectSize();
3672 size_t parameterIndex = 0;
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003673
3674 while (remainingComponents > 0)
3675 {
3676 const TType &parameter = ctorParameters[parameterIndex];
Jamie Madill94bf7f22013-07-08 13:31:15 -04003677 const size_t parameterSize = parameter.getObjectSize();
3678 bool moreParameters = parameterIndex + 1 < ctorParameters.size();
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003679
3680 constructor += "x" + str(parameterIndex);
3681
3682 if (parameter.isScalar())
3683 {
3684 remainingComponents -= parameter.getObjectSize();
3685 }
3686 else if (parameter.isVector())
3687 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003688 if (remainingComponents == parameterSize || moreParameters)
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003689 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003690 ASSERT(parameterSize <= remainingComponents);
3691 remainingComponents -= parameterSize;
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003692 }
Jamie Madill94bf7f22013-07-08 13:31:15 -04003693 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003694 {
3695 switch (remainingComponents)
3696 {
3697 case 1: constructor += ".x"; break;
3698 case 2: constructor += ".xy"; break;
3699 case 3: constructor += ".xyz"; break;
3700 case 4: constructor += ".xyzw"; break;
3701 default: UNREACHABLE();
3702 }
3703
3704 remainingComponents = 0;
3705 }
3706 else UNREACHABLE();
3707 }
3708 else if (parameter.isMatrix() || parameter.getStruct())
3709 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003710 ASSERT(remainingComponents == parameterSize || moreParameters);
3711 ASSERT(parameterSize <= remainingComponents);
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003712
Jamie Madill94bf7f22013-07-08 13:31:15 -04003713 remainingComponents -= parameterSize;
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003714 }
3715 else UNREACHABLE();
3716
3717 if (moreParameters)
3718 {
3719 parameterIndex++;
3720 }
3721
3722 if (remainingComponents)
3723 {
3724 constructor += ", ";
3725 }
3726 }
3727 }
3728
3729 if (ctorType.getStruct())
3730 {
3731 constructor += "};\n"
3732 " return structure;\n"
3733 "}\n";
3734 }
3735 else
3736 {
3737 constructor += ");\n"
3738 "}\n";
3739 }
3740
daniel@transgaming.com63691862010-04-29 03:32:42 +00003741 mConstructors.insert(constructor);
3742}
3743
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003744const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
3745{
3746 TInfoSinkBase &out = mBody;
3747
Jamie Madill98493dd2013-07-08 14:39:03 -04003748 const TStructure* structure = type.getStruct();
3749 if (structure)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003750 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003751 out << structLookup(structure->name()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003752
Jamie Madill98493dd2013-07-08 14:39:03 -04003753 const TFieldList& fields = structure->fields();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003754
Jamie Madill98493dd2013-07-08 14:39:03 -04003755 for (size_t i = 0; i < fields.size(); i++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003756 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003757 const TType *fieldType = fields[i]->type();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003758
3759 constUnion = writeConstantUnion(*fieldType, constUnion);
3760
Jamie Madill98493dd2013-07-08 14:39:03 -04003761 if (i != fields.size() - 1)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003762 {
3763 out << ", ";
3764 }
3765 }
3766
3767 out << ")";
3768 }
3769 else
3770 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04003771 size_t size = type.getObjectSize();
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003772 bool writeType = size > 1;
3773
3774 if (writeType)
3775 {
3776 out << typeString(type) << "(";
3777 }
3778
Jamie Madill94bf7f22013-07-08 13:31:15 -04003779 for (size_t i = 0; i < size; i++, constUnion++)
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003780 {
3781 switch (constUnion->getType())
3782 {
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +00003783 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003784 case EbtInt: out << constUnion->getIConst(); break;
Nicolas Capensc0f7c612013-06-05 11:46:09 -04003785 case EbtUInt: out << constUnion->getUConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00003786 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00003787 default: UNREACHABLE();
3788 }
3789
3790 if (i != size - 1)
3791 {
3792 out << ", ";
3793 }
3794 }
3795
3796 if (writeType)
3797 {
3798 out << ")";
3799 }
3800 }
3801
3802 return constUnion;
3803}
3804
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00003805TString OutputHLSL::scopeString(unsigned int depthLimit)
3806{
3807 TString string;
3808
3809 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
3810 {
3811 string += "_" + str(i);
3812 }
3813
3814 return string;
3815}
3816
3817TString OutputHLSL::scopedStruct(const TString &typeName)
3818{
3819 if (typeName == "")
3820 {
3821 return typeName;
3822 }
3823
3824 return typeName + scopeString(mScopeDepth);
3825}
3826
3827TString OutputHLSL::structLookup(const TString &typeName)
3828{
3829 for (int depth = mScopeDepth; depth >= 0; depth--)
3830 {
3831 TString scopedName = decorate(typeName + scopeString(depth));
3832
3833 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
3834 {
3835 if (*structName == scopedName)
3836 {
3837 return scopedName;
3838 }
3839 }
3840 }
3841
3842 UNREACHABLE(); // Should have found a matching constructor
3843
3844 return typeName;
3845}
3846
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003847TString OutputHLSL::decorate(const TString &string)
3848{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00003849 if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003850 {
3851 return "_" + string;
3852 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00003853
3854 return string;
3855}
3856
apatrick@chromium.org65756022012-01-17 21:45:38 +00003857TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00003858{
daniel@transgaming.comdb019952012-12-20 21:13:32 +00003859 if (type.getBasicType() == EbtSamplerExternalOES)
apatrick@chromium.org65756022012-01-17 21:45:38 +00003860 {
3861 return "ex_" + string;
3862 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00003863
3864 return decorate(string);
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00003865}
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00003866
Jamie Madill98493dd2013-07-08 14:39:03 -04003867TString OutputHLSL::decorateField(const TString &string, const TStructure &structure)
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00003868{
Jamie Madill98493dd2013-07-08 14:39:03 -04003869 if (structure.name().compare(0, 3, "gl_") != 0)
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00003870 {
3871 return decorate(string);
3872 }
3873
3874 return string;
3875}
daniel@transgaming.com652468c2012-12-20 21:11:57 +00003876
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003877void OutputHLSL::declareInterfaceBlockField(const TType &type, const TString &name, std::vector<InterfaceBlockField>& output)
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003878{
Jamie Madill98493dd2013-07-08 14:39:03 -04003879 const TStructure *structure = type.getStruct();
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003880
3881 if (!structure)
3882 {
Jamie Madill010fffa2013-06-20 11:55:53 -04003883 const bool isRowMajorMatrix = (type.isMatrix() && type.getLayoutQualifier().matrixPacking == EmpRowMajor);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003884 InterfaceBlockField field(glVariableType(type), glVariablePrecision(type), name.c_str(),
3885 (unsigned int)type.getArraySize(), isRowMajorMatrix);
3886 output.push_back(field);
3887 }
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003888 else
3889 {
Jamie Madill28167c62013-08-30 13:21:10 -04003890 InterfaceBlockField structField(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), false);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003891
3892 const TFieldList &fields = structure->fields();
3893
3894 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
3895 {
3896 TField *field = fields[fieldIndex];
3897 TType *fieldType = field->type();
3898
3899 // make sure to copy matrix packing information
3900 fieldType->setLayoutQualifier(type.getLayoutQualifier());
3901
3902 declareInterfaceBlockField(*fieldType, field->name(), structField.fields);
3903 }
3904
3905 output.push_back(structField);
3906 }
3907}
3908
Jamie Madillc2141fb2013-08-30 13:21:08 -04003909Uniform OutputHLSL::declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<Uniform>& output)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003910{
3911 const TStructure *structure = type.getStruct();
3912
3913 if (!structure)
3914 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003915 Uniform uniform(glVariableType(type), glVariablePrecision(type), name.c_str(),
Jamie Madill56093782013-08-30 13:21:11 -04003916 (unsigned int)type.getArraySize(), (unsigned int)registerIndex, 0);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003917 output.push_back(uniform);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003918
3919 return uniform;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04003920 }
3921 else
3922 {
Jamie Madill56093782013-08-30 13:21:11 -04003923 Uniform structUniform(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(),
3924 (unsigned int)registerIndex, GL_INVALID_INDEX);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003925
Jamie Madill98493dd2013-07-08 14:39:03 -04003926 const TFieldList &fields = structure->fields();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003927
Jamie Madill98493dd2013-07-08 14:39:03 -04003928 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003929 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003930 TField *field = fields[fieldIndex];
3931 TType *fieldType = field->type();
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003932
Jamie Madill56093782013-08-30 13:21:11 -04003933 declareUniformToList(*fieldType, field->name(), GL_INVALID_INDEX, structUniform.fields);
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003934 }
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003935
Jamie Madill56093782013-08-30 13:21:11 -04003936 // assign register offset information -- this will override the information in any sub-structures.
3937 HLSLVariableGetRegisterInfo(registerIndex, &structUniform);
3938
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003939 output.push_back(structUniform);
Jamie Madillc2141fb2013-08-30 13:21:08 -04003940
3941 return structUniform;
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00003942 }
3943}
3944
Jamie Madill139b9092013-08-30 13:21:06 -04003945InterpolationType getInterpolationType(TQualifier qualifier)
3946{
3947 switch (qualifier)
3948 {
3949 case EvqFlatIn:
3950 case EvqFlatOut:
3951 return INTERPOLATION_FLAT;
3952
3953 case EvqSmoothIn:
3954 case EvqSmoothOut:
3955 case EvqVertexOut:
3956 case EvqFragmentIn:
Jamie Madill384b6042013-09-13 10:06:24 -04003957 case EvqVaryingIn:
3958 case EvqVaryingOut:
Jamie Madill139b9092013-08-30 13:21:06 -04003959 return INTERPOLATION_SMOOTH;
3960
3961 case EvqCentroidIn:
3962 case EvqCentroidOut:
3963 return INTERPOLATION_CENTROID;
3964
3965 default: UNREACHABLE();
3966 return INTERPOLATION_SMOOTH;
3967 }
3968}
3969
Jamie Madill94599662013-08-30 13:21:10 -04003970void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<Varying>& fieldsOut)
Jamie Madill47fdd132013-08-30 13:21:04 -04003971{
3972 const TStructure *structure = type.getStruct();
3973
Jamie Madill94599662013-08-30 13:21:10 -04003974 InterpolationType interpolation = getInterpolationType(baseTypeQualifier);
Jamie Madill47fdd132013-08-30 13:21:04 -04003975 if (!structure)
3976 {
Jamie Madill139b9092013-08-30 13:21:06 -04003977 Varying varying(glVariableType(type), glVariablePrecision(type), name.c_str(), (unsigned int)type.getArraySize(), interpolation);
Jamie Madill47fdd132013-08-30 13:21:04 -04003978 fieldsOut.push_back(varying);
3979 }
3980 else
3981 {
Jamie Madill28167c62013-08-30 13:21:10 -04003982 Varying structVarying(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), interpolation);
Jamie Madill47fdd132013-08-30 13:21:04 -04003983 const TFieldList &fields = structure->fields();
3984
Jamie Madill28167c62013-08-30 13:21:10 -04003985 structVarying.structName = structure->name().c_str();
3986
Jamie Madill47fdd132013-08-30 13:21:04 -04003987 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
3988 {
3989 const TField &field = *fields[fieldIndex];
Jamie Madill94599662013-08-30 13:21:10 -04003990 declareVaryingToList(*field.type(), baseTypeQualifier, field.name(), structVarying.fields);
Jamie Madill47fdd132013-08-30 13:21:04 -04003991 }
3992
3993 fieldsOut.push_back(structVarying);
3994 }
3995}
3996
Jamie Madillc2141fb2013-08-30 13:21:08 -04003997int OutputHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00003998{
Jamie Madillc2141fb2013-08-30 13:21:08 -04003999 int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
4000
4001 const Uniform &uniform = declareUniformToList(type, name, registerIndex, mActiveUniforms);
4002
4003 if (IsSampler(type.getBasicType()))
4004 {
4005 mSamplerRegister += HLSLVariableRegisterCount(uniform);
4006 }
4007 else
4008 {
4009 mUniformRegister += HLSLVariableRegisterCount(uniform);
4010 }
4011
4012 return registerIndex;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00004013}
4014
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004015GLenum OutputHLSL::glVariableType(const TType &type)
4016{
4017 if (type.getBasicType() == EbtFloat)
4018 {
4019 if (type.isScalar())
4020 {
4021 return GL_FLOAT;
4022 }
4023 else if (type.isVector())
4024 {
4025 switch(type.getNominalSize())
4026 {
4027 case 2: return GL_FLOAT_VEC2;
4028 case 3: return GL_FLOAT_VEC3;
4029 case 4: return GL_FLOAT_VEC4;
4030 default: UNREACHABLE();
4031 }
4032 }
4033 else if (type.isMatrix())
4034 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00004035 switch (type.getCols())
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004036 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00004037 case 2:
4038 switch(type.getRows())
4039 {
4040 case 2: return GL_FLOAT_MAT2;
4041 case 3: return GL_FLOAT_MAT2x3;
4042 case 4: return GL_FLOAT_MAT2x4;
4043 default: UNREACHABLE();
4044 }
4045
4046 case 3:
4047 switch(type.getRows())
4048 {
4049 case 2: return GL_FLOAT_MAT3x2;
4050 case 3: return GL_FLOAT_MAT3;
4051 case 4: return GL_FLOAT_MAT3x4;
4052 default: UNREACHABLE();
4053 }
4054
4055 case 4:
4056 switch(type.getRows())
4057 {
4058 case 2: return GL_FLOAT_MAT4x2;
4059 case 3: return GL_FLOAT_MAT4x3;
4060 case 4: return GL_FLOAT_MAT4;
4061 default: UNREACHABLE();
4062 }
4063
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004064 default: UNREACHABLE();
4065 }
4066 }
4067 else UNREACHABLE();
4068 }
4069 else if (type.getBasicType() == EbtInt)
4070 {
4071 if (type.isScalar())
4072 {
4073 return GL_INT;
4074 }
4075 else if (type.isVector())
4076 {
4077 switch(type.getNominalSize())
4078 {
4079 case 2: return GL_INT_VEC2;
4080 case 3: return GL_INT_VEC3;
4081 case 4: return GL_INT_VEC4;
4082 default: UNREACHABLE();
4083 }
4084 }
4085 else UNREACHABLE();
4086 }
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00004087 else if (type.getBasicType() == EbtUInt)
4088 {
4089 if (type.isScalar())
4090 {
4091 return GL_UNSIGNED_INT;
4092 }
4093 else if (type.isVector())
4094 {
Jamie Madill22d63da2013-06-07 12:45:12 -04004095 switch(type.getNominalSize())
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +00004096 {
4097 case 2: return GL_UNSIGNED_INT_VEC2;
4098 case 3: return GL_UNSIGNED_INT_VEC3;
4099 case 4: return GL_UNSIGNED_INT_VEC4;
4100 default: UNREACHABLE();
4101 }
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00004102 }
4103 else UNREACHABLE();
4104 }
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004105 else if (type.getBasicType() == EbtBool)
4106 {
4107 if (type.isScalar())
4108 {
4109 return GL_BOOL;
4110 }
4111 else if (type.isVector())
4112 {
4113 switch(type.getNominalSize())
4114 {
4115 case 2: return GL_BOOL_VEC2;
4116 case 3: return GL_BOOL_VEC3;
4117 case 4: return GL_BOOL_VEC4;
4118 default: UNREACHABLE();
4119 }
4120 }
4121 else UNREACHABLE();
4122 }
Nicolas Capens354ed2d2013-07-11 11:26:26 -04004123
4124 switch(type.getBasicType())
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004125 {
Nicolas Capens354ed2d2013-07-11 11:26:26 -04004126 case EbtSampler2D: return GL_SAMPLER_2D;
4127 case EbtSampler3D: return GL_SAMPLER_3D;
4128 case EbtSamplerCube: return GL_SAMPLER_CUBE;
4129 case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY;
4130 case EbtISampler2D: return GL_INT_SAMPLER_2D;
4131 case EbtISampler3D: return GL_INT_SAMPLER_3D;
4132 case EbtISamplerCube: return GL_INT_SAMPLER_CUBE;
4133 case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY;
4134 case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D;
4135 case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D;
4136 case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE;
4137 case EbtUSampler2DArray: return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
4138 case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW;
4139 case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW;
4140 case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW;
4141 default: UNREACHABLE();
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004142 }
Nicolas Capens354ed2d2013-07-11 11:26:26 -04004143
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00004144 return GL_NONE;
4145}
4146
shannon.woods@transgaming.comfe3c0ef2013-02-28 23:17:22 +00004147GLenum OutputHLSL::glVariablePrecision(const TType &type)
4148{
4149 if (type.getBasicType() == EbtFloat)
4150 {
4151 switch (type.getPrecision())
4152 {
4153 case EbpHigh: return GL_HIGH_FLOAT;
4154 case EbpMedium: return GL_MEDIUM_FLOAT;
4155 case EbpLow: return GL_LOW_FLOAT;
4156 case EbpUndefined:
4157 // Should be defined as the default precision by the parser
4158 default: UNREACHABLE();
4159 }
4160 }
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00004161 else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt)
shannon.woods@transgaming.comfe3c0ef2013-02-28 23:17:22 +00004162 {
4163 switch (type.getPrecision())
4164 {
4165 case EbpHigh: return GL_HIGH_INT;
4166 case EbpMedium: return GL_MEDIUM_INT;
4167 case EbpLow: return GL_LOW_INT;
4168 case EbpUndefined:
4169 // Should be defined as the default precision by the parser
4170 default: UNREACHABLE();
4171 }
4172 }
shannon.woods@transgaming.comfe3c0ef2013-02-28 23:17:22 +00004173
shannon.woods@transgaming.com10aadb22013-02-28 23:17:52 +00004174 // Other types (boolean, sampler) don't have a precision
shannon.woods@transgaming.comfe3c0ef2013-02-28 23:17:22 +00004175 return GL_NONE;
4176}
4177
shannon.woods%transgaming.com@gtempaccount.com6f273e32013-04-13 03:41:15 +00004178bool OutputHLSL::isVaryingOut(TQualifier qualifier)
4179{
4180 switch(qualifier)
4181 {
4182 case EvqVaryingOut:
4183 case EvqInvariantVaryingOut:
4184 case EvqSmoothOut:
4185 case EvqFlatOut:
4186 case EvqCentroidOut:
Jamie Madill19571812013-08-12 15:26:34 -07004187 case EvqVertexOut:
shannon.woods%transgaming.com@gtempaccount.com6f273e32013-04-13 03:41:15 +00004188 return true;
4189 }
4190
4191 return false;
4192}
4193
4194bool OutputHLSL::isVaryingIn(TQualifier qualifier)
4195{
4196 switch(qualifier)
4197 {
4198 case EvqVaryingIn:
4199 case EvqInvariantVaryingIn:
4200 case EvqSmoothIn:
4201 case EvqFlatIn:
4202 case EvqCentroidIn:
Jamie Madill19571812013-08-12 15:26:34 -07004203 case EvqFragmentIn:
shannon.woods%transgaming.com@gtempaccount.com6f273e32013-04-13 03:41:15 +00004204 return true;
4205 }
4206
4207 return false;
4208}
4209
4210bool OutputHLSL::isVarying(TQualifier qualifier)
4211{
4212 return isVaryingIn(qualifier) || isVaryingOut(qualifier);
4213}
4214
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00004215}