|
1 // |
|
2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. |
|
3 // Use of this source code is governed by a BSD-style license that can be |
|
4 // found in the LICENSE file. |
|
5 // |
|
6 |
|
7 #include "compiler/OutputHLSL.h" |
|
8 |
|
9 #include "common/angleutils.h" |
|
10 #include "compiler/compiler_debug.h" |
|
11 #include "compiler/DetectDiscontinuity.h" |
|
12 #include "compiler/InfoSink.h" |
|
13 #include "compiler/SearchSymbol.h" |
|
14 #include "compiler/UnfoldShortCircuit.h" |
|
15 |
|
16 #include <algorithm> |
|
17 #include <cfloat> |
|
18 #include <stdio.h> |
|
19 |
|
20 namespace sh |
|
21 { |
|
22 // Integer to TString conversion |
|
23 TString str(int i) |
|
24 { |
|
25 char buffer[20]; |
|
26 snprintf(buffer, sizeof(buffer), "%d", i); |
|
27 return buffer; |
|
28 } |
|
29 |
|
30 OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType) |
|
31 : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType) |
|
32 { |
|
33 mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); |
|
34 mInsideFunction = false; |
|
35 |
|
36 mUsesTexture2D = false; |
|
37 mUsesTexture2D_bias = false; |
|
38 mUsesTexture2DProj = false; |
|
39 mUsesTexture2DProj_bias = false; |
|
40 mUsesTexture2DProjLod = false; |
|
41 mUsesTexture2DLod = false; |
|
42 mUsesTextureCube = false; |
|
43 mUsesTextureCube_bias = false; |
|
44 mUsesTextureCubeLod = false; |
|
45 mUsesTexture2DLod0 = false; |
|
46 mUsesTexture2DLod0_bias = false; |
|
47 mUsesTexture2DProjLod0 = false; |
|
48 mUsesTexture2DProjLod0_bias = false; |
|
49 mUsesTextureCubeLod0 = false; |
|
50 mUsesTextureCubeLod0_bias = false; |
|
51 mUsesFragColor = false; |
|
52 mUsesFragData = false; |
|
53 mUsesDepthRange = false; |
|
54 mUsesFragCoord = false; |
|
55 mUsesPointCoord = false; |
|
56 mUsesFrontFacing = false; |
|
57 mUsesPointSize = false; |
|
58 mUsesFragDepth = false; |
|
59 mUsesXor = false; |
|
60 mUsesMod1 = false; |
|
61 mUsesMod2v = false; |
|
62 mUsesMod2f = false; |
|
63 mUsesMod3v = false; |
|
64 mUsesMod3f = false; |
|
65 mUsesMod4v = false; |
|
66 mUsesMod4f = false; |
|
67 mUsesFaceforward1 = false; |
|
68 mUsesFaceforward2 = false; |
|
69 mUsesFaceforward3 = false; |
|
70 mUsesFaceforward4 = false; |
|
71 mUsesAtan2_1 = false; |
|
72 mUsesAtan2_2 = false; |
|
73 mUsesAtan2_3 = false; |
|
74 mUsesAtan2_4 = false; |
|
75 |
|
76 mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; |
|
77 |
|
78 mScopeDepth = 0; |
|
79 |
|
80 mUniqueIndex = 0; |
|
81 |
|
82 mContainsLoopDiscontinuity = false; |
|
83 mOutputLod0Function = false; |
|
84 mInsideDiscontinuousLoop = false; |
|
85 |
|
86 mExcessiveLoopIndex = NULL; |
|
87 |
|
88 if (mOutputType == SH_HLSL9_OUTPUT) |
|
89 { |
|
90 if (mContext.shaderType == SH_FRAGMENT_SHADER) |
|
91 { |
|
92 mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront |
|
93 } |
|
94 else |
|
95 { |
|
96 mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust |
|
97 } |
|
98 } |
|
99 else |
|
100 { |
|
101 mUniformRegister = 0; |
|
102 } |
|
103 |
|
104 mSamplerRegister = 0; |
|
105 } |
|
106 |
|
107 OutputHLSL::~OutputHLSL() |
|
108 { |
|
109 delete mUnfoldShortCircuit; |
|
110 } |
|
111 |
|
112 void OutputHLSL::output() |
|
113 { |
|
114 mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); |
|
115 |
|
116 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header |
|
117 header(); |
|
118 |
|
119 mContext.infoSink().obj << mHeader.c_str(); |
|
120 mContext.infoSink().obj << mBody.c_str(); |
|
121 } |
|
122 |
|
123 TInfoSinkBase &OutputHLSL::getBodyStream() |
|
124 { |
|
125 return mBody; |
|
126 } |
|
127 |
|
128 const ActiveUniforms &OutputHLSL::getUniforms() |
|
129 { |
|
130 return mActiveUniforms; |
|
131 } |
|
132 |
|
133 int OutputHLSL::vectorSize(const TType &type) const |
|
134 { |
|
135 int elementSize = type.isMatrix() ? type.getNominalSize() : 1; |
|
136 int arraySize = type.isArray() ? type.getArraySize() : 1; |
|
137 |
|
138 return elementSize * arraySize; |
|
139 } |
|
140 |
|
141 void OutputHLSL::header() |
|
142 { |
|
143 ShShaderType shaderType = mContext.shaderType; |
|
144 TInfoSinkBase &out = mHeader; |
|
145 |
|
146 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++) |
|
147 { |
|
148 out << *structDeclaration; |
|
149 } |
|
150 |
|
151 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++) |
|
152 { |
|
153 out << *constructor; |
|
154 } |
|
155 |
|
156 TString uniforms; |
|
157 TString varyings; |
|
158 TString attributes; |
|
159 |
|
160 for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++) |
|
161 { |
|
162 const TType &type = uniform->second->getType(); |
|
163 const TString &name = uniform->second->getSymbol(); |
|
164 |
|
165 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture |
|
166 { |
|
167 int index = samplerRegister(mReferencedUniforms[name]); |
|
168 |
|
169 uniforms += "uniform SamplerState sampler_" + decorateUniform(name, type) + arrayString(type) + |
|
170 " : register(s" + str(index) + ");\n"; |
|
171 |
|
172 uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) + |
|
173 " : register(t" + str(index) + ");\n"; |
|
174 } |
|
175 else |
|
176 { |
|
177 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + |
|
178 " : register(" + registerString(mReferencedUniforms[name]) + ");\n"; |
|
179 } |
|
180 } |
|
181 |
|
182 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++) |
|
183 { |
|
184 const TType &type = varying->second->getType(); |
|
185 const TString &name = varying->second->getSymbol(); |
|
186 |
|
187 // Program linking depends on this exact format |
|
188 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; |
|
189 } |
|
190 |
|
191 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++) |
|
192 { |
|
193 const TType &type = attribute->second->getType(); |
|
194 const TString &name = attribute->second->getSymbol(); |
|
195 |
|
196 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; |
|
197 } |
|
198 |
|
199 if (shaderType == SH_FRAGMENT_SHADER) |
|
200 { |
|
201 TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); |
|
202 const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire)); |
|
203 |
|
204 const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; |
|
205 |
|
206 out << "// Varyings\n"; |
|
207 out << varyings; |
|
208 out << "\n" |
|
209 "static float4 gl_Color[" << numColorValues << "] =\n" |
|
210 "{\n"; |
|
211 for (unsigned int i = 0; i < numColorValues; i++) |
|
212 { |
|
213 out << " float4(0, 0, 0, 0)"; |
|
214 if (i + 1 != numColorValues) |
|
215 { |
|
216 out << ","; |
|
217 } |
|
218 out << "\n"; |
|
219 } |
|
220 out << "};\n"; |
|
221 |
|
222 if (mUsesFragDepth) |
|
223 { |
|
224 out << "static float gl_Depth = 0.0;\n"; |
|
225 } |
|
226 |
|
227 if (mUsesFragCoord) |
|
228 { |
|
229 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"; |
|
230 } |
|
231 |
|
232 if (mUsesPointCoord) |
|
233 { |
|
234 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n"; |
|
235 } |
|
236 |
|
237 if (mUsesFrontFacing) |
|
238 { |
|
239 out << "static bool gl_FrontFacing = false;\n"; |
|
240 } |
|
241 |
|
242 out << "\n"; |
|
243 |
|
244 if (mUsesDepthRange) |
|
245 { |
|
246 out << "struct gl_DepthRangeParameters\n" |
|
247 "{\n" |
|
248 " float near;\n" |
|
249 " float far;\n" |
|
250 " float diff;\n" |
|
251 "};\n" |
|
252 "\n"; |
|
253 } |
|
254 |
|
255 if (mOutputType == SH_HLSL11_OUTPUT) |
|
256 { |
|
257 out << "cbuffer DriverConstants : register(b1)\n" |
|
258 "{\n"; |
|
259 |
|
260 if (mUsesDepthRange) |
|
261 { |
|
262 out << " float3 dx_DepthRange : packoffset(c0);\n"; |
|
263 } |
|
264 |
|
265 if (mUsesFragCoord) |
|
266 { |
|
267 out << " float4 dx_ViewCoords : packoffset(c1);\n"; |
|
268 } |
|
269 |
|
270 if (mUsesFragCoord || mUsesFrontFacing) |
|
271 { |
|
272 out << " float3 dx_DepthFront : packoffset(c2);\n"; |
|
273 } |
|
274 |
|
275 out << "};\n"; |
|
276 } |
|
277 else |
|
278 { |
|
279 if (mUsesDepthRange) |
|
280 { |
|
281 out << "uniform float3 dx_DepthRange : register(c0);"; |
|
282 } |
|
283 |
|
284 if (mUsesFragCoord) |
|
285 { |
|
286 out << "uniform float4 dx_ViewCoords : register(c1);\n"; |
|
287 } |
|
288 |
|
289 if (mUsesFragCoord || mUsesFrontFacing) |
|
290 { |
|
291 out << "uniform float3 dx_DepthFront : register(c2);\n"; |
|
292 } |
|
293 } |
|
294 |
|
295 out << "\n"; |
|
296 |
|
297 if (mUsesDepthRange) |
|
298 { |
|
299 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" |
|
300 "\n"; |
|
301 } |
|
302 |
|
303 out << uniforms; |
|
304 out << "\n"; |
|
305 |
|
306 if (mUsesTexture2D) |
|
307 { |
|
308 if (mOutputType == SH_HLSL9_OUTPUT) |
|
309 { |
|
310 out << "float4 gl_texture2D(sampler2D s, float2 t)\n" |
|
311 "{\n" |
|
312 " return tex2D(s, t);\n" |
|
313 "}\n" |
|
314 "\n"; |
|
315 } |
|
316 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
317 { |
|
318 out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n" |
|
319 "{\n" |
|
320 " return t.Sample(s, uv);\n" |
|
321 "}\n" |
|
322 "\n"; |
|
323 } |
|
324 else UNREACHABLE(); |
|
325 } |
|
326 |
|
327 if (mUsesTexture2D_bias) |
|
328 { |
|
329 if (mOutputType == SH_HLSL9_OUTPUT) |
|
330 { |
|
331 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n" |
|
332 "{\n" |
|
333 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n" |
|
334 "}\n" |
|
335 "\n"; |
|
336 } |
|
337 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
338 { |
|
339 out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv, float bias)\n" |
|
340 "{\n" |
|
341 " return t.SampleBias(s, uv, bias);\n" |
|
342 "}\n" |
|
343 "\n"; |
|
344 } |
|
345 else UNREACHABLE(); |
|
346 } |
|
347 |
|
348 if (mUsesTexture2DProj) |
|
349 { |
|
350 if (mOutputType == SH_HLSL9_OUTPUT) |
|
351 { |
|
352 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" |
|
353 "{\n" |
|
354 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n" |
|
355 "}\n" |
|
356 "\n" |
|
357 "float4 gl_texture2DProj(sampler2D s, float4 t)\n" |
|
358 "{\n" |
|
359 " return tex2Dproj(s, t);\n" |
|
360 "}\n" |
|
361 "\n"; |
|
362 } |
|
363 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
364 { |
|
365 out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n" |
|
366 "{\n" |
|
367 " return t.Sample(s, float2(uvw.x / uvw.z, uvw.y / uvw.z));\n" |
|
368 "}\n" |
|
369 "\n" |
|
370 "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n" |
|
371 "{\n" |
|
372 " return t.Sample(s, float2(uvw.x / uvw.w, uvw.y / uvw.w));\n" |
|
373 "}\n" |
|
374 "\n"; |
|
375 } |
|
376 else UNREACHABLE(); |
|
377 } |
|
378 |
|
379 if (mUsesTexture2DProj_bias) |
|
380 { |
|
381 if (mOutputType == SH_HLSL9_OUTPUT) |
|
382 { |
|
383 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n" |
|
384 "{\n" |
|
385 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n" |
|
386 "}\n" |
|
387 "\n" |
|
388 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n" |
|
389 "{\n" |
|
390 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n" |
|
391 "}\n" |
|
392 "\n"; |
|
393 } |
|
394 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
395 { |
|
396 out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float bias)\n" |
|
397 "{\n" |
|
398 " return t.SampleBias(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), bias);\n" |
|
399 "}\n" |
|
400 "\n" |
|
401 "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw, float bias)\n" |
|
402 "{\n" |
|
403 " return t.SampleBias(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), bias);\n" |
|
404 "}\n" |
|
405 "\n"; |
|
406 } |
|
407 else UNREACHABLE(); |
|
408 } |
|
409 |
|
410 if (mUsesTextureCube) |
|
411 { |
|
412 if (mOutputType == SH_HLSL9_OUTPUT) |
|
413 { |
|
414 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" |
|
415 "{\n" |
|
416 " return texCUBE(s, t);\n" |
|
417 "}\n" |
|
418 "\n"; |
|
419 } |
|
420 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
421 { |
|
422 out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n" |
|
423 "{\n" |
|
424 " return t.Sample(s, uvw);\n" |
|
425 "}\n" |
|
426 "\n"; |
|
427 } |
|
428 else UNREACHABLE(); |
|
429 } |
|
430 |
|
431 if (mUsesTextureCube_bias) |
|
432 { |
|
433 if (mOutputType == SH_HLSL9_OUTPUT) |
|
434 { |
|
435 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n" |
|
436 "{\n" |
|
437 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n" |
|
438 "}\n" |
|
439 "\n"; |
|
440 } |
|
441 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
442 { |
|
443 out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw, float bias)\n" |
|
444 "{\n" |
|
445 " return t.SampleBias(s, uvw, bias);\n" |
|
446 "}\n" |
|
447 "\n"; |
|
448 } |
|
449 else UNREACHABLE(); |
|
450 } |
|
451 |
|
452 // These *Lod0 intrinsics are not available in GL fragment shaders. |
|
453 // They are used to sample using discontinuous texture coordinates. |
|
454 if (mUsesTexture2DLod0) |
|
455 { |
|
456 if (mOutputType == SH_HLSL9_OUTPUT) |
|
457 { |
|
458 out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n" |
|
459 "{\n" |
|
460 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" |
|
461 "}\n" |
|
462 "\n"; |
|
463 } |
|
464 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
465 { |
|
466 out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv)\n" |
|
467 "{\n" |
|
468 " return t.SampleLevel(s, uv, 0);\n" |
|
469 "}\n" |
|
470 "\n"; |
|
471 } |
|
472 else UNREACHABLE(); |
|
473 } |
|
474 |
|
475 if (mUsesTexture2DLod0_bias) |
|
476 { |
|
477 if (mOutputType == SH_HLSL9_OUTPUT) |
|
478 { |
|
479 out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n" |
|
480 "{\n" |
|
481 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" |
|
482 "}\n" |
|
483 "\n"; |
|
484 } |
|
485 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
486 { |
|
487 out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv, float bias)\n" |
|
488 "{\n" |
|
489 " return t.SampleLevel(s, uv, 0);\n" |
|
490 "}\n" |
|
491 "\n"; |
|
492 } |
|
493 else UNREACHABLE(); |
|
494 } |
|
495 |
|
496 if (mUsesTexture2DProjLod0) |
|
497 { |
|
498 if (mOutputType == SH_HLSL9_OUTPUT) |
|
499 { |
|
500 out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n" |
|
501 "{\n" |
|
502 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" |
|
503 "}\n" |
|
504 "\n" |
|
505 "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n" |
|
506 "{\n" |
|
507 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" |
|
508 "}\n" |
|
509 "\n"; |
|
510 } |
|
511 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
512 { |
|
513 out << "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float3 uvw)\n" |
|
514 "{\n" |
|
515 " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" |
|
516 "}\n" |
|
517 "\n" |
|
518 "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float4 uvw)\n" |
|
519 "{\n" |
|
520 " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" |
|
521 "}\n" |
|
522 "\n"; |
|
523 } |
|
524 else UNREACHABLE(); |
|
525 } |
|
526 |
|
527 if (mUsesTexture2DProjLod0_bias) |
|
528 { |
|
529 if (mOutputType == SH_HLSL9_OUTPUT) |
|
530 { |
|
531 out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n" |
|
532 "{\n" |
|
533 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" |
|
534 "}\n" |
|
535 "\n" |
|
536 "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n" |
|
537 "{\n" |
|
538 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" |
|
539 "}\n" |
|
540 "\n"; |
|
541 } |
|
542 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
543 { |
|
544 out << "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float3 uvw, float bias)\n" |
|
545 "{\n" |
|
546 " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" |
|
547 "}\n" |
|
548 "\n" |
|
549 "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float4 uvw, float bias)\n" |
|
550 "{\n" |
|
551 " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" |
|
552 "}\n" |
|
553 "\n"; |
|
554 } |
|
555 else UNREACHABLE(); |
|
556 } |
|
557 |
|
558 if (mUsesTextureCubeLod0) |
|
559 { |
|
560 if (mOutputType == SH_HLSL9_OUTPUT) |
|
561 { |
|
562 out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n" |
|
563 "{\n" |
|
564 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" |
|
565 "}\n" |
|
566 "\n"; |
|
567 } |
|
568 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
569 { |
|
570 out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw)\n" |
|
571 "{\n" |
|
572 " return t.SampleLevel(s, uvw, 0);\n" |
|
573 "}\n" |
|
574 "\n"; |
|
575 } |
|
576 else UNREACHABLE(); |
|
577 } |
|
578 |
|
579 if (mUsesTextureCubeLod0_bias) |
|
580 { |
|
581 if (mOutputType == SH_HLSL9_OUTPUT) |
|
582 { |
|
583 out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n" |
|
584 "{\n" |
|
585 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" |
|
586 "}\n" |
|
587 "\n"; |
|
588 } |
|
589 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
590 { |
|
591 out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw, float bias)\n" |
|
592 "{\n" |
|
593 " return t.SampleLevel(s, uvw, 0);\n" |
|
594 "}\n" |
|
595 "\n"; |
|
596 } |
|
597 else UNREACHABLE(); |
|
598 } |
|
599 |
|
600 if (usingMRTExtension && mNumRenderTargets > 1) |
|
601 { |
|
602 out << "#define GL_USES_MRT\n"; |
|
603 } |
|
604 |
|
605 if (mUsesFragColor) |
|
606 { |
|
607 out << "#define GL_USES_FRAG_COLOR\n"; |
|
608 } |
|
609 |
|
610 if (mUsesFragData) |
|
611 { |
|
612 out << "#define GL_USES_FRAG_DATA\n"; |
|
613 } |
|
614 } |
|
615 else // Vertex shader |
|
616 { |
|
617 out << "// Attributes\n"; |
|
618 out << attributes; |
|
619 out << "\n" |
|
620 "static float4 gl_Position = float4(0, 0, 0, 0);\n"; |
|
621 |
|
622 if (mUsesPointSize) |
|
623 { |
|
624 out << "static float gl_PointSize = float(1);\n"; |
|
625 } |
|
626 |
|
627 out << "\n" |
|
628 "// Varyings\n"; |
|
629 out << varyings; |
|
630 out << "\n"; |
|
631 |
|
632 if (mUsesDepthRange) |
|
633 { |
|
634 out << "struct gl_DepthRangeParameters\n" |
|
635 "{\n" |
|
636 " float near;\n" |
|
637 " float far;\n" |
|
638 " float diff;\n" |
|
639 "};\n" |
|
640 "\n"; |
|
641 } |
|
642 |
|
643 if (mOutputType == SH_HLSL11_OUTPUT) |
|
644 { |
|
645 if (mUsesDepthRange) |
|
646 { |
|
647 out << "cbuffer DriverConstants : register(b1)\n" |
|
648 "{\n" |
|
649 " float3 dx_DepthRange : packoffset(c0);\n" |
|
650 "};\n" |
|
651 "\n"; |
|
652 } |
|
653 } |
|
654 else |
|
655 { |
|
656 if (mUsesDepthRange) |
|
657 { |
|
658 out << "uniform float3 dx_DepthRange : register(c0);\n"; |
|
659 } |
|
660 |
|
661 out << "uniform float4 dx_ViewAdjust : register(c1);\n" |
|
662 "\n"; |
|
663 } |
|
664 |
|
665 if (mUsesDepthRange) |
|
666 { |
|
667 out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" |
|
668 "\n"; |
|
669 } |
|
670 |
|
671 out << uniforms; |
|
672 out << "\n"; |
|
673 |
|
674 if (mUsesTexture2D) |
|
675 { |
|
676 if (mOutputType == SH_HLSL9_OUTPUT) |
|
677 { |
|
678 out << "float4 gl_texture2D(sampler2D s, float2 t)\n" |
|
679 "{\n" |
|
680 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" |
|
681 "}\n" |
|
682 "\n"; |
|
683 } |
|
684 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
685 { |
|
686 out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n" |
|
687 "{\n" |
|
688 " return t.SampleLevel(s, uv, 0);\n" |
|
689 "}\n" |
|
690 "\n"; |
|
691 } |
|
692 else UNREACHABLE(); |
|
693 } |
|
694 |
|
695 if (mUsesTexture2DLod) |
|
696 { |
|
697 if (mOutputType == SH_HLSL9_OUTPUT) |
|
698 { |
|
699 out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n" |
|
700 "{\n" |
|
701 " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n" |
|
702 "}\n" |
|
703 "\n"; |
|
704 } |
|
705 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
706 { |
|
707 out << "float4 gl_texture2DLod(Texture2D t, SamplerState s, float2 uv, float lod)\n" |
|
708 "{\n" |
|
709 " return t.SampleLevel(s, uv, lod);\n" |
|
710 "}\n" |
|
711 "\n"; |
|
712 } |
|
713 else UNREACHABLE(); |
|
714 } |
|
715 |
|
716 if (mUsesTexture2DProj) |
|
717 { |
|
718 if (mOutputType == SH_HLSL9_OUTPUT) |
|
719 { |
|
720 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" |
|
721 "{\n" |
|
722 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" |
|
723 "}\n" |
|
724 "\n" |
|
725 "float4 gl_texture2DProj(sampler2D s, float4 t)\n" |
|
726 "{\n" |
|
727 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" |
|
728 "}\n" |
|
729 "\n"; |
|
730 } |
|
731 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
732 { |
|
733 out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n" |
|
734 "{\n" |
|
735 " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n" |
|
736 "}\n" |
|
737 "\n" |
|
738 "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n" |
|
739 "{\n" |
|
740 " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n" |
|
741 "}\n" |
|
742 "\n"; |
|
743 } |
|
744 else UNREACHABLE(); |
|
745 } |
|
746 |
|
747 if (mUsesTexture2DProjLod) |
|
748 { |
|
749 if (mOutputType == SH_HLSL9_OUTPUT) |
|
750 { |
|
751 out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n" |
|
752 "{\n" |
|
753 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n" |
|
754 "}\n" |
|
755 "\n" |
|
756 "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n" |
|
757 "{\n" |
|
758 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n" |
|
759 "}\n" |
|
760 "\n"; |
|
761 } |
|
762 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
763 { |
|
764 out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float lod)\n" |
|
765 "{\n" |
|
766 " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), lod);\n" |
|
767 "}\n" |
|
768 "\n" |
|
769 "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n" |
|
770 "{\n" |
|
771 " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), lod);\n" |
|
772 "}\n" |
|
773 "\n"; |
|
774 } |
|
775 else UNREACHABLE(); |
|
776 } |
|
777 |
|
778 if (mUsesTextureCube) |
|
779 { |
|
780 if (mOutputType == SH_HLSL9_OUTPUT) |
|
781 { |
|
782 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" |
|
783 "{\n" |
|
784 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" |
|
785 "}\n" |
|
786 "\n"; |
|
787 } |
|
788 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
789 { |
|
790 out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n" |
|
791 "{\n" |
|
792 " return t.SampleLevel(s, uvw, 0);\n" |
|
793 "}\n" |
|
794 "\n"; |
|
795 } |
|
796 else UNREACHABLE(); |
|
797 } |
|
798 |
|
799 if (mUsesTextureCubeLod) |
|
800 { |
|
801 if (mOutputType == SH_HLSL9_OUTPUT) |
|
802 { |
|
803 out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n" |
|
804 "{\n" |
|
805 " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n" |
|
806 "}\n" |
|
807 "\n"; |
|
808 } |
|
809 else if (mOutputType == SH_HLSL11_OUTPUT) |
|
810 { |
|
811 out << "float4 gl_textureCubeLod(TextureCube t, SamplerState s, float3 uvw, float lod)\n" |
|
812 "{\n" |
|
813 " return t.SampleLevel(s, uvw, lod);\n" |
|
814 "}\n" |
|
815 "\n"; |
|
816 } |
|
817 else UNREACHABLE(); |
|
818 } |
|
819 } |
|
820 |
|
821 if (mUsesFragCoord) |
|
822 { |
|
823 out << "#define GL_USES_FRAG_COORD\n"; |
|
824 } |
|
825 |
|
826 if (mUsesPointCoord) |
|
827 { |
|
828 out << "#define GL_USES_POINT_COORD\n"; |
|
829 } |
|
830 |
|
831 if (mUsesFrontFacing) |
|
832 { |
|
833 out << "#define GL_USES_FRONT_FACING\n"; |
|
834 } |
|
835 |
|
836 if (mUsesPointSize) |
|
837 { |
|
838 out << "#define GL_USES_POINT_SIZE\n"; |
|
839 } |
|
840 |
|
841 if (mUsesFragDepth) |
|
842 { |
|
843 out << "#define GL_USES_FRAG_DEPTH\n"; |
|
844 } |
|
845 |
|
846 if (mUsesDepthRange) |
|
847 { |
|
848 out << "#define GL_USES_DEPTH_RANGE\n"; |
|
849 } |
|
850 |
|
851 if (mUsesXor) |
|
852 { |
|
853 out << "bool xor(bool p, bool q)\n" |
|
854 "{\n" |
|
855 " return (p || q) && !(p && q);\n" |
|
856 "}\n" |
|
857 "\n"; |
|
858 } |
|
859 |
|
860 if (mUsesMod1) |
|
861 { |
|
862 out << "float mod(float x, float y)\n" |
|
863 "{\n" |
|
864 " return x - y * floor(x / y);\n" |
|
865 "}\n" |
|
866 "\n"; |
|
867 } |
|
868 |
|
869 if (mUsesMod2v) |
|
870 { |
|
871 out << "float2 mod(float2 x, float2 y)\n" |
|
872 "{\n" |
|
873 " return x - y * floor(x / y);\n" |
|
874 "}\n" |
|
875 "\n"; |
|
876 } |
|
877 |
|
878 if (mUsesMod2f) |
|
879 { |
|
880 out << "float2 mod(float2 x, float y)\n" |
|
881 "{\n" |
|
882 " return x - y * floor(x / y);\n" |
|
883 "}\n" |
|
884 "\n"; |
|
885 } |
|
886 |
|
887 if (mUsesMod3v) |
|
888 { |
|
889 out << "float3 mod(float3 x, float3 y)\n" |
|
890 "{\n" |
|
891 " return x - y * floor(x / y);\n" |
|
892 "}\n" |
|
893 "\n"; |
|
894 } |
|
895 |
|
896 if (mUsesMod3f) |
|
897 { |
|
898 out << "float3 mod(float3 x, float y)\n" |
|
899 "{\n" |
|
900 " return x - y * floor(x / y);\n" |
|
901 "}\n" |
|
902 "\n"; |
|
903 } |
|
904 |
|
905 if (mUsesMod4v) |
|
906 { |
|
907 out << "float4 mod(float4 x, float4 y)\n" |
|
908 "{\n" |
|
909 " return x - y * floor(x / y);\n" |
|
910 "}\n" |
|
911 "\n"; |
|
912 } |
|
913 |
|
914 if (mUsesMod4f) |
|
915 { |
|
916 out << "float4 mod(float4 x, float y)\n" |
|
917 "{\n" |
|
918 " return x - y * floor(x / y);\n" |
|
919 "}\n" |
|
920 "\n"; |
|
921 } |
|
922 |
|
923 if (mUsesFaceforward1) |
|
924 { |
|
925 out << "float faceforward(float N, float I, float Nref)\n" |
|
926 "{\n" |
|
927 " if(dot(Nref, I) >= 0)\n" |
|
928 " {\n" |
|
929 " return -N;\n" |
|
930 " }\n" |
|
931 " else\n" |
|
932 " {\n" |
|
933 " return N;\n" |
|
934 " }\n" |
|
935 "}\n" |
|
936 "\n"; |
|
937 } |
|
938 |
|
939 if (mUsesFaceforward2) |
|
940 { |
|
941 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n" |
|
942 "{\n" |
|
943 " if(dot(Nref, I) >= 0)\n" |
|
944 " {\n" |
|
945 " return -N;\n" |
|
946 " }\n" |
|
947 " else\n" |
|
948 " {\n" |
|
949 " return N;\n" |
|
950 " }\n" |
|
951 "}\n" |
|
952 "\n"; |
|
953 } |
|
954 |
|
955 if (mUsesFaceforward3) |
|
956 { |
|
957 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n" |
|
958 "{\n" |
|
959 " if(dot(Nref, I) >= 0)\n" |
|
960 " {\n" |
|
961 " return -N;\n" |
|
962 " }\n" |
|
963 " else\n" |
|
964 " {\n" |
|
965 " return N;\n" |
|
966 " }\n" |
|
967 "}\n" |
|
968 "\n"; |
|
969 } |
|
970 |
|
971 if (mUsesFaceforward4) |
|
972 { |
|
973 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n" |
|
974 "{\n" |
|
975 " if(dot(Nref, I) >= 0)\n" |
|
976 " {\n" |
|
977 " return -N;\n" |
|
978 " }\n" |
|
979 " else\n" |
|
980 " {\n" |
|
981 " return N;\n" |
|
982 " }\n" |
|
983 "}\n" |
|
984 "\n"; |
|
985 } |
|
986 |
|
987 if (mUsesAtan2_1) |
|
988 { |
|
989 out << "float atanyx(float y, float x)\n" |
|
990 "{\n" |
|
991 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN |
|
992 " return atan2(y, x);\n" |
|
993 "}\n"; |
|
994 } |
|
995 |
|
996 if (mUsesAtan2_2) |
|
997 { |
|
998 out << "float2 atanyx(float2 y, float2 x)\n" |
|
999 "{\n" |
|
1000 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" |
|
1001 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" |
|
1002 " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" |
|
1003 "}\n"; |
|
1004 } |
|
1005 |
|
1006 if (mUsesAtan2_3) |
|
1007 { |
|
1008 out << "float3 atanyx(float3 y, float3 x)\n" |
|
1009 "{\n" |
|
1010 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" |
|
1011 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" |
|
1012 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" |
|
1013 " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" |
|
1014 "}\n"; |
|
1015 } |
|
1016 |
|
1017 if (mUsesAtan2_4) |
|
1018 { |
|
1019 out << "float4 atanyx(float4 y, float4 x)\n" |
|
1020 "{\n" |
|
1021 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" |
|
1022 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" |
|
1023 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" |
|
1024 " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" |
|
1025 " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" |
|
1026 "}\n"; |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 void OutputHLSL::visitSymbol(TIntermSymbol *node) |
|
1031 { |
|
1032 TInfoSinkBase &out = mBody; |
|
1033 |
|
1034 TString name = node->getSymbol(); |
|
1035 |
|
1036 if (name == "gl_FragColor") |
|
1037 { |
|
1038 out << "gl_Color[0]"; |
|
1039 mUsesFragColor = true; |
|
1040 } |
|
1041 else if (name == "gl_FragData") |
|
1042 { |
|
1043 out << "gl_Color"; |
|
1044 mUsesFragData = true; |
|
1045 } |
|
1046 else if (name == "gl_DepthRange") |
|
1047 { |
|
1048 mUsesDepthRange = true; |
|
1049 out << name; |
|
1050 } |
|
1051 else if (name == "gl_FragCoord") |
|
1052 { |
|
1053 mUsesFragCoord = true; |
|
1054 out << name; |
|
1055 } |
|
1056 else if (name == "gl_PointCoord") |
|
1057 { |
|
1058 mUsesPointCoord = true; |
|
1059 out << name; |
|
1060 } |
|
1061 else if (name == "gl_FrontFacing") |
|
1062 { |
|
1063 mUsesFrontFacing = true; |
|
1064 out << name; |
|
1065 } |
|
1066 else if (name == "gl_PointSize") |
|
1067 { |
|
1068 mUsesPointSize = true; |
|
1069 out << name; |
|
1070 } |
|
1071 else if (name == "gl_FragDepthEXT") |
|
1072 { |
|
1073 mUsesFragDepth = true; |
|
1074 out << "gl_Depth"; |
|
1075 } |
|
1076 else |
|
1077 { |
|
1078 TQualifier qualifier = node->getQualifier(); |
|
1079 |
|
1080 if (qualifier == EvqUniform) |
|
1081 { |
|
1082 mReferencedUniforms[name] = node; |
|
1083 out << decorateUniform(name, node->getType()); |
|
1084 } |
|
1085 else if (qualifier == EvqAttribute) |
|
1086 { |
|
1087 mReferencedAttributes[name] = node; |
|
1088 out << decorate(name); |
|
1089 } |
|
1090 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn) |
|
1091 { |
|
1092 mReferencedVaryings[name] = node; |
|
1093 out << decorate(name); |
|
1094 } |
|
1095 else |
|
1096 { |
|
1097 out << decorate(name); |
|
1098 } |
|
1099 } |
|
1100 } |
|
1101 |
|
1102 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) |
|
1103 { |
|
1104 TInfoSinkBase &out = mBody; |
|
1105 |
|
1106 switch (node->getOp()) |
|
1107 { |
|
1108 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; |
|
1109 case EOpInitialize: |
|
1110 if (visit == PreVisit) |
|
1111 { |
|
1112 // GLSL allows to write things like "float x = x;" where a new variable x is defined |
|
1113 // and the value of an existing variable x is assigned. HLSL uses C semantics (the |
|
1114 // new variable is created before the assignment is evaluated), so we need to convert |
|
1115 // this to "float t = x, x = t;". |
|
1116 |
|
1117 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); |
|
1118 TIntermTyped *expression = node->getRight(); |
|
1119 |
|
1120 sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); |
|
1121 expression->traverse(&searchSymbol); |
|
1122 bool sameSymbol = searchSymbol.foundMatch(); |
|
1123 |
|
1124 if (sameSymbol) |
|
1125 { |
|
1126 // Type already printed |
|
1127 out << "t" + str(mUniqueIndex) + " = "; |
|
1128 expression->traverse(this); |
|
1129 out << ", "; |
|
1130 symbolNode->traverse(this); |
|
1131 out << " = t" + str(mUniqueIndex); |
|
1132 |
|
1133 mUniqueIndex++; |
|
1134 return false; |
|
1135 } |
|
1136 } |
|
1137 else if (visit == InVisit) |
|
1138 { |
|
1139 out << " = "; |
|
1140 } |
|
1141 break; |
|
1142 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break; |
|
1143 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break; |
|
1144 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break; |
|
1145 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; |
|
1146 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; |
|
1147 case EOpVectorTimesMatrixAssign: |
|
1148 if (visit == PreVisit) |
|
1149 { |
|
1150 out << "("; |
|
1151 } |
|
1152 else if (visit == InVisit) |
|
1153 { |
|
1154 out << " = mul("; |
|
1155 node->getLeft()->traverse(this); |
|
1156 out << ", transpose("; |
|
1157 } |
|
1158 else |
|
1159 { |
|
1160 out << ")))"; |
|
1161 } |
|
1162 break; |
|
1163 case EOpMatrixTimesMatrixAssign: |
|
1164 if (visit == PreVisit) |
|
1165 { |
|
1166 out << "("; |
|
1167 } |
|
1168 else if (visit == InVisit) |
|
1169 { |
|
1170 out << " = mul("; |
|
1171 node->getLeft()->traverse(this); |
|
1172 out << ", "; |
|
1173 } |
|
1174 else |
|
1175 { |
|
1176 out << "))"; |
|
1177 } |
|
1178 break; |
|
1179 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; |
|
1180 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break; |
|
1181 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break; |
|
1182 case EOpIndexDirectStruct: |
|
1183 if (visit == InVisit) |
|
1184 { |
|
1185 const TStructure* structure = node->getLeft()->getType().getStruct(); |
|
1186 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); |
|
1187 const TField* field = structure->fields()[index->getIConst(0)]; |
|
1188 out << "." + decorateField(field->name(), node->getLeft()->getType()); |
|
1189 |
|
1190 return false; |
|
1191 } |
|
1192 break; |
|
1193 case EOpVectorSwizzle: |
|
1194 if (visit == InVisit) |
|
1195 { |
|
1196 out << "."; |
|
1197 |
|
1198 TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); |
|
1199 |
|
1200 if (swizzle) |
|
1201 { |
|
1202 TIntermSequence &sequence = swizzle->getSequence(); |
|
1203 |
|
1204 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) |
|
1205 { |
|
1206 TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); |
|
1207 |
|
1208 if (element) |
|
1209 { |
|
1210 int i = element->getIConst(0); |
|
1211 |
|
1212 switch (i) |
|
1213 { |
|
1214 case 0: out << "x"; break; |
|
1215 case 1: out << "y"; break; |
|
1216 case 2: out << "z"; break; |
|
1217 case 3: out << "w"; break; |
|
1218 default: UNREACHABLE(); |
|
1219 } |
|
1220 } |
|
1221 else UNREACHABLE(); |
|
1222 } |
|
1223 } |
|
1224 else UNREACHABLE(); |
|
1225 |
|
1226 return false; // Fully processed |
|
1227 } |
|
1228 break; |
|
1229 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break; |
|
1230 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; |
|
1231 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; |
|
1232 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; |
|
1233 case EOpEqual: |
|
1234 case EOpNotEqual: |
|
1235 if (node->getLeft()->isScalar()) |
|
1236 { |
|
1237 if (node->getOp() == EOpEqual) |
|
1238 { |
|
1239 outputTriplet(visit, "(", " == ", ")"); |
|
1240 } |
|
1241 else |
|
1242 { |
|
1243 outputTriplet(visit, "(", " != ", ")"); |
|
1244 } |
|
1245 } |
|
1246 else if (node->getLeft()->getBasicType() == EbtStruct) |
|
1247 { |
|
1248 if (node->getOp() == EOpEqual) |
|
1249 { |
|
1250 out << "("; |
|
1251 } |
|
1252 else |
|
1253 { |
|
1254 out << "!("; |
|
1255 } |
|
1256 |
|
1257 const TFieldList &fields = node->getLeft()->getType().getStruct()->fields(); |
|
1258 |
|
1259 for (size_t i = 0; i < fields.size(); i++) |
|
1260 { |
|
1261 const TField *field = fields[i]; |
|
1262 |
|
1263 node->getLeft()->traverse(this); |
|
1264 out << "." + decorateField(field->name(), node->getLeft()->getType()) + " == "; |
|
1265 node->getRight()->traverse(this); |
|
1266 out << "." + decorateField(field->name(), node->getLeft()->getType()); |
|
1267 |
|
1268 if (i < fields.size() - 1) |
|
1269 { |
|
1270 out << " && "; |
|
1271 } |
|
1272 } |
|
1273 |
|
1274 out << ")"; |
|
1275 |
|
1276 return false; |
|
1277 } |
|
1278 else |
|
1279 { |
|
1280 ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector()); |
|
1281 |
|
1282 if (node->getOp() == EOpEqual) |
|
1283 { |
|
1284 outputTriplet(visit, "all(", " == ", ")"); |
|
1285 } |
|
1286 else |
|
1287 { |
|
1288 outputTriplet(visit, "!all(", " == ", ")"); |
|
1289 } |
|
1290 } |
|
1291 break; |
|
1292 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; |
|
1293 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; |
|
1294 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; |
|
1295 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; |
|
1296 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; |
|
1297 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; |
|
1298 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break; |
|
1299 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break; |
|
1300 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break; |
|
1301 case EOpLogicalOr: |
|
1302 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); |
|
1303 return false; |
|
1304 case EOpLogicalXor: |
|
1305 mUsesXor = true; |
|
1306 outputTriplet(visit, "xor(", ", ", ")"); |
|
1307 break; |
|
1308 case EOpLogicalAnd: |
|
1309 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); |
|
1310 return false; |
|
1311 default: UNREACHABLE(); |
|
1312 } |
|
1313 |
|
1314 return true; |
|
1315 } |
|
1316 |
|
1317 bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) |
|
1318 { |
|
1319 switch (node->getOp()) |
|
1320 { |
|
1321 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; |
|
1322 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; |
|
1323 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; |
|
1324 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; |
|
1325 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; |
|
1326 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; |
|
1327 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break; |
|
1328 case EOpConvIntToBool: |
|
1329 case EOpConvFloatToBool: |
|
1330 switch (node->getOperand()->getType().getNominalSize()) |
|
1331 { |
|
1332 case 1: outputTriplet(visit, "bool(", "", ")"); break; |
|
1333 case 2: outputTriplet(visit, "bool2(", "", ")"); break; |
|
1334 case 3: outputTriplet(visit, "bool3(", "", ")"); break; |
|
1335 case 4: outputTriplet(visit, "bool4(", "", ")"); break; |
|
1336 default: UNREACHABLE(); |
|
1337 } |
|
1338 break; |
|
1339 case EOpConvBoolToFloat: |
|
1340 case EOpConvIntToFloat: |
|
1341 switch (node->getOperand()->getType().getNominalSize()) |
|
1342 { |
|
1343 case 1: outputTriplet(visit, "float(", "", ")"); break; |
|
1344 case 2: outputTriplet(visit, "float2(", "", ")"); break; |
|
1345 case 3: outputTriplet(visit, "float3(", "", ")"); break; |
|
1346 case 4: outputTriplet(visit, "float4(", "", ")"); break; |
|
1347 default: UNREACHABLE(); |
|
1348 } |
|
1349 break; |
|
1350 case EOpConvFloatToInt: |
|
1351 case EOpConvBoolToInt: |
|
1352 switch (node->getOperand()->getType().getNominalSize()) |
|
1353 { |
|
1354 case 1: outputTriplet(visit, "int(", "", ")"); break; |
|
1355 case 2: outputTriplet(visit, "int2(", "", ")"); break; |
|
1356 case 3: outputTriplet(visit, "int3(", "", ")"); break; |
|
1357 case 4: outputTriplet(visit, "int4(", "", ")"); break; |
|
1358 default: UNREACHABLE(); |
|
1359 } |
|
1360 break; |
|
1361 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break; |
|
1362 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break; |
|
1363 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break; |
|
1364 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break; |
|
1365 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break; |
|
1366 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break; |
|
1367 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break; |
|
1368 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break; |
|
1369 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break; |
|
1370 case EOpLog: outputTriplet(visit, "log(", "", ")"); break; |
|
1371 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break; |
|
1372 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break; |
|
1373 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break; |
|
1374 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break; |
|
1375 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break; |
|
1376 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break; |
|
1377 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break; |
|
1378 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break; |
|
1379 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break; |
|
1380 case EOpLength: outputTriplet(visit, "length(", "", ")"); break; |
|
1381 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; |
|
1382 case EOpDFdx: |
|
1383 if(mInsideDiscontinuousLoop || mOutputLod0Function) |
|
1384 { |
|
1385 outputTriplet(visit, "(", "", ", 0.0)"); |
|
1386 } |
|
1387 else |
|
1388 { |
|
1389 outputTriplet(visit, "ddx(", "", ")"); |
|
1390 } |
|
1391 break; |
|
1392 case EOpDFdy: |
|
1393 if(mInsideDiscontinuousLoop || mOutputLod0Function) |
|
1394 { |
|
1395 outputTriplet(visit, "(", "", ", 0.0)"); |
|
1396 } |
|
1397 else |
|
1398 { |
|
1399 outputTriplet(visit, "ddy(", "", ")"); |
|
1400 } |
|
1401 break; |
|
1402 case EOpFwidth: |
|
1403 if(mInsideDiscontinuousLoop || mOutputLod0Function) |
|
1404 { |
|
1405 outputTriplet(visit, "(", "", ", 0.0)"); |
|
1406 } |
|
1407 else |
|
1408 { |
|
1409 outputTriplet(visit, "fwidth(", "", ")"); |
|
1410 } |
|
1411 break; |
|
1412 case EOpAny: outputTriplet(visit, "any(", "", ")"); break; |
|
1413 case EOpAll: outputTriplet(visit, "all(", "", ")"); break; |
|
1414 default: UNREACHABLE(); |
|
1415 } |
|
1416 |
|
1417 return true; |
|
1418 } |
|
1419 |
|
1420 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) |
|
1421 { |
|
1422 TInfoSinkBase &out = mBody; |
|
1423 |
|
1424 switch (node->getOp()) |
|
1425 { |
|
1426 case EOpSequence: |
|
1427 { |
|
1428 if (mInsideFunction) |
|
1429 { |
|
1430 outputLineDirective(node->getLine().first_line); |
|
1431 out << "{\n"; |
|
1432 |
|
1433 mScopeDepth++; |
|
1434 |
|
1435 if (mScopeBracket.size() < mScopeDepth) |
|
1436 { |
|
1437 mScopeBracket.push_back(0); // New scope level |
|
1438 } |
|
1439 else |
|
1440 { |
|
1441 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level |
|
1442 } |
|
1443 } |
|
1444 |
|
1445 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++) |
|
1446 { |
|
1447 outputLineDirective((*sit)->getLine().first_line); |
|
1448 |
|
1449 traverseStatements(*sit); |
|
1450 |
|
1451 out << ";\n"; |
|
1452 } |
|
1453 |
|
1454 if (mInsideFunction) |
|
1455 { |
|
1456 outputLineDirective(node->getLine().last_line); |
|
1457 out << "}\n"; |
|
1458 |
|
1459 mScopeDepth--; |
|
1460 } |
|
1461 |
|
1462 return false; |
|
1463 } |
|
1464 case EOpDeclaration: |
|
1465 if (visit == PreVisit) |
|
1466 { |
|
1467 TIntermSequence &sequence = node->getSequence(); |
|
1468 TIntermTyped *variable = sequence[0]->getAsTyped(); |
|
1469 |
|
1470 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal)) |
|
1471 { |
|
1472 if (variable->getType().getStruct()) |
|
1473 { |
|
1474 addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL); |
|
1475 } |
|
1476 |
|
1477 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration |
|
1478 { |
|
1479 if (!mInsideFunction) |
|
1480 { |
|
1481 out << "static "; |
|
1482 } |
|
1483 |
|
1484 out << typeString(variable->getType()) + " "; |
|
1485 |
|
1486 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) |
|
1487 { |
|
1488 TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); |
|
1489 |
|
1490 if (symbol) |
|
1491 { |
|
1492 symbol->traverse(this); |
|
1493 out << arrayString(symbol->getType()); |
|
1494 out << " = " + initializer(variable->getType()); |
|
1495 } |
|
1496 else |
|
1497 { |
|
1498 (*sit)->traverse(this); |
|
1499 } |
|
1500 |
|
1501 if (*sit != sequence.back()) |
|
1502 { |
|
1503 out << ", "; |
|
1504 } |
|
1505 } |
|
1506 } |
|
1507 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration |
|
1508 { |
|
1509 // Already added to constructor map |
|
1510 } |
|
1511 else UNREACHABLE(); |
|
1512 } |
|
1513 else if (variable && (variable->getQualifier() == EvqVaryingOut || variable->getQualifier() == EvqInvariantVaryingOut)) |
|
1514 { |
|
1515 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) |
|
1516 { |
|
1517 TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); |
|
1518 |
|
1519 if (symbol) |
|
1520 { |
|
1521 // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking |
|
1522 mReferencedVaryings[symbol->getSymbol()] = symbol; |
|
1523 } |
|
1524 else |
|
1525 { |
|
1526 (*sit)->traverse(this); |
|
1527 } |
|
1528 } |
|
1529 } |
|
1530 |
|
1531 return false; |
|
1532 } |
|
1533 else if (visit == InVisit) |
|
1534 { |
|
1535 out << ", "; |
|
1536 } |
|
1537 break; |
|
1538 case EOpPrototype: |
|
1539 if (visit == PreVisit) |
|
1540 { |
|
1541 out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); |
|
1542 |
|
1543 TIntermSequence &arguments = node->getSequence(); |
|
1544 |
|
1545 for (unsigned int i = 0; i < arguments.size(); i++) |
|
1546 { |
|
1547 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); |
|
1548 |
|
1549 if (symbol) |
|
1550 { |
|
1551 out << argumentString(symbol); |
|
1552 |
|
1553 if (i < arguments.size() - 1) |
|
1554 { |
|
1555 out << ", "; |
|
1556 } |
|
1557 } |
|
1558 else UNREACHABLE(); |
|
1559 } |
|
1560 |
|
1561 out << ");\n"; |
|
1562 |
|
1563 // Also prototype the Lod0 variant if needed |
|
1564 if (mContainsLoopDiscontinuity && !mOutputLod0Function) |
|
1565 { |
|
1566 mOutputLod0Function = true; |
|
1567 node->traverse(this); |
|
1568 mOutputLod0Function = false; |
|
1569 } |
|
1570 |
|
1571 return false; |
|
1572 } |
|
1573 break; |
|
1574 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break; |
|
1575 case EOpFunction: |
|
1576 { |
|
1577 TString name = TFunction::unmangleName(node->getName()); |
|
1578 |
|
1579 out << typeString(node->getType()) << " "; |
|
1580 |
|
1581 if (name == "main") |
|
1582 { |
|
1583 out << "gl_main("; |
|
1584 } |
|
1585 else |
|
1586 { |
|
1587 out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "("); |
|
1588 } |
|
1589 |
|
1590 TIntermSequence &sequence = node->getSequence(); |
|
1591 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence(); |
|
1592 |
|
1593 for (unsigned int i = 0; i < arguments.size(); i++) |
|
1594 { |
|
1595 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); |
|
1596 |
|
1597 if (symbol) |
|
1598 { |
|
1599 if (symbol->getType().getStruct()) |
|
1600 { |
|
1601 addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL); |
|
1602 } |
|
1603 |
|
1604 out << argumentString(symbol); |
|
1605 |
|
1606 if (i < arguments.size() - 1) |
|
1607 { |
|
1608 out << ", "; |
|
1609 } |
|
1610 } |
|
1611 else UNREACHABLE(); |
|
1612 } |
|
1613 |
|
1614 out << ")\n" |
|
1615 "{\n"; |
|
1616 |
|
1617 if (sequence.size() > 1) |
|
1618 { |
|
1619 mInsideFunction = true; |
|
1620 sequence[1]->traverse(this); |
|
1621 mInsideFunction = false; |
|
1622 } |
|
1623 |
|
1624 out << "}\n"; |
|
1625 |
|
1626 if (mContainsLoopDiscontinuity && !mOutputLod0Function) |
|
1627 { |
|
1628 if (name != "main") |
|
1629 { |
|
1630 mOutputLod0Function = true; |
|
1631 node->traverse(this); |
|
1632 mOutputLod0Function = false; |
|
1633 } |
|
1634 } |
|
1635 |
|
1636 return false; |
|
1637 } |
|
1638 break; |
|
1639 case EOpFunctionCall: |
|
1640 { |
|
1641 TString name = TFunction::unmangleName(node->getName()); |
|
1642 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; |
|
1643 |
|
1644 if (node->isUserDefined()) |
|
1645 { |
|
1646 out << decorate(name) << (lod0 ? "Lod0(" : "("); |
|
1647 } |
|
1648 else |
|
1649 { |
|
1650 if (name == "texture2D") |
|
1651 { |
|
1652 if (!lod0) |
|
1653 { |
|
1654 if (node->getSequence().size() == 2) |
|
1655 { |
|
1656 mUsesTexture2D = true; |
|
1657 } |
|
1658 else if (node->getSequence().size() == 3) |
|
1659 { |
|
1660 mUsesTexture2D_bias = true; |
|
1661 } |
|
1662 else UNREACHABLE(); |
|
1663 |
|
1664 out << "gl_texture2D("; |
|
1665 } |
|
1666 else |
|
1667 { |
|
1668 if (node->getSequence().size() == 2) |
|
1669 { |
|
1670 mUsesTexture2DLod0 = true; |
|
1671 } |
|
1672 else if (node->getSequence().size() == 3) |
|
1673 { |
|
1674 mUsesTexture2DLod0_bias = true; |
|
1675 } |
|
1676 else UNREACHABLE(); |
|
1677 |
|
1678 out << "gl_texture2DLod0("; |
|
1679 } |
|
1680 } |
|
1681 else if (name == "texture2DProj") |
|
1682 { |
|
1683 if (!lod0) |
|
1684 { |
|
1685 if (node->getSequence().size() == 2) |
|
1686 { |
|
1687 mUsesTexture2DProj = true; |
|
1688 } |
|
1689 else if (node->getSequence().size() == 3) |
|
1690 { |
|
1691 mUsesTexture2DProj_bias = true; |
|
1692 } |
|
1693 else UNREACHABLE(); |
|
1694 |
|
1695 out << "gl_texture2DProj("; |
|
1696 } |
|
1697 else |
|
1698 { |
|
1699 if (node->getSequence().size() == 2) |
|
1700 { |
|
1701 mUsesTexture2DProjLod0 = true; |
|
1702 } |
|
1703 else if (node->getSequence().size() == 3) |
|
1704 { |
|
1705 mUsesTexture2DProjLod0_bias = true; |
|
1706 } |
|
1707 else UNREACHABLE(); |
|
1708 |
|
1709 out << "gl_texture2DProjLod0("; |
|
1710 } |
|
1711 } |
|
1712 else if (name == "textureCube") |
|
1713 { |
|
1714 if (!lod0) |
|
1715 { |
|
1716 if (node->getSequence().size() == 2) |
|
1717 { |
|
1718 mUsesTextureCube = true; |
|
1719 } |
|
1720 else if (node->getSequence().size() == 3) |
|
1721 { |
|
1722 mUsesTextureCube_bias = true; |
|
1723 } |
|
1724 else UNREACHABLE(); |
|
1725 |
|
1726 out << "gl_textureCube("; |
|
1727 } |
|
1728 else |
|
1729 { |
|
1730 if (node->getSequence().size() == 2) |
|
1731 { |
|
1732 mUsesTextureCubeLod0 = true; |
|
1733 } |
|
1734 else if (node->getSequence().size() == 3) |
|
1735 { |
|
1736 mUsesTextureCubeLod0_bias = true; |
|
1737 } |
|
1738 else UNREACHABLE(); |
|
1739 |
|
1740 out << "gl_textureCubeLod0("; |
|
1741 } |
|
1742 } |
|
1743 else if (name == "texture2DLod") |
|
1744 { |
|
1745 if (node->getSequence().size() == 3) |
|
1746 { |
|
1747 mUsesTexture2DLod = true; |
|
1748 } |
|
1749 else UNREACHABLE(); |
|
1750 |
|
1751 out << "gl_texture2DLod("; |
|
1752 } |
|
1753 else if (name == "texture2DProjLod") |
|
1754 { |
|
1755 if (node->getSequence().size() == 3) |
|
1756 { |
|
1757 mUsesTexture2DProjLod = true; |
|
1758 } |
|
1759 else UNREACHABLE(); |
|
1760 |
|
1761 out << "gl_texture2DProjLod("; |
|
1762 } |
|
1763 else if (name == "textureCubeLod") |
|
1764 { |
|
1765 if (node->getSequence().size() == 3) |
|
1766 { |
|
1767 mUsesTextureCubeLod = true; |
|
1768 } |
|
1769 else UNREACHABLE(); |
|
1770 |
|
1771 out << "gl_textureCubeLod("; |
|
1772 } |
|
1773 else UNREACHABLE(); |
|
1774 } |
|
1775 |
|
1776 TIntermSequence &arguments = node->getSequence(); |
|
1777 |
|
1778 for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++) |
|
1779 { |
|
1780 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType())) |
|
1781 { |
|
1782 out << "texture_"; |
|
1783 (*arg)->traverse(this); |
|
1784 out << ", sampler_"; |
|
1785 } |
|
1786 |
|
1787 (*arg)->traverse(this); |
|
1788 |
|
1789 if (arg < arguments.end() - 1) |
|
1790 { |
|
1791 out << ", "; |
|
1792 } |
|
1793 } |
|
1794 |
|
1795 out << ")"; |
|
1796 |
|
1797 return false; |
|
1798 } |
|
1799 break; |
|
1800 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; |
|
1801 case EOpConstructFloat: |
|
1802 addConstructor(node->getType(), "vec1", &node->getSequence()); |
|
1803 outputTriplet(visit, "vec1(", "", ")"); |
|
1804 break; |
|
1805 case EOpConstructVec2: |
|
1806 addConstructor(node->getType(), "vec2", &node->getSequence()); |
|
1807 outputTriplet(visit, "vec2(", ", ", ")"); |
|
1808 break; |
|
1809 case EOpConstructVec3: |
|
1810 addConstructor(node->getType(), "vec3", &node->getSequence()); |
|
1811 outputTriplet(visit, "vec3(", ", ", ")"); |
|
1812 break; |
|
1813 case EOpConstructVec4: |
|
1814 addConstructor(node->getType(), "vec4", &node->getSequence()); |
|
1815 outputTriplet(visit, "vec4(", ", ", ")"); |
|
1816 break; |
|
1817 case EOpConstructBool: |
|
1818 addConstructor(node->getType(), "bvec1", &node->getSequence()); |
|
1819 outputTriplet(visit, "bvec1(", "", ")"); |
|
1820 break; |
|
1821 case EOpConstructBVec2: |
|
1822 addConstructor(node->getType(), "bvec2", &node->getSequence()); |
|
1823 outputTriplet(visit, "bvec2(", ", ", ")"); |
|
1824 break; |
|
1825 case EOpConstructBVec3: |
|
1826 addConstructor(node->getType(), "bvec3", &node->getSequence()); |
|
1827 outputTriplet(visit, "bvec3(", ", ", ")"); |
|
1828 break; |
|
1829 case EOpConstructBVec4: |
|
1830 addConstructor(node->getType(), "bvec4", &node->getSequence()); |
|
1831 outputTriplet(visit, "bvec4(", ", ", ")"); |
|
1832 break; |
|
1833 case EOpConstructInt: |
|
1834 addConstructor(node->getType(), "ivec1", &node->getSequence()); |
|
1835 outputTriplet(visit, "ivec1(", "", ")"); |
|
1836 break; |
|
1837 case EOpConstructIVec2: |
|
1838 addConstructor(node->getType(), "ivec2", &node->getSequence()); |
|
1839 outputTriplet(visit, "ivec2(", ", ", ")"); |
|
1840 break; |
|
1841 case EOpConstructIVec3: |
|
1842 addConstructor(node->getType(), "ivec3", &node->getSequence()); |
|
1843 outputTriplet(visit, "ivec3(", ", ", ")"); |
|
1844 break; |
|
1845 case EOpConstructIVec4: |
|
1846 addConstructor(node->getType(), "ivec4", &node->getSequence()); |
|
1847 outputTriplet(visit, "ivec4(", ", ", ")"); |
|
1848 break; |
|
1849 case EOpConstructMat2: |
|
1850 addConstructor(node->getType(), "mat2", &node->getSequence()); |
|
1851 outputTriplet(visit, "mat2(", ", ", ")"); |
|
1852 break; |
|
1853 case EOpConstructMat3: |
|
1854 addConstructor(node->getType(), "mat3", &node->getSequence()); |
|
1855 outputTriplet(visit, "mat3(", ", ", ")"); |
|
1856 break; |
|
1857 case EOpConstructMat4: |
|
1858 addConstructor(node->getType(), "mat4", &node->getSequence()); |
|
1859 outputTriplet(visit, "mat4(", ", ", ")"); |
|
1860 break; |
|
1861 case EOpConstructStruct: |
|
1862 addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence()); |
|
1863 outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")"); |
|
1864 break; |
|
1865 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; |
|
1866 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; |
|
1867 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; |
|
1868 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; |
|
1869 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; |
|
1870 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; |
|
1871 case EOpMod: |
|
1872 { |
|
1873 // We need to look at the number of components in both arguments |
|
1874 switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10 |
|
1875 + node->getSequence()[1]->getAsTyped()->getNominalSize()) |
|
1876 { |
|
1877 case 11: mUsesMod1 = true; break; |
|
1878 case 22: mUsesMod2v = true; break; |
|
1879 case 21: mUsesMod2f = true; break; |
|
1880 case 33: mUsesMod3v = true; break; |
|
1881 case 31: mUsesMod3f = true; break; |
|
1882 case 44: mUsesMod4v = true; break; |
|
1883 case 41: mUsesMod4f = true; break; |
|
1884 default: UNREACHABLE(); |
|
1885 } |
|
1886 |
|
1887 outputTriplet(visit, "mod(", ", ", ")"); |
|
1888 } |
|
1889 break; |
|
1890 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; |
|
1891 case EOpAtan: |
|
1892 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator |
|
1893 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) |
|
1894 { |
|
1895 case 1: mUsesAtan2_1 = true; break; |
|
1896 case 2: mUsesAtan2_2 = true; break; |
|
1897 case 3: mUsesAtan2_3 = true; break; |
|
1898 case 4: mUsesAtan2_4 = true; break; |
|
1899 default: UNREACHABLE(); |
|
1900 } |
|
1901 outputTriplet(visit, "atanyx(", ", ", ")"); |
|
1902 break; |
|
1903 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; |
|
1904 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; |
|
1905 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break; |
|
1906 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break; |
|
1907 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break; |
|
1908 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break; |
|
1909 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break; |
|
1910 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; |
|
1911 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; |
|
1912 case EOpFaceForward: |
|
1913 { |
|
1914 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument |
|
1915 { |
|
1916 case 1: mUsesFaceforward1 = true; break; |
|
1917 case 2: mUsesFaceforward2 = true; break; |
|
1918 case 3: mUsesFaceforward3 = true; break; |
|
1919 case 4: mUsesFaceforward4 = true; break; |
|
1920 default: UNREACHABLE(); |
|
1921 } |
|
1922 |
|
1923 outputTriplet(visit, "faceforward(", ", ", ")"); |
|
1924 } |
|
1925 break; |
|
1926 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; |
|
1927 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; |
|
1928 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; |
|
1929 default: UNREACHABLE(); |
|
1930 } |
|
1931 |
|
1932 return true; |
|
1933 } |
|
1934 |
|
1935 bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) |
|
1936 { |
|
1937 TInfoSinkBase &out = mBody; |
|
1938 |
|
1939 if (node->usesTernaryOperator()) |
|
1940 { |
|
1941 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); |
|
1942 } |
|
1943 else // if/else statement |
|
1944 { |
|
1945 mUnfoldShortCircuit->traverse(node->getCondition()); |
|
1946 |
|
1947 out << "if("; |
|
1948 |
|
1949 node->getCondition()->traverse(this); |
|
1950 |
|
1951 out << ")\n"; |
|
1952 |
|
1953 outputLineDirective(node->getLine().first_line); |
|
1954 out << "{\n"; |
|
1955 |
|
1956 if (node->getTrueBlock()) |
|
1957 { |
|
1958 traverseStatements(node->getTrueBlock()); |
|
1959 } |
|
1960 |
|
1961 outputLineDirective(node->getLine().first_line); |
|
1962 out << ";\n}\n"; |
|
1963 |
|
1964 if (node->getFalseBlock()) |
|
1965 { |
|
1966 out << "else\n"; |
|
1967 |
|
1968 outputLineDirective(node->getFalseBlock()->getLine().first_line); |
|
1969 out << "{\n"; |
|
1970 |
|
1971 outputLineDirective(node->getFalseBlock()->getLine().first_line); |
|
1972 traverseStatements(node->getFalseBlock()); |
|
1973 |
|
1974 outputLineDirective(node->getFalseBlock()->getLine().first_line); |
|
1975 out << ";\n}\n"; |
|
1976 } |
|
1977 } |
|
1978 |
|
1979 return false; |
|
1980 } |
|
1981 |
|
1982 void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) |
|
1983 { |
|
1984 writeConstantUnion(node->getType(), node->getUnionArrayPointer()); |
|
1985 } |
|
1986 |
|
1987 bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) |
|
1988 { |
|
1989 bool wasDiscontinuous = mInsideDiscontinuousLoop; |
|
1990 |
|
1991 if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop) |
|
1992 { |
|
1993 mInsideDiscontinuousLoop = containsLoopDiscontinuity(node); |
|
1994 } |
|
1995 |
|
1996 if (mOutputType == SH_HLSL9_OUTPUT) |
|
1997 { |
|
1998 if (handleExcessiveLoop(node)) |
|
1999 { |
|
2000 return false; |
|
2001 } |
|
2002 } |
|
2003 |
|
2004 TInfoSinkBase &out = mBody; |
|
2005 |
|
2006 if (node->getType() == ELoopDoWhile) |
|
2007 { |
|
2008 out << "{do\n"; |
|
2009 |
|
2010 outputLineDirective(node->getLine().first_line); |
|
2011 out << "{\n"; |
|
2012 } |
|
2013 else |
|
2014 { |
|
2015 out << "{for("; |
|
2016 |
|
2017 if (node->getInit()) |
|
2018 { |
|
2019 node->getInit()->traverse(this); |
|
2020 } |
|
2021 |
|
2022 out << "; "; |
|
2023 |
|
2024 if (node->getCondition()) |
|
2025 { |
|
2026 node->getCondition()->traverse(this); |
|
2027 } |
|
2028 |
|
2029 out << "; "; |
|
2030 |
|
2031 if (node->getExpression()) |
|
2032 { |
|
2033 node->getExpression()->traverse(this); |
|
2034 } |
|
2035 |
|
2036 out << ")\n"; |
|
2037 |
|
2038 outputLineDirective(node->getLine().first_line); |
|
2039 out << "{\n"; |
|
2040 } |
|
2041 |
|
2042 if (node->getBody()) |
|
2043 { |
|
2044 traverseStatements(node->getBody()); |
|
2045 } |
|
2046 |
|
2047 outputLineDirective(node->getLine().first_line); |
|
2048 out << ";}\n"; |
|
2049 |
|
2050 if (node->getType() == ELoopDoWhile) |
|
2051 { |
|
2052 outputLineDirective(node->getCondition()->getLine().first_line); |
|
2053 out << "while(\n"; |
|
2054 |
|
2055 node->getCondition()->traverse(this); |
|
2056 |
|
2057 out << ");"; |
|
2058 } |
|
2059 |
|
2060 out << "}\n"; |
|
2061 |
|
2062 mInsideDiscontinuousLoop = wasDiscontinuous; |
|
2063 |
|
2064 return false; |
|
2065 } |
|
2066 |
|
2067 bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) |
|
2068 { |
|
2069 TInfoSinkBase &out = mBody; |
|
2070 |
|
2071 switch (node->getFlowOp()) |
|
2072 { |
|
2073 case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break; |
|
2074 case EOpBreak: |
|
2075 if (visit == PreVisit) |
|
2076 { |
|
2077 if (mExcessiveLoopIndex) |
|
2078 { |
|
2079 out << "{Break"; |
|
2080 mExcessiveLoopIndex->traverse(this); |
|
2081 out << " = true; break;}\n"; |
|
2082 } |
|
2083 else |
|
2084 { |
|
2085 out << "break;\n"; |
|
2086 } |
|
2087 } |
|
2088 break; |
|
2089 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break; |
|
2090 case EOpReturn: |
|
2091 if (visit == PreVisit) |
|
2092 { |
|
2093 if (node->getExpression()) |
|
2094 { |
|
2095 out << "return "; |
|
2096 } |
|
2097 else |
|
2098 { |
|
2099 out << "return;\n"; |
|
2100 } |
|
2101 } |
|
2102 else if (visit == PostVisit) |
|
2103 { |
|
2104 if (node->getExpression()) |
|
2105 { |
|
2106 out << ";\n"; |
|
2107 } |
|
2108 } |
|
2109 break; |
|
2110 default: UNREACHABLE(); |
|
2111 } |
|
2112 |
|
2113 return true; |
|
2114 } |
|
2115 |
|
2116 void OutputHLSL::traverseStatements(TIntermNode *node) |
|
2117 { |
|
2118 if (isSingleStatement(node)) |
|
2119 { |
|
2120 mUnfoldShortCircuit->traverse(node); |
|
2121 } |
|
2122 |
|
2123 node->traverse(this); |
|
2124 } |
|
2125 |
|
2126 bool OutputHLSL::isSingleStatement(TIntermNode *node) |
|
2127 { |
|
2128 TIntermAggregate *aggregate = node->getAsAggregate(); |
|
2129 |
|
2130 if (aggregate) |
|
2131 { |
|
2132 if (aggregate->getOp() == EOpSequence) |
|
2133 { |
|
2134 return false; |
|
2135 } |
|
2136 else |
|
2137 { |
|
2138 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++) |
|
2139 { |
|
2140 if (!isSingleStatement(*sit)) |
|
2141 { |
|
2142 return false; |
|
2143 } |
|
2144 } |
|
2145 |
|
2146 return true; |
|
2147 } |
|
2148 } |
|
2149 |
|
2150 return true; |
|
2151 } |
|
2152 |
|
2153 // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them |
|
2154 // (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254). |
|
2155 bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) |
|
2156 { |
|
2157 const int MAX_LOOP_ITERATIONS = 254; |
|
2158 TInfoSinkBase &out = mBody; |
|
2159 |
|
2160 // Parse loops of the form: |
|
2161 // for(int index = initial; index [comparator] limit; index += increment) |
|
2162 TIntermSymbol *index = NULL; |
|
2163 TOperator comparator = EOpNull; |
|
2164 int initial = 0; |
|
2165 int limit = 0; |
|
2166 int increment = 0; |
|
2167 |
|
2168 // Parse index name and intial value |
|
2169 if (node->getInit()) |
|
2170 { |
|
2171 TIntermAggregate *init = node->getInit()->getAsAggregate(); |
|
2172 |
|
2173 if (init) |
|
2174 { |
|
2175 TIntermSequence &sequence = init->getSequence(); |
|
2176 TIntermTyped *variable = sequence[0]->getAsTyped(); |
|
2177 |
|
2178 if (variable && variable->getQualifier() == EvqTemporary) |
|
2179 { |
|
2180 TIntermBinary *assign = variable->getAsBinaryNode(); |
|
2181 |
|
2182 if (assign->getOp() == EOpInitialize) |
|
2183 { |
|
2184 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); |
|
2185 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion(); |
|
2186 |
|
2187 if (symbol && constant) |
|
2188 { |
|
2189 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) |
|
2190 { |
|
2191 index = symbol; |
|
2192 initial = constant->getIConst(0); |
|
2193 } |
|
2194 } |
|
2195 } |
|
2196 } |
|
2197 } |
|
2198 } |
|
2199 |
|
2200 // Parse comparator and limit value |
|
2201 if (index != NULL && node->getCondition()) |
|
2202 { |
|
2203 TIntermBinary *test = node->getCondition()->getAsBinaryNode(); |
|
2204 |
|
2205 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId()) |
|
2206 { |
|
2207 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion(); |
|
2208 |
|
2209 if (constant) |
|
2210 { |
|
2211 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) |
|
2212 { |
|
2213 comparator = test->getOp(); |
|
2214 limit = constant->getIConst(0); |
|
2215 } |
|
2216 } |
|
2217 } |
|
2218 } |
|
2219 |
|
2220 // Parse increment |
|
2221 if (index != NULL && comparator != EOpNull && node->getExpression()) |
|
2222 { |
|
2223 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); |
|
2224 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); |
|
2225 |
|
2226 if (binaryTerminal) |
|
2227 { |
|
2228 TOperator op = binaryTerminal->getOp(); |
|
2229 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion(); |
|
2230 |
|
2231 if (constant) |
|
2232 { |
|
2233 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) |
|
2234 { |
|
2235 int value = constant->getIConst(0); |
|
2236 |
|
2237 switch (op) |
|
2238 { |
|
2239 case EOpAddAssign: increment = value; break; |
|
2240 case EOpSubAssign: increment = -value; break; |
|
2241 default: UNIMPLEMENTED(); |
|
2242 } |
|
2243 } |
|
2244 } |
|
2245 } |
|
2246 else if (unaryTerminal) |
|
2247 { |
|
2248 TOperator op = unaryTerminal->getOp(); |
|
2249 |
|
2250 switch (op) |
|
2251 { |
|
2252 case EOpPostIncrement: increment = 1; break; |
|
2253 case EOpPostDecrement: increment = -1; break; |
|
2254 case EOpPreIncrement: increment = 1; break; |
|
2255 case EOpPreDecrement: increment = -1; break; |
|
2256 default: UNIMPLEMENTED(); |
|
2257 } |
|
2258 } |
|
2259 } |
|
2260 |
|
2261 if (index != NULL && comparator != EOpNull && increment != 0) |
|
2262 { |
|
2263 if (comparator == EOpLessThanEqual) |
|
2264 { |
|
2265 comparator = EOpLessThan; |
|
2266 limit += 1; |
|
2267 } |
|
2268 |
|
2269 if (comparator == EOpLessThan) |
|
2270 { |
|
2271 int iterations = (limit - initial) / increment; |
|
2272 |
|
2273 if (iterations <= MAX_LOOP_ITERATIONS) |
|
2274 { |
|
2275 return false; // Not an excessive loop |
|
2276 } |
|
2277 |
|
2278 TIntermSymbol *restoreIndex = mExcessiveLoopIndex; |
|
2279 mExcessiveLoopIndex = index; |
|
2280 |
|
2281 out << "{int "; |
|
2282 index->traverse(this); |
|
2283 out << ";\n" |
|
2284 "bool Break"; |
|
2285 index->traverse(this); |
|
2286 out << " = false;\n"; |
|
2287 |
|
2288 bool firstLoopFragment = true; |
|
2289 |
|
2290 while (iterations > 0) |
|
2291 { |
|
2292 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations); |
|
2293 |
|
2294 if (!firstLoopFragment) |
|
2295 { |
|
2296 out << "if(!Break"; |
|
2297 index->traverse(this); |
|
2298 out << ") {\n"; |
|
2299 } |
|
2300 |
|
2301 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment |
|
2302 { |
|
2303 mExcessiveLoopIndex = NULL; // Stops setting the Break flag |
|
2304 } |
|
2305 |
|
2306 // for(int index = initial; index < clampedLimit; index += increment) |
|
2307 |
|
2308 out << "for("; |
|
2309 index->traverse(this); |
|
2310 out << " = "; |
|
2311 out << initial; |
|
2312 |
|
2313 out << "; "; |
|
2314 index->traverse(this); |
|
2315 out << " < "; |
|
2316 out << clampedLimit; |
|
2317 |
|
2318 out << "; "; |
|
2319 index->traverse(this); |
|
2320 out << " += "; |
|
2321 out << increment; |
|
2322 out << ")\n"; |
|
2323 |
|
2324 outputLineDirective(node->getLine().first_line); |
|
2325 out << "{\n"; |
|
2326 |
|
2327 if (node->getBody()) |
|
2328 { |
|
2329 node->getBody()->traverse(this); |
|
2330 } |
|
2331 |
|
2332 outputLineDirective(node->getLine().first_line); |
|
2333 out << ";}\n"; |
|
2334 |
|
2335 if (!firstLoopFragment) |
|
2336 { |
|
2337 out << "}\n"; |
|
2338 } |
|
2339 |
|
2340 firstLoopFragment = false; |
|
2341 |
|
2342 initial += MAX_LOOP_ITERATIONS * increment; |
|
2343 iterations -= MAX_LOOP_ITERATIONS; |
|
2344 } |
|
2345 |
|
2346 out << "}"; |
|
2347 |
|
2348 mExcessiveLoopIndex = restoreIndex; |
|
2349 |
|
2350 return true; |
|
2351 } |
|
2352 else UNIMPLEMENTED(); |
|
2353 } |
|
2354 |
|
2355 return false; // Not handled as an excessive loop |
|
2356 } |
|
2357 |
|
2358 void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) |
|
2359 { |
|
2360 TInfoSinkBase &out = mBody; |
|
2361 |
|
2362 if (visit == PreVisit) |
|
2363 { |
|
2364 out << preString; |
|
2365 } |
|
2366 else if (visit == InVisit) |
|
2367 { |
|
2368 out << inString; |
|
2369 } |
|
2370 else if (visit == PostVisit) |
|
2371 { |
|
2372 out << postString; |
|
2373 } |
|
2374 } |
|
2375 |
|
2376 void OutputHLSL::outputLineDirective(int line) |
|
2377 { |
|
2378 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) |
|
2379 { |
|
2380 mBody << "\n"; |
|
2381 mBody << "#line " << line; |
|
2382 |
|
2383 if (mContext.sourcePath) |
|
2384 { |
|
2385 mBody << " \"" << mContext.sourcePath << "\""; |
|
2386 } |
|
2387 |
|
2388 mBody << "\n"; |
|
2389 } |
|
2390 } |
|
2391 |
|
2392 TString OutputHLSL::argumentString(const TIntermSymbol *symbol) |
|
2393 { |
|
2394 TQualifier qualifier = symbol->getQualifier(); |
|
2395 const TType &type = symbol->getType(); |
|
2396 TString name = symbol->getSymbol(); |
|
2397 |
|
2398 if (name.empty()) // HLSL demands named arguments, also for prototypes |
|
2399 { |
|
2400 name = "x" + str(mUniqueIndex++); |
|
2401 } |
|
2402 else |
|
2403 { |
|
2404 name = decorate(name); |
|
2405 } |
|
2406 |
|
2407 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) |
|
2408 { |
|
2409 return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " + |
|
2410 qualifierString(qualifier) + " SamplerState sampler_" + name + arrayString(type); |
|
2411 } |
|
2412 |
|
2413 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type); |
|
2414 } |
|
2415 |
|
2416 TString OutputHLSL::qualifierString(TQualifier qualifier) |
|
2417 { |
|
2418 switch(qualifier) |
|
2419 { |
|
2420 case EvqIn: return "in"; |
|
2421 case EvqOut: return "out"; |
|
2422 case EvqInOut: return "inout"; |
|
2423 case EvqConstReadOnly: return "const"; |
|
2424 default: UNREACHABLE(); |
|
2425 } |
|
2426 |
|
2427 return ""; |
|
2428 } |
|
2429 |
|
2430 TString OutputHLSL::typeString(const TType &type) |
|
2431 { |
|
2432 if (type.getBasicType() == EbtStruct) |
|
2433 { |
|
2434 const TString& typeName = type.getStruct()->name(); |
|
2435 if (typeName != "") |
|
2436 { |
|
2437 return structLookup(typeName); |
|
2438 } |
|
2439 else // Nameless structure, define in place |
|
2440 { |
|
2441 const TFieldList &fields = type.getStruct()->fields(); |
|
2442 |
|
2443 TString string = "struct\n" |
|
2444 "{\n"; |
|
2445 |
|
2446 for (unsigned int i = 0; i < fields.size(); i++) |
|
2447 { |
|
2448 const TField *field = fields[i]; |
|
2449 |
|
2450 string += " " + typeString(*field->type()) + " " + decorate(field->name()) + arrayString(*field->type()) + ";\n"; |
|
2451 } |
|
2452 |
|
2453 string += "} "; |
|
2454 |
|
2455 return string; |
|
2456 } |
|
2457 } |
|
2458 else if (type.isMatrix()) |
|
2459 { |
|
2460 switch (type.getNominalSize()) |
|
2461 { |
|
2462 case 2: return "float2x2"; |
|
2463 case 3: return "float3x3"; |
|
2464 case 4: return "float4x4"; |
|
2465 } |
|
2466 } |
|
2467 else |
|
2468 { |
|
2469 switch (type.getBasicType()) |
|
2470 { |
|
2471 case EbtFloat: |
|
2472 switch (type.getNominalSize()) |
|
2473 { |
|
2474 case 1: return "float"; |
|
2475 case 2: return "float2"; |
|
2476 case 3: return "float3"; |
|
2477 case 4: return "float4"; |
|
2478 } |
|
2479 case EbtInt: |
|
2480 switch (type.getNominalSize()) |
|
2481 { |
|
2482 case 1: return "int"; |
|
2483 case 2: return "int2"; |
|
2484 case 3: return "int3"; |
|
2485 case 4: return "int4"; |
|
2486 } |
|
2487 case EbtBool: |
|
2488 switch (type.getNominalSize()) |
|
2489 { |
|
2490 case 1: return "bool"; |
|
2491 case 2: return "bool2"; |
|
2492 case 3: return "bool3"; |
|
2493 case 4: return "bool4"; |
|
2494 } |
|
2495 case EbtVoid: |
|
2496 return "void"; |
|
2497 case EbtSampler2D: |
|
2498 return "sampler2D"; |
|
2499 case EbtSamplerCube: |
|
2500 return "samplerCUBE"; |
|
2501 case EbtSamplerExternalOES: |
|
2502 return "sampler2D"; |
|
2503 default: |
|
2504 break; |
|
2505 } |
|
2506 } |
|
2507 |
|
2508 UNREACHABLE(); |
|
2509 return "<unknown type>"; |
|
2510 } |
|
2511 |
|
2512 TString OutputHLSL::textureString(const TType &type) |
|
2513 { |
|
2514 switch (type.getBasicType()) |
|
2515 { |
|
2516 case EbtSampler2D: |
|
2517 return "Texture2D"; |
|
2518 case EbtSamplerCube: |
|
2519 return "TextureCube"; |
|
2520 case EbtSamplerExternalOES: |
|
2521 return "Texture2D"; |
|
2522 default: |
|
2523 break; |
|
2524 } |
|
2525 |
|
2526 UNREACHABLE(); |
|
2527 return "<unknown texture type>"; |
|
2528 } |
|
2529 |
|
2530 TString OutputHLSL::arrayString(const TType &type) |
|
2531 { |
|
2532 if (!type.isArray()) |
|
2533 { |
|
2534 return ""; |
|
2535 } |
|
2536 |
|
2537 return "[" + str(type.getArraySize()) + "]"; |
|
2538 } |
|
2539 |
|
2540 TString OutputHLSL::initializer(const TType &type) |
|
2541 { |
|
2542 TString string; |
|
2543 |
|
2544 size_t size = type.getObjectSize(); |
|
2545 for (size_t component = 0; component < size; component++) |
|
2546 { |
|
2547 string += "0"; |
|
2548 |
|
2549 if (component + 1 < size) |
|
2550 { |
|
2551 string += ", "; |
|
2552 } |
|
2553 } |
|
2554 |
|
2555 return "{" + string + "}"; |
|
2556 } |
|
2557 |
|
2558 void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) |
|
2559 { |
|
2560 if (name == "") |
|
2561 { |
|
2562 return; // Nameless structures don't have constructors |
|
2563 } |
|
2564 |
|
2565 if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end()) |
|
2566 { |
|
2567 return; // Already added |
|
2568 } |
|
2569 |
|
2570 TType ctorType = type; |
|
2571 ctorType.clearArrayness(); |
|
2572 ctorType.setPrecision(EbpHigh); |
|
2573 ctorType.setQualifier(EvqTemporary); |
|
2574 |
|
2575 TString ctorName = type.getStruct() ? decorate(name) : name; |
|
2576 |
|
2577 typedef std::vector<TType> ParameterArray; |
|
2578 ParameterArray ctorParameters; |
|
2579 |
|
2580 if (type.getStruct()) |
|
2581 { |
|
2582 mStructNames.insert(decorate(name)); |
|
2583 |
|
2584 TString structure; |
|
2585 structure += "struct " + decorate(name) + "\n" |
|
2586 "{\n"; |
|
2587 |
|
2588 const TFieldList &fields = type.getStruct()->fields(); |
|
2589 |
|
2590 for (unsigned int i = 0; i < fields.size(); i++) |
|
2591 { |
|
2592 const TField *field = fields[i]; |
|
2593 |
|
2594 structure += " " + typeString(*field->type()) + " " + decorateField(field->name(), type) + arrayString(*field->type()) + ";\n"; |
|
2595 } |
|
2596 |
|
2597 structure += "};\n"; |
|
2598 |
|
2599 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end()) |
|
2600 { |
|
2601 mStructDeclarations.push_back(structure); |
|
2602 } |
|
2603 |
|
2604 for (unsigned int i = 0; i < fields.size(); i++) |
|
2605 { |
|
2606 ctorParameters.push_back(*fields[i]->type()); |
|
2607 } |
|
2608 } |
|
2609 else if (parameters) |
|
2610 { |
|
2611 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) |
|
2612 { |
|
2613 ctorParameters.push_back((*parameter)->getAsTyped()->getType()); |
|
2614 } |
|
2615 } |
|
2616 else UNREACHABLE(); |
|
2617 |
|
2618 TString constructor; |
|
2619 |
|
2620 if (ctorType.getStruct()) |
|
2621 { |
|
2622 constructor += ctorName + " " + ctorName + "_ctor("; |
|
2623 } |
|
2624 else // Built-in type |
|
2625 { |
|
2626 constructor += typeString(ctorType) + " " + ctorName + "("; |
|
2627 } |
|
2628 |
|
2629 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) |
|
2630 { |
|
2631 const TType &type = ctorParameters[parameter]; |
|
2632 |
|
2633 constructor += typeString(type) + " x" + str(parameter) + arrayString(type); |
|
2634 |
|
2635 if (parameter < ctorParameters.size() - 1) |
|
2636 { |
|
2637 constructor += ", "; |
|
2638 } |
|
2639 } |
|
2640 |
|
2641 constructor += ")\n" |
|
2642 "{\n"; |
|
2643 |
|
2644 if (ctorType.getStruct()) |
|
2645 { |
|
2646 constructor += " " + ctorName + " structure = {"; |
|
2647 } |
|
2648 else |
|
2649 { |
|
2650 constructor += " return " + typeString(ctorType) + "("; |
|
2651 } |
|
2652 |
|
2653 if (ctorType.isMatrix() && ctorParameters.size() == 1) |
|
2654 { |
|
2655 int dim = ctorType.getNominalSize(); |
|
2656 const TType ¶meter = ctorParameters[0]; |
|
2657 |
|
2658 if (parameter.isScalar()) |
|
2659 { |
|
2660 for (int row = 0; row < dim; row++) |
|
2661 { |
|
2662 for (int col = 0; col < dim; col++) |
|
2663 { |
|
2664 constructor += TString((row == col) ? "x0" : "0.0"); |
|
2665 |
|
2666 if (row < dim - 1 || col < dim - 1) |
|
2667 { |
|
2668 constructor += ", "; |
|
2669 } |
|
2670 } |
|
2671 } |
|
2672 } |
|
2673 else if (parameter.isMatrix()) |
|
2674 { |
|
2675 for (int row = 0; row < dim; row++) |
|
2676 { |
|
2677 for (int col = 0; col < dim; col++) |
|
2678 { |
|
2679 if (row < parameter.getNominalSize() && col < parameter.getNominalSize()) |
|
2680 { |
|
2681 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]"; |
|
2682 } |
|
2683 else |
|
2684 { |
|
2685 constructor += TString((row == col) ? "1.0" : "0.0"); |
|
2686 } |
|
2687 |
|
2688 if (row < dim - 1 || col < dim - 1) |
|
2689 { |
|
2690 constructor += ", "; |
|
2691 } |
|
2692 } |
|
2693 } |
|
2694 } |
|
2695 else UNREACHABLE(); |
|
2696 } |
|
2697 else |
|
2698 { |
|
2699 size_t remainingComponents = ctorType.getObjectSize(); |
|
2700 size_t parameterIndex = 0; |
|
2701 |
|
2702 while (remainingComponents > 0) |
|
2703 { |
|
2704 const TType ¶meter = ctorParameters[parameterIndex]; |
|
2705 const size_t parameterSize = parameter.getObjectSize(); |
|
2706 bool moreParameters = parameterIndex + 1 < ctorParameters.size(); |
|
2707 |
|
2708 constructor += "x" + str(parameterIndex); |
|
2709 |
|
2710 if (parameter.isScalar()) |
|
2711 { |
|
2712 ASSERT(parameterSize <= remainingComponents); |
|
2713 remainingComponents -= parameterSize; |
|
2714 } |
|
2715 else if (parameter.isVector()) |
|
2716 { |
|
2717 if (remainingComponents == parameterSize || moreParameters) |
|
2718 { |
|
2719 ASSERT(parameterSize <= remainingComponents); |
|
2720 remainingComponents -= parameterSize; |
|
2721 } |
|
2722 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize())) |
|
2723 { |
|
2724 switch (remainingComponents) |
|
2725 { |
|
2726 case 1: constructor += ".x"; break; |
|
2727 case 2: constructor += ".xy"; break; |
|
2728 case 3: constructor += ".xyz"; break; |
|
2729 case 4: constructor += ".xyzw"; break; |
|
2730 default: UNREACHABLE(); |
|
2731 } |
|
2732 |
|
2733 remainingComponents = 0; |
|
2734 } |
|
2735 else UNREACHABLE(); |
|
2736 } |
|
2737 else if (parameter.isMatrix() || parameter.getStruct()) |
|
2738 { |
|
2739 ASSERT(remainingComponents == parameterSize || moreParameters); |
|
2740 ASSERT(parameterSize <= remainingComponents); |
|
2741 |
|
2742 remainingComponents -= parameterSize; |
|
2743 } |
|
2744 else UNREACHABLE(); |
|
2745 |
|
2746 if (moreParameters) |
|
2747 { |
|
2748 parameterIndex++; |
|
2749 } |
|
2750 |
|
2751 if (remainingComponents) |
|
2752 { |
|
2753 constructor += ", "; |
|
2754 } |
|
2755 } |
|
2756 } |
|
2757 |
|
2758 if (ctorType.getStruct()) |
|
2759 { |
|
2760 constructor += "};\n" |
|
2761 " return structure;\n" |
|
2762 "}\n"; |
|
2763 } |
|
2764 else |
|
2765 { |
|
2766 constructor += ");\n" |
|
2767 "}\n"; |
|
2768 } |
|
2769 |
|
2770 mConstructors.insert(constructor); |
|
2771 } |
|
2772 |
|
2773 const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) |
|
2774 { |
|
2775 TInfoSinkBase &out = mBody; |
|
2776 |
|
2777 if (type.getBasicType() == EbtStruct) |
|
2778 { |
|
2779 out << structLookup(type.getStruct()->name()) + "_ctor("; |
|
2780 |
|
2781 const TFieldList &fields = type.getStruct()->fields(); |
|
2782 |
|
2783 for (size_t i = 0; i < fields.size(); i++) |
|
2784 { |
|
2785 const TType *fieldType = fields[i]->type(); |
|
2786 |
|
2787 constUnion = writeConstantUnion(*fieldType, constUnion); |
|
2788 |
|
2789 if (i != fields.size() - 1) |
|
2790 { |
|
2791 out << ", "; |
|
2792 } |
|
2793 } |
|
2794 |
|
2795 out << ")"; |
|
2796 } |
|
2797 else |
|
2798 { |
|
2799 size_t size = type.getObjectSize(); |
|
2800 bool writeType = size > 1; |
|
2801 |
|
2802 if (writeType) |
|
2803 { |
|
2804 out << typeString(type) << "("; |
|
2805 } |
|
2806 |
|
2807 for (size_t i = 0; i < size; i++, constUnion++) |
|
2808 { |
|
2809 switch (constUnion->getType()) |
|
2810 { |
|
2811 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break; |
|
2812 case EbtInt: out << constUnion->getIConst(); break; |
|
2813 case EbtBool: out << constUnion->getBConst(); break; |
|
2814 default: UNREACHABLE(); |
|
2815 } |
|
2816 |
|
2817 if (i != size - 1) |
|
2818 { |
|
2819 out << ", "; |
|
2820 } |
|
2821 } |
|
2822 |
|
2823 if (writeType) |
|
2824 { |
|
2825 out << ")"; |
|
2826 } |
|
2827 } |
|
2828 |
|
2829 return constUnion; |
|
2830 } |
|
2831 |
|
2832 TString OutputHLSL::scopeString(unsigned int depthLimit) |
|
2833 { |
|
2834 TString string; |
|
2835 |
|
2836 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++) |
|
2837 { |
|
2838 string += "_" + str(i); |
|
2839 } |
|
2840 |
|
2841 return string; |
|
2842 } |
|
2843 |
|
2844 TString OutputHLSL::scopedStruct(const TString &typeName) |
|
2845 { |
|
2846 if (typeName == "") |
|
2847 { |
|
2848 return typeName; |
|
2849 } |
|
2850 |
|
2851 return typeName + scopeString(mScopeDepth); |
|
2852 } |
|
2853 |
|
2854 TString OutputHLSL::structLookup(const TString &typeName) |
|
2855 { |
|
2856 for (int depth = mScopeDepth; depth >= 0; depth--) |
|
2857 { |
|
2858 TString scopedName = decorate(typeName + scopeString(depth)); |
|
2859 |
|
2860 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++) |
|
2861 { |
|
2862 if (*structName == scopedName) |
|
2863 { |
|
2864 return scopedName; |
|
2865 } |
|
2866 } |
|
2867 } |
|
2868 |
|
2869 UNREACHABLE(); // Should have found a matching constructor |
|
2870 |
|
2871 return typeName; |
|
2872 } |
|
2873 |
|
2874 TString OutputHLSL::decorate(const TString &string) |
|
2875 { |
|
2876 if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0) |
|
2877 { |
|
2878 return "_" + string; |
|
2879 } |
|
2880 |
|
2881 return string; |
|
2882 } |
|
2883 |
|
2884 TString OutputHLSL::decorateUniform(const TString &string, const TType &type) |
|
2885 { |
|
2886 if (type.getBasicType() == EbtSamplerExternalOES) |
|
2887 { |
|
2888 return "ex_" + string; |
|
2889 } |
|
2890 |
|
2891 return decorate(string); |
|
2892 } |
|
2893 |
|
2894 TString OutputHLSL::decorateField(const TString &string, const TType &structure) |
|
2895 { |
|
2896 if (structure.getStruct()->name().compare(0, 3, "gl_") != 0) |
|
2897 { |
|
2898 return decorate(string); |
|
2899 } |
|
2900 |
|
2901 return string; |
|
2902 } |
|
2903 |
|
2904 TString OutputHLSL::registerString(TIntermSymbol *operand) |
|
2905 { |
|
2906 ASSERT(operand->getQualifier() == EvqUniform); |
|
2907 |
|
2908 if (IsSampler(operand->getBasicType())) |
|
2909 { |
|
2910 return "s" + str(samplerRegister(operand)); |
|
2911 } |
|
2912 |
|
2913 return "c" + str(uniformRegister(operand)); |
|
2914 } |
|
2915 |
|
2916 int OutputHLSL::samplerRegister(TIntermSymbol *sampler) |
|
2917 { |
|
2918 const TType &type = sampler->getType(); |
|
2919 ASSERT(IsSampler(type.getBasicType())); |
|
2920 |
|
2921 int index = mSamplerRegister; |
|
2922 mSamplerRegister += sampler->totalRegisterCount(); |
|
2923 |
|
2924 declareUniform(type, sampler->getSymbol(), index); |
|
2925 |
|
2926 return index; |
|
2927 } |
|
2928 |
|
2929 int OutputHLSL::uniformRegister(TIntermSymbol *uniform) |
|
2930 { |
|
2931 const TType &type = uniform->getType(); |
|
2932 ASSERT(!IsSampler(type.getBasicType())); |
|
2933 |
|
2934 int index = mUniformRegister; |
|
2935 mUniformRegister += uniform->totalRegisterCount(); |
|
2936 |
|
2937 declareUniform(type, uniform->getSymbol(), index); |
|
2938 |
|
2939 return index; |
|
2940 } |
|
2941 |
|
2942 void OutputHLSL::declareUniform(const TType &type, const TString &name, int index) |
|
2943 { |
|
2944 TStructure *structure = type.getStruct(); |
|
2945 |
|
2946 if (!structure) |
|
2947 { |
|
2948 mActiveUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index)); |
|
2949 } |
|
2950 else |
|
2951 { |
|
2952 const TFieldList &fields = structure->fields(); |
|
2953 |
|
2954 if (type.isArray()) |
|
2955 { |
|
2956 int elementIndex = index; |
|
2957 |
|
2958 for (int i = 0; i < type.getArraySize(); i++) |
|
2959 { |
|
2960 for (size_t j = 0; j < fields.size(); j++) |
|
2961 { |
|
2962 const TType &fieldType = *fields[j]->type(); |
|
2963 const TString uniformName = name + "[" + str(i) + "]." + fields[j]->name(); |
|
2964 declareUniform(fieldType, uniformName, elementIndex); |
|
2965 elementIndex += fieldType.totalRegisterCount(); |
|
2966 } |
|
2967 } |
|
2968 } |
|
2969 else |
|
2970 { |
|
2971 int fieldIndex = index; |
|
2972 |
|
2973 for (size_t i = 0; i < fields.size(); i++) |
|
2974 { |
|
2975 const TType &fieldType = *fields[i]->type(); |
|
2976 const TString uniformName = name + "." + fields[i]->name(); |
|
2977 declareUniform(fieldType, uniformName, fieldIndex); |
|
2978 fieldIndex += fieldType.totalRegisterCount(); |
|
2979 } |
|
2980 } |
|
2981 } |
|
2982 } |
|
2983 |
|
2984 GLenum OutputHLSL::glVariableType(const TType &type) |
|
2985 { |
|
2986 if (type.getBasicType() == EbtFloat) |
|
2987 { |
|
2988 if (type.isScalar()) |
|
2989 { |
|
2990 return GL_FLOAT; |
|
2991 } |
|
2992 else if (type.isVector()) |
|
2993 { |
|
2994 switch(type.getNominalSize()) |
|
2995 { |
|
2996 case 2: return GL_FLOAT_VEC2; |
|
2997 case 3: return GL_FLOAT_VEC3; |
|
2998 case 4: return GL_FLOAT_VEC4; |
|
2999 default: UNREACHABLE(); |
|
3000 } |
|
3001 } |
|
3002 else if (type.isMatrix()) |
|
3003 { |
|
3004 switch(type.getNominalSize()) |
|
3005 { |
|
3006 case 2: return GL_FLOAT_MAT2; |
|
3007 case 3: return GL_FLOAT_MAT3; |
|
3008 case 4: return GL_FLOAT_MAT4; |
|
3009 default: UNREACHABLE(); |
|
3010 } |
|
3011 } |
|
3012 else UNREACHABLE(); |
|
3013 } |
|
3014 else if (type.getBasicType() == EbtInt) |
|
3015 { |
|
3016 if (type.isScalar()) |
|
3017 { |
|
3018 return GL_INT; |
|
3019 } |
|
3020 else if (type.isVector()) |
|
3021 { |
|
3022 switch(type.getNominalSize()) |
|
3023 { |
|
3024 case 2: return GL_INT_VEC2; |
|
3025 case 3: return GL_INT_VEC3; |
|
3026 case 4: return GL_INT_VEC4; |
|
3027 default: UNREACHABLE(); |
|
3028 } |
|
3029 } |
|
3030 else UNREACHABLE(); |
|
3031 } |
|
3032 else if (type.getBasicType() == EbtBool) |
|
3033 { |
|
3034 if (type.isScalar()) |
|
3035 { |
|
3036 return GL_BOOL; |
|
3037 } |
|
3038 else if (type.isVector()) |
|
3039 { |
|
3040 switch(type.getNominalSize()) |
|
3041 { |
|
3042 case 2: return GL_BOOL_VEC2; |
|
3043 case 3: return GL_BOOL_VEC3; |
|
3044 case 4: return GL_BOOL_VEC4; |
|
3045 default: UNREACHABLE(); |
|
3046 } |
|
3047 } |
|
3048 else UNREACHABLE(); |
|
3049 } |
|
3050 else if (type.getBasicType() == EbtSampler2D) |
|
3051 { |
|
3052 return GL_SAMPLER_2D; |
|
3053 } |
|
3054 else if (type.getBasicType() == EbtSamplerCube) |
|
3055 { |
|
3056 return GL_SAMPLER_CUBE; |
|
3057 } |
|
3058 else UNREACHABLE(); |
|
3059 |
|
3060 return GL_NONE; |
|
3061 } |
|
3062 |
|
3063 GLenum OutputHLSL::glVariablePrecision(const TType &type) |
|
3064 { |
|
3065 if (type.getBasicType() == EbtFloat) |
|
3066 { |
|
3067 switch (type.getPrecision()) |
|
3068 { |
|
3069 case EbpHigh: return GL_HIGH_FLOAT; |
|
3070 case EbpMedium: return GL_MEDIUM_FLOAT; |
|
3071 case EbpLow: return GL_LOW_FLOAT; |
|
3072 case EbpUndefined: |
|
3073 // Should be defined as the default precision by the parser |
|
3074 default: UNREACHABLE(); |
|
3075 } |
|
3076 } |
|
3077 else if (type.getBasicType() == EbtInt) |
|
3078 { |
|
3079 switch (type.getPrecision()) |
|
3080 { |
|
3081 case EbpHigh: return GL_HIGH_INT; |
|
3082 case EbpMedium: return GL_MEDIUM_INT; |
|
3083 case EbpLow: return GL_LOW_INT; |
|
3084 case EbpUndefined: |
|
3085 // Should be defined as the default precision by the parser |
|
3086 default: UNREACHABLE(); |
|
3087 } |
|
3088 } |
|
3089 |
|
3090 // Other types (boolean, sampler) don't have a precision |
|
3091 return GL_NONE; |
|
3092 } |
|
3093 |
|
3094 } |