blob: 16660042a3addd3163cc53087a03d7074351098e [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
Olli Etuaho12c03762018-01-25 12:22:33 +020014#include "compiler/translator/ImmutableStringBuilder.h"
Olli Etuaho5858f7e2016-04-08 13:08:46 +030015#include "compiler/translator/UtilsHLSL.h"
16
17namespace sh
18{
19
20namespace
21{
22
23void OutputIntTexCoordWrap(TInfoSinkBase &out,
24 const char *wrapMode,
25 const char *size,
Olli Etuahob4cc49f2018-01-25 14:37:06 +020026 const ImmutableString &texCoord,
27 const char *texCoordOffset,
Olli Etuaho5858f7e2016-04-08 13:08:46 +030028 const char *texCoordOutName)
29{
30 // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
31 // but rather use equivalent formulas that map better to HLSL.
32 out << "int " << texCoordOutName << ";\n";
33 out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
34 << ") / " << size << ";\n";
35
36 // CLAMP_TO_EDGE
37 out << "if (" << wrapMode << " == 1)\n";
38 out << "{\n";
39 out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
40 << "Offset)), 0, int(" << size << ") - 1);\n";
41 out << "}\n";
42
43 // MIRRORED_REPEAT
44 out << "else if (" << wrapMode << " == 3)\n";
45 out << "{\n";
46 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
47 << "Offset) * 0.5) * 2.0 - 1.0);\n";
48 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
49 out << "}\n";
50
51 // REPEAT
52 out << "else\n";
53 out << "{\n";
54 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
55 << "Offset)));\n";
56 out << "}\n";
57}
58
59void OutputIntTexCoordWraps(TInfoSinkBase &out,
60 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +020061 ImmutableString *texCoordX,
62 ImmutableString *texCoordY,
63 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +030064{
65 // Convert from normalized floating-point to integer
66 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
67 if (textureFunction.offset)
68 {
69 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
70 }
71 else
72 {
73 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
74 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020075 *texCoordX = ImmutableString("tix");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030076 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
77 if (textureFunction.offset)
78 {
79 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
80 }
81 else
82 {
83 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
84 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020085 *texCoordY = ImmutableString("tiy");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030086
87 if (IsSamplerArray(textureFunction.sampler))
88 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +020089 *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030090 }
91 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
92 {
93 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
94 if (textureFunction.offset)
95 {
96 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
97 }
98 else
99 {
100 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
101 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200102 *texCoordZ = ImmutableString("tiz");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300103 }
104}
105
106void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
107 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200108 const ImmutableString &textureReference,
109 const ImmutableString &samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300110{
111 out << textureReference;
112 if (IsIntegerSampler(textureFunction.sampler) ||
113 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
114 {
115 out << ".Load(";
116 return;
117 }
118
119 if (IsShadowSampler(textureFunction.sampler))
120 {
121 switch (textureFunction.method)
122 {
123 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
124 case TextureFunctionHLSL::TextureFunction::BIAS:
125 case TextureFunctionHLSL::TextureFunction::LOD:
126 out << ".SampleCmp(";
127 break;
128 case TextureFunctionHLSL::TextureFunction::LOD0:
129 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
130 case TextureFunctionHLSL::TextureFunction::GRAD:
131 out << ".SampleCmpLevelZero(";
132 break;
133 default:
134 UNREACHABLE();
135 }
136 }
137 else
138 {
139 switch (textureFunction.method)
140 {
141 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
142 out << ".Sample(";
143 break;
144 case TextureFunctionHLSL::TextureFunction::BIAS:
145 out << ".SampleBias(";
146 break;
147 case TextureFunctionHLSL::TextureFunction::LOD:
148 case TextureFunctionHLSL::TextureFunction::LOD0:
149 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
150 out << ".SampleLevel(";
151 break;
152 case TextureFunctionHLSL::TextureFunction::GRAD:
153 out << ".SampleGrad(";
154 break;
155 default:
156 UNREACHABLE();
157 }
158 }
159 out << samplerReference << ", ";
160}
161
162const char *GetSamplerCoordinateTypeString(
163 const TextureFunctionHLSL::TextureFunction &textureFunction,
164 int hlslCoords)
165{
166 if (IsIntegerSampler(textureFunction.sampler) ||
167 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
168 {
169 switch (hlslCoords)
170 {
171 case 2:
Olli Etuaho2da04532018-08-24 13:59:44 +0300172 if (IsSampler2DMS(textureFunction.sampler))
173 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800174 return "int2";
Olli Etuaho2da04532018-08-24 13:59:44 +0300175 }
JiangYizhou5b03f472017-01-09 10:22:53 +0800176 else
Olli Etuaho2da04532018-08-24 13:59:44 +0300177 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800178 return "int3";
Olli Etuaho2da04532018-08-24 13:59:44 +0300179 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300180 case 3:
Olli Etuaho2da04532018-08-24 13:59:44 +0300181 if (IsSampler2DMSArray(textureFunction.sampler))
182 {
183 return "int3";
184 }
185 else
186 {
187 return "int4";
188 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300189 default:
190 UNREACHABLE();
191 }
192 }
193 else
194 {
195 switch (hlslCoords)
196 {
197 case 2:
198 return "float2";
199 case 3:
200 return "float3";
201 case 4:
202 return "float4";
203 default:
204 UNREACHABLE();
205 }
206 }
207 return "";
208}
209
210int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
211 ShShaderOutput outputType)
212{
213 if (outputType == SH_HLSL_3_0_OUTPUT)
214 {
215 int hlslCoords = 2;
216 switch (textureFunction.sampler)
217 {
218 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400219 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800220 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300221 hlslCoords = 2;
222 break;
223 case EbtSamplerCube:
224 hlslCoords = 3;
225 break;
226 default:
227 UNREACHABLE();
228 }
229
230 switch (textureFunction.method)
231 {
232 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400233 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300234 return hlslCoords;
235 case TextureFunctionHLSL::TextureFunction::BIAS:
236 case TextureFunctionHLSL::TextureFunction::LOD:
237 case TextureFunctionHLSL::TextureFunction::LOD0:
238 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
239 return 4;
240 default:
241 UNREACHABLE();
242 }
243 }
244 else
245 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300246 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
247 IsSamplerCube(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300248 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300249 return 3;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300250 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300251 ASSERT(IsSampler2D(textureFunction.sampler));
252 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300253 }
254 return 0;
255}
256
257void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
258 const TextureFunctionHLSL::TextureFunction &textureFunction,
259 const ShShaderOutput outputType)
260{
261 if (outputType == SH_HLSL_3_0_OUTPUT)
262 {
263 switch (textureFunction.sampler)
264 {
265 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400266 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300267 out << "sampler2D s";
268 break;
269 case EbtSamplerCube:
270 out << "samplerCUBE s";
271 break;
272 default:
273 UNREACHABLE();
274 }
275 }
276 else
277 {
278 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
279 {
280 out << TextureString(textureFunction.sampler) << " x, "
281 << SamplerString(textureFunction.sampler) << " s";
282 }
283 else
284 {
285 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400286 // A bug in the D3D compiler causes some nested sampling operations to fail.
287 // See http://anglebug.com/1923
288 // TODO(jmadill): Reinstate the const keyword when possible.
289 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300290 }
291 }
292
293 if (textureFunction.method ==
294 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
295 {
296 switch (textureFunction.coords)
297 {
298 case 2:
299 out << ", int2 t";
300 break;
301 case 3:
302 out << ", int3 t";
303 break;
304 default:
305 UNREACHABLE();
306 }
307 }
308 else // Floating-point coordinates (except textureSize)
309 {
310 switch (textureFunction.coords)
311 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000312 case 0:
313 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300314 case 1:
315 out << ", int lod";
316 break; // textureSize()
317 case 2:
318 out << ", float2 t";
319 break;
320 case 3:
321 out << ", float3 t";
322 break;
323 case 4:
324 out << ", float4 t";
325 break;
326 default:
327 UNREACHABLE();
328 }
329 }
330
331 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
332 {
333 switch (textureFunction.sampler)
334 {
335 case EbtSampler2D:
336 case EbtISampler2D:
337 case EbtUSampler2D:
338 case EbtSampler2DArray:
339 case EbtISampler2DArray:
340 case EbtUSampler2DArray:
341 case EbtSampler2DShadow:
342 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400343 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300344 out << ", float2 ddx, float2 ddy";
345 break;
346 case EbtSampler3D:
347 case EbtISampler3D:
348 case EbtUSampler3D:
349 case EbtSamplerCube:
350 case EbtISamplerCube:
351 case EbtUSamplerCube:
352 case EbtSamplerCubeShadow:
353 out << ", float3 ddx, float3 ddy";
354 break;
355 default:
356 UNREACHABLE();
357 }
358 }
359
360 switch (textureFunction.method)
361 {
362 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
363 break;
364 case TextureFunctionHLSL::TextureFunction::BIAS:
365 break; // Comes after the offset parameter
366 case TextureFunctionHLSL::TextureFunction::LOD:
367 out << ", float lod";
368 break;
369 case TextureFunctionHLSL::TextureFunction::LOD0:
370 break;
371 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
372 break; // Comes after the offset parameter
373 case TextureFunctionHLSL::TextureFunction::SIZE:
374 break;
375 case TextureFunctionHLSL::TextureFunction::FETCH:
Olli Etuaho2da04532018-08-24 13:59:44 +0300376 if (IsSampler2DMS(textureFunction.sampler) ||
377 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +0800378 out << ", int index";
379 else
380 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300381 break;
382 case TextureFunctionHLSL::TextureFunction::GRAD:
383 break;
384 default:
385 UNREACHABLE();
386 }
387
388 if (textureFunction.offset)
389 {
390 switch (textureFunction.sampler)
391 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300392 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300393 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300394 case EbtUSampler3D:
395 out << ", int3 offset";
396 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300397 case EbtSampler2D:
398 case EbtSampler2DArray:
399 case EbtISampler2D:
400 case EbtISampler2DArray:
401 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300402 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300403 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300404 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400405 case EbtSamplerExternalOES:
406 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300407 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300408 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300409 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300410 UNREACHABLE();
411 }
412 }
413
414 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
415 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
416 {
417 out << ", float bias";
418 }
419}
420
421void GetTextureReference(TInfoSinkBase &out,
422 const TextureFunctionHLSL::TextureFunction &textureFunction,
423 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200424 ImmutableString *textureReference,
425 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300426{
427 if (outputType == SH_HLSL_4_1_OUTPUT)
428 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200429 static const ImmutableString kTexturesStr("textures");
430 static const ImmutableString kSamplersStr("samplers");
431 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
432 static const ImmutableString kTextureIndexStr("[textureIndex]");
433 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
434 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
435
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300436 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
437 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200438 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
439 kSamplerIndexStr.length());
440 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
441 *textureReference = textureRefBuilder;
442 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
443 kSamplerIndexStr.length());
444 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
445 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300446 }
447 else
448 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200449 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
450 << suffix.data() << ";\n";
451 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
452 kTextureIndexStr.length());
453 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
454 *textureReference = textureRefBuilder;
455
456 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
457 << suffix.data() << ";\n";
458 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
459 kSamplerArrayIndexStr.length());
460 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
461 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300462 }
463 }
464 else
465 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200466 *textureReference = ImmutableString("x");
467 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300468 }
469}
470
471void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
472 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200473 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400474 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300475{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000476 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400477 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000478 out << " uint width; uint height; uint samples;\n"
479 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400480 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300481 else if (IsSampler2DMSArray(textureFunction.sampler))
482 {
483 out << " uint width; uint height; uint depth; uint samples;\n"
484 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
485 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400486 else
487 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000488 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400489 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000490 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400491 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000492 else
493 {
494 out << " int baseLevel = 0;\n";
495 }
496
497 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
498 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
499 {
500 // "depth" stores either the number of layers in an array texture or 3D depth
501 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
502 << " " << textureReference
503 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
504 << " width = max(width >> lod, 1);\n"
505 << " height = max(height >> lod, 1);\n";
506
507 if (!IsSamplerArray(textureFunction.sampler))
508 {
509 out << " depth = max(depth >> lod, 1);\n";
510 }
511 }
512 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
513 {
514 out << " uint width; uint height; uint numberOfLevels;\n"
515 << " " << textureReference
516 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
517 << " width = max(width >> lod, 1);\n"
518 << " height = max(height >> lod, 1);\n";
519 }
520 else
521 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300522 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300523
524 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
525 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000526 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300527 }
528 else
529 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000530 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300531 }
532}
533
534void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200535 ImmutableString *texCoordX,
536 ImmutableString *texCoordY,
537 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300538{
539 if (textureFunction.proj)
540 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200541 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300542 switch (textureFunction.coords)
543 {
544 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200545 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300546 break;
547 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200548 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300549 break;
550 default:
551 UNREACHABLE();
552 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200553 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
554 texCoordXBuilder << '(' << *texCoordX << proj << ')';
555 *texCoordX = texCoordXBuilder;
556 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
557 texCoordYBuilder << '(' << *texCoordY << proj << ')';
558 *texCoordY = texCoordYBuilder;
559 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
560 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
561 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300562 }
563}
564
565void OutputIntegerTextureSampleFunctionComputations(
566 TInfoSinkBase &out,
567 const TextureFunctionHLSL::TextureFunction &textureFunction,
568 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200569 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200570 ImmutableString *texCoordX,
571 ImmutableString *texCoordY,
572 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300573{
574 if (!IsIntegerSampler(textureFunction.sampler))
575 {
576 return;
577 }
578 if (IsSamplerCube(textureFunction.sampler))
579 {
580 out << " float width; float height; float layers; float levels;\n";
581
582 out << " uint mip = 0;\n";
583
584 out << " " << textureReference
585 << ".GetDimensions(mip, width, height, layers, levels);\n";
586
587 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
588 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
589 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
590 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
591 "(zMajor && t.z < 0.0f);\n";
592
593 // FACE_POSITIVE_X = 000b
594 // FACE_NEGATIVE_X = 001b
595 // FACE_POSITIVE_Y = 010b
596 // FACE_NEGATIVE_Y = 011b
597 // FACE_POSITIVE_Z = 100b
598 // FACE_NEGATIVE_Z = 101b
599 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
600
601 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
602 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
603 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
604
605 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
606 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
607
608 // Mip level computation.
609 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
610 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
611 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
612 {
613 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
614 {
615 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
616 " float2 dx = ddx(tSized);\n"
617 " float2 dy = ddy(tSized);\n"
618 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
619 }
620 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
621 {
622 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
623 // derivatives of P are assumed to be in the coordinate system used before
624 // texture coordinates are projected onto the appropriate cube face."
625 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
626 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
627 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
628 // Determine the derivatives of u, v and m
629 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
630 ": ddx[0]);\n"
631 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
632 ": ddy[0]);\n"
633 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
634 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
635 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
636 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
637 // Now determine the derivatives of the face coordinates, using the
638 // derivatives calculated above.
639 // d / dx (u(x) * 0.5 / m(x) + 0.5)
640 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
641 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
642 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
643 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
644 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
645 " float2 sizeVec = float2(width, height);\n"
646 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
647 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
648 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
649 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
650 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
651 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
652 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
653 }
654 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
655 << " " << textureReference
656 << ".GetDimensions(mip, width, height, layers, levels);\n";
657 }
658
659 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200660 static const ImmutableString kXPrefix("int(floor(width * frac(");
661 static const ImmutableString kYPrefix("int(floor(height * frac(");
662 static const ImmutableString kSuffix(")))");
663 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
664 kSuffix.length());
665 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
666 *texCoordX = texCoordXBuilder;
667 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
668 kSuffix.length());
669 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
670 *texCoordY = texCoordYBuilder;
671 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300672 }
673 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
674 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300675 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300676 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300677 out << " float width; float height; float layers; float levels;\n";
678
679 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300680 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300681 out << " uint mip = 0;\n";
682 }
683 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
684 {
685 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300686 }
687 else
688 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300689
690 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300691 << ".GetDimensions(0, width, height, layers, levels);\n";
692 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
693 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
694 {
695 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
696 " float dx = length(ddx(tSized));\n"
697 " float dy = length(ddy(tSized));\n"
698 " float lod = log2(max(dx, dy));\n";
699
700 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
701 {
702 out << " lod += bias;\n";
703 }
704 }
705 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
706 {
707 out << " float2 sizeVec = float2(width, height);\n"
708 " float2 sizeDdx = ddx * sizeVec;\n"
709 " float2 sizeDdy = ddy * sizeVec;\n"
710 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
711 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
712 }
713
714 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300715 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300716
717 out << " " << textureReference
718 << ".GetDimensions(mip, width, height, layers, levels);\n";
719 }
720 else if (IsSampler2D(textureFunction.sampler))
721 {
722 out << " float width; float height; float levels;\n";
723
724 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
725 {
726 out << " uint mip = 0;\n";
727 }
728 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
729 {
730 out << " uint mip = bias;\n";
731 }
732 else
733 {
734 out << " " << textureReference << ".GetDimensions(0, width, height, levels);\n";
735
736 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
737 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
738 {
739 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
740 " float dx = length(ddx(tSized));\n"
741 " float dy = length(ddy(tSized));\n"
742 " float lod = log2(max(dx, dy));\n";
743
744 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
745 {
746 out << " lod += bias;\n";
747 }
748 }
749 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
750 {
751 out << " float2 sizeVec = float2(width, height);\n"
752 " float2 sizeDdx = ddx * sizeVec;\n"
753 " float2 sizeDdy = ddy * sizeVec;\n"
754 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
755 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
756 }
757
758 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
759 }
760
761 out << " " << textureReference << ".GetDimensions(mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300762 }
763 else if (IsSampler3D(textureFunction.sampler))
764 {
765 out << " float width; float height; float depth; float levels;\n";
766
767 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
768 {
769 out << " uint mip = 0;\n";
770 }
771 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
772 {
773 out << " uint mip = bias;\n";
774 }
775 else
776 {
777 out << " " << textureReference
778 << ".GetDimensions(0, width, height, depth, levels);\n";
779
780 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
781 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
782 {
783 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
784 " float dx = length(ddx(tSized));\n"
785 " float dy = length(ddy(tSized));\n"
786 " float lod = log2(max(dx, dy));\n";
787
788 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
789 {
790 out << " lod += bias;\n";
791 }
792 }
793 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
794 {
795 out << " float3 sizeVec = float3(width, height, depth);\n"
796 " float3 sizeDdx = ddx * sizeVec;\n"
797 " float3 sizeDdy = ddy * sizeVec;\n"
798 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
799 "sizeDdy))) * 0.5f;\n";
800 }
801
802 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
803 }
804
805 out << " " << textureReference
806 << ".GetDimensions(mip, width, height, depth, levels);\n";
807 }
808 else
809 UNREACHABLE();
810
811 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
812 }
813}
814
815void OutputTextureSampleFunctionReturnStatement(
816 TInfoSinkBase &out,
817 const TextureFunctionHLSL::TextureFunction &textureFunction,
818 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200819 const ImmutableString &textureReference,
820 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200821 const ImmutableString &texCoordX,
822 const ImmutableString &texCoordY,
823 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300824{
825 out << " return ";
826
827 // HLSL intrinsic
828 if (outputType == SH_HLSL_3_0_OUTPUT)
829 {
830 switch (textureFunction.sampler)
831 {
832 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400833 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300834 out << "tex2D";
835 break;
836 case EbtSamplerCube:
837 out << "texCUBE";
838 break;
839 default:
840 UNREACHABLE();
841 }
842
843 switch (textureFunction.method)
844 {
845 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
846 out << "(" << samplerReference << ", ";
847 break;
848 case TextureFunctionHLSL::TextureFunction::BIAS:
849 out << "bias(" << samplerReference << ", ";
850 break;
851 case TextureFunctionHLSL::TextureFunction::LOD:
852 out << "lod(" << samplerReference << ", ";
853 break;
854 case TextureFunctionHLSL::TextureFunction::LOD0:
855 out << "lod(" << samplerReference << ", ";
856 break;
857 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
858 out << "lod(" << samplerReference << ", ";
859 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400860 case TextureFunctionHLSL::TextureFunction::GRAD:
861 out << "grad(" << samplerReference << ", ";
862 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300863 default:
864 UNREACHABLE();
865 }
866 }
867 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
868 {
869 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
870 }
871 else
872 UNREACHABLE();
873
874 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
875
876 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
877 << texCoordY;
878
879 if (outputType == SH_HLSL_3_0_OUTPUT)
880 {
881 if (hlslCoords >= 3)
882 {
883 if (textureFunction.coords < 3)
884 {
885 out << ", 0";
886 }
887 else
888 {
889 out << ", " << texCoordZ;
890 }
891 }
892
893 if (hlslCoords == 4)
894 {
895 switch (textureFunction.method)
896 {
897 case TextureFunctionHLSL::TextureFunction::BIAS:
898 out << ", bias";
899 break;
900 case TextureFunctionHLSL::TextureFunction::LOD:
901 out << ", lod";
902 break;
903 case TextureFunctionHLSL::TextureFunction::LOD0:
904 out << ", 0";
905 break;
906 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
907 out << ", bias";
908 break;
909 default:
910 UNREACHABLE();
911 }
912 }
913
914 out << ")";
915 }
916 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
917 {
918 if (hlslCoords >= 3)
919 {
920 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
921 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
922 out << ", " << texCoordZ;
923 }
924
925 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
926 {
927 if (IsIntegerSampler(textureFunction.sampler))
928 {
929 out << ", mip)";
930 }
931 else if (IsShadowSampler(textureFunction.sampler))
932 {
933 // Compare value
934 if (textureFunction.proj)
935 {
936 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
937 // The resulting third component of P' in the shadow forms is used as
938 // Dref
939 out << "), " << texCoordZ;
940 }
941 else
942 {
943 switch (textureFunction.coords)
944 {
945 case 3:
946 out << "), t.z";
947 break;
948 case 4:
949 out << "), t.w";
950 break;
951 default:
952 UNREACHABLE();
953 }
954 }
955 }
956 else
957 {
958 out << "), ddx, ddy";
959 }
960 }
961 else if (IsIntegerSampler(textureFunction.sampler) ||
962 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
963 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300964 if (IsSampler2DMS(textureFunction.sampler) ||
965 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +0800966 out << "), index";
967 else
968 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300969 }
970 else if (IsShadowSampler(textureFunction.sampler))
971 {
972 // Compare value
973 if (textureFunction.proj)
974 {
975 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
976 // The resulting third component of P' in the shadow forms is used as Dref
977 out << "), " << texCoordZ;
978 }
979 else
980 {
981 switch (textureFunction.coords)
982 {
983 case 3:
984 out << "), t.z";
985 break;
986 case 4:
987 out << "), t.w";
988 break;
989 default:
990 UNREACHABLE();
991 }
992 }
993 }
994 else
995 {
996 switch (textureFunction.method)
997 {
998 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
999 out << ")";
1000 break;
1001 case TextureFunctionHLSL::TextureFunction::BIAS:
1002 out << "), bias";
1003 break;
1004 case TextureFunctionHLSL::TextureFunction::LOD:
1005 out << "), lod";
1006 break;
1007 case TextureFunctionHLSL::TextureFunction::LOD0:
1008 out << "), 0";
1009 break;
1010 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1011 out << "), bias";
1012 break;
1013 default:
1014 UNREACHABLE();
1015 }
1016 }
1017
1018 if (textureFunction.offset &&
1019 (!IsIntegerSampler(textureFunction.sampler) ||
1020 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1021 {
1022 out << ", offset";
1023 }
1024 }
1025 else
1026 UNREACHABLE();
1027
1028 out << ");\n"; // Close the sample function call and return statement
1029}
1030
1031} // Anonymous namespace
1032
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001033ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001034{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001035 static const ImmutableString kGlTextureName("gl_texture");
1036
1037 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1038
1039 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1040
1041 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001042
1043 // We need to include full the sampler type in the function name to make the signature unique
1044 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001045 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001046
1047 if (proj)
1048 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001049 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001050 }
1051
1052 if (offset)
1053 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001054 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001055 }
1056
1057 switch (method)
1058 {
1059 case IMPLICIT:
1060 break;
1061 case BIAS:
1062 break; // Extra parameter makes the signature unique
1063 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001064 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001065 break;
1066 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001067 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001068 break;
1069 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001070 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001071 break; // Extra parameter makes the signature unique
1072 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001073 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001074 break;
1075 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001076 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001077 break;
1078 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001079 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001080 break;
1081 default:
1082 UNREACHABLE();
1083 }
1084
1085 return name;
1086}
1087
1088const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1089{
1090 if (method == TextureFunction::SIZE)
1091 {
1092 switch (sampler)
1093 {
1094 case EbtSampler2D:
1095 case EbtISampler2D:
1096 case EbtUSampler2D:
1097 case EbtSampler2DShadow:
1098 case EbtSamplerCube:
1099 case EbtISamplerCube:
1100 case EbtUSamplerCube:
1101 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001102 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001103 case EbtSampler2DMS:
1104 case EbtISampler2DMS:
1105 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001106 return "int2";
1107 case EbtSampler3D:
1108 case EbtISampler3D:
1109 case EbtUSampler3D:
1110 case EbtSampler2DArray:
1111 case EbtISampler2DArray:
1112 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001113 case EbtSampler2DMSArray:
1114 case EbtISampler2DMSArray:
1115 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001116 case EbtSampler2DArrayShadow:
1117 return "int3";
1118 default:
1119 UNREACHABLE();
1120 }
1121 }
1122 else // Sampling function
1123 {
1124 switch (sampler)
1125 {
1126 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001127 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001128 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001129 case EbtSampler3D:
1130 case EbtSamplerCube:
1131 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001132 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001133 return "float4";
1134 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001135 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001136 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001137 case EbtISampler3D:
1138 case EbtISamplerCube:
1139 case EbtISampler2DArray:
1140 return "int4";
1141 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001142 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001143 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001144 case EbtUSampler3D:
1145 case EbtUSamplerCube:
1146 case EbtUSampler2DArray:
1147 return "uint4";
1148 case EbtSampler2DShadow:
1149 case EbtSamplerCubeShadow:
1150 case EbtSampler2DArrayShadow:
1151 return "float";
1152 default:
1153 UNREACHABLE();
1154 }
1155 }
1156 return "";
1157}
1158
1159bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1160{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001161 return std::tie(sampler, coords, proj, offset, method) <
1162 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001163}
1164
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001165ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1166 TBasicType samplerType,
1167 int coords,
1168 size_t argumentCount,
1169 bool lod0,
1170 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001171{
1172 TextureFunction textureFunction;
1173 textureFunction.sampler = samplerType;
1174 textureFunction.coords = coords;
1175 textureFunction.method = TextureFunction::IMPLICIT;
1176 textureFunction.proj = false;
1177 textureFunction.offset = false;
1178
1179 if (name == "texture2D" || name == "textureCube" || name == "texture")
1180 {
1181 textureFunction.method = TextureFunction::IMPLICIT;
1182 }
1183 else if (name == "texture2DProj" || name == "textureProj")
1184 {
1185 textureFunction.method = TextureFunction::IMPLICIT;
1186 textureFunction.proj = true;
1187 }
1188 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1189 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1190 {
1191 textureFunction.method = TextureFunction::LOD;
1192 }
1193 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1194 name == "texture2DProjLodEXT")
1195 {
1196 textureFunction.method = TextureFunction::LOD;
1197 textureFunction.proj = true;
1198 }
1199 else if (name == "textureSize")
1200 {
1201 textureFunction.method = TextureFunction::SIZE;
1202 }
1203 else if (name == "textureOffset")
1204 {
1205 textureFunction.method = TextureFunction::IMPLICIT;
1206 textureFunction.offset = true;
1207 }
1208 else if (name == "textureProjOffset")
1209 {
1210 textureFunction.method = TextureFunction::IMPLICIT;
1211 textureFunction.offset = true;
1212 textureFunction.proj = true;
1213 }
1214 else if (name == "textureLodOffset")
1215 {
1216 textureFunction.method = TextureFunction::LOD;
1217 textureFunction.offset = true;
1218 }
1219 else if (name == "textureProjLodOffset")
1220 {
1221 textureFunction.method = TextureFunction::LOD;
1222 textureFunction.proj = true;
1223 textureFunction.offset = true;
1224 }
1225 else if (name == "texelFetch")
1226 {
1227 textureFunction.method = TextureFunction::FETCH;
1228 }
1229 else if (name == "texelFetchOffset")
1230 {
1231 textureFunction.method = TextureFunction::FETCH;
1232 textureFunction.offset = true;
1233 }
1234 else if (name == "textureGrad" || name == "texture2DGradEXT")
1235 {
1236 textureFunction.method = TextureFunction::GRAD;
1237 }
1238 else if (name == "textureGradOffset")
1239 {
1240 textureFunction.method = TextureFunction::GRAD;
1241 textureFunction.offset = true;
1242 }
1243 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1244 name == "textureCubeGradEXT")
1245 {
1246 textureFunction.method = TextureFunction::GRAD;
1247 textureFunction.proj = true;
1248 }
1249 else if (name == "textureProjGradOffset")
1250 {
1251 textureFunction.method = TextureFunction::GRAD;
1252 textureFunction.proj = true;
1253 textureFunction.offset = true;
1254 }
1255 else
1256 UNREACHABLE();
1257
1258 if (textureFunction.method ==
1259 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1260 {
1261 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1262
1263 if (textureFunction.offset)
1264 {
1265 mandatoryArgumentCount++;
1266 }
1267
1268 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1269
1270 if (lod0 || shaderType == GL_VERTEX_SHADER)
1271 {
1272 if (bias)
1273 {
1274 textureFunction.method = TextureFunction::LOD0BIAS;
1275 }
1276 else
1277 {
1278 textureFunction.method = TextureFunction::LOD0;
1279 }
1280 }
1281 else if (bias)
1282 {
1283 textureFunction.method = TextureFunction::BIAS;
1284 }
1285 }
1286
1287 mUsesTexture.insert(textureFunction);
1288 return textureFunction.name();
1289}
1290
Geoff Lang1fe74c72016-08-25 13:23:01 -04001291void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1292 const ShShaderOutput outputType,
1293 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001294{
1295 for (const TextureFunction &textureFunction : mUsesTexture)
1296 {
1297 // Function header
1298 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1299
1300 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1301
1302 out << ")\n"
1303 "{\n";
1304
1305 // In some cases we use a variable to store the texture/sampler objects, but to work around
1306 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1307 // sampling we need to call the function directly on references to the texture and sampler
1308 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1309 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001310 ImmutableString textureReference("");
1311 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001312 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1313
1314 if (textureFunction.method == TextureFunction::SIZE)
1315 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001316 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1317 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001318 }
1319 else
1320 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001321 ImmutableString texCoordX("t.x");
1322 ImmutableString texCoordY("t.y");
1323 ImmutableString texCoordZ("t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001324 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1325 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1326 textureReference, &texCoordX, &texCoordY,
1327 &texCoordZ);
1328 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1329 textureReference, samplerReference,
1330 texCoordX, texCoordY, texCoordZ);
1331 }
1332
1333 out << "}\n"
1334 "\n";
1335 }
1336}
1337
1338} // namespace sh