blob: 685c904ee8a060c0ba91f920dd46a5ad98228291 [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
853 out << " switch(comp)\n"
854 " {\n"
855 " case 0:\n"
856 " return "
857 << textureReference << ".GatherRed(" << samplerReference << ", " << samplerCoordString
858 << ");\n"
859 " case 1:\n"
860 " return "
861 << textureReference << ".GatherGreen(" << samplerReference << ", " << samplerCoordString
862 << ");\n"
863 " case 2:\n"
864 " return "
865 << textureReference << ".GatherBlue(" << samplerReference << ", " << samplerCoordString
866 << ");\n"
867 " case 3:\n"
868 " return "
869 << textureReference << ".GatherAlpha(" << samplerReference << ", " << samplerCoordString
870 << ");\n"
871 " default:\n"
872 " return float4(0.0, 0.0, 0.0, 1.0);\n"
873 " }\n";
874}
875
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300876void OutputTextureSampleFunctionReturnStatement(
877 TInfoSinkBase &out,
878 const TextureFunctionHLSL::TextureFunction &textureFunction,
879 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200880 const ImmutableString &textureReference,
881 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200882 const ImmutableString &texCoordX,
883 const ImmutableString &texCoordY,
884 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300885{
886 out << " return ";
887
888 // HLSL intrinsic
889 if (outputType == SH_HLSL_3_0_OUTPUT)
890 {
891 switch (textureFunction.sampler)
892 {
893 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400894 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300895 out << "tex2D";
896 break;
897 case EbtSamplerCube:
898 out << "texCUBE";
899 break;
900 default:
901 UNREACHABLE();
902 }
903
904 switch (textureFunction.method)
905 {
906 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
907 out << "(" << samplerReference << ", ";
908 break;
909 case TextureFunctionHLSL::TextureFunction::BIAS:
910 out << "bias(" << samplerReference << ", ";
911 break;
912 case TextureFunctionHLSL::TextureFunction::LOD:
913 out << "lod(" << samplerReference << ", ";
914 break;
915 case TextureFunctionHLSL::TextureFunction::LOD0:
916 out << "lod(" << samplerReference << ", ";
917 break;
918 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
919 out << "lod(" << samplerReference << ", ";
920 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400921 case TextureFunctionHLSL::TextureFunction::GRAD:
922 out << "grad(" << samplerReference << ", ";
923 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300924 default:
925 UNREACHABLE();
926 }
927 }
928 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
929 {
930 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
931 }
932 else
933 UNREACHABLE();
934
935 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
936
937 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
938 << texCoordY;
939
940 if (outputType == SH_HLSL_3_0_OUTPUT)
941 {
942 if (hlslCoords >= 3)
943 {
944 if (textureFunction.coords < 3)
945 {
946 out << ", 0";
947 }
948 else
949 {
950 out << ", " << texCoordZ;
951 }
952 }
953
954 if (hlslCoords == 4)
955 {
956 switch (textureFunction.method)
957 {
958 case TextureFunctionHLSL::TextureFunction::BIAS:
959 out << ", bias";
960 break;
961 case TextureFunctionHLSL::TextureFunction::LOD:
962 out << ", lod";
963 break;
964 case TextureFunctionHLSL::TextureFunction::LOD0:
965 out << ", 0";
966 break;
967 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
968 out << ", bias";
969 break;
970 default:
971 UNREACHABLE();
972 }
973 }
974
975 out << ")";
976 }
977 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
978 {
979 if (hlslCoords >= 3)
980 {
981 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
982 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
983 out << ", " << texCoordZ;
984 }
985
986 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
987 {
988 if (IsIntegerSampler(textureFunction.sampler))
989 {
990 out << ", mip)";
991 }
992 else if (IsShadowSampler(textureFunction.sampler))
993 {
994 // Compare value
995 if (textureFunction.proj)
996 {
997 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
998 // The resulting third component of P' in the shadow forms is used as
999 // Dref
1000 out << "), " << texCoordZ;
1001 }
1002 else
1003 {
1004 switch (textureFunction.coords)
1005 {
1006 case 3:
1007 out << "), t.z";
1008 break;
1009 case 4:
1010 out << "), t.w";
1011 break;
1012 default:
1013 UNREACHABLE();
1014 }
1015 }
1016 }
1017 else
1018 {
1019 out << "), ddx, ddy";
1020 }
1021 }
1022 else if (IsIntegerSampler(textureFunction.sampler) ||
1023 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1024 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001025 if (IsSampler2DMS(textureFunction.sampler) ||
1026 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001027 out << "), index";
1028 else
1029 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001030 }
1031 else if (IsShadowSampler(textureFunction.sampler))
1032 {
1033 // Compare value
1034 if (textureFunction.proj)
1035 {
1036 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1037 // The resulting third component of P' in the shadow forms is used as Dref
1038 out << "), " << texCoordZ;
1039 }
1040 else
1041 {
1042 switch (textureFunction.coords)
1043 {
1044 case 3:
1045 out << "), t.z";
1046 break;
1047 case 4:
1048 out << "), t.w";
1049 break;
1050 default:
1051 UNREACHABLE();
1052 }
1053 }
1054 }
1055 else
1056 {
1057 switch (textureFunction.method)
1058 {
1059 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1060 out << ")";
1061 break;
1062 case TextureFunctionHLSL::TextureFunction::BIAS:
1063 out << "), bias";
1064 break;
1065 case TextureFunctionHLSL::TextureFunction::LOD:
1066 out << "), lod";
1067 break;
1068 case TextureFunctionHLSL::TextureFunction::LOD0:
1069 out << "), 0";
1070 break;
1071 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1072 out << "), bias";
1073 break;
1074 default:
1075 UNREACHABLE();
1076 }
1077 }
1078
1079 if (textureFunction.offset &&
1080 (!IsIntegerSampler(textureFunction.sampler) ||
1081 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1082 {
1083 out << ", offset";
1084 }
1085 }
1086 else
1087 UNREACHABLE();
1088
1089 out << ");\n"; // Close the sample function call and return statement
1090}
1091
1092} // Anonymous namespace
1093
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001094ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001095{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001096 static const ImmutableString kGlTextureName("gl_texture");
1097
1098 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1099
1100 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1101
1102 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001103
1104 // We need to include full the sampler type in the function name to make the signature unique
1105 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001106 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001107
1108 if (proj)
1109 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001110 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001111 }
1112
1113 if (offset)
1114 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001115 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001116 }
1117
1118 switch (method)
1119 {
1120 case IMPLICIT:
1121 break;
1122 case BIAS:
1123 break; // Extra parameter makes the signature unique
1124 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001125 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001126 break;
1127 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001128 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001129 break;
1130 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001131 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001132 break; // Extra parameter makes the signature unique
1133 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001134 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001135 break;
1136 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001137 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001138 break;
1139 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001140 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001141 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001142 case GATHER:
1143 name << "Gather";
1144 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001145 default:
1146 UNREACHABLE();
1147 }
1148
1149 return name;
1150}
1151
1152const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1153{
1154 if (method == TextureFunction::SIZE)
1155 {
1156 switch (sampler)
1157 {
1158 case EbtSampler2D:
1159 case EbtISampler2D:
1160 case EbtUSampler2D:
1161 case EbtSampler2DShadow:
1162 case EbtSamplerCube:
1163 case EbtISamplerCube:
1164 case EbtUSamplerCube:
1165 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001166 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001167 case EbtSampler2DMS:
1168 case EbtISampler2DMS:
1169 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001170 return "int2";
1171 case EbtSampler3D:
1172 case EbtISampler3D:
1173 case EbtUSampler3D:
1174 case EbtSampler2DArray:
1175 case EbtISampler2DArray:
1176 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001177 case EbtSampler2DMSArray:
1178 case EbtISampler2DMSArray:
1179 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001180 case EbtSampler2DArrayShadow:
1181 return "int3";
1182 default:
1183 UNREACHABLE();
1184 }
1185 }
1186 else // Sampling function
1187 {
1188 switch (sampler)
1189 {
1190 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001191 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001192 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001193 case EbtSampler3D:
1194 case EbtSamplerCube:
1195 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001196 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001197 return "float4";
1198 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001199 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001200 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001201 case EbtISampler3D:
1202 case EbtISamplerCube:
1203 case EbtISampler2DArray:
1204 return "int4";
1205 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001206 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001207 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001208 case EbtUSampler3D:
1209 case EbtUSamplerCube:
1210 case EbtUSampler2DArray:
1211 return "uint4";
1212 case EbtSampler2DShadow:
1213 case EbtSamplerCubeShadow:
1214 case EbtSampler2DArrayShadow:
1215 return "float";
1216 default:
1217 UNREACHABLE();
1218 }
1219 }
1220 return "";
1221}
1222
1223bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1224{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001225 return std::tie(sampler, coords, proj, offset, method) <
1226 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001227}
1228
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001229ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1230 TBasicType samplerType,
1231 int coords,
1232 size_t argumentCount,
1233 bool lod0,
1234 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001235{
1236 TextureFunction textureFunction;
1237 textureFunction.sampler = samplerType;
1238 textureFunction.coords = coords;
1239 textureFunction.method = TextureFunction::IMPLICIT;
1240 textureFunction.proj = false;
1241 textureFunction.offset = false;
1242
1243 if (name == "texture2D" || name == "textureCube" || name == "texture")
1244 {
1245 textureFunction.method = TextureFunction::IMPLICIT;
1246 }
1247 else if (name == "texture2DProj" || name == "textureProj")
1248 {
1249 textureFunction.method = TextureFunction::IMPLICIT;
1250 textureFunction.proj = true;
1251 }
1252 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1253 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1254 {
1255 textureFunction.method = TextureFunction::LOD;
1256 }
1257 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1258 name == "texture2DProjLodEXT")
1259 {
1260 textureFunction.method = TextureFunction::LOD;
1261 textureFunction.proj = true;
1262 }
1263 else if (name == "textureSize")
1264 {
1265 textureFunction.method = TextureFunction::SIZE;
1266 }
1267 else if (name == "textureOffset")
1268 {
1269 textureFunction.method = TextureFunction::IMPLICIT;
1270 textureFunction.offset = true;
1271 }
1272 else if (name == "textureProjOffset")
1273 {
1274 textureFunction.method = TextureFunction::IMPLICIT;
1275 textureFunction.offset = true;
1276 textureFunction.proj = true;
1277 }
1278 else if (name == "textureLodOffset")
1279 {
1280 textureFunction.method = TextureFunction::LOD;
1281 textureFunction.offset = true;
1282 }
1283 else if (name == "textureProjLodOffset")
1284 {
1285 textureFunction.method = TextureFunction::LOD;
1286 textureFunction.proj = true;
1287 textureFunction.offset = true;
1288 }
1289 else if (name == "texelFetch")
1290 {
1291 textureFunction.method = TextureFunction::FETCH;
1292 }
1293 else if (name == "texelFetchOffset")
1294 {
1295 textureFunction.method = TextureFunction::FETCH;
1296 textureFunction.offset = true;
1297 }
1298 else if (name == "textureGrad" || name == "texture2DGradEXT")
1299 {
1300 textureFunction.method = TextureFunction::GRAD;
1301 }
1302 else if (name == "textureGradOffset")
1303 {
1304 textureFunction.method = TextureFunction::GRAD;
1305 textureFunction.offset = true;
1306 }
1307 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1308 name == "textureCubeGradEXT")
1309 {
1310 textureFunction.method = TextureFunction::GRAD;
1311 textureFunction.proj = true;
1312 }
1313 else if (name == "textureProjGradOffset")
1314 {
1315 textureFunction.method = TextureFunction::GRAD;
1316 textureFunction.proj = true;
1317 textureFunction.offset = true;
1318 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001319 else if (name == "textureGather")
1320 {
1321 textureFunction.method = TextureFunction::GATHER;
1322 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001323 else
1324 UNREACHABLE();
1325
1326 if (textureFunction.method ==
1327 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1328 {
1329 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1330
1331 if (textureFunction.offset)
1332 {
1333 mandatoryArgumentCount++;
1334 }
1335
1336 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1337
1338 if (lod0 || shaderType == GL_VERTEX_SHADER)
1339 {
1340 if (bias)
1341 {
1342 textureFunction.method = TextureFunction::LOD0BIAS;
1343 }
1344 else
1345 {
1346 textureFunction.method = TextureFunction::LOD0;
1347 }
1348 }
1349 else if (bias)
1350 {
1351 textureFunction.method = TextureFunction::BIAS;
1352 }
1353 }
1354
1355 mUsesTexture.insert(textureFunction);
1356 return textureFunction.name();
1357}
1358
Geoff Lang1fe74c72016-08-25 13:23:01 -04001359void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1360 const ShShaderOutput outputType,
1361 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001362{
1363 for (const TextureFunction &textureFunction : mUsesTexture)
1364 {
1365 // Function header
1366 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1367
1368 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1369
1370 out << ")\n"
1371 "{\n";
1372
1373 // In some cases we use a variable to store the texture/sampler objects, but to work around
1374 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1375 // sampling we need to call the function directly on references to the texture and sampler
1376 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1377 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001378 ImmutableString textureReference("");
1379 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001380 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1381
1382 if (textureFunction.method == TextureFunction::SIZE)
1383 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001384 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1385 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001386 }
1387 else
1388 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001389 ImmutableString texCoordX("t.x");
1390 ImmutableString texCoordY("t.y");
1391 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001392 if (textureFunction.method == TextureFunction::GATHER)
1393 {
1394 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1395 samplerReference, texCoordX, texCoordY, texCoordZ);
1396 }
1397 else
1398 {
1399 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1400 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1401 textureReference, &texCoordX,
1402 &texCoordY, &texCoordZ);
1403 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1404 textureReference, samplerReference,
1405 texCoordX, texCoordY, texCoordZ);
1406 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001407 }
1408
1409 out << "}\n"
1410 "\n";
1411 }
1412}
1413
1414} // namespace sh