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