blob: edaf6fd1e6573cd146b0f18c4e31636b5ce60ace [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{
Jiawei Shaoa1ac3fe2018-10-10 12:29:31 +0800166 // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or
167 // unsigned integer formats.
168 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather
169 if ((IsIntegerSampler(textureFunction.sampler) &&
170 textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) ||
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300171 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
172 {
173 switch (hlslCoords)
174 {
175 case 2:
Olli Etuaho2da04532018-08-24 13:59:44 +0300176 if (IsSampler2DMS(textureFunction.sampler))
177 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800178 return "int2";
Olli Etuaho2da04532018-08-24 13:59:44 +0300179 }
JiangYizhou5b03f472017-01-09 10:22:53 +0800180 else
Olli Etuaho2da04532018-08-24 13:59:44 +0300181 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800182 return "int3";
Olli Etuaho2da04532018-08-24 13:59:44 +0300183 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300184 case 3:
Olli Etuaho2da04532018-08-24 13:59:44 +0300185 if (IsSampler2DMSArray(textureFunction.sampler))
186 {
187 return "int3";
188 }
189 else
190 {
191 return "int4";
192 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300193 default:
194 UNREACHABLE();
195 }
196 }
197 else
198 {
199 switch (hlslCoords)
200 {
201 case 2:
202 return "float2";
203 case 3:
204 return "float3";
205 case 4:
206 return "float4";
207 default:
208 UNREACHABLE();
209 }
210 }
211 return "";
212}
213
214int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
215 ShShaderOutput outputType)
216{
217 if (outputType == SH_HLSL_3_0_OUTPUT)
218 {
219 int hlslCoords = 2;
220 switch (textureFunction.sampler)
221 {
222 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400223 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800224 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300225 hlslCoords = 2;
226 break;
227 case EbtSamplerCube:
228 hlslCoords = 3;
229 break;
230 default:
231 UNREACHABLE();
232 }
233
234 switch (textureFunction.method)
235 {
236 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400237 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300238 return hlslCoords;
239 case TextureFunctionHLSL::TextureFunction::BIAS:
240 case TextureFunctionHLSL::TextureFunction::LOD:
241 case TextureFunctionHLSL::TextureFunction::LOD0:
242 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
243 return 4;
244 default:
245 UNREACHABLE();
246 }
247 }
248 else
249 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300250 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
251 IsSamplerCube(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300252 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300253 return 3;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300254 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300255 ASSERT(IsSampler2D(textureFunction.sampler));
256 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300257 }
258 return 0;
259}
260
261void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
262 const TextureFunctionHLSL::TextureFunction &textureFunction,
263 const ShShaderOutput outputType)
264{
265 if (outputType == SH_HLSL_3_0_OUTPUT)
266 {
267 switch (textureFunction.sampler)
268 {
269 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400270 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300271 out << "sampler2D s";
272 break;
273 case EbtSamplerCube:
274 out << "samplerCUBE s";
275 break;
276 default:
277 UNREACHABLE();
278 }
279 }
280 else
281 {
282 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
283 {
284 out << TextureString(textureFunction.sampler) << " x, "
285 << SamplerString(textureFunction.sampler) << " s";
286 }
287 else
288 {
289 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400290 // A bug in the D3D compiler causes some nested sampling operations to fail.
291 // See http://anglebug.com/1923
292 // TODO(jmadill): Reinstate the const keyword when possible.
293 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300294 }
295 }
296
297 if (textureFunction.method ==
298 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
299 {
300 switch (textureFunction.coords)
301 {
302 case 2:
303 out << ", int2 t";
304 break;
305 case 3:
306 out << ", int3 t";
307 break;
308 default:
309 UNREACHABLE();
310 }
311 }
312 else // Floating-point coordinates (except textureSize)
313 {
314 switch (textureFunction.coords)
315 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000316 case 0:
317 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300318 case 1:
319 out << ", int lod";
320 break; // textureSize()
321 case 2:
322 out << ", float2 t";
323 break;
324 case 3:
325 out << ", float3 t";
326 break;
327 case 4:
328 out << ", float4 t";
329 break;
330 default:
331 UNREACHABLE();
332 }
333 }
334
335 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
336 {
337 switch (textureFunction.sampler)
338 {
339 case EbtSampler2D:
340 case EbtISampler2D:
341 case EbtUSampler2D:
342 case EbtSampler2DArray:
343 case EbtISampler2DArray:
344 case EbtUSampler2DArray:
345 case EbtSampler2DShadow:
346 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400347 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300348 out << ", float2 ddx, float2 ddy";
349 break;
350 case EbtSampler3D:
351 case EbtISampler3D:
352 case EbtUSampler3D:
353 case EbtSamplerCube:
354 case EbtISamplerCube:
355 case EbtUSamplerCube:
356 case EbtSamplerCubeShadow:
357 out << ", float3 ddx, float3 ddy";
358 break;
359 default:
360 UNREACHABLE();
361 }
362 }
363
364 switch (textureFunction.method)
365 {
366 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
367 break;
368 case TextureFunctionHLSL::TextureFunction::BIAS:
369 break; // Comes after the offset parameter
370 case TextureFunctionHLSL::TextureFunction::LOD:
371 out << ", float lod";
372 break;
373 case TextureFunctionHLSL::TextureFunction::LOD0:
374 break;
375 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
376 break; // Comes after the offset parameter
377 case TextureFunctionHLSL::TextureFunction::SIZE:
378 break;
379 case TextureFunctionHLSL::TextureFunction::FETCH:
Olli Etuaho2da04532018-08-24 13:59:44 +0300380 if (IsSampler2DMS(textureFunction.sampler) ||
381 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +0800382 out << ", int index";
383 else
384 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300385 break;
386 case TextureFunctionHLSL::TextureFunction::GRAD:
387 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800388 case TextureFunctionHLSL::TextureFunction::GATHER:
389 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300390 default:
391 UNREACHABLE();
392 }
393
Jiawei Shao19b51d22018-09-19 15:14:45 +0800394 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
395 IsShadowSampler(textureFunction.sampler))
396 {
397 out << ", float refZ";
398 }
399
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300400 if (textureFunction.offset)
401 {
402 switch (textureFunction.sampler)
403 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300404 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300405 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300406 case EbtUSampler3D:
407 out << ", int3 offset";
408 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300409 case EbtSampler2D:
410 case EbtSampler2DArray:
411 case EbtISampler2D:
412 case EbtISampler2DArray:
413 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300414 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300415 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300416 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400417 case EbtSamplerExternalOES:
418 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300419 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300420 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300421 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300422 UNREACHABLE();
423 }
424 }
425
426 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
427 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
428 {
429 out << ", float bias";
430 }
Jiawei Shao19b51d22018-09-19 15:14:45 +0800431 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
432 !IsShadowSampler(textureFunction.sampler))
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800433 {
434 out << ", int comp = 0";
435 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300436}
437
438void GetTextureReference(TInfoSinkBase &out,
439 const TextureFunctionHLSL::TextureFunction &textureFunction,
440 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200441 ImmutableString *textureReference,
442 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300443{
444 if (outputType == SH_HLSL_4_1_OUTPUT)
445 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200446 static const ImmutableString kTexturesStr("textures");
447 static const ImmutableString kSamplersStr("samplers");
448 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
449 static const ImmutableString kTextureIndexStr("[textureIndex]");
450 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
451 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
452
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300453 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
454 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200455 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
456 kSamplerIndexStr.length());
457 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
458 *textureReference = textureRefBuilder;
459 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
460 kSamplerIndexStr.length());
461 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
462 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300463 }
464 else
465 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200466 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
467 << suffix.data() << ";\n";
468 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
469 kTextureIndexStr.length());
470 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
471 *textureReference = textureRefBuilder;
472
473 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
474 << suffix.data() << ";\n";
475 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
476 kSamplerArrayIndexStr.length());
477 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
478 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300479 }
480 }
481 else
482 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200483 *textureReference = ImmutableString("x");
484 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300485 }
486}
487
488void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
489 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200490 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400491 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300492{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000493 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400494 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000495 out << " uint width; uint height; uint samples;\n"
496 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400497 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300498 else if (IsSampler2DMSArray(textureFunction.sampler))
499 {
500 out << " uint width; uint height; uint depth; uint samples;\n"
501 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
502 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400503 else
504 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000505 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400506 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000507 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400508 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000509 else
510 {
511 out << " int baseLevel = 0;\n";
512 }
513
514 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
515 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
516 {
517 // "depth" stores either the number of layers in an array texture or 3D depth
518 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
519 << " " << textureReference
520 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
521 << " width = max(width >> lod, 1);\n"
522 << " height = max(height >> lod, 1);\n";
523
524 if (!IsSamplerArray(textureFunction.sampler))
525 {
526 out << " depth = max(depth >> lod, 1);\n";
527 }
528 }
529 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
530 {
531 out << " uint width; uint height; uint numberOfLevels;\n"
532 << " " << textureReference
533 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
534 << " width = max(width >> lod, 1);\n"
535 << " height = max(height >> lod, 1);\n";
536 }
537 else
538 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300539 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300540
541 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
542 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000543 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300544 }
545 else
546 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000547 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300548 }
549}
550
551void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200552 ImmutableString *texCoordX,
553 ImmutableString *texCoordY,
554 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300555{
556 if (textureFunction.proj)
557 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200558 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300559 switch (textureFunction.coords)
560 {
561 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200562 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300563 break;
564 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200565 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300566 break;
567 default:
568 UNREACHABLE();
569 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200570 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
571 texCoordXBuilder << '(' << *texCoordX << proj << ')';
572 *texCoordX = texCoordXBuilder;
573 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
574 texCoordYBuilder << '(' << *texCoordY << proj << ')';
575 *texCoordY = texCoordYBuilder;
576 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
577 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
578 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300579 }
580}
581
582void OutputIntegerTextureSampleFunctionComputations(
583 TInfoSinkBase &out,
584 const TextureFunctionHLSL::TextureFunction &textureFunction,
585 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200586 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200587 ImmutableString *texCoordX,
588 ImmutableString *texCoordY,
589 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300590{
591 if (!IsIntegerSampler(textureFunction.sampler))
592 {
593 return;
594 }
595 if (IsSamplerCube(textureFunction.sampler))
596 {
597 out << " float width; float height; float layers; float levels;\n";
598
599 out << " uint mip = 0;\n";
600
601 out << " " << textureReference
602 << ".GetDimensions(mip, width, height, layers, levels);\n";
603
604 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
605 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
606 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
607 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
608 "(zMajor && t.z < 0.0f);\n";
609
610 // FACE_POSITIVE_X = 000b
611 // FACE_NEGATIVE_X = 001b
612 // FACE_POSITIVE_Y = 010b
613 // FACE_NEGATIVE_Y = 011b
614 // FACE_POSITIVE_Z = 100b
615 // FACE_NEGATIVE_Z = 101b
616 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
617
618 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
619 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
620 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
621
622 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
623 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
624
625 // Mip level computation.
626 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
627 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
628 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
629 {
630 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
631 {
632 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
633 " float2 dx = ddx(tSized);\n"
634 " float2 dy = ddy(tSized);\n"
635 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
636 }
637 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
638 {
639 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
640 // derivatives of P are assumed to be in the coordinate system used before
641 // texture coordinates are projected onto the appropriate cube face."
642 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
643 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
644 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
645 // Determine the derivatives of u, v and m
646 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
647 ": ddx[0]);\n"
648 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
649 ": ddy[0]);\n"
650 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
651 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
652 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
653 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
654 // Now determine the derivatives of the face coordinates, using the
655 // derivatives calculated above.
656 // d / dx (u(x) * 0.5 / m(x) + 0.5)
657 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
658 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
659 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
660 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
661 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
662 " float2 sizeVec = float2(width, height);\n"
663 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
664 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
665 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
666 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
667 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
668 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
669 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
670 }
671 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
672 << " " << textureReference
673 << ".GetDimensions(mip, width, height, layers, levels);\n";
674 }
675
676 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200677 static const ImmutableString kXPrefix("int(floor(width * frac(");
678 static const ImmutableString kYPrefix("int(floor(height * frac(");
679 static const ImmutableString kSuffix(")))");
680 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
681 kSuffix.length());
682 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
683 *texCoordX = texCoordXBuilder;
684 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
685 kSuffix.length());
686 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
687 *texCoordY = texCoordYBuilder;
688 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300689 }
690 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
691 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300692 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300693 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300694 out << " float width; float height; float layers; float levels;\n";
695
696 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300697 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300698 out << " uint mip = 0;\n";
699 }
700 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
701 {
702 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300703 }
704 else
705 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300706
707 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300708 << ".GetDimensions(0, width, height, layers, levels);\n";
709 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
710 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
711 {
712 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
713 " float dx = length(ddx(tSized));\n"
714 " float dy = length(ddy(tSized));\n"
715 " float lod = log2(max(dx, dy));\n";
716
717 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
718 {
719 out << " lod += bias;\n";
720 }
721 }
722 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
723 {
724 out << " float2 sizeVec = float2(width, height);\n"
725 " float2 sizeDdx = ddx * sizeVec;\n"
726 " float2 sizeDdy = ddy * sizeVec;\n"
727 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
728 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
729 }
730
731 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300732 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300733
734 out << " " << textureReference
735 << ".GetDimensions(mip, width, height, layers, levels);\n";
736 }
737 else if (IsSampler2D(textureFunction.sampler))
738 {
739 out << " float width; float height; float levels;\n";
740
741 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
742 {
743 out << " uint mip = 0;\n";
744 }
745 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
746 {
747 out << " uint mip = bias;\n";
748 }
749 else
750 {
751 out << " " << textureReference << ".GetDimensions(0, width, height, levels);\n";
752
753 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
754 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
755 {
756 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
757 " float dx = length(ddx(tSized));\n"
758 " float dy = length(ddy(tSized));\n"
759 " float lod = log2(max(dx, dy));\n";
760
761 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
762 {
763 out << " lod += bias;\n";
764 }
765 }
766 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
767 {
768 out << " float2 sizeVec = float2(width, height);\n"
769 " float2 sizeDdx = ddx * sizeVec;\n"
770 " float2 sizeDdy = ddy * sizeVec;\n"
771 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
772 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
773 }
774
775 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
776 }
777
778 out << " " << textureReference << ".GetDimensions(mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300779 }
780 else if (IsSampler3D(textureFunction.sampler))
781 {
782 out << " float width; float height; float depth; float levels;\n";
783
784 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
785 {
786 out << " uint mip = 0;\n";
787 }
788 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
789 {
790 out << " uint mip = bias;\n";
791 }
792 else
793 {
794 out << " " << textureReference
795 << ".GetDimensions(0, width, height, depth, levels);\n";
796
797 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
798 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
799 {
800 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
801 " float dx = length(ddx(tSized));\n"
802 " float dy = length(ddy(tSized));\n"
803 " float lod = log2(max(dx, dy));\n";
804
805 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
806 {
807 out << " lod += bias;\n";
808 }
809 }
810 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
811 {
812 out << " float3 sizeVec = float3(width, height, depth);\n"
813 " float3 sizeDdx = ddx * sizeVec;\n"
814 " float3 sizeDdy = ddy * sizeVec;\n"
815 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
816 "sizeDdy))) * 0.5f;\n";
817 }
818
819 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
820 }
821
822 out << " " << textureReference
823 << ".GetDimensions(mip, width, height, depth, levels);\n";
824 }
825 else
826 UNREACHABLE();
827
828 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
829 }
830}
831
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800832void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
833 const TextureFunctionHLSL::TextureFunction &textureFunction,
834 ShShaderOutput outputType,
835 const ImmutableString &textureReference,
836 const ImmutableString &samplerReference,
837 const ImmutableString &texCoordX,
838 const ImmutableString &texCoordY,
839 const ImmutableString &texCoordZ)
840{
841 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
842 ImmutableString samplerCoordTypeString(
843 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
844 ImmutableStringBuilder samplerCoordBuilder(
845 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
846 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
847
848 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
849 if (hlslCoords >= 3)
850 {
851 if (textureFunction.coords < 3)
852 {
853 samplerCoordBuilder << ", 0";
854 }
855 else
856 {
857 samplerCoordBuilder << ", " << texCoordZ;
858 }
859 }
860 samplerCoordBuilder << ")";
861
862 ImmutableString samplerCoordString(samplerCoordBuilder);
863
Jiawei Shao19b51d22018-09-19 15:14:45 +0800864 if (IsShadowSampler(textureFunction.sampler))
865 {
866 out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
867 << samplerCoordString << ", refZ";
868 if (textureFunction.offset)
869 {
870 out << ", offset";
871 }
872 out << ");\n";
873 return;
874 }
875
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800876 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
877 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
878
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800879 out << " switch(comp)\n"
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800880 " {\n";
881 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
882 {
883 out << " case " << component << ":\n"
884 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
885 << "(" << samplerReference << ", " << samplerCoordString;
886 if (textureFunction.offset)
887 {
888 out << ", offset";
889 }
890 out << ");\n";
891 }
892
893 out << " default:\n"
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800894 " return float4(0.0, 0.0, 0.0, 1.0);\n"
895 " }\n";
896}
897
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300898void OutputTextureSampleFunctionReturnStatement(
899 TInfoSinkBase &out,
900 const TextureFunctionHLSL::TextureFunction &textureFunction,
901 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200902 const ImmutableString &textureReference,
903 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200904 const ImmutableString &texCoordX,
905 const ImmutableString &texCoordY,
906 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300907{
908 out << " return ";
909
910 // HLSL intrinsic
911 if (outputType == SH_HLSL_3_0_OUTPUT)
912 {
913 switch (textureFunction.sampler)
914 {
915 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400916 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300917 out << "tex2D";
918 break;
919 case EbtSamplerCube:
920 out << "texCUBE";
921 break;
922 default:
923 UNREACHABLE();
924 }
925
926 switch (textureFunction.method)
927 {
928 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
929 out << "(" << samplerReference << ", ";
930 break;
931 case TextureFunctionHLSL::TextureFunction::BIAS:
932 out << "bias(" << samplerReference << ", ";
933 break;
934 case TextureFunctionHLSL::TextureFunction::LOD:
935 out << "lod(" << samplerReference << ", ";
936 break;
937 case TextureFunctionHLSL::TextureFunction::LOD0:
938 out << "lod(" << samplerReference << ", ";
939 break;
940 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
941 out << "lod(" << samplerReference << ", ";
942 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400943 case TextureFunctionHLSL::TextureFunction::GRAD:
944 out << "grad(" << samplerReference << ", ";
945 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300946 default:
947 UNREACHABLE();
948 }
949 }
950 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
951 {
952 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
953 }
954 else
955 UNREACHABLE();
956
957 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
958
959 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
960 << texCoordY;
961
962 if (outputType == SH_HLSL_3_0_OUTPUT)
963 {
964 if (hlslCoords >= 3)
965 {
966 if (textureFunction.coords < 3)
967 {
968 out << ", 0";
969 }
970 else
971 {
972 out << ", " << texCoordZ;
973 }
974 }
975
976 if (hlslCoords == 4)
977 {
978 switch (textureFunction.method)
979 {
980 case TextureFunctionHLSL::TextureFunction::BIAS:
981 out << ", bias";
982 break;
983 case TextureFunctionHLSL::TextureFunction::LOD:
984 out << ", lod";
985 break;
986 case TextureFunctionHLSL::TextureFunction::LOD0:
987 out << ", 0";
988 break;
989 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
990 out << ", bias";
991 break;
992 default:
993 UNREACHABLE();
994 }
995 }
996
997 out << ")";
998 }
999 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1000 {
1001 if (hlslCoords >= 3)
1002 {
1003 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
1004 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
1005 out << ", " << texCoordZ;
1006 }
1007
1008 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
1009 {
1010 if (IsIntegerSampler(textureFunction.sampler))
1011 {
1012 out << ", mip)";
1013 }
1014 else if (IsShadowSampler(textureFunction.sampler))
1015 {
1016 // Compare value
1017 if (textureFunction.proj)
1018 {
1019 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1020 // The resulting third component of P' in the shadow forms is used as
1021 // Dref
1022 out << "), " << texCoordZ;
1023 }
1024 else
1025 {
1026 switch (textureFunction.coords)
1027 {
1028 case 3:
1029 out << "), t.z";
1030 break;
1031 case 4:
1032 out << "), t.w";
1033 break;
1034 default:
1035 UNREACHABLE();
1036 }
1037 }
1038 }
1039 else
1040 {
1041 out << "), ddx, ddy";
1042 }
1043 }
1044 else if (IsIntegerSampler(textureFunction.sampler) ||
1045 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1046 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001047 if (IsSampler2DMS(textureFunction.sampler) ||
1048 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001049 out << "), index";
1050 else
1051 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001052 }
1053 else if (IsShadowSampler(textureFunction.sampler))
1054 {
1055 // Compare value
1056 if (textureFunction.proj)
1057 {
1058 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1059 // The resulting third component of P' in the shadow forms is used as Dref
1060 out << "), " << texCoordZ;
1061 }
1062 else
1063 {
1064 switch (textureFunction.coords)
1065 {
1066 case 3:
1067 out << "), t.z";
1068 break;
1069 case 4:
1070 out << "), t.w";
1071 break;
1072 default:
1073 UNREACHABLE();
1074 }
1075 }
1076 }
1077 else
1078 {
1079 switch (textureFunction.method)
1080 {
1081 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1082 out << ")";
1083 break;
1084 case TextureFunctionHLSL::TextureFunction::BIAS:
1085 out << "), bias";
1086 break;
1087 case TextureFunctionHLSL::TextureFunction::LOD:
1088 out << "), lod";
1089 break;
1090 case TextureFunctionHLSL::TextureFunction::LOD0:
1091 out << "), 0";
1092 break;
1093 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1094 out << "), bias";
1095 break;
1096 default:
1097 UNREACHABLE();
1098 }
1099 }
1100
1101 if (textureFunction.offset &&
1102 (!IsIntegerSampler(textureFunction.sampler) ||
1103 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1104 {
1105 out << ", offset";
1106 }
1107 }
1108 else
1109 UNREACHABLE();
1110
1111 out << ");\n"; // Close the sample function call and return statement
1112}
1113
1114} // Anonymous namespace
1115
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001116ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001117{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001118 static const ImmutableString kGlTextureName("gl_texture");
1119
1120 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1121
1122 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1123
1124 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001125
1126 // We need to include full the sampler type in the function name to make the signature unique
1127 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001128 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001129
1130 if (proj)
1131 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001132 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001133 }
1134
1135 if (offset)
1136 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001137 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001138 }
1139
1140 switch (method)
1141 {
1142 case IMPLICIT:
1143 break;
1144 case BIAS:
1145 break; // Extra parameter makes the signature unique
1146 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001147 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001148 break;
1149 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001150 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001151 break;
1152 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001153 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001154 break; // Extra parameter makes the signature unique
1155 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001156 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001157 break;
1158 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001159 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001160 break;
1161 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001162 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001163 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001164 case GATHER:
1165 name << "Gather";
1166 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001167 default:
1168 UNREACHABLE();
1169 }
1170
1171 return name;
1172}
1173
1174const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1175{
1176 if (method == TextureFunction::SIZE)
1177 {
1178 switch (sampler)
1179 {
1180 case EbtSampler2D:
1181 case EbtISampler2D:
1182 case EbtUSampler2D:
1183 case EbtSampler2DShadow:
1184 case EbtSamplerCube:
1185 case EbtISamplerCube:
1186 case EbtUSamplerCube:
1187 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001188 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001189 case EbtSampler2DMS:
1190 case EbtISampler2DMS:
1191 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001192 return "int2";
1193 case EbtSampler3D:
1194 case EbtISampler3D:
1195 case EbtUSampler3D:
1196 case EbtSampler2DArray:
1197 case EbtISampler2DArray:
1198 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001199 case EbtSampler2DMSArray:
1200 case EbtISampler2DMSArray:
1201 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001202 case EbtSampler2DArrayShadow:
1203 return "int3";
1204 default:
1205 UNREACHABLE();
1206 }
1207 }
1208 else // Sampling function
1209 {
1210 switch (sampler)
1211 {
1212 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001213 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001214 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001215 case EbtSampler3D:
1216 case EbtSamplerCube:
1217 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001218 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001219 return "float4";
1220 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001221 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001222 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001223 case EbtISampler3D:
1224 case EbtISamplerCube:
1225 case EbtISampler2DArray:
1226 return "int4";
1227 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001228 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001229 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001230 case EbtUSampler3D:
1231 case EbtUSamplerCube:
1232 case EbtUSampler2DArray:
1233 return "uint4";
1234 case EbtSampler2DShadow:
1235 case EbtSamplerCubeShadow:
1236 case EbtSampler2DArrayShadow:
Jiawei Shao19b51d22018-09-19 15:14:45 +08001237 if (method == TextureFunctionHLSL::TextureFunction::GATHER)
1238 {
1239 return "float4";
1240 }
1241 else
1242 {
1243 return "float";
1244 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001245 default:
1246 UNREACHABLE();
1247 }
1248 }
1249 return "";
1250}
1251
1252bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1253{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001254 return std::tie(sampler, coords, proj, offset, method) <
1255 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001256}
1257
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001258ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1259 TBasicType samplerType,
1260 int coords,
1261 size_t argumentCount,
1262 bool lod0,
1263 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001264{
1265 TextureFunction textureFunction;
1266 textureFunction.sampler = samplerType;
1267 textureFunction.coords = coords;
1268 textureFunction.method = TextureFunction::IMPLICIT;
1269 textureFunction.proj = false;
1270 textureFunction.offset = false;
1271
1272 if (name == "texture2D" || name == "textureCube" || name == "texture")
1273 {
1274 textureFunction.method = TextureFunction::IMPLICIT;
1275 }
1276 else if (name == "texture2DProj" || name == "textureProj")
1277 {
1278 textureFunction.method = TextureFunction::IMPLICIT;
1279 textureFunction.proj = true;
1280 }
1281 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1282 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1283 {
1284 textureFunction.method = TextureFunction::LOD;
1285 }
1286 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1287 name == "texture2DProjLodEXT")
1288 {
1289 textureFunction.method = TextureFunction::LOD;
1290 textureFunction.proj = true;
1291 }
1292 else if (name == "textureSize")
1293 {
1294 textureFunction.method = TextureFunction::SIZE;
1295 }
1296 else if (name == "textureOffset")
1297 {
1298 textureFunction.method = TextureFunction::IMPLICIT;
1299 textureFunction.offset = true;
1300 }
1301 else if (name == "textureProjOffset")
1302 {
1303 textureFunction.method = TextureFunction::IMPLICIT;
1304 textureFunction.offset = true;
1305 textureFunction.proj = true;
1306 }
1307 else if (name == "textureLodOffset")
1308 {
1309 textureFunction.method = TextureFunction::LOD;
1310 textureFunction.offset = true;
1311 }
1312 else if (name == "textureProjLodOffset")
1313 {
1314 textureFunction.method = TextureFunction::LOD;
1315 textureFunction.proj = true;
1316 textureFunction.offset = true;
1317 }
1318 else if (name == "texelFetch")
1319 {
1320 textureFunction.method = TextureFunction::FETCH;
1321 }
1322 else if (name == "texelFetchOffset")
1323 {
1324 textureFunction.method = TextureFunction::FETCH;
1325 textureFunction.offset = true;
1326 }
1327 else if (name == "textureGrad" || name == "texture2DGradEXT")
1328 {
1329 textureFunction.method = TextureFunction::GRAD;
1330 }
1331 else if (name == "textureGradOffset")
1332 {
1333 textureFunction.method = TextureFunction::GRAD;
1334 textureFunction.offset = true;
1335 }
1336 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1337 name == "textureCubeGradEXT")
1338 {
1339 textureFunction.method = TextureFunction::GRAD;
1340 textureFunction.proj = true;
1341 }
1342 else if (name == "textureProjGradOffset")
1343 {
1344 textureFunction.method = TextureFunction::GRAD;
1345 textureFunction.proj = true;
1346 textureFunction.offset = true;
1347 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001348 else if (name == "textureGather")
1349 {
1350 textureFunction.method = TextureFunction::GATHER;
1351 }
Jiawei Shaocf8ad762018-09-21 09:11:35 +08001352 else if (name == "textureGatherOffset")
1353 {
1354 textureFunction.method = TextureFunction::GATHER;
1355 textureFunction.offset = true;
1356 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001357 else
1358 UNREACHABLE();
1359
1360 if (textureFunction.method ==
1361 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1362 {
1363 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1364
1365 if (textureFunction.offset)
1366 {
1367 mandatoryArgumentCount++;
1368 }
1369
1370 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1371
1372 if (lod0 || shaderType == GL_VERTEX_SHADER)
1373 {
1374 if (bias)
1375 {
1376 textureFunction.method = TextureFunction::LOD0BIAS;
1377 }
1378 else
1379 {
1380 textureFunction.method = TextureFunction::LOD0;
1381 }
1382 }
1383 else if (bias)
1384 {
1385 textureFunction.method = TextureFunction::BIAS;
1386 }
1387 }
1388
1389 mUsesTexture.insert(textureFunction);
1390 return textureFunction.name();
1391}
1392
Geoff Lang1fe74c72016-08-25 13:23:01 -04001393void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1394 const ShShaderOutput outputType,
1395 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001396{
1397 for (const TextureFunction &textureFunction : mUsesTexture)
1398 {
1399 // Function header
1400 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1401
1402 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1403
1404 out << ")\n"
1405 "{\n";
1406
1407 // In some cases we use a variable to store the texture/sampler objects, but to work around
1408 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1409 // sampling we need to call the function directly on references to the texture and sampler
1410 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1411 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001412 ImmutableString textureReference("");
1413 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001414 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1415
1416 if (textureFunction.method == TextureFunction::SIZE)
1417 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001418 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1419 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001420 }
1421 else
1422 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001423 ImmutableString texCoordX("t.x");
1424 ImmutableString texCoordY("t.y");
1425 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001426 if (textureFunction.method == TextureFunction::GATHER)
1427 {
1428 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1429 samplerReference, texCoordX, texCoordY, texCoordZ);
1430 }
1431 else
1432 {
1433 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1434 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1435 textureReference, &texCoordX,
1436 &texCoordY, &texCoordZ);
1437 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1438 textureReference, samplerReference,
1439 texCoordX, texCoordY, texCoordZ);
1440 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001441 }
1442
1443 out << "}\n"
1444 "\n";
1445 }
1446}
1447
1448} // namespace sh