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