blob: b859310acb0ced1351646ee6c77369f61f51e848 [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:
204 hlslCoords = 2;
205 break;
206 case EbtSamplerCube:
207 hlslCoords = 3;
208 break;
209 default:
210 UNREACHABLE();
211 }
212
213 switch (textureFunction.method)
214 {
215 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
216 return hlslCoords;
217 case TextureFunctionHLSL::TextureFunction::BIAS:
218 case TextureFunctionHLSL::TextureFunction::LOD:
219 case TextureFunctionHLSL::TextureFunction::LOD0:
220 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
221 return 4;
222 default:
223 UNREACHABLE();
224 }
225 }
226 else
227 {
228 switch (textureFunction.sampler)
229 {
230 case EbtSampler2D:
231 return 2;
232 case EbtSampler3D:
233 return 3;
234 case EbtSamplerCube:
235 return 3;
236 case EbtSampler2DArray:
237 return 3;
Ian Ewellbda75592016-04-18 17:25:54 -0400238 case EbtSamplerExternalOES:
239 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300240 case EbtISampler2D:
241 return 2;
242 case EbtISampler3D:
243 return 3;
244 case EbtISamplerCube:
245 return 3;
246 case EbtISampler2DArray:
247 return 3;
248 case EbtUSampler2D:
249 return 2;
250 case EbtUSampler3D:
251 return 3;
252 case EbtUSamplerCube:
253 return 3;
254 case EbtUSampler2DArray:
255 return 3;
256 case EbtSampler2DShadow:
257 return 2;
258 case EbtSamplerCubeShadow:
259 return 3;
260 case EbtSampler2DArrayShadow:
261 return 3;
262 default:
263 UNREACHABLE();
264 }
265 }
266 return 0;
267}
268
269void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
270 const TextureFunctionHLSL::TextureFunction &textureFunction,
271 const ShShaderOutput outputType)
272{
273 if (outputType == SH_HLSL_3_0_OUTPUT)
274 {
275 switch (textureFunction.sampler)
276 {
277 case EbtSampler2D:
278 out << "sampler2D s";
279 break;
280 case EbtSamplerCube:
281 out << "samplerCUBE s";
282 break;
283 default:
284 UNREACHABLE();
285 }
286 }
287 else
288 {
289 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
290 {
291 out << TextureString(textureFunction.sampler) << " x, "
292 << SamplerString(textureFunction.sampler) << " s";
293 }
294 else
295 {
296 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
297 out << "const uint samplerIndex";
298 }
299 }
300
301 if (textureFunction.method ==
302 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
303 {
304 switch (textureFunction.coords)
305 {
306 case 2:
307 out << ", int2 t";
308 break;
309 case 3:
310 out << ", int3 t";
311 break;
312 default:
313 UNREACHABLE();
314 }
315 }
316 else // Floating-point coordinates (except textureSize)
317 {
318 switch (textureFunction.coords)
319 {
320 case 1:
321 out << ", int lod";
322 break; // textureSize()
323 case 2:
324 out << ", float2 t";
325 break;
326 case 3:
327 out << ", float3 t";
328 break;
329 case 4:
330 out << ", float4 t";
331 break;
332 default:
333 UNREACHABLE();
334 }
335 }
336
337 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
338 {
339 switch (textureFunction.sampler)
340 {
341 case EbtSampler2D:
342 case EbtISampler2D:
343 case EbtUSampler2D:
344 case EbtSampler2DArray:
345 case EbtISampler2DArray:
346 case EbtUSampler2DArray:
347 case EbtSampler2DShadow:
348 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400349 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300350 out << ", float2 ddx, float2 ddy";
351 break;
352 case EbtSampler3D:
353 case EbtISampler3D:
354 case EbtUSampler3D:
355 case EbtSamplerCube:
356 case EbtISamplerCube:
357 case EbtUSamplerCube:
358 case EbtSamplerCubeShadow:
359 out << ", float3 ddx, float3 ddy";
360 break;
361 default:
362 UNREACHABLE();
363 }
364 }
365
366 switch (textureFunction.method)
367 {
368 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
369 break;
370 case TextureFunctionHLSL::TextureFunction::BIAS:
371 break; // Comes after the offset parameter
372 case TextureFunctionHLSL::TextureFunction::LOD:
373 out << ", float lod";
374 break;
375 case TextureFunctionHLSL::TextureFunction::LOD0:
376 break;
377 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
378 break; // Comes after the offset parameter
379 case TextureFunctionHLSL::TextureFunction::SIZE:
380 break;
381 case TextureFunctionHLSL::TextureFunction::FETCH:
382 out << ", int mip";
383 break;
384 case TextureFunctionHLSL::TextureFunction::GRAD:
385 break;
386 default:
387 UNREACHABLE();
388 }
389
390 if (textureFunction.offset)
391 {
392 switch (textureFunction.sampler)
393 {
394 case EbtSampler2D:
395 out << ", int2 offset";
396 break;
397 case EbtSampler3D:
398 out << ", int3 offset";
399 break;
400 case EbtSampler2DArray:
401 out << ", int2 offset";
402 break;
403 case EbtISampler2D:
404 out << ", int2 offset";
405 break;
406 case EbtISampler3D:
407 out << ", int3 offset";
408 break;
409 case EbtISampler2DArray:
410 out << ", int2 offset";
411 break;
412 case EbtUSampler2D:
413 out << ", int2 offset";
414 break;
415 case EbtUSampler3D:
416 out << ", int3 offset";
417 break;
418 case EbtUSampler2DArray:
419 out << ", int2 offset";
420 break;
421 case EbtSampler2DShadow:
422 out << ", int2 offset";
423 break;
424 case EbtSampler2DArrayShadow:
425 out << ", int2 offset";
426 break;
Ian Ewellbda75592016-04-18 17:25:54 -0400427 case EbtSamplerExternalOES:
428 out << ", int2 offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300429 default:
430 UNREACHABLE();
431 }
432 }
433
434 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
435 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
436 {
437 out << ", float bias";
438 }
439}
440
441void GetTextureReference(TInfoSinkBase &out,
442 const TextureFunctionHLSL::TextureFunction &textureFunction,
443 const ShShaderOutput outputType,
444 TString *textureReference,
445 TString *samplerReference)
446{
447 if (outputType == SH_HLSL_4_1_OUTPUT)
448 {
449 TString suffix = TextureGroupSuffix(textureFunction.sampler);
450 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
451 {
452 *textureReference = TString("textures") + suffix + "[samplerIndex]";
453 *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
454 }
455 else
456 {
457 out << " const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
458 << ";\n";
459 *textureReference = TString("textures") + suffix + "[textureIndex]";
460 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
461 << ";\n";
462 *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
463 }
464 }
465 else
466 {
467 *textureReference = "x";
468 *samplerReference = "s";
469 }
470}
471
472void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
473 const TextureFunctionHLSL::TextureFunction &textureFunction,
474 const TString &textureReference)
475{
476 out << "int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
477 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
478 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
479 {
480 // "depth" stores either the number of layers in an array texture or 3D depth
481 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
482 << " " << textureReference
483 << ".GetDimensions(baseLevel + lod, width, height, depth, numberOfLevels);\n";
484 }
485 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
486 {
487 out << " uint width; uint height; uint numberOfLevels;\n"
488 << " " << textureReference
489 << ".GetDimensions(baseLevel + lod, width, height, numberOfLevels);\n";
490 }
491 else
492 UNREACHABLE();
493
494 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
495 {
496 out << " return int3(width, height, depth);";
497 }
498 else
499 {
500 out << " return int2(width, height);";
501 }
502}
503
504void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
505 TString *texCoordX,
506 TString *texCoordY,
507 TString *texCoordZ)
508{
509 if (textureFunction.proj)
510 {
511 TString proj("");
512 switch (textureFunction.coords)
513 {
514 case 3:
515 proj = " / t.z";
516 break;
517 case 4:
518 proj = " / t.w";
519 break;
520 default:
521 UNREACHABLE();
522 }
523 *texCoordX = "(" + *texCoordX + proj + ")";
524 *texCoordY = "(" + *texCoordY + proj + ")";
525 *texCoordZ = "(" + *texCoordZ + proj + ")";
526 }
527}
528
529void OutputIntegerTextureSampleFunctionComputations(
530 TInfoSinkBase &out,
531 const TextureFunctionHLSL::TextureFunction &textureFunction,
532 const ShShaderOutput outputType,
533 const TString &textureReference,
534 TString *texCoordX,
535 TString *texCoordY,
536 TString *texCoordZ)
537{
538 if (!IsIntegerSampler(textureFunction.sampler))
539 {
540 return;
541 }
542 if (IsSamplerCube(textureFunction.sampler))
543 {
544 out << " float width; float height; float layers; float levels;\n";
545
546 out << " uint mip = 0;\n";
547
548 out << " " << textureReference
549 << ".GetDimensions(mip, width, height, layers, levels);\n";
550
551 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
552 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
553 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
554 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
555 "(zMajor && t.z < 0.0f);\n";
556
557 // FACE_POSITIVE_X = 000b
558 // FACE_NEGATIVE_X = 001b
559 // FACE_POSITIVE_Y = 010b
560 // FACE_NEGATIVE_Y = 011b
561 // FACE_POSITIVE_Z = 100b
562 // FACE_NEGATIVE_Z = 101b
563 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
564
565 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
566 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
567 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
568
569 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
570 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
571
572 // Mip level computation.
573 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
574 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
575 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
576 {
577 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
578 {
579 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
580 " float2 dx = ddx(tSized);\n"
581 " float2 dy = ddy(tSized);\n"
582 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
583 }
584 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
585 {
586 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
587 // derivatives of P are assumed to be in the coordinate system used before
588 // texture coordinates are projected onto the appropriate cube face."
589 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
590 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
591 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
592 // Determine the derivatives of u, v and m
593 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
594 ": ddx[0]);\n"
595 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
596 ": ddy[0]);\n"
597 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
598 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
599 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
600 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
601 // Now determine the derivatives of the face coordinates, using the
602 // derivatives calculated above.
603 // d / dx (u(x) * 0.5 / m(x) + 0.5)
604 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
605 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
606 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
607 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
608 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
609 " float2 sizeVec = float2(width, height);\n"
610 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
611 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
612 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
613 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
614 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
615 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
616 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
617 }
618 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
619 << " " << textureReference
620 << ".GetDimensions(mip, width, height, layers, levels);\n";
621 }
622
623 // Convert from normalized floating-point to integer
624 *texCoordX = "int(floor(width * frac(" + *texCoordX + ")))";
625 *texCoordY = "int(floor(height * frac(" + *texCoordY + ")))";
626 *texCoordZ = "face";
627 }
628 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
629 {
630 if (IsSampler2D(textureFunction.sampler))
631 {
632 if (IsSamplerArray(textureFunction.sampler))
633 {
634 out << " float width; float height; float layers; float levels;\n";
635
636 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
637 {
638 out << " uint mip = 0;\n";
639 }
640 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
641 {
642 out << " uint mip = bias;\n";
643 }
644 else
645 {
646
647 out << " " << textureReference
648 << ".GetDimensions(0, width, height, layers, levels);\n";
649 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
650 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
651 {
652 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
653 " float dx = length(ddx(tSized));\n"
654 " float dy = length(ddy(tSized));\n"
655 " float lod = log2(max(dx, dy));\n";
656
657 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
658 {
659 out << " lod += bias;\n";
660 }
661 }
662 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
663 {
664 out << " float2 sizeVec = float2(width, height);\n"
665 " float2 sizeDdx = ddx * sizeVec;\n"
666 " float2 sizeDdy = ddy * sizeVec;\n"
667 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
668 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
669 }
670
671 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
672 }
673
674 out << " " << textureReference
675 << ".GetDimensions(mip, width, height, layers, levels);\n";
676 }
677 else
678 {
679 out << " float width; float height; float levels;\n";
680
681 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
682 {
683 out << " uint mip = 0;\n";
684 }
685 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
686 {
687 out << " uint mip = bias;\n";
688 }
689 else
690 {
691 out << " " << textureReference
692 << ".GetDimensions(0, width, height, levels);\n";
693
694 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
695 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
696 {
697 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
698 " float dx = length(ddx(tSized));\n"
699 " float dy = length(ddy(tSized));\n"
700 " float lod = log2(max(dx, dy));\n";
701
702 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
703 {
704 out << " lod += bias;\n";
705 }
706 }
707 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
708 {
709 out << " float2 sizeVec = float2(width, height);\n"
710 " float2 sizeDdx = ddx * sizeVec;\n"
711 " float2 sizeDdy = ddy * sizeVec;\n"
712 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
713 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
714 }
715
716 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
717 }
718
719 out << " " << textureReference
720 << ".GetDimensions(mip, width, height, levels);\n";
721 }
722 }
723 else if (IsSampler3D(textureFunction.sampler))
724 {
725 out << " float width; float height; float depth; float levels;\n";
726
727 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
728 {
729 out << " uint mip = 0;\n";
730 }
731 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
732 {
733 out << " uint mip = bias;\n";
734 }
735 else
736 {
737 out << " " << textureReference
738 << ".GetDimensions(0, width, height, depth, levels);\n";
739
740 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
741 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
742 {
743 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
744 " float dx = length(ddx(tSized));\n"
745 " float dy = length(ddy(tSized));\n"
746 " float lod = log2(max(dx, dy));\n";
747
748 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
749 {
750 out << " lod += bias;\n";
751 }
752 }
753 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
754 {
755 out << " float3 sizeVec = float3(width, height, depth);\n"
756 " float3 sizeDdx = ddx * sizeVec;\n"
757 " float3 sizeDdy = ddy * sizeVec;\n"
758 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
759 "sizeDdy))) * 0.5f;\n";
760 }
761
762 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
763 }
764
765 out << " " << textureReference
766 << ".GetDimensions(mip, width, height, depth, levels);\n";
767 }
768 else
769 UNREACHABLE();
770
771 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
772 }
773}
774
775void OutputTextureSampleFunctionReturnStatement(
776 TInfoSinkBase &out,
777 const TextureFunctionHLSL::TextureFunction &textureFunction,
778 const ShShaderOutput outputType,
779 const TString &textureReference,
780 const TString &samplerReference,
781 const TString &texCoordX,
782 const TString &texCoordY,
783 const TString &texCoordZ)
784{
785 out << " return ";
786
787 // HLSL intrinsic
788 if (outputType == SH_HLSL_3_0_OUTPUT)
789 {
790 switch (textureFunction.sampler)
791 {
792 case EbtSampler2D:
793 out << "tex2D";
794 break;
795 case EbtSamplerCube:
796 out << "texCUBE";
797 break;
798 default:
799 UNREACHABLE();
800 }
801
802 switch (textureFunction.method)
803 {
804 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
805 out << "(" << samplerReference << ", ";
806 break;
807 case TextureFunctionHLSL::TextureFunction::BIAS:
808 out << "bias(" << samplerReference << ", ";
809 break;
810 case TextureFunctionHLSL::TextureFunction::LOD:
811 out << "lod(" << samplerReference << ", ";
812 break;
813 case TextureFunctionHLSL::TextureFunction::LOD0:
814 out << "lod(" << samplerReference << ", ";
815 break;
816 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
817 out << "lod(" << samplerReference << ", ";
818 break;
819 default:
820 UNREACHABLE();
821 }
822 }
823 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
824 {
825 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
826 }
827 else
828 UNREACHABLE();
829
830 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
831
832 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
833 << texCoordY;
834
835 if (outputType == SH_HLSL_3_0_OUTPUT)
836 {
837 if (hlslCoords >= 3)
838 {
839 if (textureFunction.coords < 3)
840 {
841 out << ", 0";
842 }
843 else
844 {
845 out << ", " << texCoordZ;
846 }
847 }
848
849 if (hlslCoords == 4)
850 {
851 switch (textureFunction.method)
852 {
853 case TextureFunctionHLSL::TextureFunction::BIAS:
854 out << ", bias";
855 break;
856 case TextureFunctionHLSL::TextureFunction::LOD:
857 out << ", lod";
858 break;
859 case TextureFunctionHLSL::TextureFunction::LOD0:
860 out << ", 0";
861 break;
862 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
863 out << ", bias";
864 break;
865 default:
866 UNREACHABLE();
867 }
868 }
869
870 out << ")";
871 }
872 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
873 {
874 if (hlslCoords >= 3)
875 {
876 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
877 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
878 out << ", " << texCoordZ;
879 }
880
881 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
882 {
883 if (IsIntegerSampler(textureFunction.sampler))
884 {
885 out << ", mip)";
886 }
887 else if (IsShadowSampler(textureFunction.sampler))
888 {
889 // Compare value
890 if (textureFunction.proj)
891 {
892 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
893 // The resulting third component of P' in the shadow forms is used as
894 // Dref
895 out << "), " << texCoordZ;
896 }
897 else
898 {
899 switch (textureFunction.coords)
900 {
901 case 3:
902 out << "), t.z";
903 break;
904 case 4:
905 out << "), t.w";
906 break;
907 default:
908 UNREACHABLE();
909 }
910 }
911 }
912 else
913 {
914 out << "), ddx, ddy";
915 }
916 }
917 else if (IsIntegerSampler(textureFunction.sampler) ||
918 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
919 {
920 out << ", mip)";
921 }
922 else if (IsShadowSampler(textureFunction.sampler))
923 {
924 // Compare value
925 if (textureFunction.proj)
926 {
927 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
928 // The resulting third component of P' in the shadow forms is used as Dref
929 out << "), " << texCoordZ;
930 }
931 else
932 {
933 switch (textureFunction.coords)
934 {
935 case 3:
936 out << "), t.z";
937 break;
938 case 4:
939 out << "), t.w";
940 break;
941 default:
942 UNREACHABLE();
943 }
944 }
945 }
946 else
947 {
948 switch (textureFunction.method)
949 {
950 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
951 out << ")";
952 break;
953 case TextureFunctionHLSL::TextureFunction::BIAS:
954 out << "), bias";
955 break;
956 case TextureFunctionHLSL::TextureFunction::LOD:
957 out << "), lod";
958 break;
959 case TextureFunctionHLSL::TextureFunction::LOD0:
960 out << "), 0";
961 break;
962 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
963 out << "), bias";
964 break;
965 default:
966 UNREACHABLE();
967 }
968 }
969
970 if (textureFunction.offset &&
971 (!IsIntegerSampler(textureFunction.sampler) ||
972 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
973 {
974 out << ", offset";
975 }
976 }
977 else
978 UNREACHABLE();
979
980 out << ");\n"; // Close the sample function call and return statement
981}
982
983} // Anonymous namespace
984
985TString TextureFunctionHLSL::TextureFunction::name() const
986{
987 TString name = "gl_texture";
988
989 // We need to include full the sampler type in the function name to make the signature unique
990 // on D3D11, where samplers are passed to texture functions as indices.
991 name += TextureTypeSuffix(this->sampler);
992
993 if (proj)
994 {
995 name += "Proj";
996 }
997
998 if (offset)
999 {
1000 name += "Offset";
1001 }
1002
1003 switch (method)
1004 {
1005 case IMPLICIT:
1006 break;
1007 case BIAS:
1008 break; // Extra parameter makes the signature unique
1009 case LOD:
1010 name += "Lod";
1011 break;
1012 case LOD0:
1013 name += "Lod0";
1014 break;
1015 case LOD0BIAS:
1016 name += "Lod0";
1017 break; // Extra parameter makes the signature unique
1018 case SIZE:
1019 name += "Size";
1020 break;
1021 case FETCH:
1022 name += "Fetch";
1023 break;
1024 case GRAD:
1025 name += "Grad";
1026 break;
1027 default:
1028 UNREACHABLE();
1029 }
1030
1031 return name;
1032}
1033
1034const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1035{
1036 if (method == TextureFunction::SIZE)
1037 {
1038 switch (sampler)
1039 {
1040 case EbtSampler2D:
1041 case EbtISampler2D:
1042 case EbtUSampler2D:
1043 case EbtSampler2DShadow:
1044 case EbtSamplerCube:
1045 case EbtISamplerCube:
1046 case EbtUSamplerCube:
1047 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001048 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001049 return "int2";
1050 case EbtSampler3D:
1051 case EbtISampler3D:
1052 case EbtUSampler3D:
1053 case EbtSampler2DArray:
1054 case EbtISampler2DArray:
1055 case EbtUSampler2DArray:
1056 case EbtSampler2DArrayShadow:
1057 return "int3";
1058 default:
1059 UNREACHABLE();
1060 }
1061 }
1062 else // Sampling function
1063 {
1064 switch (sampler)
1065 {
1066 case EbtSampler2D:
1067 case EbtSampler3D:
1068 case EbtSamplerCube:
1069 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001070 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001071 return "float4";
1072 case EbtISampler2D:
1073 case EbtISampler3D:
1074 case EbtISamplerCube:
1075 case EbtISampler2DArray:
1076 return "int4";
1077 case EbtUSampler2D:
1078 case EbtUSampler3D:
1079 case EbtUSamplerCube:
1080 case EbtUSampler2DArray:
1081 return "uint4";
1082 case EbtSampler2DShadow:
1083 case EbtSamplerCubeShadow:
1084 case EbtSampler2DArrayShadow:
1085 return "float";
1086 default:
1087 UNREACHABLE();
1088 }
1089 }
1090 return "";
1091}
1092
1093bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1094{
1095 if (sampler < rhs.sampler)
1096 return true;
1097 if (sampler > rhs.sampler)
1098 return false;
1099
1100 if (coords < rhs.coords)
1101 return true;
1102 if (coords > rhs.coords)
1103 return false;
1104
1105 if (!proj && rhs.proj)
1106 return true;
1107 if (proj && !rhs.proj)
1108 return false;
1109
1110 if (!offset && rhs.offset)
1111 return true;
1112 if (offset && !rhs.offset)
1113 return false;
1114
1115 if (method < rhs.method)
1116 return true;
1117 if (method > rhs.method)
1118 return false;
1119
1120 return false;
1121}
1122
1123TString TextureFunctionHLSL::useTextureFunction(const TString &name,
1124 TBasicType samplerType,
1125 int coords,
1126 size_t argumentCount,
1127 bool lod0,
1128 sh::GLenum shaderType)
1129{
1130 TextureFunction textureFunction;
1131 textureFunction.sampler = samplerType;
1132 textureFunction.coords = coords;
1133 textureFunction.method = TextureFunction::IMPLICIT;
1134 textureFunction.proj = false;
1135 textureFunction.offset = false;
1136
1137 if (name == "texture2D" || name == "textureCube" || name == "texture")
1138 {
1139 textureFunction.method = TextureFunction::IMPLICIT;
1140 }
1141 else if (name == "texture2DProj" || name == "textureProj")
1142 {
1143 textureFunction.method = TextureFunction::IMPLICIT;
1144 textureFunction.proj = true;
1145 }
1146 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1147 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1148 {
1149 textureFunction.method = TextureFunction::LOD;
1150 }
1151 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1152 name == "texture2DProjLodEXT")
1153 {
1154 textureFunction.method = TextureFunction::LOD;
1155 textureFunction.proj = true;
1156 }
1157 else if (name == "textureSize")
1158 {
1159 textureFunction.method = TextureFunction::SIZE;
1160 }
1161 else if (name == "textureOffset")
1162 {
1163 textureFunction.method = TextureFunction::IMPLICIT;
1164 textureFunction.offset = true;
1165 }
1166 else if (name == "textureProjOffset")
1167 {
1168 textureFunction.method = TextureFunction::IMPLICIT;
1169 textureFunction.offset = true;
1170 textureFunction.proj = true;
1171 }
1172 else if (name == "textureLodOffset")
1173 {
1174 textureFunction.method = TextureFunction::LOD;
1175 textureFunction.offset = true;
1176 }
1177 else if (name == "textureProjLodOffset")
1178 {
1179 textureFunction.method = TextureFunction::LOD;
1180 textureFunction.proj = true;
1181 textureFunction.offset = true;
1182 }
1183 else if (name == "texelFetch")
1184 {
1185 textureFunction.method = TextureFunction::FETCH;
1186 }
1187 else if (name == "texelFetchOffset")
1188 {
1189 textureFunction.method = TextureFunction::FETCH;
1190 textureFunction.offset = true;
1191 }
1192 else if (name == "textureGrad" || name == "texture2DGradEXT")
1193 {
1194 textureFunction.method = TextureFunction::GRAD;
1195 }
1196 else if (name == "textureGradOffset")
1197 {
1198 textureFunction.method = TextureFunction::GRAD;
1199 textureFunction.offset = true;
1200 }
1201 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1202 name == "textureCubeGradEXT")
1203 {
1204 textureFunction.method = TextureFunction::GRAD;
1205 textureFunction.proj = true;
1206 }
1207 else if (name == "textureProjGradOffset")
1208 {
1209 textureFunction.method = TextureFunction::GRAD;
1210 textureFunction.proj = true;
1211 textureFunction.offset = true;
1212 }
1213 else
1214 UNREACHABLE();
1215
1216 if (textureFunction.method ==
1217 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1218 {
1219 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1220
1221 if (textureFunction.offset)
1222 {
1223 mandatoryArgumentCount++;
1224 }
1225
1226 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1227
1228 if (lod0 || shaderType == GL_VERTEX_SHADER)
1229 {
1230 if (bias)
1231 {
1232 textureFunction.method = TextureFunction::LOD0BIAS;
1233 }
1234 else
1235 {
1236 textureFunction.method = TextureFunction::LOD0;
1237 }
1238 }
1239 else if (bias)
1240 {
1241 textureFunction.method = TextureFunction::BIAS;
1242 }
1243 }
1244
1245 mUsesTexture.insert(textureFunction);
1246 return textureFunction.name();
1247}
1248
1249void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, const ShShaderOutput outputType)
1250{
1251 for (const TextureFunction &textureFunction : mUsesTexture)
1252 {
1253 // Function header
1254 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1255
1256 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1257
1258 out << ")\n"
1259 "{\n";
1260
1261 // In some cases we use a variable to store the texture/sampler objects, but to work around
1262 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1263 // sampling we need to call the function directly on references to the texture and sampler
1264 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1265 // tests.
1266 TString textureReference;
1267 TString samplerReference;
1268 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1269
1270 if (textureFunction.method == TextureFunction::SIZE)
1271 {
1272 OutputTextureSizeFunctionBody(out, textureFunction, textureReference);
1273 }
1274 else
1275 {
1276 TString texCoordX("t.x");
1277 TString texCoordY("t.y");
1278 TString texCoordZ("t.z");
1279 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1280 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1281 textureReference, &texCoordX, &texCoordY,
1282 &texCoordZ);
1283 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1284 textureReference, samplerReference,
1285 texCoordX, texCoordY, texCoordZ);
1286 }
1287
1288 out << "}\n"
1289 "\n";
1290 }
1291}
1292
1293} // namespace sh