blob: 333d246f0fadda3025a11e652c1c13ecf1bc9fa0 [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:
JiangYizhou5b03f472017-01-09 10:22:53 +0800172 if (textureFunction.sampler == EbtSampler2DMS ||
173 textureFunction.sampler == EbtISampler2DMS ||
174 textureFunction.sampler == EbtUSampler2DMS)
175 return "int2";
176 else
177 return "int3";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300178 case 3:
179 return "int4";
180 default:
181 UNREACHABLE();
182 }
183 }
184 else
185 {
186 switch (hlslCoords)
187 {
188 case 2:
189 return "float2";
190 case 3:
191 return "float3";
192 case 4:
193 return "float4";
194 default:
195 UNREACHABLE();
196 }
197 }
198 return "";
199}
200
201int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
202 ShShaderOutput outputType)
203{
204 if (outputType == SH_HLSL_3_0_OUTPUT)
205 {
206 int hlslCoords = 2;
207 switch (textureFunction.sampler)
208 {
209 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400210 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800211 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300212 hlslCoords = 2;
213 break;
214 case EbtSamplerCube:
215 hlslCoords = 3;
216 break;
217 default:
218 UNREACHABLE();
219 }
220
221 switch (textureFunction.method)
222 {
223 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400224 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300225 return hlslCoords;
226 case TextureFunctionHLSL::TextureFunction::BIAS:
227 case TextureFunctionHLSL::TextureFunction::LOD:
228 case TextureFunctionHLSL::TextureFunction::LOD0:
229 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
230 return 4;
231 default:
232 UNREACHABLE();
233 }
234 }
235 else
236 {
237 switch (textureFunction.sampler)
238 {
239 case EbtSampler2D:
240 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800241 case EbtSampler2DMS:
242 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300243 case EbtSampler3D:
244 return 3;
245 case EbtSamplerCube:
246 return 3;
247 case EbtSampler2DArray:
248 return 3;
Ian Ewellbda75592016-04-18 17:25:54 -0400249 case EbtSamplerExternalOES:
250 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300251 case EbtISampler2D:
252 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800253 case EbtISampler2DMS:
254 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300255 case EbtISampler3D:
256 return 3;
257 case EbtISamplerCube:
258 return 3;
259 case EbtISampler2DArray:
260 return 3;
261 case EbtUSampler2D:
262 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800263 case EbtUSampler2DMS:
264 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300265 case EbtUSampler3D:
266 return 3;
267 case EbtUSamplerCube:
268 return 3;
269 case EbtUSampler2DArray:
270 return 3;
271 case EbtSampler2DShadow:
272 return 2;
273 case EbtSamplerCubeShadow:
274 return 3;
275 case EbtSampler2DArrayShadow:
276 return 3;
277 default:
278 UNREACHABLE();
279 }
280 }
281 return 0;
282}
283
284void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
285 const TextureFunctionHLSL::TextureFunction &textureFunction,
286 const ShShaderOutput outputType)
287{
288 if (outputType == SH_HLSL_3_0_OUTPUT)
289 {
290 switch (textureFunction.sampler)
291 {
292 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400293 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300294 out << "sampler2D s";
295 break;
296 case EbtSamplerCube:
297 out << "samplerCUBE s";
298 break;
299 default:
300 UNREACHABLE();
301 }
302 }
303 else
304 {
305 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
306 {
307 out << TextureString(textureFunction.sampler) << " x, "
308 << SamplerString(textureFunction.sampler) << " s";
309 }
310 else
311 {
312 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400313 // A bug in the D3D compiler causes some nested sampling operations to fail.
314 // See http://anglebug.com/1923
315 // TODO(jmadill): Reinstate the const keyword when possible.
316 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300317 }
318 }
319
320 if (textureFunction.method ==
321 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
322 {
323 switch (textureFunction.coords)
324 {
325 case 2:
326 out << ", int2 t";
327 break;
328 case 3:
329 out << ", int3 t";
330 break;
331 default:
332 UNREACHABLE();
333 }
334 }
335 else // Floating-point coordinates (except textureSize)
336 {
337 switch (textureFunction.coords)
338 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000339 case 0:
340 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300341 case 1:
342 out << ", int lod";
343 break; // textureSize()
344 case 2:
345 out << ", float2 t";
346 break;
347 case 3:
348 out << ", float3 t";
349 break;
350 case 4:
351 out << ", float4 t";
352 break;
353 default:
354 UNREACHABLE();
355 }
356 }
357
358 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
359 {
360 switch (textureFunction.sampler)
361 {
362 case EbtSampler2D:
363 case EbtISampler2D:
364 case EbtUSampler2D:
365 case EbtSampler2DArray:
366 case EbtISampler2DArray:
367 case EbtUSampler2DArray:
368 case EbtSampler2DShadow:
369 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400370 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300371 out << ", float2 ddx, float2 ddy";
372 break;
373 case EbtSampler3D:
374 case EbtISampler3D:
375 case EbtUSampler3D:
376 case EbtSamplerCube:
377 case EbtISamplerCube:
378 case EbtUSamplerCube:
379 case EbtSamplerCubeShadow:
380 out << ", float3 ddx, float3 ddy";
381 break;
382 default:
383 UNREACHABLE();
384 }
385 }
386
387 switch (textureFunction.method)
388 {
389 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
390 break;
391 case TextureFunctionHLSL::TextureFunction::BIAS:
392 break; // Comes after the offset parameter
393 case TextureFunctionHLSL::TextureFunction::LOD:
394 out << ", float lod";
395 break;
396 case TextureFunctionHLSL::TextureFunction::LOD0:
397 break;
398 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
399 break; // Comes after the offset parameter
400 case TextureFunctionHLSL::TextureFunction::SIZE:
401 break;
402 case TextureFunctionHLSL::TextureFunction::FETCH:
JiangYizhou5b03f472017-01-09 10:22:53 +0800403 if (textureFunction.sampler == EbtSampler2DMS ||
404 textureFunction.sampler == EbtISampler2DMS ||
405 textureFunction.sampler == EbtUSampler2DMS)
406 out << ", int index";
407 else
408 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300409 break;
410 case TextureFunctionHLSL::TextureFunction::GRAD:
411 break;
412 default:
413 UNREACHABLE();
414 }
415
416 if (textureFunction.offset)
417 {
418 switch (textureFunction.sampler)
419 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300420 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300421 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300422 case EbtUSampler3D:
423 out << ", int3 offset";
424 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300425 case EbtSampler2D:
426 case EbtSampler2DArray:
427 case EbtISampler2D:
428 case EbtISampler2DArray:
429 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300430 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300431 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300432 case EbtSampler2DArrayShadow:
JiangYizhou5b03f472017-01-09 10:22:53 +0800433 case EbtSampler2DMS:
434 case EbtISampler2DMS:
435 case EbtUSampler2DMS:
Ian Ewellbda75592016-04-18 17:25:54 -0400436 case EbtSamplerExternalOES:
437 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300438 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300439 default:
440 UNREACHABLE();
441 }
442 }
443
444 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
445 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
446 {
447 out << ", float bias";
448 }
449}
450
451void GetTextureReference(TInfoSinkBase &out,
452 const TextureFunctionHLSL::TextureFunction &textureFunction,
453 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200454 ImmutableString *textureReference,
455 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300456{
457 if (outputType == SH_HLSL_4_1_OUTPUT)
458 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200459 static const ImmutableString kTexturesStr("textures");
460 static const ImmutableString kSamplersStr("samplers");
461 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
462 static const ImmutableString kTextureIndexStr("[textureIndex]");
463 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
464 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
465
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300466 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
467 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200468 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
469 kSamplerIndexStr.length());
470 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
471 *textureReference = textureRefBuilder;
472 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
473 kSamplerIndexStr.length());
474 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
475 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300476 }
477 else
478 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200479 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
480 << suffix.data() << ";\n";
481 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
482 kTextureIndexStr.length());
483 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
484 *textureReference = textureRefBuilder;
485
486 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
487 << suffix.data() << ";\n";
488 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
489 kSamplerArrayIndexStr.length());
490 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
491 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300492 }
493 }
494 else
495 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200496 *textureReference = ImmutableString("x");
497 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300498 }
499}
500
501void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
502 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200503 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400504 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300505{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000506 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400507 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000508 out << " uint width; uint height; uint samples;\n"
509 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400510 }
511 else
512 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000513 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400514 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000515 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400516 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000517 else
518 {
519 out << " int baseLevel = 0;\n";
520 }
521
522 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
523 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
524 {
525 // "depth" stores either the number of layers in an array texture or 3D depth
526 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
527 << " " << textureReference
528 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
529 << " width = max(width >> lod, 1);\n"
530 << " height = max(height >> lod, 1);\n";
531
532 if (!IsSamplerArray(textureFunction.sampler))
533 {
534 out << " depth = max(depth >> lod, 1);\n";
535 }
536 }
537 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
538 {
539 out << " uint width; uint height; uint numberOfLevels;\n"
540 << " " << textureReference
541 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
542 << " width = max(width >> lod, 1);\n"
543 << " height = max(height >> lod, 1);\n";
544 }
545 else
546 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300547 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300548
549 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
550 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000551 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300552 }
553 else
554 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000555 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300556 }
557}
558
559void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200560 ImmutableString *texCoordX,
561 ImmutableString *texCoordY,
562 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300563{
564 if (textureFunction.proj)
565 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200566 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300567 switch (textureFunction.coords)
568 {
569 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200570 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300571 break;
572 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200573 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300574 break;
575 default:
576 UNREACHABLE();
577 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200578 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
579 texCoordXBuilder << '(' << *texCoordX << proj << ')';
580 *texCoordX = texCoordXBuilder;
581 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
582 texCoordYBuilder << '(' << *texCoordY << proj << ')';
583 *texCoordY = texCoordYBuilder;
584 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
585 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
586 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300587 }
588}
589
590void OutputIntegerTextureSampleFunctionComputations(
591 TInfoSinkBase &out,
592 const TextureFunctionHLSL::TextureFunction &textureFunction,
593 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200594 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200595 ImmutableString *texCoordX,
596 ImmutableString *texCoordY,
597 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300598{
599 if (!IsIntegerSampler(textureFunction.sampler))
600 {
601 return;
602 }
603 if (IsSamplerCube(textureFunction.sampler))
604 {
605 out << " float width; float height; float layers; float levels;\n";
606
607 out << " uint mip = 0;\n";
608
609 out << " " << textureReference
610 << ".GetDimensions(mip, width, height, layers, levels);\n";
611
612 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
613 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
614 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
615 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
616 "(zMajor && t.z < 0.0f);\n";
617
618 // FACE_POSITIVE_X = 000b
619 // FACE_NEGATIVE_X = 001b
620 // FACE_POSITIVE_Y = 010b
621 // FACE_NEGATIVE_Y = 011b
622 // FACE_POSITIVE_Z = 100b
623 // FACE_NEGATIVE_Z = 101b
624 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
625
626 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
627 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
628 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
629
630 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
631 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
632
633 // Mip level computation.
634 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
635 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
636 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
637 {
638 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
639 {
640 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
641 " float2 dx = ddx(tSized);\n"
642 " float2 dy = ddy(tSized);\n"
643 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
644 }
645 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
646 {
647 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
648 // derivatives of P are assumed to be in the coordinate system used before
649 // texture coordinates are projected onto the appropriate cube face."
650 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
651 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
652 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
653 // Determine the derivatives of u, v and m
654 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
655 ": ddx[0]);\n"
656 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
657 ": ddy[0]);\n"
658 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
659 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
660 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
661 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
662 // Now determine the derivatives of the face coordinates, using the
663 // derivatives calculated above.
664 // d / dx (u(x) * 0.5 / m(x) + 0.5)
665 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
666 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
667 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
668 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
669 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
670 " float2 sizeVec = float2(width, height);\n"
671 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
672 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
673 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
674 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
675 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
676 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
677 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
678 }
679 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
680 << " " << textureReference
681 << ".GetDimensions(mip, width, height, layers, levels);\n";
682 }
683
684 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200685 static const ImmutableString kXPrefix("int(floor(width * frac(");
686 static const ImmutableString kYPrefix("int(floor(height * frac(");
687 static const ImmutableString kSuffix(")))");
688 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
689 kSuffix.length());
690 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
691 *texCoordX = texCoordXBuilder;
692 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
693 kSuffix.length());
694 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
695 *texCoordY = texCoordYBuilder;
696 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300697 }
698 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
699 {
700 if (IsSampler2D(textureFunction.sampler))
701 {
702 if (IsSamplerArray(textureFunction.sampler))
703 {
704 out << " float width; float height; float layers; float levels;\n";
705
706 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
707 {
708 out << " uint mip = 0;\n";
709 }
710 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
711 {
712 out << " uint mip = bias;\n";
713 }
714 else
715 {
716
717 out << " " << textureReference
718 << ".GetDimensions(0, width, height, layers, levels);\n";
719 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
720 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
721 {
722 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
723 " float dx = length(ddx(tSized));\n"
724 " float dy = length(ddy(tSized));\n"
725 " float lod = log2(max(dx, dy));\n";
726
727 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
728 {
729 out << " lod += bias;\n";
730 }
731 }
732 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
733 {
734 out << " float2 sizeVec = float2(width, height);\n"
735 " float2 sizeDdx = ddx * sizeVec;\n"
736 " float2 sizeDdy = ddy * sizeVec;\n"
737 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
738 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
739 }
740
741 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
742 }
743
744 out << " " << textureReference
745 << ".GetDimensions(mip, width, height, layers, levels);\n";
746 }
747 else
748 {
749 out << " float width; float height; float levels;\n";
750
751 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
752 {
753 out << " uint mip = 0;\n";
754 }
755 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
756 {
757 out << " uint mip = bias;\n";
758 }
759 else
760 {
761 out << " " << textureReference
762 << ".GetDimensions(0, width, height, levels);\n";
763
764 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
765 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
766 {
767 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
768 " float dx = length(ddx(tSized));\n"
769 " float dy = length(ddy(tSized));\n"
770 " float lod = log2(max(dx, dy));\n";
771
772 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
773 {
774 out << " lod += bias;\n";
775 }
776 }
777 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
778 {
779 out << " float2 sizeVec = float2(width, height);\n"
780 " float2 sizeDdx = ddx * sizeVec;\n"
781 " float2 sizeDdy = ddy * sizeVec;\n"
782 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
783 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
784 }
785
786 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
787 }
788
789 out << " " << textureReference
790 << ".GetDimensions(mip, width, height, levels);\n";
791 }
792 }
793 else if (IsSampler3D(textureFunction.sampler))
794 {
795 out << " float width; float height; float depth; float levels;\n";
796
797 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
798 {
799 out << " uint mip = 0;\n";
800 }
801 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
802 {
803 out << " uint mip = bias;\n";
804 }
805 else
806 {
807 out << " " << textureReference
808 << ".GetDimensions(0, width, height, depth, levels);\n";
809
810 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
811 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
812 {
813 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
814 " float dx = length(ddx(tSized));\n"
815 " float dy = length(ddy(tSized));\n"
816 " float lod = log2(max(dx, dy));\n";
817
818 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
819 {
820 out << " lod += bias;\n";
821 }
822 }
823 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
824 {
825 out << " float3 sizeVec = float3(width, height, depth);\n"
826 " float3 sizeDdx = ddx * sizeVec;\n"
827 " float3 sizeDdy = ddy * sizeVec;\n"
828 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
829 "sizeDdy))) * 0.5f;\n";
830 }
831
832 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
833 }
834
835 out << " " << textureReference
836 << ".GetDimensions(mip, width, height, depth, levels);\n";
837 }
838 else
839 UNREACHABLE();
840
841 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
842 }
843}
844
845void OutputTextureSampleFunctionReturnStatement(
846 TInfoSinkBase &out,
847 const TextureFunctionHLSL::TextureFunction &textureFunction,
848 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200849 const ImmutableString &textureReference,
850 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200851 const ImmutableString &texCoordX,
852 const ImmutableString &texCoordY,
853 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300854{
855 out << " return ";
856
857 // HLSL intrinsic
858 if (outputType == SH_HLSL_3_0_OUTPUT)
859 {
860 switch (textureFunction.sampler)
861 {
862 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400863 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300864 out << "tex2D";
865 break;
866 case EbtSamplerCube:
867 out << "texCUBE";
868 break;
869 default:
870 UNREACHABLE();
871 }
872
873 switch (textureFunction.method)
874 {
875 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
876 out << "(" << samplerReference << ", ";
877 break;
878 case TextureFunctionHLSL::TextureFunction::BIAS:
879 out << "bias(" << samplerReference << ", ";
880 break;
881 case TextureFunctionHLSL::TextureFunction::LOD:
882 out << "lod(" << samplerReference << ", ";
883 break;
884 case TextureFunctionHLSL::TextureFunction::LOD0:
885 out << "lod(" << samplerReference << ", ";
886 break;
887 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
888 out << "lod(" << samplerReference << ", ";
889 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400890 case TextureFunctionHLSL::TextureFunction::GRAD:
891 out << "grad(" << samplerReference << ", ";
892 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300893 default:
894 UNREACHABLE();
895 }
896 }
897 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
898 {
899 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
900 }
901 else
902 UNREACHABLE();
903
904 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
905
906 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
907 << texCoordY;
908
909 if (outputType == SH_HLSL_3_0_OUTPUT)
910 {
911 if (hlslCoords >= 3)
912 {
913 if (textureFunction.coords < 3)
914 {
915 out << ", 0";
916 }
917 else
918 {
919 out << ", " << texCoordZ;
920 }
921 }
922
923 if (hlslCoords == 4)
924 {
925 switch (textureFunction.method)
926 {
927 case TextureFunctionHLSL::TextureFunction::BIAS:
928 out << ", bias";
929 break;
930 case TextureFunctionHLSL::TextureFunction::LOD:
931 out << ", lod";
932 break;
933 case TextureFunctionHLSL::TextureFunction::LOD0:
934 out << ", 0";
935 break;
936 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
937 out << ", bias";
938 break;
939 default:
940 UNREACHABLE();
941 }
942 }
943
944 out << ")";
945 }
946 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
947 {
948 if (hlslCoords >= 3)
949 {
950 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
951 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
952 out << ", " << texCoordZ;
953 }
954
955 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
956 {
957 if (IsIntegerSampler(textureFunction.sampler))
958 {
959 out << ", mip)";
960 }
961 else if (IsShadowSampler(textureFunction.sampler))
962 {
963 // Compare value
964 if (textureFunction.proj)
965 {
966 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
967 // The resulting third component of P' in the shadow forms is used as
968 // Dref
969 out << "), " << texCoordZ;
970 }
971 else
972 {
973 switch (textureFunction.coords)
974 {
975 case 3:
976 out << "), t.z";
977 break;
978 case 4:
979 out << "), t.w";
980 break;
981 default:
982 UNREACHABLE();
983 }
984 }
985 }
986 else
987 {
988 out << "), ddx, ddy";
989 }
990 }
991 else if (IsIntegerSampler(textureFunction.sampler) ||
992 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
993 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800994 if (textureFunction.sampler == EbtSampler2DMS ||
995 textureFunction.sampler == EbtISampler2DMS ||
996 textureFunction.sampler == EbtUSampler2DMS)
997 out << "), index";
998 else
999 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001000 }
1001 else if (IsShadowSampler(textureFunction.sampler))
1002 {
1003 // Compare value
1004 if (textureFunction.proj)
1005 {
1006 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1007 // The resulting third component of P' in the shadow forms is used as Dref
1008 out << "), " << texCoordZ;
1009 }
1010 else
1011 {
1012 switch (textureFunction.coords)
1013 {
1014 case 3:
1015 out << "), t.z";
1016 break;
1017 case 4:
1018 out << "), t.w";
1019 break;
1020 default:
1021 UNREACHABLE();
1022 }
1023 }
1024 }
1025 else
1026 {
1027 switch (textureFunction.method)
1028 {
1029 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1030 out << ")";
1031 break;
1032 case TextureFunctionHLSL::TextureFunction::BIAS:
1033 out << "), bias";
1034 break;
1035 case TextureFunctionHLSL::TextureFunction::LOD:
1036 out << "), lod";
1037 break;
1038 case TextureFunctionHLSL::TextureFunction::LOD0:
1039 out << "), 0";
1040 break;
1041 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1042 out << "), bias";
1043 break;
1044 default:
1045 UNREACHABLE();
1046 }
1047 }
1048
1049 if (textureFunction.offset &&
1050 (!IsIntegerSampler(textureFunction.sampler) ||
1051 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1052 {
1053 out << ", offset";
1054 }
1055 }
1056 else
1057 UNREACHABLE();
1058
1059 out << ");\n"; // Close the sample function call and return statement
1060}
1061
1062} // Anonymous namespace
1063
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001064ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001065{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001066 static const ImmutableString kGlTextureName("gl_texture");
1067
1068 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1069
1070 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1071
1072 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001073
1074 // We need to include full the sampler type in the function name to make the signature unique
1075 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001076 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001077
1078 if (proj)
1079 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001080 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001081 }
1082
1083 if (offset)
1084 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001085 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001086 }
1087
1088 switch (method)
1089 {
1090 case IMPLICIT:
1091 break;
1092 case BIAS:
1093 break; // Extra parameter makes the signature unique
1094 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001095 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001096 break;
1097 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001098 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001099 break;
1100 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001101 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001102 break; // Extra parameter makes the signature unique
1103 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001104 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001105 break;
1106 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001107 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001108 break;
1109 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001110 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001111 break;
1112 default:
1113 UNREACHABLE();
1114 }
1115
1116 return name;
1117}
1118
1119const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1120{
1121 if (method == TextureFunction::SIZE)
1122 {
1123 switch (sampler)
1124 {
1125 case EbtSampler2D:
1126 case EbtISampler2D:
1127 case EbtUSampler2D:
1128 case EbtSampler2DShadow:
1129 case EbtSamplerCube:
1130 case EbtISamplerCube:
1131 case EbtUSamplerCube:
1132 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001133 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001134 case EbtSampler2DMS:
1135 case EbtISampler2DMS:
1136 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001137 return "int2";
1138 case EbtSampler3D:
1139 case EbtISampler3D:
1140 case EbtUSampler3D:
1141 case EbtSampler2DArray:
1142 case EbtISampler2DArray:
1143 case EbtUSampler2DArray:
1144 case EbtSampler2DArrayShadow:
1145 return "int3";
1146 default:
1147 UNREACHABLE();
1148 }
1149 }
1150 else // Sampling function
1151 {
1152 switch (sampler)
1153 {
1154 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001155 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001156 case EbtSampler3D:
1157 case EbtSamplerCube:
1158 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001159 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001160 return "float4";
1161 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001162 case EbtISampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001163 case EbtISampler3D:
1164 case EbtISamplerCube:
1165 case EbtISampler2DArray:
1166 return "int4";
1167 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001168 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001169 case EbtUSampler3D:
1170 case EbtUSamplerCube:
1171 case EbtUSampler2DArray:
1172 return "uint4";
1173 case EbtSampler2DShadow:
1174 case EbtSamplerCubeShadow:
1175 case EbtSampler2DArrayShadow:
1176 return "float";
1177 default:
1178 UNREACHABLE();
1179 }
1180 }
1181 return "";
1182}
1183
1184bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1185{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001186 return std::tie(sampler, coords, proj, offset, method) <
1187 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001188}
1189
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001190ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1191 TBasicType samplerType,
1192 int coords,
1193 size_t argumentCount,
1194 bool lod0,
1195 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001196{
1197 TextureFunction textureFunction;
1198 textureFunction.sampler = samplerType;
1199 textureFunction.coords = coords;
1200 textureFunction.method = TextureFunction::IMPLICIT;
1201 textureFunction.proj = false;
1202 textureFunction.offset = false;
1203
1204 if (name == "texture2D" || name == "textureCube" || name == "texture")
1205 {
1206 textureFunction.method = TextureFunction::IMPLICIT;
1207 }
1208 else if (name == "texture2DProj" || name == "textureProj")
1209 {
1210 textureFunction.method = TextureFunction::IMPLICIT;
1211 textureFunction.proj = true;
1212 }
1213 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1214 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1215 {
1216 textureFunction.method = TextureFunction::LOD;
1217 }
1218 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1219 name == "texture2DProjLodEXT")
1220 {
1221 textureFunction.method = TextureFunction::LOD;
1222 textureFunction.proj = true;
1223 }
1224 else if (name == "textureSize")
1225 {
1226 textureFunction.method = TextureFunction::SIZE;
1227 }
1228 else if (name == "textureOffset")
1229 {
1230 textureFunction.method = TextureFunction::IMPLICIT;
1231 textureFunction.offset = true;
1232 }
1233 else if (name == "textureProjOffset")
1234 {
1235 textureFunction.method = TextureFunction::IMPLICIT;
1236 textureFunction.offset = true;
1237 textureFunction.proj = true;
1238 }
1239 else if (name == "textureLodOffset")
1240 {
1241 textureFunction.method = TextureFunction::LOD;
1242 textureFunction.offset = true;
1243 }
1244 else if (name == "textureProjLodOffset")
1245 {
1246 textureFunction.method = TextureFunction::LOD;
1247 textureFunction.proj = true;
1248 textureFunction.offset = true;
1249 }
1250 else if (name == "texelFetch")
1251 {
1252 textureFunction.method = TextureFunction::FETCH;
1253 }
1254 else if (name == "texelFetchOffset")
1255 {
1256 textureFunction.method = TextureFunction::FETCH;
1257 textureFunction.offset = true;
1258 }
1259 else if (name == "textureGrad" || name == "texture2DGradEXT")
1260 {
1261 textureFunction.method = TextureFunction::GRAD;
1262 }
1263 else if (name == "textureGradOffset")
1264 {
1265 textureFunction.method = TextureFunction::GRAD;
1266 textureFunction.offset = true;
1267 }
1268 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1269 name == "textureCubeGradEXT")
1270 {
1271 textureFunction.method = TextureFunction::GRAD;
1272 textureFunction.proj = true;
1273 }
1274 else if (name == "textureProjGradOffset")
1275 {
1276 textureFunction.method = TextureFunction::GRAD;
1277 textureFunction.proj = true;
1278 textureFunction.offset = true;
1279 }
1280 else
1281 UNREACHABLE();
1282
1283 if (textureFunction.method ==
1284 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1285 {
1286 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1287
1288 if (textureFunction.offset)
1289 {
1290 mandatoryArgumentCount++;
1291 }
1292
1293 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1294
1295 if (lod0 || shaderType == GL_VERTEX_SHADER)
1296 {
1297 if (bias)
1298 {
1299 textureFunction.method = TextureFunction::LOD0BIAS;
1300 }
1301 else
1302 {
1303 textureFunction.method = TextureFunction::LOD0;
1304 }
1305 }
1306 else if (bias)
1307 {
1308 textureFunction.method = TextureFunction::BIAS;
1309 }
1310 }
1311
1312 mUsesTexture.insert(textureFunction);
1313 return textureFunction.name();
1314}
1315
Geoff Lang1fe74c72016-08-25 13:23:01 -04001316void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1317 const ShShaderOutput outputType,
1318 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001319{
1320 for (const TextureFunction &textureFunction : mUsesTexture)
1321 {
1322 // Function header
1323 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1324
1325 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1326
1327 out << ")\n"
1328 "{\n";
1329
1330 // In some cases we use a variable to store the texture/sampler objects, but to work around
1331 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1332 // sampling we need to call the function directly on references to the texture and sampler
1333 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1334 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001335 ImmutableString textureReference("");
1336 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001337 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1338
1339 if (textureFunction.method == TextureFunction::SIZE)
1340 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001341 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1342 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001343 }
1344 else
1345 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001346 ImmutableString texCoordX("t.x");
1347 ImmutableString texCoordY("t.y");
1348 ImmutableString texCoordZ("t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001349 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1350 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1351 textureReference, &texCoordX, &texCoordY,
1352 &texCoordZ);
1353 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1354 textureReference, samplerReference,
1355 texCoordX, texCoordY, texCoordZ);
1356 }
1357
1358 out << "}\n"
1359 "\n";
1360 }
1361}
1362
1363} // namespace sh