1 //
2 // Copyright 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/ImmutableStringBuilder.h"
15 #include "compiler/translator/UtilsHLSL.h"
16
17 namespace sh
18 {
19
20 namespace
21 {
22
OutputIntTexCoordWrap(TInfoSinkBase & out,const char * wrapMode,const char * size,const ImmutableString & texCoord,const char * texCoordOffset,const char * texCoordOutName)23 void OutputIntTexCoordWrap(TInfoSinkBase &out,
24 const char *wrapMode,
25 const char *size,
26 const ImmutableString &texCoord,
27 const char *texCoordOffset,
28 const char *texCoordOutName)
29 {
30 // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
31 // but rather use equivalent formulas that map better to HLSL.
32 out << "int " << texCoordOutName << ";\n";
33 out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
34 << ") / " << size << ";\n";
35 out << "bool " << texCoordOutName << "UseBorderColor = false;\n";
36
37 // CLAMP_TO_EDGE
38 out << "if (" << wrapMode << " == 0)\n";
39 out << "{\n";
40 out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
41 << "Offset)), 0, int(" << size << ") - 1);\n";
42 out << "}\n";
43
44 // CLAMP_TO_BORDER
45 out << "else if (" << wrapMode << " == 3)\n";
46 out << "{\n";
47 out << " int texCoordInt = int(floor(" << size << " * " << texCoordOutName << "Offset));\n";
48 out << " " << texCoordOutName << " = clamp(texCoordInt, 0, int(" << size << ") - 1);\n";
49 out << " " << texCoordOutName << "UseBorderColor = (texCoordInt != " << texCoordOutName
50 << ");\n";
51 out << "}\n";
52
53 // MIRRORED_REPEAT
54 out << "else if (" << wrapMode << " == 2)\n";
55 out << "{\n";
56 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
57 << "Offset) * 0.5) * 2.0 - 1.0);\n";
58 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
59 out << "}\n";
60
61 // REPEAT
62 out << "else\n";
63 out << "{\n";
64 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
65 << "Offset)));\n";
66 out << "}\n";
67 }
68
OutputIntTexCoordWraps(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,ImmutableString * texCoordX,ImmutableString * texCoordY,ImmutableString * texCoordZ)69 void OutputIntTexCoordWraps(TInfoSinkBase &out,
70 const TextureFunctionHLSL::TextureFunction &textureFunction,
71 ImmutableString *texCoordX,
72 ImmutableString *texCoordY,
73 ImmutableString *texCoordZ)
74 {
75 // Convert from normalized floating-point to integer
76 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
77 if (textureFunction.offset)
78 {
79 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
80 }
81 else
82 {
83 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
84 }
85 *texCoordX = ImmutableString("tix");
86 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
87 if (textureFunction.offset)
88 {
89 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
90 }
91 else
92 {
93 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
94 }
95 *texCoordY = ImmutableString("tiy");
96
97 bool tizAvailable = false;
98
99 if (IsSamplerArray(textureFunction.sampler))
100 {
101 *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))");
102 }
103 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
104 {
105 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
106 if (textureFunction.offset)
107 {
108 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
109 }
110 else
111 {
112 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
113 }
114 *texCoordZ = ImmutableString("tiz");
115 tizAvailable = true;
116 }
117
118 out << "bool useBorderColor = tixUseBorderColor || tiyUseBorderColor"
119 << (tizAvailable ? " || tizUseBorderColor" : "") << ";\n";
120 }
121
OutputHLSL4SampleFunctionPrefix(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ImmutableString & textureReference,const ImmutableString & samplerReference)122 void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
123 const TextureFunctionHLSL::TextureFunction &textureFunction,
124 const ImmutableString &textureReference,
125 const ImmutableString &samplerReference)
126 {
127 out << textureReference;
128 if (IsIntegerSampler(textureFunction.sampler) ||
129 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
130 {
131 out << ".Load(";
132 return;
133 }
134
135 if (IsShadowSampler(textureFunction.sampler))
136 {
137 switch (textureFunction.method)
138 {
139 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
140 case TextureFunctionHLSL::TextureFunction::BIAS:
141 case TextureFunctionHLSL::TextureFunction::LOD:
142 out << ".SampleCmp(";
143 break;
144 case TextureFunctionHLSL::TextureFunction::LOD0:
145 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
146 case TextureFunctionHLSL::TextureFunction::GRAD:
147 out << ".SampleCmpLevelZero(";
148 break;
149 default:
150 UNREACHABLE();
151 }
152 }
153 else
154 {
155 switch (textureFunction.method)
156 {
157 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
158 out << ".Sample(";
159 break;
160 case TextureFunctionHLSL::TextureFunction::BIAS:
161 out << ".SampleBias(";
162 break;
163 case TextureFunctionHLSL::TextureFunction::LOD:
164 case TextureFunctionHLSL::TextureFunction::LOD0:
165 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
166 out << ".SampleLevel(";
167 break;
168 case TextureFunctionHLSL::TextureFunction::GRAD:
169 out << ".SampleGrad(";
170 break;
171 default:
172 UNREACHABLE();
173 }
174 }
175 out << samplerReference << ", ";
176 }
177
GetSamplerCoordinateTypeString(const TextureFunctionHLSL::TextureFunction & textureFunction,int hlslCoords)178 const char *GetSamplerCoordinateTypeString(
179 const TextureFunctionHLSL::TextureFunction &textureFunction,
180 int hlslCoords)
181 {
182 // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or
183 // unsigned integer formats.
184 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather
185 if ((IsIntegerSampler(textureFunction.sampler) &&
186 textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) ||
187 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
188 {
189 switch (hlslCoords)
190 {
191 case 2:
192 if (IsSampler2DMS(textureFunction.sampler))
193 {
194 return "int2";
195 }
196 else
197 {
198 return "int3";
199 }
200 case 3:
201 if (IsSampler2DMSArray(textureFunction.sampler))
202 {
203 return "int3";
204 }
205 else
206 {
207 return "int4";
208 }
209 default:
210 UNREACHABLE();
211 }
212 }
213 else
214 {
215 switch (hlslCoords)
216 {
217 case 2:
218 return "float2";
219 case 3:
220 return "float3";
221 case 4:
222 return "float4";
223 default:
224 UNREACHABLE();
225 }
226 }
227 return "";
228 }
229
GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction & textureFunction,ShShaderOutput outputType)230 int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
231 ShShaderOutput outputType)
232 {
233 if (outputType == SH_HLSL_3_0_OUTPUT)
234 {
235 int hlslCoords = 2;
236 switch (textureFunction.sampler)
237 {
238 case EbtSampler2D:
239 case EbtSamplerExternalOES:
240 case EbtSampler2DMS:
241 case EbtSamplerVideoWEBGL:
242 hlslCoords = 2;
243 break;
244 case EbtSamplerCube:
245 hlslCoords = 3;
246 break;
247 default:
248 UNREACHABLE();
249 }
250
251 switch (textureFunction.method)
252 {
253 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
254 case TextureFunctionHLSL::TextureFunction::GRAD:
255 return hlslCoords;
256 case TextureFunctionHLSL::TextureFunction::BIAS:
257 case TextureFunctionHLSL::TextureFunction::LOD:
258 case TextureFunctionHLSL::TextureFunction::LOD0:
259 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
260 return 4;
261 default:
262 UNREACHABLE();
263 }
264 }
265 else
266 {
267 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
268 IsSamplerCube(textureFunction.sampler))
269 {
270 return 3;
271 }
272 ASSERT(IsSampler2D(textureFunction.sampler));
273 return 2;
274 }
275 return 0;
276 }
277
OutputTextureFunctionArgumentList(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ShShaderOutput outputType)278 void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
279 const TextureFunctionHLSL::TextureFunction &textureFunction,
280 const ShShaderOutput outputType)
281 {
282 if (outputType == SH_HLSL_3_0_OUTPUT)
283 {
284 switch (textureFunction.sampler)
285 {
286 case EbtSampler2D:
287 case EbtSamplerVideoWEBGL:
288 case EbtSamplerExternalOES:
289 out << "sampler2D s";
290 break;
291 case EbtSamplerCube:
292 out << "samplerCUBE s";
293 break;
294 default:
295 UNREACHABLE();
296 }
297 }
298 else
299 {
300 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
301 {
302 out << TextureString(textureFunction.sampler) << " x, "
303 << SamplerString(textureFunction.sampler) << " s";
304 }
305 else
306 {
307 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
308 // A bug in the D3D compiler causes some nested sampling operations to fail.
309 // See http://anglebug.com/1923
310 // TODO(jmadill): Reinstate the const keyword when possible.
311 out << /*"const"*/ "uint samplerIndex";
312 }
313 }
314
315 if (textureFunction.method ==
316 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
317 {
318 switch (textureFunction.coords)
319 {
320 case 2:
321 out << ", int2 t";
322 break;
323 case 3:
324 out << ", int3 t";
325 break;
326 default:
327 UNREACHABLE();
328 }
329 }
330 else // Floating-point coordinates (except textureSize)
331 {
332 switch (textureFunction.coords)
333 {
334 case 0:
335 break; // textureSize(gSampler2DMS sampler)
336 case 1:
337 out << ", int lod";
338 break; // textureSize()
339 case 2:
340 out << ", float2 t";
341 break;
342 case 3:
343 out << ", float3 t";
344 break;
345 case 4:
346 out << ", float4 t";
347 break;
348 default:
349 UNREACHABLE();
350 }
351 }
352
353 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
354 {
355 switch (textureFunction.sampler)
356 {
357 case EbtSampler2D:
358 case EbtISampler2D:
359 case EbtUSampler2D:
360 case EbtSampler2DArray:
361 case EbtISampler2DArray:
362 case EbtUSampler2DArray:
363 case EbtSampler2DShadow:
364 case EbtSampler2DArrayShadow:
365 case EbtSamplerExternalOES:
366 case EbtSamplerVideoWEBGL:
367 out << ", float2 ddx, float2 ddy";
368 break;
369 case EbtSampler3D:
370 case EbtISampler3D:
371 case EbtUSampler3D:
372 case EbtSamplerCube:
373 case EbtISamplerCube:
374 case EbtUSamplerCube:
375 case EbtSamplerCubeShadow:
376 out << ", float3 ddx, float3 ddy";
377 break;
378 default:
379 UNREACHABLE();
380 }
381 }
382
383 switch (textureFunction.method)
384 {
385 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
386 break;
387 case TextureFunctionHLSL::TextureFunction::BIAS:
388 break; // Comes after the offset parameter
389 case TextureFunctionHLSL::TextureFunction::LOD:
390 out << ", float lod";
391 break;
392 case TextureFunctionHLSL::TextureFunction::LOD0:
393 break;
394 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
395 break; // Comes after the offset parameter
396 case TextureFunctionHLSL::TextureFunction::SIZE:
397 break;
398 case TextureFunctionHLSL::TextureFunction::FETCH:
399 if (IsSampler2DMS(textureFunction.sampler) ||
400 IsSampler2DMSArray(textureFunction.sampler))
401 out << ", int index";
402 else
403 out << ", int mip";
404 break;
405 case TextureFunctionHLSL::TextureFunction::GRAD:
406 break;
407 case TextureFunctionHLSL::TextureFunction::GATHER:
408 break;
409 default:
410 UNREACHABLE();
411 }
412
413 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
414 IsShadowSampler(textureFunction.sampler))
415 {
416 out << ", float refZ";
417 }
418
419 if (textureFunction.offset)
420 {
421 switch (textureFunction.sampler)
422 {
423 case EbtSampler3D:
424 case EbtISampler3D:
425 case EbtUSampler3D:
426 out << ", int3 offset";
427 break;
428 case EbtSampler2D:
429 case EbtSampler2DArray:
430 case EbtISampler2D:
431 case EbtISampler2DArray:
432 case EbtUSampler2D:
433 case EbtUSampler2DArray:
434 case EbtSampler2DShadow:
435 case EbtSampler2DArrayShadow:
436 case EbtSamplerExternalOES:
437 case EbtSamplerVideoWEBGL:
438 out << ", int2 offset";
439 break;
440 default:
441 // Offset is not supported for multisampled textures.
442 UNREACHABLE();
443 }
444 }
445
446 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
447 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
448 {
449 out << ", float bias";
450 }
451 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
452 !IsShadowSampler(textureFunction.sampler))
453 {
454 out << ", int comp = 0";
455 }
456 }
457
GetTextureReference(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ShShaderOutput outputType,ImmutableString * textureReference,ImmutableString * samplerReference)458 void GetTextureReference(TInfoSinkBase &out,
459 const TextureFunctionHLSL::TextureFunction &textureFunction,
460 const ShShaderOutput outputType,
461 ImmutableString *textureReference,
462 ImmutableString *samplerReference)
463 {
464 if (outputType == SH_HLSL_4_1_OUTPUT)
465 {
466 static const ImmutableString kTexturesStr("textures");
467 static const ImmutableString kSamplersStr("samplers");
468 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
469 static const ImmutableString kTextureIndexStr("[textureIndex]");
470 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
471 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
472
473 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
474 {
475 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
476 kSamplerIndexStr.length());
477 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
478 *textureReference = textureRefBuilder;
479 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
480 kSamplerIndexStr.length());
481 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
482 *samplerReference = samplerRefBuilder;
483 }
484 else
485 {
486 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
487 << suffix.data() << ";\n";
488 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
489 kTextureIndexStr.length());
490 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
491 *textureReference = textureRefBuilder;
492
493 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
494 << suffix.data() << ";\n";
495 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
496 kSamplerArrayIndexStr.length());
497 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
498 *samplerReference = samplerRefBuilder;
499 }
500 }
501 else
502 {
503 *textureReference = ImmutableString("x");
504 *samplerReference = ImmutableString("s");
505 }
506 }
507
OutputTextureSizeFunctionBody(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ImmutableString & textureReference,bool getDimensionsIgnoresBaseLevel)508 void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
509 const TextureFunctionHLSL::TextureFunction &textureFunction,
510 const ImmutableString &textureReference,
511 bool getDimensionsIgnoresBaseLevel)
512 {
513 if (IsSampler2DMS(textureFunction.sampler))
514 {
515 out << " uint width; uint height; uint samples;\n"
516 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
517 }
518 else if (IsSampler2DMSArray(textureFunction.sampler))
519 {
520 out << " uint width; uint height; uint depth; uint samples;\n"
521 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
522 }
523 else
524 {
525 if (getDimensionsIgnoresBaseLevel)
526 {
527 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
528 }
529 else
530 {
531 out << " int baseLevel = 0;\n";
532 }
533
534 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
535 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
536 {
537 // "depth" stores either the number of layers in an array texture or 3D depth
538 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
539 << " " << textureReference
540 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
541 << " width = max(width >> lod, 1);\n"
542 << " height = max(height >> lod, 1);\n";
543
544 if (!IsSamplerArray(textureFunction.sampler))
545 {
546 out << " depth = max(depth >> lod, 1);\n";
547 }
548 }
549 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
550 {
551 out << " uint width; uint height; uint numberOfLevels;\n"
552 << " " << textureReference
553 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
554 << " width = max(width >> lod, 1);\n"
555 << " height = max(height >> lod, 1);\n";
556 }
557 else
558 UNREACHABLE();
559 }
560
561 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
562 {
563 out << " return int3(width, height, depth);\n";
564 }
565 else
566 {
567 out << " return int2(width, height);\n";
568 }
569 }
570
ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction & textureFunction,ImmutableString * texCoordX,ImmutableString * texCoordY,ImmutableString * texCoordZ)571 void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
572 ImmutableString *texCoordX,
573 ImmutableString *texCoordY,
574 ImmutableString *texCoordZ)
575 {
576 if (textureFunction.proj)
577 {
578 ImmutableString proj("");
579 switch (textureFunction.coords)
580 {
581 case 3:
582 proj = ImmutableString(" / t.z");
583 break;
584 case 4:
585 proj = ImmutableString(" / t.w");
586 break;
587 default:
588 UNREACHABLE();
589 }
590 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
591 texCoordXBuilder << '(' << *texCoordX << proj << ')';
592 *texCoordX = texCoordXBuilder;
593 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
594 texCoordYBuilder << '(' << *texCoordY << proj << ')';
595 *texCoordY = texCoordYBuilder;
596 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
597 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
598 *texCoordZ = texCoordZBuilder;
599 }
600 }
601
OutputIntegerTextureSampleFunctionComputations(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ShShaderOutput outputType,const ImmutableString & textureReference,ImmutableString * texCoordX,ImmutableString * texCoordY,ImmutableString * texCoordZ,bool getDimensionsIgnoresBaseLevel)602 void OutputIntegerTextureSampleFunctionComputations(
603 TInfoSinkBase &out,
604 const TextureFunctionHLSL::TextureFunction &textureFunction,
605 const ShShaderOutput outputType,
606 const ImmutableString &textureReference,
607 ImmutableString *texCoordX,
608 ImmutableString *texCoordY,
609 ImmutableString *texCoordZ,
610 bool getDimensionsIgnoresBaseLevel)
611 {
612 if (!IsIntegerSampler(textureFunction.sampler))
613 {
614 return;
615 }
616
617 if (getDimensionsIgnoresBaseLevel)
618 {
619 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
620 }
621 else
622 {
623 out << " int baseLevel = 0;\n";
624 }
625
626 if (IsSamplerCube(textureFunction.sampler))
627 {
628 out << " float width; float height; float layers; float levels;\n";
629
630 out << " uint mip = 0;\n";
631
632 out << " " << textureReference
633 << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
634
635 out << " bool xMajor = abs(t.x) >= abs(t.y) && abs(t.x) >= abs(t.z);\n";
636 out << " bool yMajor = abs(t.y) >= abs(t.z) && abs(t.y) > abs(t.x);\n";
637 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
638 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
639 "(zMajor && t.z < 0.0f);\n";
640
641 // FACE_POSITIVE_X = 000b
642 // FACE_NEGATIVE_X = 001b
643 // FACE_POSITIVE_Y = 010b
644 // FACE_NEGATIVE_Y = 011b
645 // FACE_POSITIVE_Z = 100b
646 // FACE_NEGATIVE_Z = 101b
647 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
648
649 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
650 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
651 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
652
653 out << " float3 r = any(t) ? t : float3(1, 0, 0);\n";
654 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
655 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
656
657 // Mip level computation.
658 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
659 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
660 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
661 {
662 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
663 {
664 // We would like to calculate tha maximum of how many texels we move in the major
665 // face's texture as we move across the screen in any direction. Namely, we want the
666 // length of the directional derivative of the function p (defined below), maximized
667 // over screen space directions. (For short: we want the norm of Dp.) For
668 // simplicity, assume that z-axis is the major axis. By symmetry, we can assume that
669 // the positive z direction is major. (The calculated value will be the same even if
670 // this is false.) Let r denote the function from screen position to cube texture
671 // coordinates. Then p can be written as p = s . P . r, where P(r) = (r.x, r.y)/r.z
672 // is the projection onto the major cube face, and s = diag(width, height)/2. (s
673 // linearly maps from the cube face into texture space, so that p(r) is in units of
674 // texels.) The derivative is
675 // Dp(r) = s |1 0 -r.x/r.z|
676 // |0 1 -r.y/r.z| |ddx(r) ddy(r)| / r.z
677 // = |dot(a, ddx(r)) dot(a, ddy(r))|
678 // |dot(b, ddx(r)) dot(b, ddy(r))| / (2 r.z)
679 // where a = w * vec3(1, 0, -r.x/r.z)
680 // b = h * vec3(0, 1, -r.y/r.z)
681 // We would like to know max(L(x)) over unit vectors x, where L(x) = |Dp(r) x|^2.
682 // Since ddx(r) and ddy(r) are unknown, the best we can do is to sample L in some
683 // directions and take the maximum across the samples.
684 //
685 // Some implementations use max(L(n1), L(n2)) where n1 = vec2(1,0) and n2 =
686 // vec2(0,1).
687 //
688 // Some implementations use max(L(n1), L(n2), L(n3), L(n4)),
689 // where n3 = (n1 + n2) / |n1 + n2| = (n1 + n2)/sqrt(2)
690 // n4 = (n1 - n2) / |n1 - n2| = (n1 - n2)/sqrt(2).
691 // In other words, two samples along the diagonal screen space directions have been
692 // added, giving a strictly better estimate of the true maximum.
693 //
694 // It turns out we can get twice the sample count very cheaply.
695 // We can use the linearity of Dp(r) to get these extra samples of L cheaply in
696 // terms of the already taken samples, L(n1) and L(n2):
697 // Denoting
698 // dpx = Dp(r)n1
699 // dpy = Dp(r)n2
700 // dpxx = dot(dpx, dpx)
701 // dpyy = dot(dpy, dpy)
702 // dpxy = dot(dpx, dpy)
703 // we obtain
704 // L(n3) = |Dp(r)n1 + Dp(r)n2|^2/2 = (dpxx + dpyy)/2 + dpxy
705 // L(n4) = |Dp(r)n1 - Dp(r)n2|^2/2 = (dpxx + dpyy)/2 - dpxy
706 // max(L(n1), L(n2), L(n3), L(n4))
707 // = max(max(L(n1), L(n2)), max(L(n3), L(n4)))
708 // = max(max(dpxx, dpyy), (dpxx + dpyy)/2 + abs(dpxy))
709 // So the extra cost is: one dot, one abs, one add, one multiply-add and one max.
710 // (All scalar.)
711 //
712 // In section 3.8.10.1, the OpenGL ES 3 specification defines the "scale factor",
713 // rho. In our terminology, this definition works out to taking sqrt(max(L(n1),
714 // L(n2))). Some implementations will use this estimate, here we use the strictly
715 // better sqrt(max(L(n1), L(n2), L(n3), L(n4))), since it's not much more expensive
716 // to calculate.
717
718 // Swap coordinates such that we can assume that the positive z-axis is major, in
719 // what follows.
720 out << " float3 ddxr = xMajor ? ddx(r).yzx : yMajor ? ddx(r).zxy : ddx(r).xyz;\n"
721 " float3 ddyr = xMajor ? ddy(r).yzx : yMajor ? ddy(r).zxy : ddy(r).xyz;\n"
722 " r = xMajor ? r.yzx : yMajor ? r.zxy : r.xyz;\n";
723
724 out << " float2 s = 0.5*float2(width, height);\n"
725 " float2 dpx = s * (ddxr.xy - ddxr.z*r.xy/r.z)/r.z;\n"
726 " float2 dpy = s * (ddyr.xy - ddyr.z*r.xy/r.z)/r.z;\n"
727 " float dpxx = dot(dpx, dpx);\n;"
728 " float dpyy = dot(dpy, dpy);\n;"
729 " float dpxy = dot(dpx, dpy);\n"
730 " float ma = max(dpxx, dpyy);\n"
731 " float mb = 0.5 * (dpxx + dpyy) + abs(dpxy);\n"
732 " float mab = max(ma, mb);\n"
733 " float lod = 0.5f * log2(mab);\n";
734 }
735 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
736 {
737 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
738 // derivatives of P are assumed to be in the coordinate system used before
739 // texture coordinates are projected onto the appropriate cube face."
740 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
741 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
742 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
743 // Determine the derivatives of u, v and m
744 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
745 ": ddx[0]);\n"
746 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
747 ": ddy[0]);\n"
748 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
749 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
750 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
751 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
752 // Now determine the derivatives of the face coordinates, using the
753 // derivatives calculated above.
754 // d / dx (u(x) * 0.5 / m(x) + 0.5)
755 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
756 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
757 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
758 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
759 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
760 " float2 sizeVec = float2(width, height);\n"
761 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
762 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
763 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
764 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
765 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
766 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
767 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
768 }
769 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
770 << " " << textureReference
771 << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
772 }
773
774 // Convert from normalized floating-point to integer
775 static const ImmutableString kXPrefix("int(floor(width * frac(");
776 static const ImmutableString kYPrefix("int(floor(height * frac(");
777 static const ImmutableString kSuffix(")))");
778 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
779 kSuffix.length());
780 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
781 *texCoordX = texCoordXBuilder;
782 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
783 kSuffix.length());
784 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
785 *texCoordY = texCoordYBuilder;
786 *texCoordZ = ImmutableString("face");
787 }
788 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
789 {
790 if (IsSamplerArray(textureFunction.sampler))
791 {
792 out << " float width; float height; float layers; float levels;\n";
793 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
794 {
795 out << " uint mip = 0;\n";
796 }
797 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
798 {
799 out << " uint mip = bias;\n";
800 }
801 else
802 {
803
804 out << " " << textureReference
805 << ".GetDimensions(baseLevel, width, height, layers, levels);\n";
806 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
807 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
808 {
809 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
810 " float dx = length(ddx(tSized));\n"
811 " float dy = length(ddy(tSized));\n"
812 " float lod = log2(max(dx, dy));\n";
813
814 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
815 {
816 out << " lod += bias;\n";
817 }
818 }
819 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
820 {
821 out << " float2 sizeVec = float2(width, height);\n"
822 " float2 sizeDdx = ddx * sizeVec;\n"
823 " float2 sizeDdy = ddy * sizeVec;\n"
824 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
825 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
826 }
827
828 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
829 }
830
831 out << " " << textureReference
832 << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
833 }
834 else if (IsSampler2D(textureFunction.sampler))
835 {
836 out << " float width; float height; float levels;\n";
837
838 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
839 {
840 out << " uint mip = 0;\n";
841 }
842 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
843 {
844 out << " uint mip = bias;\n";
845 }
846 else
847 {
848 out << " " << textureReference
849 << ".GetDimensions(baseLevel, width, height, levels);\n";
850
851 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
852 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
853 {
854 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
855 " float dx = length(ddx(tSized));\n"
856 " float dy = length(ddy(tSized));\n"
857 " float lod = log2(max(dx, dy));\n";
858
859 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
860 {
861 out << " lod += bias;\n";
862 }
863 }
864 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
865 {
866 out << " float2 sizeVec = float2(width, height);\n"
867 " float2 sizeDdx = ddx * sizeVec;\n"
868 " float2 sizeDdy = ddy * sizeVec;\n"
869 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
870 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
871 }
872
873 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
874 }
875
876 out << " " << textureReference
877 << ".GetDimensions(baseLevel + mip, width, height, levels);\n";
878 }
879 else if (IsSampler3D(textureFunction.sampler))
880 {
881 out << " float width; float height; float depth; float levels;\n";
882
883 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
884 {
885 out << " uint mip = 0;\n";
886 }
887 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
888 {
889 out << " uint mip = bias;\n";
890 }
891 else
892 {
893 out << " " << textureReference
894 << ".GetDimensions(baseLevel, width, height, depth, levels);\n";
895
896 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
897 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
898 {
899 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
900 " float dx = length(ddx(tSized));\n"
901 " float dy = length(ddy(tSized));\n"
902 " float lod = log2(max(dx, dy));\n";
903
904 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
905 {
906 out << " lod += bias;\n";
907 }
908 }
909 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
910 {
911 out << " float3 sizeVec = float3(width, height, depth);\n"
912 " float3 sizeDdx = ddx * sizeVec;\n"
913 " float3 sizeDdy = ddy * sizeVec;\n"
914 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
915 "sizeDdy))) * 0.5f;\n";
916 }
917
918 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
919 }
920
921 out << " " << textureReference
922 << ".GetDimensions(baseLevel + mip, width, height, depth, levels);\n";
923 }
924 else
925 UNREACHABLE();
926
927 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
928 }
929 }
930
OutputTextureGatherFunctionBody(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,ShShaderOutput outputType,const ImmutableString & textureReference,const ImmutableString & samplerReference,const ImmutableString & texCoordX,const ImmutableString & texCoordY,const ImmutableString & texCoordZ)931 void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
932 const TextureFunctionHLSL::TextureFunction &textureFunction,
933 ShShaderOutput outputType,
934 const ImmutableString &textureReference,
935 const ImmutableString &samplerReference,
936 const ImmutableString &texCoordX,
937 const ImmutableString &texCoordY,
938 const ImmutableString &texCoordZ)
939 {
940 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
941 ImmutableString samplerCoordTypeString(
942 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
943 ImmutableStringBuilder samplerCoordBuilder(
944 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
945 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
946
947 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
948 if (hlslCoords >= 3)
949 {
950 if (textureFunction.coords < 3)
951 {
952 samplerCoordBuilder << ", 0";
953 }
954 else
955 {
956 samplerCoordBuilder << ", " << texCoordZ;
957 }
958 }
959 samplerCoordBuilder << ")";
960
961 ImmutableString samplerCoordString(samplerCoordBuilder);
962
963 if (IsShadowSampler(textureFunction.sampler))
964 {
965 out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
966 << samplerCoordString << ", refZ";
967 if (textureFunction.offset)
968 {
969 out << ", offset";
970 }
971 out << ");\n";
972 return;
973 }
974
975 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
976 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
977
978 out << " switch(comp)\n"
979 " {\n";
980 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
981 {
982 out << " case " << component << ":\n"
983 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
984 << "(" << samplerReference << ", " << samplerCoordString;
985 if (textureFunction.offset)
986 {
987 out << ", offset";
988 }
989 out << ");\n";
990 }
991
992 out << " default:\n"
993 " return float4(0.0, 0.0, 0.0, 1.0);\n"
994 " }\n";
995 }
996
OutputTextureSampleFunctionReturnStatement(TInfoSinkBase & out,const TextureFunctionHLSL::TextureFunction & textureFunction,const ShShaderOutput outputType,const ImmutableString & textureReference,const ImmutableString & samplerReference,const ImmutableString & texCoordX,const ImmutableString & texCoordY,const ImmutableString & texCoordZ)997 void OutputTextureSampleFunctionReturnStatement(
998 TInfoSinkBase &out,
999 const TextureFunctionHLSL::TextureFunction &textureFunction,
1000 const ShShaderOutput outputType,
1001 const ImmutableString &textureReference,
1002 const ImmutableString &samplerReference,
1003 const ImmutableString &texCoordX,
1004 const ImmutableString &texCoordY,
1005 const ImmutableString &texCoordZ)
1006 {
1007 out << " return ";
1008
1009 if (IsIntegerSampler(textureFunction.sampler) && !IsSamplerCube(textureFunction.sampler) &&
1010 textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
1011 {
1012 out << " useBorderColor ? ";
1013 if (IsIntegerSamplerUnsigned(textureFunction.sampler))
1014 {
1015 out << "asuint";
1016 }
1017 out << "(samplerMetadata[samplerIndex].intBorderColor) : ";
1018 }
1019
1020 // HLSL intrinsic
1021 if (outputType == SH_HLSL_3_0_OUTPUT)
1022 {
1023 switch (textureFunction.sampler)
1024 {
1025 case EbtSampler2D:
1026 case EbtSamplerVideoWEBGL:
1027 case EbtSamplerExternalOES:
1028 out << "tex2D";
1029 break;
1030 case EbtSamplerCube:
1031 out << "texCUBE";
1032 break;
1033 default:
1034 UNREACHABLE();
1035 }
1036
1037 switch (textureFunction.method)
1038 {
1039 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1040 out << "(" << samplerReference << ", ";
1041 break;
1042 case TextureFunctionHLSL::TextureFunction::BIAS:
1043 out << "bias(" << samplerReference << ", ";
1044 break;
1045 case TextureFunctionHLSL::TextureFunction::LOD:
1046 out << "lod(" << samplerReference << ", ";
1047 break;
1048 case TextureFunctionHLSL::TextureFunction::LOD0:
1049 out << "lod(" << samplerReference << ", ";
1050 break;
1051 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1052 out << "lod(" << samplerReference << ", ";
1053 break;
1054 case TextureFunctionHLSL::TextureFunction::GRAD:
1055 out << "grad(" << samplerReference << ", ";
1056 break;
1057 default:
1058 UNREACHABLE();
1059 }
1060 }
1061 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1062 {
1063 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
1064 }
1065 else
1066 UNREACHABLE();
1067
1068 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
1069
1070 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
1071 << texCoordY;
1072
1073 if (outputType == SH_HLSL_3_0_OUTPUT)
1074 {
1075 if (hlslCoords >= 3)
1076 {
1077 if (textureFunction.coords < 3)
1078 {
1079 out << ", 0";
1080 }
1081 else
1082 {
1083 out << ", " << texCoordZ;
1084 }
1085 }
1086
1087 if (hlslCoords == 4)
1088 {
1089 switch (textureFunction.method)
1090 {
1091 case TextureFunctionHLSL::TextureFunction::BIAS:
1092 out << ", bias";
1093 break;
1094 case TextureFunctionHLSL::TextureFunction::LOD:
1095 out << ", lod";
1096 break;
1097 case TextureFunctionHLSL::TextureFunction::LOD0:
1098 out << ", 0";
1099 break;
1100 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1101 out << ", bias";
1102 break;
1103 default:
1104 UNREACHABLE();
1105 }
1106 }
1107
1108 out << ")";
1109 }
1110 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1111 {
1112 if (hlslCoords >= 3)
1113 {
1114 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
1115 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
1116 out << ", " << texCoordZ;
1117 }
1118
1119 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
1120 {
1121 if (IsIntegerSampler(textureFunction.sampler))
1122 {
1123 out << ", mip)";
1124 }
1125 else if (IsShadowSampler(textureFunction.sampler))
1126 {
1127 // Compare value
1128 if (textureFunction.proj)
1129 {
1130 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1131 // The resulting third component of P' in the shadow forms is used as
1132 // Dref
1133 out << "), " << texCoordZ;
1134 }
1135 else
1136 {
1137 switch (textureFunction.coords)
1138 {
1139 case 3:
1140 out << "), t.z";
1141 break;
1142 case 4:
1143 out << "), t.w";
1144 break;
1145 default:
1146 UNREACHABLE();
1147 }
1148 }
1149 }
1150 else
1151 {
1152 out << "), ddx, ddy";
1153 }
1154 }
1155 else if (IsIntegerSampler(textureFunction.sampler) ||
1156 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1157 {
1158 if (IsSampler2DMS(textureFunction.sampler) ||
1159 IsSampler2DMSArray(textureFunction.sampler))
1160 out << "), index";
1161 else
1162 out << ", mip)";
1163 }
1164 else if (IsShadowSampler(textureFunction.sampler))
1165 {
1166 // Compare value
1167 if (textureFunction.proj)
1168 {
1169 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1170 // The resulting third component of P' in the shadow forms is used as Dref
1171 out << "), " << texCoordZ;
1172 }
1173 else
1174 {
1175 switch (textureFunction.coords)
1176 {
1177 case 3:
1178 out << "), t.z";
1179 break;
1180 case 4:
1181 out << "), t.w";
1182 break;
1183 default:
1184 UNREACHABLE();
1185 }
1186 }
1187 }
1188 else
1189 {
1190 switch (textureFunction.method)
1191 {
1192 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1193 out << ")";
1194 break;
1195 case TextureFunctionHLSL::TextureFunction::BIAS:
1196 out << "), bias";
1197 break;
1198 case TextureFunctionHLSL::TextureFunction::LOD:
1199 out << "), lod";
1200 break;
1201 case TextureFunctionHLSL::TextureFunction::LOD0:
1202 out << "), 0";
1203 break;
1204 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1205 out << "), bias";
1206 break;
1207 default:
1208 UNREACHABLE();
1209 }
1210 }
1211
1212 if (textureFunction.offset &&
1213 (!IsIntegerSampler(textureFunction.sampler) ||
1214 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1215 {
1216 out << ", offset";
1217 }
1218 }
1219 else
1220 UNREACHABLE();
1221
1222 out << ");\n"; // Close the sample function call and return statement
1223 }
1224
1225 } // Anonymous namespace
1226
name() const1227 ImmutableString TextureFunctionHLSL::TextureFunction::name() const
1228 {
1229 static const ImmutableString kGlTextureName("gl_texture");
1230
1231 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1232
1233 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1234
1235 name << kGlTextureName;
1236
1237 // We need to include full the sampler type in the function name to make the signature unique
1238 // on D3D11, where samplers are passed to texture functions as indices.
1239 name << suffix;
1240
1241 if (proj)
1242 {
1243 name << "Proj";
1244 }
1245
1246 if (offset)
1247 {
1248 name << "Offset";
1249 }
1250
1251 switch (method)
1252 {
1253 case IMPLICIT:
1254 break;
1255 case BIAS:
1256 break; // Extra parameter makes the signature unique
1257 case LOD:
1258 name << "Lod";
1259 break;
1260 case LOD0:
1261 name << "Lod0";
1262 break;
1263 case LOD0BIAS:
1264 name << "Lod0";
1265 break; // Extra parameter makes the signature unique
1266 case SIZE:
1267 name << "Size";
1268 break;
1269 case FETCH:
1270 name << "Fetch";
1271 break;
1272 case GRAD:
1273 name << "Grad";
1274 break;
1275 case GATHER:
1276 name << "Gather";
1277 break;
1278 default:
1279 UNREACHABLE();
1280 }
1281
1282 return name;
1283 }
1284
getReturnType() const1285 const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1286 {
1287 if (method == TextureFunction::SIZE)
1288 {
1289 switch (sampler)
1290 {
1291 case EbtSampler2D:
1292 case EbtISampler2D:
1293 case EbtUSampler2D:
1294 case EbtSampler2DShadow:
1295 case EbtSamplerCube:
1296 case EbtISamplerCube:
1297 case EbtUSamplerCube:
1298 case EbtSamplerCubeShadow:
1299 case EbtSamplerExternalOES:
1300 case EbtSampler2DMS:
1301 case EbtISampler2DMS:
1302 case EbtUSampler2DMS:
1303 case EbtSamplerVideoWEBGL:
1304 return "int2";
1305 case EbtSampler3D:
1306 case EbtISampler3D:
1307 case EbtUSampler3D:
1308 case EbtSampler2DArray:
1309 case EbtISampler2DArray:
1310 case EbtUSampler2DArray:
1311 case EbtSampler2DMSArray:
1312 case EbtISampler2DMSArray:
1313 case EbtUSampler2DMSArray:
1314 case EbtSampler2DArrayShadow:
1315 return "int3";
1316 default:
1317 UNREACHABLE();
1318 }
1319 }
1320 else // Sampling function
1321 {
1322 switch (sampler)
1323 {
1324 case EbtSampler2D:
1325 case EbtSampler2DMS:
1326 case EbtSampler2DMSArray:
1327 case EbtSampler3D:
1328 case EbtSamplerCube:
1329 case EbtSampler2DArray:
1330 case EbtSamplerExternalOES:
1331 case EbtSamplerVideoWEBGL:
1332 return "float4";
1333 case EbtISampler2D:
1334 case EbtISampler2DMS:
1335 case EbtISampler2DMSArray:
1336 case EbtISampler3D:
1337 case EbtISamplerCube:
1338 case EbtISampler2DArray:
1339 return "int4";
1340 case EbtUSampler2D:
1341 case EbtUSampler2DMS:
1342 case EbtUSampler2DMSArray:
1343 case EbtUSampler3D:
1344 case EbtUSamplerCube:
1345 case EbtUSampler2DArray:
1346 return "uint4";
1347 case EbtSampler2DShadow:
1348 case EbtSamplerCubeShadow:
1349 case EbtSampler2DArrayShadow:
1350 if (method == TextureFunctionHLSL::TextureFunction::GATHER)
1351 {
1352 return "float4";
1353 }
1354 else
1355 {
1356 return "float";
1357 }
1358 default:
1359 UNREACHABLE();
1360 }
1361 }
1362 return "";
1363 }
1364
operator <(const TextureFunction & rhs) const1365 bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1366 {
1367 return std::tie(sampler, coords, proj, offset, method) <
1368 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
1369 }
1370
useTextureFunction(const ImmutableString & name,TBasicType samplerType,int coords,size_t argumentCount,bool lod0,sh::GLenum shaderType)1371 ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1372 TBasicType samplerType,
1373 int coords,
1374 size_t argumentCount,
1375 bool lod0,
1376 sh::GLenum shaderType)
1377 {
1378 TextureFunction textureFunction;
1379 textureFunction.sampler = samplerType;
1380 textureFunction.coords = coords;
1381 textureFunction.method = TextureFunction::IMPLICIT;
1382 textureFunction.proj = false;
1383 textureFunction.offset = false;
1384
1385 if (name == "texture2D" || name == "textureCube" || name == "texture")
1386 {
1387 textureFunction.method = TextureFunction::IMPLICIT;
1388 }
1389 else if (name == "texture2DProj" || name == "textureProj")
1390 {
1391 textureFunction.method = TextureFunction::IMPLICIT;
1392 textureFunction.proj = true;
1393 }
1394 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1395 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1396 {
1397 textureFunction.method = TextureFunction::LOD;
1398 }
1399 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1400 name == "texture2DProjLodEXT")
1401 {
1402 textureFunction.method = TextureFunction::LOD;
1403 textureFunction.proj = true;
1404 }
1405 else if (name == "textureSize")
1406 {
1407 textureFunction.method = TextureFunction::SIZE;
1408 }
1409 else if (name == "textureOffset")
1410 {
1411 textureFunction.method = TextureFunction::IMPLICIT;
1412 textureFunction.offset = true;
1413 }
1414 else if (name == "textureProjOffset")
1415 {
1416 textureFunction.method = TextureFunction::IMPLICIT;
1417 textureFunction.offset = true;
1418 textureFunction.proj = true;
1419 }
1420 else if (name == "textureLodOffset")
1421 {
1422 textureFunction.method = TextureFunction::LOD;
1423 textureFunction.offset = true;
1424 }
1425 else if (name == "textureProjLodOffset")
1426 {
1427 textureFunction.method = TextureFunction::LOD;
1428 textureFunction.proj = true;
1429 textureFunction.offset = true;
1430 }
1431 else if (name == "texelFetch")
1432 {
1433 textureFunction.method = TextureFunction::FETCH;
1434 }
1435 else if (name == "texelFetchOffset")
1436 {
1437 textureFunction.method = TextureFunction::FETCH;
1438 textureFunction.offset = true;
1439 }
1440 else if (name == "textureGrad" || name == "texture2DGradEXT")
1441 {
1442 textureFunction.method = TextureFunction::GRAD;
1443 }
1444 else if (name == "textureGradOffset")
1445 {
1446 textureFunction.method = TextureFunction::GRAD;
1447 textureFunction.offset = true;
1448 }
1449 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1450 name == "textureCubeGradEXT")
1451 {
1452 textureFunction.method = TextureFunction::GRAD;
1453 textureFunction.proj = true;
1454 }
1455 else if (name == "textureProjGradOffset")
1456 {
1457 textureFunction.method = TextureFunction::GRAD;
1458 textureFunction.proj = true;
1459 textureFunction.offset = true;
1460 }
1461 else if (name == "textureGather")
1462 {
1463 textureFunction.method = TextureFunction::GATHER;
1464 }
1465 else if (name == "textureGatherOffset")
1466 {
1467 textureFunction.method = TextureFunction::GATHER;
1468 textureFunction.offset = true;
1469 }
1470 else if (name == "textureVideoWEBGL")
1471 {
1472 textureFunction.method = TextureFunction::IMPLICIT;
1473 }
1474 else
1475 UNREACHABLE();
1476
1477 if (textureFunction.method ==
1478 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1479 {
1480 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1481
1482 if (textureFunction.offset)
1483 {
1484 mandatoryArgumentCount++;
1485 }
1486
1487 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1488
1489 if (lod0 || shaderType == GL_VERTEX_SHADER || shaderType == GL_COMPUTE_SHADER)
1490 {
1491 if (bias)
1492 {
1493 textureFunction.method = TextureFunction::LOD0BIAS;
1494 }
1495 else
1496 {
1497 textureFunction.method = TextureFunction::LOD0;
1498 }
1499 }
1500 else if (bias)
1501 {
1502 textureFunction.method = TextureFunction::BIAS;
1503 }
1504 }
1505
1506 mUsesTexture.insert(textureFunction);
1507 return textureFunction.name();
1508 }
1509
textureFunctionHeader(TInfoSinkBase & out,const ShShaderOutput outputType,bool getDimensionsIgnoresBaseLevel)1510 void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1511 const ShShaderOutput outputType,
1512 bool getDimensionsIgnoresBaseLevel)
1513 {
1514 for (const TextureFunction &textureFunction : mUsesTexture)
1515 {
1516 // Function header
1517 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1518
1519 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1520
1521 out << ")\n"
1522 "{\n";
1523
1524 // In some cases we use a variable to store the texture/sampler objects, but to work around
1525 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1526 // sampling we need to call the function directly on references to the texture and sampler
1527 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1528 // tests.
1529 ImmutableString textureReference("");
1530 ImmutableString samplerReference("");
1531 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1532
1533 if (textureFunction.method == TextureFunction::SIZE)
1534 {
1535 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1536 getDimensionsIgnoresBaseLevel);
1537 }
1538 else
1539 {
1540 ImmutableString texCoordX("t.x");
1541 ImmutableString texCoordY("t.y");
1542 ImmutableString texCoordZ("t.z");
1543 if (textureFunction.method == TextureFunction::GATHER)
1544 {
1545 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1546 samplerReference, texCoordX, texCoordY, texCoordZ);
1547 }
1548 else
1549 {
1550 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1551 OutputIntegerTextureSampleFunctionComputations(
1552 out, textureFunction, outputType, textureReference, &texCoordX, &texCoordY,
1553 &texCoordZ, getDimensionsIgnoresBaseLevel);
1554 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1555 textureReference, samplerReference,
1556 texCoordX, texCoordY, texCoordZ);
1557 }
1558 }
1559
1560 out << "}\n"
1561 "\n";
1562 }
1563 }
1564
1565 } // namespace sh
1566