blob: ad28eea74a41a6631ff78bb1a4b555b8c5115090 [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;
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800384 case TextureFunctionHLSL::TextureFunction::GATHER:
385 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300386 default:
387 UNREACHABLE();
388 }
389
Jiawei Shao19b51d22018-09-19 15:14:45 +0800390 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
391 IsShadowSampler(textureFunction.sampler))
392 {
393 out << ", float refZ";
394 }
395
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300396 if (textureFunction.offset)
397 {
398 switch (textureFunction.sampler)
399 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300400 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300401 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300402 case EbtUSampler3D:
403 out << ", int3 offset";
404 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300405 case EbtSampler2D:
406 case EbtSampler2DArray:
407 case EbtISampler2D:
408 case EbtISampler2DArray:
409 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300410 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300411 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300412 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400413 case EbtSamplerExternalOES:
414 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300415 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300416 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300417 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300418 UNREACHABLE();
419 }
420 }
421
422 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
423 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
424 {
425 out << ", float bias";
426 }
Jiawei Shao19b51d22018-09-19 15:14:45 +0800427 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
428 !IsShadowSampler(textureFunction.sampler))
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800429 {
430 out << ", int comp = 0";
431 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300432}
433
434void GetTextureReference(TInfoSinkBase &out,
435 const TextureFunctionHLSL::TextureFunction &textureFunction,
436 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200437 ImmutableString *textureReference,
438 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300439{
440 if (outputType == SH_HLSL_4_1_OUTPUT)
441 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200442 static const ImmutableString kTexturesStr("textures");
443 static const ImmutableString kSamplersStr("samplers");
444 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
445 static const ImmutableString kTextureIndexStr("[textureIndex]");
446 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
447 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
448
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300449 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
450 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200451 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
452 kSamplerIndexStr.length());
453 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
454 *textureReference = textureRefBuilder;
455 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
456 kSamplerIndexStr.length());
457 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
458 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300459 }
460 else
461 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200462 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
463 << suffix.data() << ";\n";
464 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
465 kTextureIndexStr.length());
466 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
467 *textureReference = textureRefBuilder;
468
469 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
470 << suffix.data() << ";\n";
471 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
472 kSamplerArrayIndexStr.length());
473 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
474 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300475 }
476 }
477 else
478 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200479 *textureReference = ImmutableString("x");
480 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300481 }
482}
483
484void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
485 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200486 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400487 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300488{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000489 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400490 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000491 out << " uint width; uint height; uint samples;\n"
492 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400493 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300494 else if (IsSampler2DMSArray(textureFunction.sampler))
495 {
496 out << " uint width; uint height; uint depth; uint samples;\n"
497 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
498 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400499 else
500 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000501 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400502 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000503 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400504 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000505 else
506 {
507 out << " int baseLevel = 0;\n";
508 }
509
510 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
511 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
512 {
513 // "depth" stores either the number of layers in an array texture or 3D depth
514 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
515 << " " << textureReference
516 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
517 << " width = max(width >> lod, 1);\n"
518 << " height = max(height >> lod, 1);\n";
519
520 if (!IsSamplerArray(textureFunction.sampler))
521 {
522 out << " depth = max(depth >> lod, 1);\n";
523 }
524 }
525 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
526 {
527 out << " uint width; uint height; uint numberOfLevels;\n"
528 << " " << textureReference
529 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
530 << " width = max(width >> lod, 1);\n"
531 << " height = max(height >> lod, 1);\n";
532 }
533 else
534 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300535 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300536
537 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
538 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000539 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300540 }
541 else
542 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000543 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300544 }
545}
546
547void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200548 ImmutableString *texCoordX,
549 ImmutableString *texCoordY,
550 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300551{
552 if (textureFunction.proj)
553 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200554 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300555 switch (textureFunction.coords)
556 {
557 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200558 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300559 break;
560 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200561 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300562 break;
563 default:
564 UNREACHABLE();
565 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200566 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
567 texCoordXBuilder << '(' << *texCoordX << proj << ')';
568 *texCoordX = texCoordXBuilder;
569 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
570 texCoordYBuilder << '(' << *texCoordY << proj << ')';
571 *texCoordY = texCoordYBuilder;
572 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
573 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
574 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300575 }
576}
577
578void OutputIntegerTextureSampleFunctionComputations(
579 TInfoSinkBase &out,
580 const TextureFunctionHLSL::TextureFunction &textureFunction,
581 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200582 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200583 ImmutableString *texCoordX,
584 ImmutableString *texCoordY,
585 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300586{
587 if (!IsIntegerSampler(textureFunction.sampler))
588 {
589 return;
590 }
591 if (IsSamplerCube(textureFunction.sampler))
592 {
593 out << " float width; float height; float layers; float levels;\n";
594
595 out << " uint mip = 0;\n";
596
597 out << " " << textureReference
598 << ".GetDimensions(mip, width, height, layers, levels);\n";
599
600 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
601 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
602 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
603 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
604 "(zMajor && t.z < 0.0f);\n";
605
606 // FACE_POSITIVE_X = 000b
607 // FACE_NEGATIVE_X = 001b
608 // FACE_POSITIVE_Y = 010b
609 // FACE_NEGATIVE_Y = 011b
610 // FACE_POSITIVE_Z = 100b
611 // FACE_NEGATIVE_Z = 101b
612 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
613
614 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
615 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
616 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
617
618 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
619 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
620
621 // Mip level computation.
622 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
623 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
624 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
625 {
626 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
627 {
628 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
629 " float2 dx = ddx(tSized);\n"
630 " float2 dy = ddy(tSized);\n"
631 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
632 }
633 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
634 {
635 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
636 // derivatives of P are assumed to be in the coordinate system used before
637 // texture coordinates are projected onto the appropriate cube face."
638 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
639 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
640 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
641 // Determine the derivatives of u, v and m
642 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
643 ": ddx[0]);\n"
644 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
645 ": ddy[0]);\n"
646 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
647 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
648 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
649 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
650 // Now determine the derivatives of the face coordinates, using the
651 // derivatives calculated above.
652 // d / dx (u(x) * 0.5 / m(x) + 0.5)
653 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
654 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
655 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
656 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
657 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
658 " float2 sizeVec = float2(width, height);\n"
659 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
660 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
661 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
662 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
663 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
664 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
665 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
666 }
667 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
668 << " " << textureReference
669 << ".GetDimensions(mip, width, height, layers, levels);\n";
670 }
671
672 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200673 static const ImmutableString kXPrefix("int(floor(width * frac(");
674 static const ImmutableString kYPrefix("int(floor(height * frac(");
675 static const ImmutableString kSuffix(")))");
676 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
677 kSuffix.length());
678 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
679 *texCoordX = texCoordXBuilder;
680 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
681 kSuffix.length());
682 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
683 *texCoordY = texCoordYBuilder;
684 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300685 }
686 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
687 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300688 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300689 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300690 out << " float width; float height; float layers; float levels;\n";
691
692 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300693 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300694 out << " uint mip = 0;\n";
695 }
696 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
697 {
698 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300699 }
700 else
701 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300702
703 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300704 << ".GetDimensions(0, width, height, layers, levels);\n";
705 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
706 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
707 {
708 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
709 " float dx = length(ddx(tSized));\n"
710 " float dy = length(ddy(tSized));\n"
711 " float lod = log2(max(dx, dy));\n";
712
713 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
714 {
715 out << " lod += bias;\n";
716 }
717 }
718 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
719 {
720 out << " float2 sizeVec = float2(width, height);\n"
721 " float2 sizeDdx = ddx * sizeVec;\n"
722 " float2 sizeDdy = ddy * sizeVec;\n"
723 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
724 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
725 }
726
727 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300728 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300729
730 out << " " << textureReference
731 << ".GetDimensions(mip, width, height, layers, levels);\n";
732 }
733 else if (IsSampler2D(textureFunction.sampler))
734 {
735 out << " float width; float height; float levels;\n";
736
737 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
738 {
739 out << " uint mip = 0;\n";
740 }
741 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
742 {
743 out << " uint mip = bias;\n";
744 }
745 else
746 {
747 out << " " << textureReference << ".GetDimensions(0, width, height, levels);\n";
748
749 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
750 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
751 {
752 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
753 " float dx = length(ddx(tSized));\n"
754 " float dy = length(ddy(tSized));\n"
755 " float lod = log2(max(dx, dy));\n";
756
757 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
758 {
759 out << " lod += bias;\n";
760 }
761 }
762 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
763 {
764 out << " float2 sizeVec = float2(width, height);\n"
765 " float2 sizeDdx = ddx * sizeVec;\n"
766 " float2 sizeDdy = ddy * sizeVec;\n"
767 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
768 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
769 }
770
771 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
772 }
773
774 out << " " << textureReference << ".GetDimensions(mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300775 }
776 else if (IsSampler3D(textureFunction.sampler))
777 {
778 out << " float width; float height; float depth; float levels;\n";
779
780 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
781 {
782 out << " uint mip = 0;\n";
783 }
784 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
785 {
786 out << " uint mip = bias;\n";
787 }
788 else
789 {
790 out << " " << textureReference
791 << ".GetDimensions(0, width, height, depth, levels);\n";
792
793 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
794 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
795 {
796 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
797 " float dx = length(ddx(tSized));\n"
798 " float dy = length(ddy(tSized));\n"
799 " float lod = log2(max(dx, dy));\n";
800
801 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
802 {
803 out << " lod += bias;\n";
804 }
805 }
806 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
807 {
808 out << " float3 sizeVec = float3(width, height, depth);\n"
809 " float3 sizeDdx = ddx * sizeVec;\n"
810 " float3 sizeDdy = ddy * sizeVec;\n"
811 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
812 "sizeDdy))) * 0.5f;\n";
813 }
814
815 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
816 }
817
818 out << " " << textureReference
819 << ".GetDimensions(mip, width, height, depth, levels);\n";
820 }
821 else
822 UNREACHABLE();
823
824 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
825 }
826}
827
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800828void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
829 const TextureFunctionHLSL::TextureFunction &textureFunction,
830 ShShaderOutput outputType,
831 const ImmutableString &textureReference,
832 const ImmutableString &samplerReference,
833 const ImmutableString &texCoordX,
834 const ImmutableString &texCoordY,
835 const ImmutableString &texCoordZ)
836{
837 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
838 ImmutableString samplerCoordTypeString(
839 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
840 ImmutableStringBuilder samplerCoordBuilder(
841 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
842 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
843
844 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
845 if (hlslCoords >= 3)
846 {
847 if (textureFunction.coords < 3)
848 {
849 samplerCoordBuilder << ", 0";
850 }
851 else
852 {
853 samplerCoordBuilder << ", " << texCoordZ;
854 }
855 }
856 samplerCoordBuilder << ")";
857
858 ImmutableString samplerCoordString(samplerCoordBuilder);
859
Jiawei Shao19b51d22018-09-19 15:14:45 +0800860 if (IsShadowSampler(textureFunction.sampler))
861 {
862 out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
863 << samplerCoordString << ", refZ";
864 if (textureFunction.offset)
865 {
866 out << ", offset";
867 }
868 out << ");\n";
869 return;
870 }
871
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800872 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
873 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
874
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800875 out << " switch(comp)\n"
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800876 " {\n";
877 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
878 {
879 out << " case " << component << ":\n"
880 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
881 << "(" << samplerReference << ", " << samplerCoordString;
882 if (textureFunction.offset)
883 {
884 out << ", offset";
885 }
886 out << ");\n";
887 }
888
889 out << " default:\n"
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800890 " return float4(0.0, 0.0, 0.0, 1.0);\n"
891 " }\n";
892}
893
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300894void OutputTextureSampleFunctionReturnStatement(
895 TInfoSinkBase &out,
896 const TextureFunctionHLSL::TextureFunction &textureFunction,
897 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200898 const ImmutableString &textureReference,
899 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200900 const ImmutableString &texCoordX,
901 const ImmutableString &texCoordY,
902 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300903{
904 out << " return ";
905
906 // HLSL intrinsic
907 if (outputType == SH_HLSL_3_0_OUTPUT)
908 {
909 switch (textureFunction.sampler)
910 {
911 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400912 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300913 out << "tex2D";
914 break;
915 case EbtSamplerCube:
916 out << "texCUBE";
917 break;
918 default:
919 UNREACHABLE();
920 }
921
922 switch (textureFunction.method)
923 {
924 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
925 out << "(" << samplerReference << ", ";
926 break;
927 case TextureFunctionHLSL::TextureFunction::BIAS:
928 out << "bias(" << samplerReference << ", ";
929 break;
930 case TextureFunctionHLSL::TextureFunction::LOD:
931 out << "lod(" << samplerReference << ", ";
932 break;
933 case TextureFunctionHLSL::TextureFunction::LOD0:
934 out << "lod(" << samplerReference << ", ";
935 break;
936 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
937 out << "lod(" << samplerReference << ", ";
938 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400939 case TextureFunctionHLSL::TextureFunction::GRAD:
940 out << "grad(" << samplerReference << ", ";
941 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300942 default:
943 UNREACHABLE();
944 }
945 }
946 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
947 {
948 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
949 }
950 else
951 UNREACHABLE();
952
953 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
954
955 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
956 << texCoordY;
957
958 if (outputType == SH_HLSL_3_0_OUTPUT)
959 {
960 if (hlslCoords >= 3)
961 {
962 if (textureFunction.coords < 3)
963 {
964 out << ", 0";
965 }
966 else
967 {
968 out << ", " << texCoordZ;
969 }
970 }
971
972 if (hlslCoords == 4)
973 {
974 switch (textureFunction.method)
975 {
976 case TextureFunctionHLSL::TextureFunction::BIAS:
977 out << ", bias";
978 break;
979 case TextureFunctionHLSL::TextureFunction::LOD:
980 out << ", lod";
981 break;
982 case TextureFunctionHLSL::TextureFunction::LOD0:
983 out << ", 0";
984 break;
985 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
986 out << ", bias";
987 break;
988 default:
989 UNREACHABLE();
990 }
991 }
992
993 out << ")";
994 }
995 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
996 {
997 if (hlslCoords >= 3)
998 {
999 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
1000 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
1001 out << ", " << texCoordZ;
1002 }
1003
1004 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
1005 {
1006 if (IsIntegerSampler(textureFunction.sampler))
1007 {
1008 out << ", mip)";
1009 }
1010 else if (IsShadowSampler(textureFunction.sampler))
1011 {
1012 // Compare value
1013 if (textureFunction.proj)
1014 {
1015 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1016 // The resulting third component of P' in the shadow forms is used as
1017 // Dref
1018 out << "), " << texCoordZ;
1019 }
1020 else
1021 {
1022 switch (textureFunction.coords)
1023 {
1024 case 3:
1025 out << "), t.z";
1026 break;
1027 case 4:
1028 out << "), t.w";
1029 break;
1030 default:
1031 UNREACHABLE();
1032 }
1033 }
1034 }
1035 else
1036 {
1037 out << "), ddx, ddy";
1038 }
1039 }
1040 else if (IsIntegerSampler(textureFunction.sampler) ||
1041 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1042 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001043 if (IsSampler2DMS(textureFunction.sampler) ||
1044 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001045 out << "), index";
1046 else
1047 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001048 }
1049 else if (IsShadowSampler(textureFunction.sampler))
1050 {
1051 // Compare value
1052 if (textureFunction.proj)
1053 {
1054 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1055 // The resulting third component of P' in the shadow forms is used as Dref
1056 out << "), " << texCoordZ;
1057 }
1058 else
1059 {
1060 switch (textureFunction.coords)
1061 {
1062 case 3:
1063 out << "), t.z";
1064 break;
1065 case 4:
1066 out << "), t.w";
1067 break;
1068 default:
1069 UNREACHABLE();
1070 }
1071 }
1072 }
1073 else
1074 {
1075 switch (textureFunction.method)
1076 {
1077 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1078 out << ")";
1079 break;
1080 case TextureFunctionHLSL::TextureFunction::BIAS:
1081 out << "), bias";
1082 break;
1083 case TextureFunctionHLSL::TextureFunction::LOD:
1084 out << "), lod";
1085 break;
1086 case TextureFunctionHLSL::TextureFunction::LOD0:
1087 out << "), 0";
1088 break;
1089 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1090 out << "), bias";
1091 break;
1092 default:
1093 UNREACHABLE();
1094 }
1095 }
1096
1097 if (textureFunction.offset &&
1098 (!IsIntegerSampler(textureFunction.sampler) ||
1099 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1100 {
1101 out << ", offset";
1102 }
1103 }
1104 else
1105 UNREACHABLE();
1106
1107 out << ");\n"; // Close the sample function call and return statement
1108}
1109
1110} // Anonymous namespace
1111
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001112ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001113{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001114 static const ImmutableString kGlTextureName("gl_texture");
1115
1116 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1117
1118 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1119
1120 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001121
1122 // We need to include full the sampler type in the function name to make the signature unique
1123 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001124 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001125
1126 if (proj)
1127 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001128 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001129 }
1130
1131 if (offset)
1132 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001133 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001134 }
1135
1136 switch (method)
1137 {
1138 case IMPLICIT:
1139 break;
1140 case BIAS:
1141 break; // Extra parameter makes the signature unique
1142 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001143 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001144 break;
1145 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001146 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001147 break;
1148 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001149 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001150 break; // Extra parameter makes the signature unique
1151 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001152 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001153 break;
1154 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001155 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001156 break;
1157 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001158 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001159 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001160 case GATHER:
1161 name << "Gather";
1162 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001163 default:
1164 UNREACHABLE();
1165 }
1166
1167 return name;
1168}
1169
1170const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1171{
1172 if (method == TextureFunction::SIZE)
1173 {
1174 switch (sampler)
1175 {
1176 case EbtSampler2D:
1177 case EbtISampler2D:
1178 case EbtUSampler2D:
1179 case EbtSampler2DShadow:
1180 case EbtSamplerCube:
1181 case EbtISamplerCube:
1182 case EbtUSamplerCube:
1183 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001184 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001185 case EbtSampler2DMS:
1186 case EbtISampler2DMS:
1187 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001188 return "int2";
1189 case EbtSampler3D:
1190 case EbtISampler3D:
1191 case EbtUSampler3D:
1192 case EbtSampler2DArray:
1193 case EbtISampler2DArray:
1194 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001195 case EbtSampler2DMSArray:
1196 case EbtISampler2DMSArray:
1197 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001198 case EbtSampler2DArrayShadow:
1199 return "int3";
1200 default:
1201 UNREACHABLE();
1202 }
1203 }
1204 else // Sampling function
1205 {
1206 switch (sampler)
1207 {
1208 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001209 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001210 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001211 case EbtSampler3D:
1212 case EbtSamplerCube:
1213 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001214 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001215 return "float4";
1216 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001217 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001218 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001219 case EbtISampler3D:
1220 case EbtISamplerCube:
1221 case EbtISampler2DArray:
1222 return "int4";
1223 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001224 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001225 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001226 case EbtUSampler3D:
1227 case EbtUSamplerCube:
1228 case EbtUSampler2DArray:
1229 return "uint4";
1230 case EbtSampler2DShadow:
1231 case EbtSamplerCubeShadow:
1232 case EbtSampler2DArrayShadow:
Jiawei Shao19b51d22018-09-19 15:14:45 +08001233 if (method == TextureFunctionHLSL::TextureFunction::GATHER)
1234 {
1235 return "float4";
1236 }
1237 else
1238 {
1239 return "float";
1240 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001241 default:
1242 UNREACHABLE();
1243 }
1244 }
1245 return "";
1246}
1247
1248bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1249{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001250 return std::tie(sampler, coords, proj, offset, method) <
1251 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001252}
1253
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001254ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1255 TBasicType samplerType,
1256 int coords,
1257 size_t argumentCount,
1258 bool lod0,
1259 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001260{
1261 TextureFunction textureFunction;
1262 textureFunction.sampler = samplerType;
1263 textureFunction.coords = coords;
1264 textureFunction.method = TextureFunction::IMPLICIT;
1265 textureFunction.proj = false;
1266 textureFunction.offset = false;
1267
1268 if (name == "texture2D" || name == "textureCube" || name == "texture")
1269 {
1270 textureFunction.method = TextureFunction::IMPLICIT;
1271 }
1272 else if (name == "texture2DProj" || name == "textureProj")
1273 {
1274 textureFunction.method = TextureFunction::IMPLICIT;
1275 textureFunction.proj = true;
1276 }
1277 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1278 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1279 {
1280 textureFunction.method = TextureFunction::LOD;
1281 }
1282 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1283 name == "texture2DProjLodEXT")
1284 {
1285 textureFunction.method = TextureFunction::LOD;
1286 textureFunction.proj = true;
1287 }
1288 else if (name == "textureSize")
1289 {
1290 textureFunction.method = TextureFunction::SIZE;
1291 }
1292 else if (name == "textureOffset")
1293 {
1294 textureFunction.method = TextureFunction::IMPLICIT;
1295 textureFunction.offset = true;
1296 }
1297 else if (name == "textureProjOffset")
1298 {
1299 textureFunction.method = TextureFunction::IMPLICIT;
1300 textureFunction.offset = true;
1301 textureFunction.proj = true;
1302 }
1303 else if (name == "textureLodOffset")
1304 {
1305 textureFunction.method = TextureFunction::LOD;
1306 textureFunction.offset = true;
1307 }
1308 else if (name == "textureProjLodOffset")
1309 {
1310 textureFunction.method = TextureFunction::LOD;
1311 textureFunction.proj = true;
1312 textureFunction.offset = true;
1313 }
1314 else if (name == "texelFetch")
1315 {
1316 textureFunction.method = TextureFunction::FETCH;
1317 }
1318 else if (name == "texelFetchOffset")
1319 {
1320 textureFunction.method = TextureFunction::FETCH;
1321 textureFunction.offset = true;
1322 }
1323 else if (name == "textureGrad" || name == "texture2DGradEXT")
1324 {
1325 textureFunction.method = TextureFunction::GRAD;
1326 }
1327 else if (name == "textureGradOffset")
1328 {
1329 textureFunction.method = TextureFunction::GRAD;
1330 textureFunction.offset = true;
1331 }
1332 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1333 name == "textureCubeGradEXT")
1334 {
1335 textureFunction.method = TextureFunction::GRAD;
1336 textureFunction.proj = true;
1337 }
1338 else if (name == "textureProjGradOffset")
1339 {
1340 textureFunction.method = TextureFunction::GRAD;
1341 textureFunction.proj = true;
1342 textureFunction.offset = true;
1343 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001344 else if (name == "textureGather")
1345 {
1346 textureFunction.method = TextureFunction::GATHER;
1347 }
Jiawei Shaocf8ad762018-09-21 09:11:35 +08001348 else if (name == "textureGatherOffset")
1349 {
1350 textureFunction.method = TextureFunction::GATHER;
1351 textureFunction.offset = true;
1352 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001353 else
1354 UNREACHABLE();
1355
1356 if (textureFunction.method ==
1357 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1358 {
1359 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1360
1361 if (textureFunction.offset)
1362 {
1363 mandatoryArgumentCount++;
1364 }
1365
1366 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1367
1368 if (lod0 || shaderType == GL_VERTEX_SHADER)
1369 {
1370 if (bias)
1371 {
1372 textureFunction.method = TextureFunction::LOD0BIAS;
1373 }
1374 else
1375 {
1376 textureFunction.method = TextureFunction::LOD0;
1377 }
1378 }
1379 else if (bias)
1380 {
1381 textureFunction.method = TextureFunction::BIAS;
1382 }
1383 }
1384
1385 mUsesTexture.insert(textureFunction);
1386 return textureFunction.name();
1387}
1388
Geoff Lang1fe74c72016-08-25 13:23:01 -04001389void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1390 const ShShaderOutput outputType,
1391 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001392{
1393 for (const TextureFunction &textureFunction : mUsesTexture)
1394 {
1395 // Function header
1396 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1397
1398 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1399
1400 out << ")\n"
1401 "{\n";
1402
1403 // In some cases we use a variable to store the texture/sampler objects, but to work around
1404 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1405 // sampling we need to call the function directly on references to the texture and sampler
1406 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1407 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001408 ImmutableString textureReference("");
1409 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001410 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1411
1412 if (textureFunction.method == TextureFunction::SIZE)
1413 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001414 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1415 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001416 }
1417 else
1418 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001419 ImmutableString texCoordX("t.x");
1420 ImmutableString texCoordY("t.y");
1421 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001422 if (textureFunction.method == TextureFunction::GATHER)
1423 {
1424 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1425 samplerReference, texCoordX, texCoordY, texCoordZ);
1426 }
1427 else
1428 {
1429 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1430 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1431 textureReference, &texCoordX,
1432 &texCoordY, &texCoordZ);
1433 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1434 textureReference, samplerReference,
1435 texCoordX, texCoordY, texCoordZ);
1436 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001437 }
1438
1439 out << "}\n"
1440 "\n";
1441 }
1442}
1443
1444} // namespace sh