blob: bbf69b14dd98b825f7a6ed950daf8b41f15b530b [file] [log] [blame]
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001//
2// Copyright (c) 2016 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// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL
7// output. Some of the implementations are straightforward and just call the HLSL equivalent of the
8// ESSL texture function, others do more work to emulate ESSL texture sampling or size query
9// behavior.
10//
11
12#include "compiler/translator/TextureFunctionHLSL.h"
13
14#include "compiler/translator/UtilsHLSL.h"
15
16namespace sh
17{
18
19namespace
20{
21
22void OutputIntTexCoordWrap(TInfoSinkBase &out,
23 const char *wrapMode,
24 const char *size,
25 const TString &texCoord,
26 const TString &texCoordOffset,
27 const char *texCoordOutName)
28{
29 // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
30 // but rather use equivalent formulas that map better to HLSL.
31 out << "int " << texCoordOutName << ";\n";
32 out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
33 << ") / " << size << ";\n";
34
35 // CLAMP_TO_EDGE
36 out << "if (" << wrapMode << " == 1)\n";
37 out << "{\n";
38 out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
39 << "Offset)), 0, int(" << size << ") - 1);\n";
40 out << "}\n";
41
42 // MIRRORED_REPEAT
43 out << "else if (" << wrapMode << " == 3)\n";
44 out << "{\n";
45 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
46 << "Offset) * 0.5) * 2.0 - 1.0);\n";
47 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
48 out << "}\n";
49
50 // REPEAT
51 out << "else\n";
52 out << "{\n";
53 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
54 << "Offset)));\n";
55 out << "}\n";
56}
57
58void OutputIntTexCoordWraps(TInfoSinkBase &out,
59 const TextureFunctionHLSL::TextureFunction &textureFunction,
60 TString *texCoordX,
61 TString *texCoordY,
62 TString *texCoordZ)
63{
64 // Convert from normalized floating-point to integer
65 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
66 if (textureFunction.offset)
67 {
68 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
69 }
70 else
71 {
72 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
73 }
74 *texCoordX = "tix";
75 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
76 if (textureFunction.offset)
77 {
78 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
79 }
80 else
81 {
82 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
83 }
84 *texCoordY = "tiy";
85
86 if (IsSamplerArray(textureFunction.sampler))
87 {
88 *texCoordZ = "int(max(0, min(layers - 1, floor(0.5 + t.z))))";
89 }
90 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
91 {
92 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
93 if (textureFunction.offset)
94 {
95 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
96 }
97 else
98 {
99 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
100 }
101 *texCoordZ = "tiz";
102 }
103}
104
105void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
106 const TextureFunctionHLSL::TextureFunction &textureFunction,
107 const TString &textureReference,
108 const TString &samplerReference)
109{
110 out << textureReference;
111 if (IsIntegerSampler(textureFunction.sampler) ||
112 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
113 {
114 out << ".Load(";
115 return;
116 }
117
118 if (IsShadowSampler(textureFunction.sampler))
119 {
120 switch (textureFunction.method)
121 {
122 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
123 case TextureFunctionHLSL::TextureFunction::BIAS:
124 case TextureFunctionHLSL::TextureFunction::LOD:
125 out << ".SampleCmp(";
126 break;
127 case TextureFunctionHLSL::TextureFunction::LOD0:
128 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
129 case TextureFunctionHLSL::TextureFunction::GRAD:
130 out << ".SampleCmpLevelZero(";
131 break;
132 default:
133 UNREACHABLE();
134 }
135 }
136 else
137 {
138 switch (textureFunction.method)
139 {
140 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
141 out << ".Sample(";
142 break;
143 case TextureFunctionHLSL::TextureFunction::BIAS:
144 out << ".SampleBias(";
145 break;
146 case TextureFunctionHLSL::TextureFunction::LOD:
147 case TextureFunctionHLSL::TextureFunction::LOD0:
148 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
149 out << ".SampleLevel(";
150 break;
151 case TextureFunctionHLSL::TextureFunction::GRAD:
152 out << ".SampleGrad(";
153 break;
154 default:
155 UNREACHABLE();
156 }
157 }
158 out << samplerReference << ", ";
159}
160
161const char *GetSamplerCoordinateTypeString(
162 const TextureFunctionHLSL::TextureFunction &textureFunction,
163 int hlslCoords)
164{
165 if (IsIntegerSampler(textureFunction.sampler) ||
166 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
167 {
168 switch (hlslCoords)
169 {
170 case 2:
171 return "int3";
172 case 3:
173 return "int4";
174 default:
175 UNREACHABLE();
176 }
177 }
178 else
179 {
180 switch (hlslCoords)
181 {
182 case 2:
183 return "float2";
184 case 3:
185 return "float3";
186 case 4:
187 return "float4";
188 default:
189 UNREACHABLE();
190 }
191 }
192 return "";
193}
194
195int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
196 ShShaderOutput outputType)
197{
198 if (outputType == SH_HLSL_3_0_OUTPUT)
199 {
200 int hlslCoords = 2;
201 switch (textureFunction.sampler)
202 {
203 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400204 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300205 hlslCoords = 2;
206 break;
207 case EbtSamplerCube:
208 hlslCoords = 3;
209 break;
210 default:
211 UNREACHABLE();
212 }
213
214 switch (textureFunction.method)
215 {
216 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400217 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300218 return hlslCoords;
219 case TextureFunctionHLSL::TextureFunction::BIAS:
220 case TextureFunctionHLSL::TextureFunction::LOD:
221 case TextureFunctionHLSL::TextureFunction::LOD0:
222 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
223 return 4;
224 default:
225 UNREACHABLE();
226 }
227 }
228 else
229 {
230 switch (textureFunction.sampler)
231 {
232 case EbtSampler2D:
233 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800234 case EbtSampler2DMS:
235 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300236 case EbtSampler3D:
237 return 3;
238 case EbtSamplerCube:
239 return 3;
240 case EbtSampler2DArray:
241 return 3;
Ian Ewellbda75592016-04-18 17:25:54 -0400242 case EbtSamplerExternalOES:
243 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300244 case EbtISampler2D:
245 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800246 case EbtISampler2DMS:
247 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300248 case EbtISampler3D:
249 return 3;
250 case EbtISamplerCube:
251 return 3;
252 case EbtISampler2DArray:
253 return 3;
254 case EbtUSampler2D:
255 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800256 case EbtUSampler2DMS:
257 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300258 case EbtUSampler3D:
259 return 3;
260 case EbtUSamplerCube:
261 return 3;
262 case EbtUSampler2DArray:
263 return 3;
264 case EbtSampler2DShadow:
265 return 2;
266 case EbtSamplerCubeShadow:
267 return 3;
268 case EbtSampler2DArrayShadow:
269 return 3;
270 default:
271 UNREACHABLE();
272 }
273 }
274 return 0;
275}
276
277void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
278 const TextureFunctionHLSL::TextureFunction &textureFunction,
279 const ShShaderOutput outputType)
280{
281 if (outputType == SH_HLSL_3_0_OUTPUT)
282 {
283 switch (textureFunction.sampler)
284 {
285 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400286 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300287 out << "sampler2D s";
288 break;
289 case EbtSamplerCube:
290 out << "samplerCUBE s";
291 break;
292 default:
293 UNREACHABLE();
294 }
295 }
296 else
297 {
298 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
299 {
300 out << TextureString(textureFunction.sampler) << " x, "
301 << SamplerString(textureFunction.sampler) << " s";
302 }
303 else
304 {
305 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400306 // A bug in the D3D compiler causes some nested sampling operations to fail.
307 // See http://anglebug.com/1923
308 // TODO(jmadill): Reinstate the const keyword when possible.
309 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300310 }
311 }
312
313 if (textureFunction.method ==
314 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
315 {
316 switch (textureFunction.coords)
317 {
318 case 2:
319 out << ", int2 t";
320 break;
321 case 3:
322 out << ", int3 t";
323 break;
324 default:
325 UNREACHABLE();
326 }
327 }
328 else // Floating-point coordinates (except textureSize)
329 {
330 switch (textureFunction.coords)
331 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000332 case 0:
333 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300334 case 1:
335 out << ", int lod";
336 break; // textureSize()
337 case 2:
338 out << ", float2 t";
339 break;
340 case 3:
341 out << ", float3 t";
342 break;
343 case 4:
344 out << ", float4 t";
345 break;
346 default:
347 UNREACHABLE();
348 }
349 }
350
351 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
352 {
353 switch (textureFunction.sampler)
354 {
355 case EbtSampler2D:
356 case EbtISampler2D:
357 case EbtUSampler2D:
358 case EbtSampler2DArray:
359 case EbtISampler2DArray:
360 case EbtUSampler2DArray:
361 case EbtSampler2DShadow:
362 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400363 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300364 out << ", float2 ddx, float2 ddy";
365 break;
366 case EbtSampler3D:
367 case EbtISampler3D:
368 case EbtUSampler3D:
369 case EbtSamplerCube:
370 case EbtISamplerCube:
371 case EbtUSamplerCube:
372 case EbtSamplerCubeShadow:
373 out << ", float3 ddx, float3 ddy";
374 break;
375 default:
376 UNREACHABLE();
377 }
378 }
379
380 switch (textureFunction.method)
381 {
382 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
383 break;
384 case TextureFunctionHLSL::TextureFunction::BIAS:
385 break; // Comes after the offset parameter
386 case TextureFunctionHLSL::TextureFunction::LOD:
387 out << ", float lod";
388 break;
389 case TextureFunctionHLSL::TextureFunction::LOD0:
390 break;
391 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
392 break; // Comes after the offset parameter
393 case TextureFunctionHLSL::TextureFunction::SIZE:
394 break;
395 case TextureFunctionHLSL::TextureFunction::FETCH:
396 out << ", int mip";
397 break;
398 case TextureFunctionHLSL::TextureFunction::GRAD:
399 break;
400 default:
401 UNREACHABLE();
402 }
403
404 if (textureFunction.offset)
405 {
406 switch (textureFunction.sampler)
407 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300408 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300409 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300410 case EbtUSampler3D:
411 out << ", int3 offset";
412 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300413 case EbtSampler2D:
414 case EbtSampler2DArray:
415 case EbtISampler2D:
416 case EbtISampler2DArray:
417 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300418 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300419 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300420 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400421 case EbtSamplerExternalOES:
422 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300423 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300424 default:
425 UNREACHABLE();
426 }
427 }
428
429 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
430 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
431 {
432 out << ", float bias";
433 }
434}
435
436void GetTextureReference(TInfoSinkBase &out,
437 const TextureFunctionHLSL::TextureFunction &textureFunction,
438 const ShShaderOutput outputType,
439 TString *textureReference,
440 TString *samplerReference)
441{
442 if (outputType == SH_HLSL_4_1_OUTPUT)
443 {
444 TString suffix = TextureGroupSuffix(textureFunction.sampler);
445 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
446 {
447 *textureReference = TString("textures") + suffix + "[samplerIndex]";
448 *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
449 }
450 else
451 {
452 out << " const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
453 << ";\n";
454 *textureReference = TString("textures") + suffix + "[textureIndex]";
455 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
456 << ";\n";
457 *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
458 }
459 }
460 else
461 {
462 *textureReference = "x";
463 *samplerReference = "s";
464 }
465}
466
467void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
468 const TextureFunctionHLSL::TextureFunction &textureFunction,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400469 const TString &textureReference,
470 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300471{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000472 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400473 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000474 out << " uint width; uint height; uint samples;\n"
475 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400476 }
477 else
478 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000479 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400480 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000481 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400482 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000483 else
484 {
485 out << " int baseLevel = 0;\n";
486 }
487
488 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
489 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
490 {
491 // "depth" stores either the number of layers in an array texture or 3D depth
492 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
493 << " " << textureReference
494 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
495 << " width = max(width >> lod, 1);\n"
496 << " height = max(height >> lod, 1);\n";
497
498 if (!IsSamplerArray(textureFunction.sampler))
499 {
500 out << " depth = max(depth >> lod, 1);\n";
501 }
502 }
503 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
504 {
505 out << " uint width; uint height; uint numberOfLevels;\n"
506 << " " << textureReference
507 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
508 << " width = max(width >> lod, 1);\n"
509 << " height = max(height >> lod, 1);\n";
510 }
511 else
512 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300513 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300514
515 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
516 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000517 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300518 }
519 else
520 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000521 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300522 }
523}
524
525void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
526 TString *texCoordX,
527 TString *texCoordY,
528 TString *texCoordZ)
529{
530 if (textureFunction.proj)
531 {
532 TString proj("");
533 switch (textureFunction.coords)
534 {
535 case 3:
536 proj = " / t.z";
537 break;
538 case 4:
539 proj = " / t.w";
540 break;
541 default:
542 UNREACHABLE();
543 }
544 *texCoordX = "(" + *texCoordX + proj + ")";
545 *texCoordY = "(" + *texCoordY + proj + ")";
546 *texCoordZ = "(" + *texCoordZ + proj + ")";
547 }
548}
549
550void OutputIntegerTextureSampleFunctionComputations(
551 TInfoSinkBase &out,
552 const TextureFunctionHLSL::TextureFunction &textureFunction,
553 const ShShaderOutput outputType,
554 const TString &textureReference,
555 TString *texCoordX,
556 TString *texCoordY,
557 TString *texCoordZ)
558{
559 if (!IsIntegerSampler(textureFunction.sampler))
560 {
561 return;
562 }
563 if (IsSamplerCube(textureFunction.sampler))
564 {
565 out << " float width; float height; float layers; float levels;\n";
566
567 out << " uint mip = 0;\n";
568
569 out << " " << textureReference
570 << ".GetDimensions(mip, width, height, layers, levels);\n";
571
572 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
573 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
574 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
575 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
576 "(zMajor && t.z < 0.0f);\n";
577
578 // FACE_POSITIVE_X = 000b
579 // FACE_NEGATIVE_X = 001b
580 // FACE_POSITIVE_Y = 010b
581 // FACE_NEGATIVE_Y = 011b
582 // FACE_POSITIVE_Z = 100b
583 // FACE_NEGATIVE_Z = 101b
584 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
585
586 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
587 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
588 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
589
590 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
591 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
592
593 // Mip level computation.
594 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
595 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
596 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
597 {
598 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
599 {
600 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
601 " float2 dx = ddx(tSized);\n"
602 " float2 dy = ddy(tSized);\n"
603 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
604 }
605 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
606 {
607 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
608 // derivatives of P are assumed to be in the coordinate system used before
609 // texture coordinates are projected onto the appropriate cube face."
610 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
611 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
612 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
613 // Determine the derivatives of u, v and m
614 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
615 ": ddx[0]);\n"
616 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
617 ": ddy[0]);\n"
618 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
619 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
620 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
621 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
622 // Now determine the derivatives of the face coordinates, using the
623 // derivatives calculated above.
624 // d / dx (u(x) * 0.5 / m(x) + 0.5)
625 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
626 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
627 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
628 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
629 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
630 " float2 sizeVec = float2(width, height);\n"
631 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
632 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
633 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
634 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
635 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
636 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
637 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
638 }
639 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
640 << " " << textureReference
641 << ".GetDimensions(mip, width, height, layers, levels);\n";
642 }
643
644 // Convert from normalized floating-point to integer
645 *texCoordX = "int(floor(width * frac(" + *texCoordX + ")))";
646 *texCoordY = "int(floor(height * frac(" + *texCoordY + ")))";
647 *texCoordZ = "face";
648 }
649 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
650 {
651 if (IsSampler2D(textureFunction.sampler))
652 {
653 if (IsSamplerArray(textureFunction.sampler))
654 {
655 out << " float width; float height; float layers; float levels;\n";
656
657 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
658 {
659 out << " uint mip = 0;\n";
660 }
661 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
662 {
663 out << " uint mip = bias;\n";
664 }
665 else
666 {
667
668 out << " " << textureReference
669 << ".GetDimensions(0, width, height, layers, levels);\n";
670 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
671 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
672 {
673 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
674 " float dx = length(ddx(tSized));\n"
675 " float dy = length(ddy(tSized));\n"
676 " float lod = log2(max(dx, dy));\n";
677
678 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
679 {
680 out << " lod += bias;\n";
681 }
682 }
683 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
684 {
685 out << " float2 sizeVec = float2(width, height);\n"
686 " float2 sizeDdx = ddx * sizeVec;\n"
687 " float2 sizeDdy = ddy * sizeVec;\n"
688 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
689 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
690 }
691
692 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
693 }
694
695 out << " " << textureReference
696 << ".GetDimensions(mip, width, height, layers, levels);\n";
697 }
698 else
699 {
700 out << " float width; float height; float levels;\n";
701
702 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
703 {
704 out << " uint mip = 0;\n";
705 }
706 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
707 {
708 out << " uint mip = bias;\n";
709 }
710 else
711 {
712 out << " " << textureReference
713 << ".GetDimensions(0, width, height, levels);\n";
714
715 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
716 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
717 {
718 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
719 " float dx = length(ddx(tSized));\n"
720 " float dy = length(ddy(tSized));\n"
721 " float lod = log2(max(dx, dy));\n";
722
723 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
724 {
725 out << " lod += bias;\n";
726 }
727 }
728 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
729 {
730 out << " float2 sizeVec = float2(width, height);\n"
731 " float2 sizeDdx = ddx * sizeVec;\n"
732 " float2 sizeDdy = ddy * sizeVec;\n"
733 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
734 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
735 }
736
737 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
738 }
739
740 out << " " << textureReference
741 << ".GetDimensions(mip, width, height, levels);\n";
742 }
743 }
744 else if (IsSampler3D(textureFunction.sampler))
745 {
746 out << " float width; float height; float depth; float levels;\n";
747
748 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
749 {
750 out << " uint mip = 0;\n";
751 }
752 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
753 {
754 out << " uint mip = bias;\n";
755 }
756 else
757 {
758 out << " " << textureReference
759 << ".GetDimensions(0, width, height, depth, levels);\n";
760
761 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
762 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
763 {
764 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
765 " float dx = length(ddx(tSized));\n"
766 " float dy = length(ddy(tSized));\n"
767 " float lod = log2(max(dx, dy));\n";
768
769 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
770 {
771 out << " lod += bias;\n";
772 }
773 }
774 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
775 {
776 out << " float3 sizeVec = float3(width, height, depth);\n"
777 " float3 sizeDdx = ddx * sizeVec;\n"
778 " float3 sizeDdy = ddy * sizeVec;\n"
779 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
780 "sizeDdy))) * 0.5f;\n";
781 }
782
783 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
784 }
785
786 out << " " << textureReference
787 << ".GetDimensions(mip, width, height, depth, levels);\n";
788 }
789 else
790 UNREACHABLE();
791
792 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
793 }
794}
795
796void OutputTextureSampleFunctionReturnStatement(
797 TInfoSinkBase &out,
798 const TextureFunctionHLSL::TextureFunction &textureFunction,
799 const ShShaderOutput outputType,
800 const TString &textureReference,
801 const TString &samplerReference,
802 const TString &texCoordX,
803 const TString &texCoordY,
804 const TString &texCoordZ)
805{
806 out << " return ";
807
808 // HLSL intrinsic
809 if (outputType == SH_HLSL_3_0_OUTPUT)
810 {
811 switch (textureFunction.sampler)
812 {
813 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400814 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300815 out << "tex2D";
816 break;
817 case EbtSamplerCube:
818 out << "texCUBE";
819 break;
820 default:
821 UNREACHABLE();
822 }
823
824 switch (textureFunction.method)
825 {
826 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
827 out << "(" << samplerReference << ", ";
828 break;
829 case TextureFunctionHLSL::TextureFunction::BIAS:
830 out << "bias(" << samplerReference << ", ";
831 break;
832 case TextureFunctionHLSL::TextureFunction::LOD:
833 out << "lod(" << samplerReference << ", ";
834 break;
835 case TextureFunctionHLSL::TextureFunction::LOD0:
836 out << "lod(" << samplerReference << ", ";
837 break;
838 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
839 out << "lod(" << samplerReference << ", ";
840 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400841 case TextureFunctionHLSL::TextureFunction::GRAD:
842 out << "grad(" << samplerReference << ", ";
843 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300844 default:
845 UNREACHABLE();
846 }
847 }
848 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
849 {
850 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
851 }
852 else
853 UNREACHABLE();
854
855 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
856
857 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
858 << texCoordY;
859
860 if (outputType == SH_HLSL_3_0_OUTPUT)
861 {
862 if (hlslCoords >= 3)
863 {
864 if (textureFunction.coords < 3)
865 {
866 out << ", 0";
867 }
868 else
869 {
870 out << ", " << texCoordZ;
871 }
872 }
873
874 if (hlslCoords == 4)
875 {
876 switch (textureFunction.method)
877 {
878 case TextureFunctionHLSL::TextureFunction::BIAS:
879 out << ", bias";
880 break;
881 case TextureFunctionHLSL::TextureFunction::LOD:
882 out << ", lod";
883 break;
884 case TextureFunctionHLSL::TextureFunction::LOD0:
885 out << ", 0";
886 break;
887 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
888 out << ", bias";
889 break;
890 default:
891 UNREACHABLE();
892 }
893 }
894
895 out << ")";
896 }
897 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
898 {
899 if (hlslCoords >= 3)
900 {
901 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
902 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
903 out << ", " << texCoordZ;
904 }
905
906 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
907 {
908 if (IsIntegerSampler(textureFunction.sampler))
909 {
910 out << ", mip)";
911 }
912 else if (IsShadowSampler(textureFunction.sampler))
913 {
914 // Compare value
915 if (textureFunction.proj)
916 {
917 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
918 // The resulting third component of P' in the shadow forms is used as
919 // Dref
920 out << "), " << texCoordZ;
921 }
922 else
923 {
924 switch (textureFunction.coords)
925 {
926 case 3:
927 out << "), t.z";
928 break;
929 case 4:
930 out << "), t.w";
931 break;
932 default:
933 UNREACHABLE();
934 }
935 }
936 }
937 else
938 {
939 out << "), ddx, ddy";
940 }
941 }
942 else if (IsIntegerSampler(textureFunction.sampler) ||
943 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
944 {
945 out << ", mip)";
946 }
947 else if (IsShadowSampler(textureFunction.sampler))
948 {
949 // Compare value
950 if (textureFunction.proj)
951 {
952 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
953 // The resulting third component of P' in the shadow forms is used as Dref
954 out << "), " << texCoordZ;
955 }
956 else
957 {
958 switch (textureFunction.coords)
959 {
960 case 3:
961 out << "), t.z";
962 break;
963 case 4:
964 out << "), t.w";
965 break;
966 default:
967 UNREACHABLE();
968 }
969 }
970 }
971 else
972 {
973 switch (textureFunction.method)
974 {
975 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
976 out << ")";
977 break;
978 case TextureFunctionHLSL::TextureFunction::BIAS:
979 out << "), bias";
980 break;
981 case TextureFunctionHLSL::TextureFunction::LOD:
982 out << "), lod";
983 break;
984 case TextureFunctionHLSL::TextureFunction::LOD0:
985 out << "), 0";
986 break;
987 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
988 out << "), bias";
989 break;
990 default:
991 UNREACHABLE();
992 }
993 }
994
995 if (textureFunction.offset &&
996 (!IsIntegerSampler(textureFunction.sampler) ||
997 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
998 {
999 out << ", offset";
1000 }
1001 }
1002 else
1003 UNREACHABLE();
1004
1005 out << ");\n"; // Close the sample function call and return statement
1006}
1007
1008} // Anonymous namespace
1009
1010TString TextureFunctionHLSL::TextureFunction::name() const
1011{
1012 TString name = "gl_texture";
1013
1014 // We need to include full the sampler type in the function name to make the signature unique
1015 // on D3D11, where samplers are passed to texture functions as indices.
1016 name += TextureTypeSuffix(this->sampler);
1017
1018 if (proj)
1019 {
1020 name += "Proj";
1021 }
1022
1023 if (offset)
1024 {
1025 name += "Offset";
1026 }
1027
1028 switch (method)
1029 {
1030 case IMPLICIT:
1031 break;
1032 case BIAS:
1033 break; // Extra parameter makes the signature unique
1034 case LOD:
1035 name += "Lod";
1036 break;
1037 case LOD0:
1038 name += "Lod0";
1039 break;
1040 case LOD0BIAS:
1041 name += "Lod0";
1042 break; // Extra parameter makes the signature unique
1043 case SIZE:
1044 name += "Size";
1045 break;
1046 case FETCH:
1047 name += "Fetch";
1048 break;
1049 case GRAD:
1050 name += "Grad";
1051 break;
1052 default:
1053 UNREACHABLE();
1054 }
1055
1056 return name;
1057}
1058
1059const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1060{
1061 if (method == TextureFunction::SIZE)
1062 {
1063 switch (sampler)
1064 {
1065 case EbtSampler2D:
1066 case EbtISampler2D:
1067 case EbtUSampler2D:
1068 case EbtSampler2DShadow:
1069 case EbtSamplerCube:
1070 case EbtISamplerCube:
1071 case EbtUSamplerCube:
1072 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001073 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001074 case EbtSampler2DMS:
1075 case EbtISampler2DMS:
1076 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001077 return "int2";
1078 case EbtSampler3D:
1079 case EbtISampler3D:
1080 case EbtUSampler3D:
1081 case EbtSampler2DArray:
1082 case EbtISampler2DArray:
1083 case EbtUSampler2DArray:
1084 case EbtSampler2DArrayShadow:
1085 return "int3";
1086 default:
1087 UNREACHABLE();
1088 }
1089 }
1090 else // Sampling function
1091 {
1092 switch (sampler)
1093 {
1094 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001095 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001096 case EbtSampler3D:
1097 case EbtSamplerCube:
1098 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001099 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001100 return "float4";
1101 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001102 case EbtISampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001103 case EbtISampler3D:
1104 case EbtISamplerCube:
1105 case EbtISampler2DArray:
1106 return "int4";
1107 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001108 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001109 case EbtUSampler3D:
1110 case EbtUSamplerCube:
1111 case EbtUSampler2DArray:
1112 return "uint4";
1113 case EbtSampler2DShadow:
1114 case EbtSamplerCubeShadow:
1115 case EbtSampler2DArrayShadow:
1116 return "float";
1117 default:
1118 UNREACHABLE();
1119 }
1120 }
1121 return "";
1122}
1123
1124bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1125{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001126 return std::tie(sampler, coords, proj, offset, method) <
1127 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001128}
1129
1130TString TextureFunctionHLSL::useTextureFunction(const TString &name,
1131 TBasicType samplerType,
1132 int coords,
1133 size_t argumentCount,
1134 bool lod0,
1135 sh::GLenum shaderType)
1136{
1137 TextureFunction textureFunction;
1138 textureFunction.sampler = samplerType;
1139 textureFunction.coords = coords;
1140 textureFunction.method = TextureFunction::IMPLICIT;
1141 textureFunction.proj = false;
1142 textureFunction.offset = false;
1143
1144 if (name == "texture2D" || name == "textureCube" || name == "texture")
1145 {
1146 textureFunction.method = TextureFunction::IMPLICIT;
1147 }
1148 else if (name == "texture2DProj" || name == "textureProj")
1149 {
1150 textureFunction.method = TextureFunction::IMPLICIT;
1151 textureFunction.proj = true;
1152 }
1153 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1154 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1155 {
1156 textureFunction.method = TextureFunction::LOD;
1157 }
1158 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1159 name == "texture2DProjLodEXT")
1160 {
1161 textureFunction.method = TextureFunction::LOD;
1162 textureFunction.proj = true;
1163 }
1164 else if (name == "textureSize")
1165 {
1166 textureFunction.method = TextureFunction::SIZE;
1167 }
1168 else if (name == "textureOffset")
1169 {
1170 textureFunction.method = TextureFunction::IMPLICIT;
1171 textureFunction.offset = true;
1172 }
1173 else if (name == "textureProjOffset")
1174 {
1175 textureFunction.method = TextureFunction::IMPLICIT;
1176 textureFunction.offset = true;
1177 textureFunction.proj = true;
1178 }
1179 else if (name == "textureLodOffset")
1180 {
1181 textureFunction.method = TextureFunction::LOD;
1182 textureFunction.offset = true;
1183 }
1184 else if (name == "textureProjLodOffset")
1185 {
1186 textureFunction.method = TextureFunction::LOD;
1187 textureFunction.proj = true;
1188 textureFunction.offset = true;
1189 }
1190 else if (name == "texelFetch")
1191 {
1192 textureFunction.method = TextureFunction::FETCH;
1193 }
1194 else if (name == "texelFetchOffset")
1195 {
1196 textureFunction.method = TextureFunction::FETCH;
1197 textureFunction.offset = true;
1198 }
1199 else if (name == "textureGrad" || name == "texture2DGradEXT")
1200 {
1201 textureFunction.method = TextureFunction::GRAD;
1202 }
1203 else if (name == "textureGradOffset")
1204 {
1205 textureFunction.method = TextureFunction::GRAD;
1206 textureFunction.offset = true;
1207 }
1208 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1209 name == "textureCubeGradEXT")
1210 {
1211 textureFunction.method = TextureFunction::GRAD;
1212 textureFunction.proj = true;
1213 }
1214 else if (name == "textureProjGradOffset")
1215 {
1216 textureFunction.method = TextureFunction::GRAD;
1217 textureFunction.proj = true;
1218 textureFunction.offset = true;
1219 }
1220 else
1221 UNREACHABLE();
1222
1223 if (textureFunction.method ==
1224 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1225 {
1226 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1227
1228 if (textureFunction.offset)
1229 {
1230 mandatoryArgumentCount++;
1231 }
1232
1233 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1234
1235 if (lod0 || shaderType == GL_VERTEX_SHADER)
1236 {
1237 if (bias)
1238 {
1239 textureFunction.method = TextureFunction::LOD0BIAS;
1240 }
1241 else
1242 {
1243 textureFunction.method = TextureFunction::LOD0;
1244 }
1245 }
1246 else if (bias)
1247 {
1248 textureFunction.method = TextureFunction::BIAS;
1249 }
1250 }
1251
1252 mUsesTexture.insert(textureFunction);
1253 return textureFunction.name();
1254}
1255
Geoff Lang1fe74c72016-08-25 13:23:01 -04001256void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1257 const ShShaderOutput outputType,
1258 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001259{
1260 for (const TextureFunction &textureFunction : mUsesTexture)
1261 {
1262 // Function header
1263 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1264
1265 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1266
1267 out << ")\n"
1268 "{\n";
1269
1270 // In some cases we use a variable to store the texture/sampler objects, but to work around
1271 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1272 // sampling we need to call the function directly on references to the texture and sampler
1273 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1274 // tests.
1275 TString textureReference;
1276 TString samplerReference;
1277 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1278
1279 if (textureFunction.method == TextureFunction::SIZE)
1280 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001281 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1282 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001283 }
1284 else
1285 {
1286 TString texCoordX("t.x");
1287 TString texCoordY("t.y");
1288 TString texCoordZ("t.z");
1289 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1290 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1291 textureReference, &texCoordX, &texCoordY,
1292 &texCoordZ);
1293 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1294 textureReference, samplerReference,
1295 texCoordX, texCoordY, texCoordZ);
1296 }
1297
1298 out << "}\n"
1299 "\n";
1300 }
1301}
1302
1303} // namespace sh