blob: 164922f064aa6ad080e53df9be8cc99eece2c40c [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
390 if (textureFunction.offset)
391 {
392 switch (textureFunction.sampler)
393 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300394 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300395 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300396 case EbtUSampler3D:
397 out << ", int3 offset";
398 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300399 case EbtSampler2D:
400 case EbtSampler2DArray:
401 case EbtISampler2D:
402 case EbtISampler2DArray:
403 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300404 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300405 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300406 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400407 case EbtSamplerExternalOES:
408 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300409 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300410 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300411 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300412 UNREACHABLE();
413 }
414 }
415
416 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
417 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
418 {
419 out << ", float bias";
420 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800421 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER)
422 {
423 out << ", int comp = 0";
424 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300425}
426
427void GetTextureReference(TInfoSinkBase &out,
428 const TextureFunctionHLSL::TextureFunction &textureFunction,
429 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200430 ImmutableString *textureReference,
431 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300432{
433 if (outputType == SH_HLSL_4_1_OUTPUT)
434 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200435 static const ImmutableString kTexturesStr("textures");
436 static const ImmutableString kSamplersStr("samplers");
437 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
438 static const ImmutableString kTextureIndexStr("[textureIndex]");
439 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
440 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
441
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300442 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
443 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200444 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
445 kSamplerIndexStr.length());
446 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
447 *textureReference = textureRefBuilder;
448 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
449 kSamplerIndexStr.length());
450 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
451 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300452 }
453 else
454 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200455 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
456 << suffix.data() << ";\n";
457 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
458 kTextureIndexStr.length());
459 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
460 *textureReference = textureRefBuilder;
461
462 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
463 << suffix.data() << ";\n";
464 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
465 kSamplerArrayIndexStr.length());
466 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
467 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300468 }
469 }
470 else
471 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200472 *textureReference = ImmutableString("x");
473 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300474 }
475}
476
477void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
478 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200479 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400480 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300481{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000482 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400483 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000484 out << " uint width; uint height; uint samples;\n"
485 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400486 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300487 else if (IsSampler2DMSArray(textureFunction.sampler))
488 {
489 out << " uint width; uint height; uint depth; uint samples;\n"
490 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
491 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400492 else
493 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000494 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400495 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000496 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400497 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000498 else
499 {
500 out << " int baseLevel = 0;\n";
501 }
502
503 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
504 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
505 {
506 // "depth" stores either the number of layers in an array texture or 3D depth
507 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
508 << " " << textureReference
509 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
510 << " width = max(width >> lod, 1);\n"
511 << " height = max(height >> lod, 1);\n";
512
513 if (!IsSamplerArray(textureFunction.sampler))
514 {
515 out << " depth = max(depth >> lod, 1);\n";
516 }
517 }
518 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
519 {
520 out << " uint width; uint height; uint numberOfLevels;\n"
521 << " " << textureReference
522 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
523 << " width = max(width >> lod, 1);\n"
524 << " height = max(height >> lod, 1);\n";
525 }
526 else
527 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300528 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300529
530 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
531 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000532 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300533 }
534 else
535 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000536 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300537 }
538}
539
540void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200541 ImmutableString *texCoordX,
542 ImmutableString *texCoordY,
543 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300544{
545 if (textureFunction.proj)
546 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200547 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300548 switch (textureFunction.coords)
549 {
550 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200551 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300552 break;
553 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200554 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300555 break;
556 default:
557 UNREACHABLE();
558 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200559 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
560 texCoordXBuilder << '(' << *texCoordX << proj << ')';
561 *texCoordX = texCoordXBuilder;
562 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
563 texCoordYBuilder << '(' << *texCoordY << proj << ')';
564 *texCoordY = texCoordYBuilder;
565 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
566 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
567 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300568 }
569}
570
571void OutputIntegerTextureSampleFunctionComputations(
572 TInfoSinkBase &out,
573 const TextureFunctionHLSL::TextureFunction &textureFunction,
574 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200575 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200576 ImmutableString *texCoordX,
577 ImmutableString *texCoordY,
578 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300579{
580 if (!IsIntegerSampler(textureFunction.sampler))
581 {
582 return;
583 }
584 if (IsSamplerCube(textureFunction.sampler))
585 {
586 out << " float width; float height; float layers; float levels;\n";
587
588 out << " uint mip = 0;\n";
589
590 out << " " << textureReference
591 << ".GetDimensions(mip, width, height, layers, levels);\n";
592
593 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
594 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
595 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
596 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
597 "(zMajor && t.z < 0.0f);\n";
598
599 // FACE_POSITIVE_X = 000b
600 // FACE_NEGATIVE_X = 001b
601 // FACE_POSITIVE_Y = 010b
602 // FACE_NEGATIVE_Y = 011b
603 // FACE_POSITIVE_Z = 100b
604 // FACE_NEGATIVE_Z = 101b
605 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
606
607 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
608 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
609 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
610
611 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
612 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
613
614 // Mip level computation.
615 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
616 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
617 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
618 {
619 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
620 {
621 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
622 " float2 dx = ddx(tSized);\n"
623 " float2 dy = ddy(tSized);\n"
624 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
625 }
626 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
627 {
628 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
629 // derivatives of P are assumed to be in the coordinate system used before
630 // texture coordinates are projected onto the appropriate cube face."
631 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
632 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
633 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
634 // Determine the derivatives of u, v and m
635 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
636 ": ddx[0]);\n"
637 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
638 ": ddy[0]);\n"
639 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
640 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
641 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
642 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
643 // Now determine the derivatives of the face coordinates, using the
644 // derivatives calculated above.
645 // d / dx (u(x) * 0.5 / m(x) + 0.5)
646 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
647 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
648 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
649 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
650 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
651 " float2 sizeVec = float2(width, height);\n"
652 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
653 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
654 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
655 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
656 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
657 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
658 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
659 }
660 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
661 << " " << textureReference
662 << ".GetDimensions(mip, width, height, layers, levels);\n";
663 }
664
665 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200666 static const ImmutableString kXPrefix("int(floor(width * frac(");
667 static const ImmutableString kYPrefix("int(floor(height * frac(");
668 static const ImmutableString kSuffix(")))");
669 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
670 kSuffix.length());
671 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
672 *texCoordX = texCoordXBuilder;
673 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
674 kSuffix.length());
675 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
676 *texCoordY = texCoordYBuilder;
677 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300678 }
679 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
680 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300681 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300682 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300683 out << " float width; float height; float layers; float levels;\n";
684
685 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300686 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300687 out << " uint mip = 0;\n";
688 }
689 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
690 {
691 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300692 }
693 else
694 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300695
696 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300697 << ".GetDimensions(0, width, height, layers, levels);\n";
698 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
699 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
700 {
701 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
702 " float dx = length(ddx(tSized));\n"
703 " float dy = length(ddy(tSized));\n"
704 " float lod = log2(max(dx, dy));\n";
705
706 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
707 {
708 out << " lod += bias;\n";
709 }
710 }
711 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
712 {
713 out << " float2 sizeVec = float2(width, height);\n"
714 " float2 sizeDdx = ddx * sizeVec;\n"
715 " float2 sizeDdy = ddy * sizeVec;\n"
716 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
717 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
718 }
719
720 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300721 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300722
723 out << " " << textureReference
724 << ".GetDimensions(mip, width, height, layers, levels);\n";
725 }
726 else if (IsSampler2D(textureFunction.sampler))
727 {
728 out << " float width; float height; float levels;\n";
729
730 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
731 {
732 out << " uint mip = 0;\n";
733 }
734 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
735 {
736 out << " uint mip = bias;\n";
737 }
738 else
739 {
740 out << " " << textureReference << ".GetDimensions(0, width, height, levels);\n";
741
742 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
743 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
744 {
745 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
746 " float dx = length(ddx(tSized));\n"
747 " float dy = length(ddy(tSized));\n"
748 " float lod = log2(max(dx, dy));\n";
749
750 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
751 {
752 out << " lod += bias;\n";
753 }
754 }
755 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
756 {
757 out << " float2 sizeVec = float2(width, height);\n"
758 " float2 sizeDdx = ddx * sizeVec;\n"
759 " float2 sizeDdy = ddy * sizeVec;\n"
760 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
761 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
762 }
763
764 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
765 }
766
767 out << " " << textureReference << ".GetDimensions(mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300768 }
769 else if (IsSampler3D(textureFunction.sampler))
770 {
771 out << " float width; float height; float depth; float levels;\n";
772
773 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
774 {
775 out << " uint mip = 0;\n";
776 }
777 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
778 {
779 out << " uint mip = bias;\n";
780 }
781 else
782 {
783 out << " " << textureReference
784 << ".GetDimensions(0, width, height, depth, levels);\n";
785
786 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
787 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
788 {
789 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
790 " float dx = length(ddx(tSized));\n"
791 " float dy = length(ddy(tSized));\n"
792 " float lod = log2(max(dx, dy));\n";
793
794 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
795 {
796 out << " lod += bias;\n";
797 }
798 }
799 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
800 {
801 out << " float3 sizeVec = float3(width, height, depth);\n"
802 " float3 sizeDdx = ddx * sizeVec;\n"
803 " float3 sizeDdy = ddy * sizeVec;\n"
804 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
805 "sizeDdy))) * 0.5f;\n";
806 }
807
808 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
809 }
810
811 out << " " << textureReference
812 << ".GetDimensions(mip, width, height, depth, levels);\n";
813 }
814 else
815 UNREACHABLE();
816
817 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
818 }
819}
820
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800821void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
822 const TextureFunctionHLSL::TextureFunction &textureFunction,
823 ShShaderOutput outputType,
824 const ImmutableString &textureReference,
825 const ImmutableString &samplerReference,
826 const ImmutableString &texCoordX,
827 const ImmutableString &texCoordY,
828 const ImmutableString &texCoordZ)
829{
830 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
831 ImmutableString samplerCoordTypeString(
832 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
833 ImmutableStringBuilder samplerCoordBuilder(
834 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
835 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
836
837 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
838 if (hlslCoords >= 3)
839 {
840 if (textureFunction.coords < 3)
841 {
842 samplerCoordBuilder << ", 0";
843 }
844 else
845 {
846 samplerCoordBuilder << ", " << texCoordZ;
847 }
848 }
849 samplerCoordBuilder << ")";
850
851 ImmutableString samplerCoordString(samplerCoordBuilder);
852
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800853 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
854 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
855
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800856 out << " switch(comp)\n"
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800857 " {\n";
858 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
859 {
860 out << " case " << component << ":\n"
861 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
862 << "(" << samplerReference << ", " << samplerCoordString;
863 if (textureFunction.offset)
864 {
865 out << ", offset";
866 }
867 out << ");\n";
868 }
869
870 out << " default:\n"
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800871 " return float4(0.0, 0.0, 0.0, 1.0);\n"
872 " }\n";
873}
874
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300875void OutputTextureSampleFunctionReturnStatement(
876 TInfoSinkBase &out,
877 const TextureFunctionHLSL::TextureFunction &textureFunction,
878 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200879 const ImmutableString &textureReference,
880 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200881 const ImmutableString &texCoordX,
882 const ImmutableString &texCoordY,
883 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300884{
885 out << " return ";
886
887 // HLSL intrinsic
888 if (outputType == SH_HLSL_3_0_OUTPUT)
889 {
890 switch (textureFunction.sampler)
891 {
892 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400893 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300894 out << "tex2D";
895 break;
896 case EbtSamplerCube:
897 out << "texCUBE";
898 break;
899 default:
900 UNREACHABLE();
901 }
902
903 switch (textureFunction.method)
904 {
905 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
906 out << "(" << samplerReference << ", ";
907 break;
908 case TextureFunctionHLSL::TextureFunction::BIAS:
909 out << "bias(" << samplerReference << ", ";
910 break;
911 case TextureFunctionHLSL::TextureFunction::LOD:
912 out << "lod(" << samplerReference << ", ";
913 break;
914 case TextureFunctionHLSL::TextureFunction::LOD0:
915 out << "lod(" << samplerReference << ", ";
916 break;
917 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
918 out << "lod(" << samplerReference << ", ";
919 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400920 case TextureFunctionHLSL::TextureFunction::GRAD:
921 out << "grad(" << samplerReference << ", ";
922 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300923 default:
924 UNREACHABLE();
925 }
926 }
927 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
928 {
929 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
930 }
931 else
932 UNREACHABLE();
933
934 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
935
936 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
937 << texCoordY;
938
939 if (outputType == SH_HLSL_3_0_OUTPUT)
940 {
941 if (hlslCoords >= 3)
942 {
943 if (textureFunction.coords < 3)
944 {
945 out << ", 0";
946 }
947 else
948 {
949 out << ", " << texCoordZ;
950 }
951 }
952
953 if (hlslCoords == 4)
954 {
955 switch (textureFunction.method)
956 {
957 case TextureFunctionHLSL::TextureFunction::BIAS:
958 out << ", bias";
959 break;
960 case TextureFunctionHLSL::TextureFunction::LOD:
961 out << ", lod";
962 break;
963 case TextureFunctionHLSL::TextureFunction::LOD0:
964 out << ", 0";
965 break;
966 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
967 out << ", bias";
968 break;
969 default:
970 UNREACHABLE();
971 }
972 }
973
974 out << ")";
975 }
976 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
977 {
978 if (hlslCoords >= 3)
979 {
980 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
981 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
982 out << ", " << texCoordZ;
983 }
984
985 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
986 {
987 if (IsIntegerSampler(textureFunction.sampler))
988 {
989 out << ", mip)";
990 }
991 else if (IsShadowSampler(textureFunction.sampler))
992 {
993 // Compare value
994 if (textureFunction.proj)
995 {
996 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
997 // The resulting third component of P' in the shadow forms is used as
998 // Dref
999 out << "), " << texCoordZ;
1000 }
1001 else
1002 {
1003 switch (textureFunction.coords)
1004 {
1005 case 3:
1006 out << "), t.z";
1007 break;
1008 case 4:
1009 out << "), t.w";
1010 break;
1011 default:
1012 UNREACHABLE();
1013 }
1014 }
1015 }
1016 else
1017 {
1018 out << "), ddx, ddy";
1019 }
1020 }
1021 else if (IsIntegerSampler(textureFunction.sampler) ||
1022 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1023 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001024 if (IsSampler2DMS(textureFunction.sampler) ||
1025 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001026 out << "), index";
1027 else
1028 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001029 }
1030 else if (IsShadowSampler(textureFunction.sampler))
1031 {
1032 // Compare value
1033 if (textureFunction.proj)
1034 {
1035 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1036 // The resulting third component of P' in the shadow forms is used as Dref
1037 out << "), " << texCoordZ;
1038 }
1039 else
1040 {
1041 switch (textureFunction.coords)
1042 {
1043 case 3:
1044 out << "), t.z";
1045 break;
1046 case 4:
1047 out << "), t.w";
1048 break;
1049 default:
1050 UNREACHABLE();
1051 }
1052 }
1053 }
1054 else
1055 {
1056 switch (textureFunction.method)
1057 {
1058 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1059 out << ")";
1060 break;
1061 case TextureFunctionHLSL::TextureFunction::BIAS:
1062 out << "), bias";
1063 break;
1064 case TextureFunctionHLSL::TextureFunction::LOD:
1065 out << "), lod";
1066 break;
1067 case TextureFunctionHLSL::TextureFunction::LOD0:
1068 out << "), 0";
1069 break;
1070 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1071 out << "), bias";
1072 break;
1073 default:
1074 UNREACHABLE();
1075 }
1076 }
1077
1078 if (textureFunction.offset &&
1079 (!IsIntegerSampler(textureFunction.sampler) ||
1080 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1081 {
1082 out << ", offset";
1083 }
1084 }
1085 else
1086 UNREACHABLE();
1087
1088 out << ");\n"; // Close the sample function call and return statement
1089}
1090
1091} // Anonymous namespace
1092
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001093ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001094{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001095 static const ImmutableString kGlTextureName("gl_texture");
1096
1097 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1098
1099 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1100
1101 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001102
1103 // We need to include full the sampler type in the function name to make the signature unique
1104 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001105 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001106
1107 if (proj)
1108 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001109 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001110 }
1111
1112 if (offset)
1113 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001114 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001115 }
1116
1117 switch (method)
1118 {
1119 case IMPLICIT:
1120 break;
1121 case BIAS:
1122 break; // Extra parameter makes the signature unique
1123 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001124 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001125 break;
1126 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001127 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001128 break;
1129 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001130 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001131 break; // Extra parameter makes the signature unique
1132 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001133 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001134 break;
1135 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001136 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001137 break;
1138 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001139 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001140 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001141 case GATHER:
1142 name << "Gather";
1143 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001144 default:
1145 UNREACHABLE();
1146 }
1147
1148 return name;
1149}
1150
1151const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1152{
1153 if (method == TextureFunction::SIZE)
1154 {
1155 switch (sampler)
1156 {
1157 case EbtSampler2D:
1158 case EbtISampler2D:
1159 case EbtUSampler2D:
1160 case EbtSampler2DShadow:
1161 case EbtSamplerCube:
1162 case EbtISamplerCube:
1163 case EbtUSamplerCube:
1164 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001165 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001166 case EbtSampler2DMS:
1167 case EbtISampler2DMS:
1168 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001169 return "int2";
1170 case EbtSampler3D:
1171 case EbtISampler3D:
1172 case EbtUSampler3D:
1173 case EbtSampler2DArray:
1174 case EbtISampler2DArray:
1175 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001176 case EbtSampler2DMSArray:
1177 case EbtISampler2DMSArray:
1178 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001179 case EbtSampler2DArrayShadow:
1180 return "int3";
1181 default:
1182 UNREACHABLE();
1183 }
1184 }
1185 else // Sampling function
1186 {
1187 switch (sampler)
1188 {
1189 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001190 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001191 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001192 case EbtSampler3D:
1193 case EbtSamplerCube:
1194 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001195 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001196 return "float4";
1197 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001198 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001199 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001200 case EbtISampler3D:
1201 case EbtISamplerCube:
1202 case EbtISampler2DArray:
1203 return "int4";
1204 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001205 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001206 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001207 case EbtUSampler3D:
1208 case EbtUSamplerCube:
1209 case EbtUSampler2DArray:
1210 return "uint4";
1211 case EbtSampler2DShadow:
1212 case EbtSamplerCubeShadow:
1213 case EbtSampler2DArrayShadow:
1214 return "float";
1215 default:
1216 UNREACHABLE();
1217 }
1218 }
1219 return "";
1220}
1221
1222bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1223{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001224 return std::tie(sampler, coords, proj, offset, method) <
1225 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001226}
1227
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001228ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1229 TBasicType samplerType,
1230 int coords,
1231 size_t argumentCount,
1232 bool lod0,
1233 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001234{
1235 TextureFunction textureFunction;
1236 textureFunction.sampler = samplerType;
1237 textureFunction.coords = coords;
1238 textureFunction.method = TextureFunction::IMPLICIT;
1239 textureFunction.proj = false;
1240 textureFunction.offset = false;
1241
1242 if (name == "texture2D" || name == "textureCube" || name == "texture")
1243 {
1244 textureFunction.method = TextureFunction::IMPLICIT;
1245 }
1246 else if (name == "texture2DProj" || name == "textureProj")
1247 {
1248 textureFunction.method = TextureFunction::IMPLICIT;
1249 textureFunction.proj = true;
1250 }
1251 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1252 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1253 {
1254 textureFunction.method = TextureFunction::LOD;
1255 }
1256 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1257 name == "texture2DProjLodEXT")
1258 {
1259 textureFunction.method = TextureFunction::LOD;
1260 textureFunction.proj = true;
1261 }
1262 else if (name == "textureSize")
1263 {
1264 textureFunction.method = TextureFunction::SIZE;
1265 }
1266 else if (name == "textureOffset")
1267 {
1268 textureFunction.method = TextureFunction::IMPLICIT;
1269 textureFunction.offset = true;
1270 }
1271 else if (name == "textureProjOffset")
1272 {
1273 textureFunction.method = TextureFunction::IMPLICIT;
1274 textureFunction.offset = true;
1275 textureFunction.proj = true;
1276 }
1277 else if (name == "textureLodOffset")
1278 {
1279 textureFunction.method = TextureFunction::LOD;
1280 textureFunction.offset = true;
1281 }
1282 else if (name == "textureProjLodOffset")
1283 {
1284 textureFunction.method = TextureFunction::LOD;
1285 textureFunction.proj = true;
1286 textureFunction.offset = true;
1287 }
1288 else if (name == "texelFetch")
1289 {
1290 textureFunction.method = TextureFunction::FETCH;
1291 }
1292 else if (name == "texelFetchOffset")
1293 {
1294 textureFunction.method = TextureFunction::FETCH;
1295 textureFunction.offset = true;
1296 }
1297 else if (name == "textureGrad" || name == "texture2DGradEXT")
1298 {
1299 textureFunction.method = TextureFunction::GRAD;
1300 }
1301 else if (name == "textureGradOffset")
1302 {
1303 textureFunction.method = TextureFunction::GRAD;
1304 textureFunction.offset = true;
1305 }
1306 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1307 name == "textureCubeGradEXT")
1308 {
1309 textureFunction.method = TextureFunction::GRAD;
1310 textureFunction.proj = true;
1311 }
1312 else if (name == "textureProjGradOffset")
1313 {
1314 textureFunction.method = TextureFunction::GRAD;
1315 textureFunction.proj = true;
1316 textureFunction.offset = true;
1317 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001318 else if (name == "textureGather")
1319 {
1320 textureFunction.method = TextureFunction::GATHER;
1321 }
Jiawei Shaocf8ad762018-09-21 09:11:35 +08001322 else if (name == "textureGatherOffset")
1323 {
1324 textureFunction.method = TextureFunction::GATHER;
1325 textureFunction.offset = true;
1326 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001327 else
1328 UNREACHABLE();
1329
1330 if (textureFunction.method ==
1331 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1332 {
1333 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1334
1335 if (textureFunction.offset)
1336 {
1337 mandatoryArgumentCount++;
1338 }
1339
1340 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1341
1342 if (lod0 || shaderType == GL_VERTEX_SHADER)
1343 {
1344 if (bias)
1345 {
1346 textureFunction.method = TextureFunction::LOD0BIAS;
1347 }
1348 else
1349 {
1350 textureFunction.method = TextureFunction::LOD0;
1351 }
1352 }
1353 else if (bias)
1354 {
1355 textureFunction.method = TextureFunction::BIAS;
1356 }
1357 }
1358
1359 mUsesTexture.insert(textureFunction);
1360 return textureFunction.name();
1361}
1362
Geoff Lang1fe74c72016-08-25 13:23:01 -04001363void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1364 const ShShaderOutput outputType,
1365 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001366{
1367 for (const TextureFunction &textureFunction : mUsesTexture)
1368 {
1369 // Function header
1370 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1371
1372 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1373
1374 out << ")\n"
1375 "{\n";
1376
1377 // In some cases we use a variable to store the texture/sampler objects, but to work around
1378 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1379 // sampling we need to call the function directly on references to the texture and sampler
1380 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1381 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001382 ImmutableString textureReference("");
1383 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001384 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1385
1386 if (textureFunction.method == TextureFunction::SIZE)
1387 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001388 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1389 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001390 }
1391 else
1392 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001393 ImmutableString texCoordX("t.x");
1394 ImmutableString texCoordY("t.y");
1395 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001396 if (textureFunction.method == TextureFunction::GATHER)
1397 {
1398 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1399 samplerReference, texCoordX, texCoordY, texCoordZ);
1400 }
1401 else
1402 {
1403 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1404 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1405 textureReference, &texCoordX,
1406 &texCoordY, &texCoordZ);
1407 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1408 textureReference, samplerReference,
1409 texCoordX, texCoordY, texCoordZ);
1410 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001411 }
1412
1413 out << "}\n"
1414 "\n";
1415 }
1416}
1417
1418} // namespace sh