blob: 4fc1fce0e4bbf438f73ba80e511c6fad777c2494 [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";
Till Rathmannb8543632018-10-02 19:46:14 +020035 out << "bool " << texCoordOutName << "UseBorderColor = false;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +030036
37 // CLAMP_TO_EDGE
Till Rathmannb8543632018-10-02 19:46:14 +020038 out << "if (" << wrapMode << " == 0)\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +030039 out << "{\n";
40 out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
41 << "Offset)), 0, int(" << size << ") - 1);\n";
42 out << "}\n";
43
Till Rathmannb8543632018-10-02 19:46:14 +020044 // CLAMP_TO_BORDER
Olli Etuaho5858f7e2016-04-08 13:08:46 +030045 out << "else if (" << wrapMode << " == 3)\n";
46 out << "{\n";
Till Rathmannb8543632018-10-02 19:46:14 +020047 out << " int texCoordInt = int(floor(" << size << " * " << texCoordOutName << "Offset));\n";
48 out << " " << texCoordOutName << " = clamp(texCoordInt, 0, int(" << size << ") - 1);\n";
Jamie Madillb980c562018-11-27 11:34:27 -050049 out << " " << texCoordOutName << "UseBorderColor = (texCoordInt != " << texCoordOutName
50 << ");\n";
Till Rathmannb8543632018-10-02 19:46:14 +020051 out << "}\n";
52
53 // MIRRORED_REPEAT
54 out << "else if (" << wrapMode << " == 2)\n";
55 out << "{\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +030056 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
57 << "Offset) * 0.5) * 2.0 - 1.0);\n";
58 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
59 out << "}\n";
60
61 // REPEAT
62 out << "else\n";
63 out << "{\n";
64 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
65 << "Offset)));\n";
66 out << "}\n";
67}
68
69void OutputIntTexCoordWraps(TInfoSinkBase &out,
70 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +020071 ImmutableString *texCoordX,
72 ImmutableString *texCoordY,
73 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +030074{
75 // Convert from normalized floating-point to integer
76 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
77 if (textureFunction.offset)
78 {
79 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
80 }
81 else
82 {
83 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
84 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020085 *texCoordX = ImmutableString("tix");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030086 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
87 if (textureFunction.offset)
88 {
89 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
90 }
91 else
92 {
93 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
94 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020095 *texCoordY = ImmutableString("tiy");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030096
Till Rathmannb8543632018-10-02 19:46:14 +020097 bool tizAvailable = false;
98
Olli Etuaho5858f7e2016-04-08 13:08:46 +030099 if (IsSamplerArray(textureFunction.sampler))
100 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200101 *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300102 }
103 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
104 {
105 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
106 if (textureFunction.offset)
107 {
108 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
109 }
110 else
111 {
112 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
113 }
Till Rathmannb8543632018-10-02 19:46:14 +0200114 *texCoordZ = ImmutableString("tiz");
115 tizAvailable = true;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300116 }
Till Rathmannb8543632018-10-02 19:46:14 +0200117
118 out << "bool useBorderColor = tixUseBorderColor || tiyUseBorderColor"
119 << (tizAvailable ? " || tizUseBorderColor" : "") << ";\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300120}
121
122void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
123 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200124 const ImmutableString &textureReference,
125 const ImmutableString &samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300126{
127 out << textureReference;
128 if (IsIntegerSampler(textureFunction.sampler) ||
129 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
130 {
131 out << ".Load(";
132 return;
133 }
134
135 if (IsShadowSampler(textureFunction.sampler))
136 {
137 switch (textureFunction.method)
138 {
139 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
140 case TextureFunctionHLSL::TextureFunction::BIAS:
141 case TextureFunctionHLSL::TextureFunction::LOD:
142 out << ".SampleCmp(";
143 break;
144 case TextureFunctionHLSL::TextureFunction::LOD0:
145 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
146 case TextureFunctionHLSL::TextureFunction::GRAD:
147 out << ".SampleCmpLevelZero(";
148 break;
149 default:
150 UNREACHABLE();
151 }
152 }
153 else
154 {
155 switch (textureFunction.method)
156 {
157 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
158 out << ".Sample(";
159 break;
160 case TextureFunctionHLSL::TextureFunction::BIAS:
161 out << ".SampleBias(";
162 break;
163 case TextureFunctionHLSL::TextureFunction::LOD:
164 case TextureFunctionHLSL::TextureFunction::LOD0:
165 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
166 out << ".SampleLevel(";
167 break;
168 case TextureFunctionHLSL::TextureFunction::GRAD:
169 out << ".SampleGrad(";
170 break;
171 default:
172 UNREACHABLE();
173 }
174 }
175 out << samplerReference << ", ";
176}
177
178const char *GetSamplerCoordinateTypeString(
179 const TextureFunctionHLSL::TextureFunction &textureFunction,
180 int hlslCoords)
181{
Jiawei Shaoa1ac3fe2018-10-10 12:29:31 +0800182 // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or
183 // unsigned integer formats.
184 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather
185 if ((IsIntegerSampler(textureFunction.sampler) &&
186 textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) ||
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300187 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
188 {
189 switch (hlslCoords)
190 {
191 case 2:
Olli Etuaho2da04532018-08-24 13:59:44 +0300192 if (IsSampler2DMS(textureFunction.sampler))
193 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800194 return "int2";
Olli Etuaho2da04532018-08-24 13:59:44 +0300195 }
JiangYizhou5b03f472017-01-09 10:22:53 +0800196 else
Olli Etuaho2da04532018-08-24 13:59:44 +0300197 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800198 return "int3";
Olli Etuaho2da04532018-08-24 13:59:44 +0300199 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300200 case 3:
Olli Etuaho2da04532018-08-24 13:59:44 +0300201 if (IsSampler2DMSArray(textureFunction.sampler))
202 {
203 return "int3";
204 }
205 else
206 {
207 return "int4";
208 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300209 default:
210 UNREACHABLE();
211 }
212 }
213 else
214 {
215 switch (hlslCoords)
216 {
217 case 2:
218 return "float2";
219 case 3:
220 return "float3";
221 case 4:
222 return "float4";
223 default:
224 UNREACHABLE();
225 }
226 }
227 return "";
228}
229
230int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
231 ShShaderOutput outputType)
232{
233 if (outputType == SH_HLSL_3_0_OUTPUT)
234 {
235 int hlslCoords = 2;
236 switch (textureFunction.sampler)
237 {
238 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400239 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800240 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300241 hlslCoords = 2;
242 break;
243 case EbtSamplerCube:
244 hlslCoords = 3;
245 break;
246 default:
247 UNREACHABLE();
248 }
249
250 switch (textureFunction.method)
251 {
252 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400253 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300254 return hlslCoords;
255 case TextureFunctionHLSL::TextureFunction::BIAS:
256 case TextureFunctionHLSL::TextureFunction::LOD:
257 case TextureFunctionHLSL::TextureFunction::LOD0:
258 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
259 return 4;
260 default:
261 UNREACHABLE();
262 }
263 }
264 else
265 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300266 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
267 IsSamplerCube(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300268 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300269 return 3;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300270 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300271 ASSERT(IsSampler2D(textureFunction.sampler));
272 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300273 }
274 return 0;
275}
276
277void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
278 const TextureFunctionHLSL::TextureFunction &textureFunction,
279 const ShShaderOutput outputType)
280{
281 if (outputType == SH_HLSL_3_0_OUTPUT)
282 {
283 switch (textureFunction.sampler)
284 {
285 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400286 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300287 out << "sampler2D s";
288 break;
289 case EbtSamplerCube:
290 out << "samplerCUBE s";
291 break;
292 default:
293 UNREACHABLE();
294 }
295 }
296 else
297 {
298 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
299 {
300 out << TextureString(textureFunction.sampler) << " x, "
301 << SamplerString(textureFunction.sampler) << " s";
302 }
303 else
304 {
305 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400306 // A bug in the D3D compiler causes some nested sampling operations to fail.
307 // See http://anglebug.com/1923
308 // TODO(jmadill): Reinstate the const keyword when possible.
309 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300310 }
311 }
312
313 if (textureFunction.method ==
314 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
315 {
316 switch (textureFunction.coords)
317 {
318 case 2:
319 out << ", int2 t";
320 break;
321 case 3:
322 out << ", int3 t";
323 break;
324 default:
325 UNREACHABLE();
326 }
327 }
328 else // Floating-point coordinates (except textureSize)
329 {
330 switch (textureFunction.coords)
331 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000332 case 0:
333 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300334 case 1:
335 out << ", int lod";
336 break; // textureSize()
337 case 2:
338 out << ", float2 t";
339 break;
340 case 3:
341 out << ", float3 t";
342 break;
343 case 4:
344 out << ", float4 t";
345 break;
346 default:
347 UNREACHABLE();
348 }
349 }
350
351 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
352 {
353 switch (textureFunction.sampler)
354 {
355 case EbtSampler2D:
356 case EbtISampler2D:
357 case EbtUSampler2D:
358 case EbtSampler2DArray:
359 case EbtISampler2DArray:
360 case EbtUSampler2DArray:
361 case EbtSampler2DShadow:
362 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400363 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300364 out << ", float2 ddx, float2 ddy";
365 break;
366 case EbtSampler3D:
367 case EbtISampler3D:
368 case EbtUSampler3D:
369 case EbtSamplerCube:
370 case EbtISamplerCube:
371 case EbtUSamplerCube:
372 case EbtSamplerCubeShadow:
373 out << ", float3 ddx, float3 ddy";
374 break;
375 default:
376 UNREACHABLE();
377 }
378 }
379
380 switch (textureFunction.method)
381 {
382 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
383 break;
384 case TextureFunctionHLSL::TextureFunction::BIAS:
385 break; // Comes after the offset parameter
386 case TextureFunctionHLSL::TextureFunction::LOD:
387 out << ", float lod";
388 break;
389 case TextureFunctionHLSL::TextureFunction::LOD0:
390 break;
391 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
392 break; // Comes after the offset parameter
393 case TextureFunctionHLSL::TextureFunction::SIZE:
394 break;
395 case TextureFunctionHLSL::TextureFunction::FETCH:
Olli Etuaho2da04532018-08-24 13:59:44 +0300396 if (IsSampler2DMS(textureFunction.sampler) ||
397 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +0800398 out << ", int index";
399 else
400 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300401 break;
402 case TextureFunctionHLSL::TextureFunction::GRAD:
403 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800404 case TextureFunctionHLSL::TextureFunction::GATHER:
405 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300406 default:
407 UNREACHABLE();
408 }
409
Jiawei Shao19b51d22018-09-19 15:14:45 +0800410 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
411 IsShadowSampler(textureFunction.sampler))
412 {
413 out << ", float refZ";
414 }
415
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300416 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:
Ian Ewellbda75592016-04-18 17:25:54 -0400433 case EbtSamplerExternalOES:
434 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300435 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300436 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300437 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300438 UNREACHABLE();
439 }
440 }
441
442 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
443 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
444 {
445 out << ", float bias";
446 }
Jiawei Shao19b51d22018-09-19 15:14:45 +0800447 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
448 !IsShadowSampler(textureFunction.sampler))
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800449 {
450 out << ", int comp = 0";
451 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300452}
453
454void GetTextureReference(TInfoSinkBase &out,
455 const TextureFunctionHLSL::TextureFunction &textureFunction,
456 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200457 ImmutableString *textureReference,
458 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300459{
460 if (outputType == SH_HLSL_4_1_OUTPUT)
461 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200462 static const ImmutableString kTexturesStr("textures");
463 static const ImmutableString kSamplersStr("samplers");
464 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
465 static const ImmutableString kTextureIndexStr("[textureIndex]");
466 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
467 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
468
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300469 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
470 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200471 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
472 kSamplerIndexStr.length());
473 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
474 *textureReference = textureRefBuilder;
475 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
476 kSamplerIndexStr.length());
477 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
478 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300479 }
480 else
481 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200482 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
483 << suffix.data() << ";\n";
484 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
485 kTextureIndexStr.length());
486 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
487 *textureReference = textureRefBuilder;
488
489 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
490 << suffix.data() << ";\n";
491 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
492 kSamplerArrayIndexStr.length());
493 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
494 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300495 }
496 }
497 else
498 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200499 *textureReference = ImmutableString("x");
500 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300501 }
502}
503
504void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
505 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200506 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400507 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300508{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000509 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400510 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000511 out << " uint width; uint height; uint samples;\n"
512 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400513 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300514 else if (IsSampler2DMSArray(textureFunction.sampler))
515 {
516 out << " uint width; uint height; uint depth; uint samples;\n"
517 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
518 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400519 else
520 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000521 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400522 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000523 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400524 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000525 else
526 {
527 out << " int baseLevel = 0;\n";
528 }
529
530 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
531 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
532 {
533 // "depth" stores either the number of layers in an array texture or 3D depth
534 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
535 << " " << textureReference
536 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
537 << " width = max(width >> lod, 1);\n"
538 << " height = max(height >> lod, 1);\n";
539
540 if (!IsSamplerArray(textureFunction.sampler))
541 {
542 out << " depth = max(depth >> lod, 1);\n";
543 }
544 }
545 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
546 {
547 out << " uint width; uint height; uint numberOfLevels;\n"
548 << " " << textureReference
549 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
550 << " width = max(width >> lod, 1);\n"
551 << " height = max(height >> lod, 1);\n";
552 }
553 else
554 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300555 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300556
557 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
558 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000559 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300560 }
561 else
562 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000563 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300564 }
565}
566
567void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200568 ImmutableString *texCoordX,
569 ImmutableString *texCoordY,
570 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300571{
572 if (textureFunction.proj)
573 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200574 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300575 switch (textureFunction.coords)
576 {
577 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200578 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300579 break;
580 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200581 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300582 break;
583 default:
584 UNREACHABLE();
585 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200586 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
587 texCoordXBuilder << '(' << *texCoordX << proj << ')';
588 *texCoordX = texCoordXBuilder;
589 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
590 texCoordYBuilder << '(' << *texCoordY << proj << ')';
591 *texCoordY = texCoordYBuilder;
592 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
593 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
594 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300595 }
596}
597
598void OutputIntegerTextureSampleFunctionComputations(
599 TInfoSinkBase &out,
600 const TextureFunctionHLSL::TextureFunction &textureFunction,
601 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200602 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200603 ImmutableString *texCoordX,
604 ImmutableString *texCoordY,
Anders Leinof6cbe442019-04-18 15:32:07 +0300605 ImmutableString *texCoordZ,
606 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300607{
608 if (!IsIntegerSampler(textureFunction.sampler))
609 {
610 return;
611 }
612 if (IsSamplerCube(textureFunction.sampler))
613 {
Anders Leino60cc7512019-05-06 09:25:27 +0300614 if (getDimensionsIgnoresBaseLevel)
615 {
616 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
617 }
618 else
619 {
620 out << " int baseLevel = 0;\n";
621 }
622
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300623 out << " float width; float height; float layers; float levels;\n";
624
625 out << " uint mip = 0;\n";
626
627 out << " " << textureReference
Anders Leino60cc7512019-05-06 09:25:27 +0300628 << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300629
630 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
631 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
632 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
633 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
634 "(zMajor && t.z < 0.0f);\n";
635
636 // FACE_POSITIVE_X = 000b
637 // FACE_NEGATIVE_X = 001b
638 // FACE_POSITIVE_Y = 010b
639 // FACE_NEGATIVE_Y = 011b
640 // FACE_POSITIVE_Z = 100b
641 // FACE_NEGATIVE_Z = 101b
642 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
643
644 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
645 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
646 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
647
648 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
649 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
650
651 // Mip level computation.
652 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
653 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
654 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
655 {
656 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
657 {
658 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
659 " float2 dx = ddx(tSized);\n"
660 " float2 dy = ddy(tSized);\n"
661 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
662 }
663 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
664 {
665 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
666 // derivatives of P are assumed to be in the coordinate system used before
667 // texture coordinates are projected onto the appropriate cube face."
668 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
669 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
670 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
671 // Determine the derivatives of u, v and m
672 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
673 ": ddx[0]);\n"
674 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
675 ": ddy[0]);\n"
676 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
677 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
678 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
679 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
680 // Now determine the derivatives of the face coordinates, using the
681 // derivatives calculated above.
682 // d / dx (u(x) * 0.5 / m(x) + 0.5)
683 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
684 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
685 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
686 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
687 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
688 " float2 sizeVec = float2(width, height);\n"
689 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
690 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
691 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
692 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
693 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
694 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
695 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
696 }
697 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
698 << " " << textureReference
Anders Leino60cc7512019-05-06 09:25:27 +0300699 << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300700 }
701
702 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200703 static const ImmutableString kXPrefix("int(floor(width * frac(");
704 static const ImmutableString kYPrefix("int(floor(height * frac(");
705 static const ImmutableString kSuffix(")))");
706 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
707 kSuffix.length());
708 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
709 *texCoordX = texCoordXBuilder;
710 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
711 kSuffix.length());
712 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
713 *texCoordY = texCoordYBuilder;
714 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300715 }
716 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
717 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300718 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300719 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300720 out << " float width; float height; float layers; float levels;\n";
721
722 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300723 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300724 out << " uint mip = 0;\n";
725 }
726 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
727 {
728 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300729 }
730 else
731 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300732
733 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300734 << ".GetDimensions(0, width, height, layers, levels);\n";
735 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
736 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
737 {
738 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
739 " float dx = length(ddx(tSized));\n"
740 " float dy = length(ddy(tSized));\n"
741 " float lod = log2(max(dx, dy));\n";
742
743 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
744 {
745 out << " lod += bias;\n";
746 }
747 }
748 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
749 {
750 out << " float2 sizeVec = float2(width, height);\n"
751 " float2 sizeDdx = ddx * sizeVec;\n"
752 " float2 sizeDdy = ddy * sizeVec;\n"
753 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
754 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
755 }
756
757 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300758 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300759
760 out << " " << textureReference
761 << ".GetDimensions(mip, width, height, layers, levels);\n";
762 }
763 else if (IsSampler2D(textureFunction.sampler))
764 {
Anders Leinof6cbe442019-04-18 15:32:07 +0300765 if (getDimensionsIgnoresBaseLevel)
766 {
767 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
768 }
769 else
770 {
771 out << " int baseLevel = 0;\n";
772 }
773
Olli Etuaho2da04532018-08-24 13:59:44 +0300774 out << " float width; float height; float levels;\n";
775
776 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
777 {
778 out << " uint mip = 0;\n";
779 }
780 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
781 {
782 out << " uint mip = bias;\n";
783 }
784 else
785 {
Anders Leinof6cbe442019-04-18 15:32:07 +0300786 out << " " << textureReference
787 << ".GetDimensions(baseLevel, width, height, levels);\n";
Olli Etuaho2da04532018-08-24 13:59:44 +0300788
789 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
790 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
791 {
792 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
793 " float dx = length(ddx(tSized));\n"
794 " float dy = length(ddy(tSized));\n"
795 " float lod = log2(max(dx, dy));\n";
796
797 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
798 {
799 out << " lod += bias;\n";
800 }
801 }
802 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
803 {
804 out << " float2 sizeVec = float2(width, height);\n"
805 " float2 sizeDdx = ddx * sizeVec;\n"
806 " float2 sizeDdy = ddy * sizeVec;\n"
807 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
808 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
809 }
810
811 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
812 }
813
Anders Leinof6cbe442019-04-18 15:32:07 +0300814 out << " " << textureReference
815 << ".GetDimensions(baseLevel + mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300816 }
817 else if (IsSampler3D(textureFunction.sampler))
818 {
819 out << " float width; float height; float depth; float levels;\n";
820
821 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
822 {
823 out << " uint mip = 0;\n";
824 }
825 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
826 {
827 out << " uint mip = bias;\n";
828 }
829 else
830 {
831 out << " " << textureReference
832 << ".GetDimensions(0, width, height, depth, levels);\n";
833
834 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
835 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
836 {
837 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
838 " float dx = length(ddx(tSized));\n"
839 " float dy = length(ddy(tSized));\n"
840 " float lod = log2(max(dx, dy));\n";
841
842 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
843 {
844 out << " lod += bias;\n";
845 }
846 }
847 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
848 {
849 out << " float3 sizeVec = float3(width, height, depth);\n"
850 " float3 sizeDdx = ddx * sizeVec;\n"
851 " float3 sizeDdy = ddy * sizeVec;\n"
852 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
853 "sizeDdy))) * 0.5f;\n";
854 }
855
856 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
857 }
858
859 out << " " << textureReference
860 << ".GetDimensions(mip, width, height, depth, levels);\n";
861 }
862 else
863 UNREACHABLE();
864
865 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
866 }
867}
868
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800869void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
870 const TextureFunctionHLSL::TextureFunction &textureFunction,
871 ShShaderOutput outputType,
872 const ImmutableString &textureReference,
873 const ImmutableString &samplerReference,
874 const ImmutableString &texCoordX,
875 const ImmutableString &texCoordY,
876 const ImmutableString &texCoordZ)
877{
878 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
879 ImmutableString samplerCoordTypeString(
880 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
881 ImmutableStringBuilder samplerCoordBuilder(
882 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
883 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
884
885 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
886 if (hlslCoords >= 3)
887 {
888 if (textureFunction.coords < 3)
889 {
890 samplerCoordBuilder << ", 0";
891 }
892 else
893 {
894 samplerCoordBuilder << ", " << texCoordZ;
895 }
896 }
897 samplerCoordBuilder << ")";
898
899 ImmutableString samplerCoordString(samplerCoordBuilder);
900
Jiawei Shao19b51d22018-09-19 15:14:45 +0800901 if (IsShadowSampler(textureFunction.sampler))
902 {
903 out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
904 << samplerCoordString << ", refZ";
905 if (textureFunction.offset)
906 {
907 out << ", offset";
908 }
909 out << ");\n";
910 return;
911 }
912
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800913 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
914 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
915
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800916 out << " switch(comp)\n"
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800917 " {\n";
918 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
919 {
920 out << " case " << component << ":\n"
921 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
922 << "(" << samplerReference << ", " << samplerCoordString;
923 if (textureFunction.offset)
924 {
925 out << ", offset";
926 }
927 out << ");\n";
928 }
929
930 out << " default:\n"
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800931 " return float4(0.0, 0.0, 0.0, 1.0);\n"
932 " }\n";
933}
934
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300935void OutputTextureSampleFunctionReturnStatement(
936 TInfoSinkBase &out,
937 const TextureFunctionHLSL::TextureFunction &textureFunction,
938 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200939 const ImmutableString &textureReference,
940 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200941 const ImmutableString &texCoordX,
942 const ImmutableString &texCoordY,
943 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300944{
945 out << " return ";
946
Till Rathmannb8543632018-10-02 19:46:14 +0200947 if (IsIntegerSampler(textureFunction.sampler) && !IsSamplerCube(textureFunction.sampler) &&
948 textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
949 {
950 out << " useBorderColor ? ";
951 if (IsIntegerSamplerUnsigned(textureFunction.sampler))
952 {
953 out << "asuint";
954 }
955 out << "(samplerMetadata[samplerIndex].intBorderColor) : ";
956 }
957
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300958 // HLSL intrinsic
959 if (outputType == SH_HLSL_3_0_OUTPUT)
960 {
961 switch (textureFunction.sampler)
962 {
963 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400964 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300965 out << "tex2D";
966 break;
967 case EbtSamplerCube:
968 out << "texCUBE";
969 break;
970 default:
971 UNREACHABLE();
972 }
973
974 switch (textureFunction.method)
975 {
976 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
977 out << "(" << samplerReference << ", ";
978 break;
979 case TextureFunctionHLSL::TextureFunction::BIAS:
980 out << "bias(" << samplerReference << ", ";
981 break;
982 case TextureFunctionHLSL::TextureFunction::LOD:
983 out << "lod(" << samplerReference << ", ";
984 break;
985 case TextureFunctionHLSL::TextureFunction::LOD0:
986 out << "lod(" << samplerReference << ", ";
987 break;
988 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
989 out << "lod(" << samplerReference << ", ";
990 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400991 case TextureFunctionHLSL::TextureFunction::GRAD:
992 out << "grad(" << samplerReference << ", ";
993 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300994 default:
995 UNREACHABLE();
996 }
997 }
998 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
999 {
1000 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
1001 }
1002 else
1003 UNREACHABLE();
1004
1005 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
1006
1007 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
1008 << texCoordY;
1009
1010 if (outputType == SH_HLSL_3_0_OUTPUT)
1011 {
1012 if (hlslCoords >= 3)
1013 {
1014 if (textureFunction.coords < 3)
1015 {
1016 out << ", 0";
1017 }
1018 else
1019 {
1020 out << ", " << texCoordZ;
1021 }
1022 }
1023
1024 if (hlslCoords == 4)
1025 {
1026 switch (textureFunction.method)
1027 {
1028 case TextureFunctionHLSL::TextureFunction::BIAS:
1029 out << ", bias";
1030 break;
1031 case TextureFunctionHLSL::TextureFunction::LOD:
1032 out << ", lod";
1033 break;
1034 case TextureFunctionHLSL::TextureFunction::LOD0:
1035 out << ", 0";
1036 break;
1037 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1038 out << ", bias";
1039 break;
1040 default:
1041 UNREACHABLE();
1042 }
1043 }
1044
1045 out << ")";
1046 }
1047 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1048 {
1049 if (hlslCoords >= 3)
1050 {
1051 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
1052 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
1053 out << ", " << texCoordZ;
1054 }
1055
1056 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
1057 {
1058 if (IsIntegerSampler(textureFunction.sampler))
1059 {
1060 out << ", mip)";
1061 }
1062 else if (IsShadowSampler(textureFunction.sampler))
1063 {
1064 // Compare value
1065 if (textureFunction.proj)
1066 {
1067 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1068 // The resulting third component of P' in the shadow forms is used as
1069 // Dref
1070 out << "), " << texCoordZ;
1071 }
1072 else
1073 {
1074 switch (textureFunction.coords)
1075 {
1076 case 3:
1077 out << "), t.z";
1078 break;
1079 case 4:
1080 out << "), t.w";
1081 break;
1082 default:
1083 UNREACHABLE();
1084 }
1085 }
1086 }
1087 else
1088 {
1089 out << "), ddx, ddy";
1090 }
1091 }
1092 else if (IsIntegerSampler(textureFunction.sampler) ||
1093 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1094 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001095 if (IsSampler2DMS(textureFunction.sampler) ||
1096 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001097 out << "), index";
1098 else
1099 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001100 }
1101 else if (IsShadowSampler(textureFunction.sampler))
1102 {
1103 // Compare value
1104 if (textureFunction.proj)
1105 {
1106 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1107 // The resulting third component of P' in the shadow forms is used as Dref
1108 out << "), " << texCoordZ;
1109 }
1110 else
1111 {
1112 switch (textureFunction.coords)
1113 {
1114 case 3:
1115 out << "), t.z";
1116 break;
1117 case 4:
1118 out << "), t.w";
1119 break;
1120 default:
1121 UNREACHABLE();
1122 }
1123 }
1124 }
1125 else
1126 {
1127 switch (textureFunction.method)
1128 {
1129 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1130 out << ")";
1131 break;
1132 case TextureFunctionHLSL::TextureFunction::BIAS:
1133 out << "), bias";
1134 break;
1135 case TextureFunctionHLSL::TextureFunction::LOD:
1136 out << "), lod";
1137 break;
1138 case TextureFunctionHLSL::TextureFunction::LOD0:
1139 out << "), 0";
1140 break;
1141 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1142 out << "), bias";
1143 break;
1144 default:
1145 UNREACHABLE();
1146 }
1147 }
1148
1149 if (textureFunction.offset &&
1150 (!IsIntegerSampler(textureFunction.sampler) ||
1151 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1152 {
1153 out << ", offset";
1154 }
1155 }
1156 else
1157 UNREACHABLE();
1158
1159 out << ");\n"; // Close the sample function call and return statement
1160}
1161
1162} // Anonymous namespace
1163
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001164ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001165{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001166 static const ImmutableString kGlTextureName("gl_texture");
1167
1168 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1169
1170 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1171
1172 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001173
1174 // We need to include full the sampler type in the function name to make the signature unique
1175 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001176 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001177
1178 if (proj)
1179 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001180 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001181 }
1182
1183 if (offset)
1184 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001185 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001186 }
1187
1188 switch (method)
1189 {
1190 case IMPLICIT:
1191 break;
1192 case BIAS:
1193 break; // Extra parameter makes the signature unique
1194 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001195 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001196 break;
1197 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001198 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001199 break;
1200 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001201 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001202 break; // Extra parameter makes the signature unique
1203 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001204 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001205 break;
1206 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001207 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001208 break;
1209 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001210 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001211 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001212 case GATHER:
1213 name << "Gather";
1214 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001215 default:
1216 UNREACHABLE();
1217 }
1218
1219 return name;
1220}
1221
1222const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1223{
1224 if (method == TextureFunction::SIZE)
1225 {
1226 switch (sampler)
1227 {
1228 case EbtSampler2D:
1229 case EbtISampler2D:
1230 case EbtUSampler2D:
1231 case EbtSampler2DShadow:
1232 case EbtSamplerCube:
1233 case EbtISamplerCube:
1234 case EbtUSamplerCube:
1235 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001236 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001237 case EbtSampler2DMS:
1238 case EbtISampler2DMS:
1239 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001240 return "int2";
1241 case EbtSampler3D:
1242 case EbtISampler3D:
1243 case EbtUSampler3D:
1244 case EbtSampler2DArray:
1245 case EbtISampler2DArray:
1246 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001247 case EbtSampler2DMSArray:
1248 case EbtISampler2DMSArray:
1249 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001250 case EbtSampler2DArrayShadow:
1251 return "int3";
1252 default:
1253 UNREACHABLE();
1254 }
1255 }
1256 else // Sampling function
1257 {
1258 switch (sampler)
1259 {
1260 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001261 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001262 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001263 case EbtSampler3D:
1264 case EbtSamplerCube:
1265 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001266 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001267 return "float4";
1268 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001269 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001270 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001271 case EbtISampler3D:
1272 case EbtISamplerCube:
1273 case EbtISampler2DArray:
1274 return "int4";
1275 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001276 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001277 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001278 case EbtUSampler3D:
1279 case EbtUSamplerCube:
1280 case EbtUSampler2DArray:
1281 return "uint4";
1282 case EbtSampler2DShadow:
1283 case EbtSamplerCubeShadow:
1284 case EbtSampler2DArrayShadow:
Jiawei Shao19b51d22018-09-19 15:14:45 +08001285 if (method == TextureFunctionHLSL::TextureFunction::GATHER)
1286 {
1287 return "float4";
1288 }
1289 else
1290 {
1291 return "float";
1292 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001293 default:
1294 UNREACHABLE();
1295 }
1296 }
1297 return "";
1298}
1299
1300bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1301{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001302 return std::tie(sampler, coords, proj, offset, method) <
1303 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001304}
1305
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001306ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1307 TBasicType samplerType,
1308 int coords,
1309 size_t argumentCount,
1310 bool lod0,
1311 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001312{
1313 TextureFunction textureFunction;
1314 textureFunction.sampler = samplerType;
1315 textureFunction.coords = coords;
1316 textureFunction.method = TextureFunction::IMPLICIT;
1317 textureFunction.proj = false;
1318 textureFunction.offset = false;
1319
1320 if (name == "texture2D" || name == "textureCube" || name == "texture")
1321 {
1322 textureFunction.method = TextureFunction::IMPLICIT;
1323 }
1324 else if (name == "texture2DProj" || name == "textureProj")
1325 {
1326 textureFunction.method = TextureFunction::IMPLICIT;
1327 textureFunction.proj = true;
1328 }
1329 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1330 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1331 {
1332 textureFunction.method = TextureFunction::LOD;
1333 }
1334 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1335 name == "texture2DProjLodEXT")
1336 {
1337 textureFunction.method = TextureFunction::LOD;
1338 textureFunction.proj = true;
1339 }
1340 else if (name == "textureSize")
1341 {
1342 textureFunction.method = TextureFunction::SIZE;
1343 }
1344 else if (name == "textureOffset")
1345 {
1346 textureFunction.method = TextureFunction::IMPLICIT;
1347 textureFunction.offset = true;
1348 }
1349 else if (name == "textureProjOffset")
1350 {
1351 textureFunction.method = TextureFunction::IMPLICIT;
1352 textureFunction.offset = true;
1353 textureFunction.proj = true;
1354 }
1355 else if (name == "textureLodOffset")
1356 {
1357 textureFunction.method = TextureFunction::LOD;
1358 textureFunction.offset = true;
1359 }
1360 else if (name == "textureProjLodOffset")
1361 {
1362 textureFunction.method = TextureFunction::LOD;
1363 textureFunction.proj = true;
1364 textureFunction.offset = true;
1365 }
1366 else if (name == "texelFetch")
1367 {
1368 textureFunction.method = TextureFunction::FETCH;
1369 }
1370 else if (name == "texelFetchOffset")
1371 {
1372 textureFunction.method = TextureFunction::FETCH;
1373 textureFunction.offset = true;
1374 }
1375 else if (name == "textureGrad" || name == "texture2DGradEXT")
1376 {
1377 textureFunction.method = TextureFunction::GRAD;
1378 }
1379 else if (name == "textureGradOffset")
1380 {
1381 textureFunction.method = TextureFunction::GRAD;
1382 textureFunction.offset = true;
1383 }
1384 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1385 name == "textureCubeGradEXT")
1386 {
1387 textureFunction.method = TextureFunction::GRAD;
1388 textureFunction.proj = true;
1389 }
1390 else if (name == "textureProjGradOffset")
1391 {
1392 textureFunction.method = TextureFunction::GRAD;
1393 textureFunction.proj = true;
1394 textureFunction.offset = true;
1395 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001396 else if (name == "textureGather")
1397 {
1398 textureFunction.method = TextureFunction::GATHER;
1399 }
Jiawei Shaocf8ad762018-09-21 09:11:35 +08001400 else if (name == "textureGatherOffset")
1401 {
1402 textureFunction.method = TextureFunction::GATHER;
1403 textureFunction.offset = true;
1404 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001405 else
1406 UNREACHABLE();
1407
1408 if (textureFunction.method ==
1409 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1410 {
1411 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1412
1413 if (textureFunction.offset)
1414 {
1415 mandatoryArgumentCount++;
1416 }
1417
1418 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1419
Xinghua Cao0d218da2018-12-17 11:53:52 +08001420 if (lod0 || shaderType == GL_VERTEX_SHADER || shaderType == GL_COMPUTE_SHADER)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001421 {
1422 if (bias)
1423 {
1424 textureFunction.method = TextureFunction::LOD0BIAS;
1425 }
1426 else
1427 {
1428 textureFunction.method = TextureFunction::LOD0;
1429 }
1430 }
1431 else if (bias)
1432 {
1433 textureFunction.method = TextureFunction::BIAS;
1434 }
1435 }
1436
1437 mUsesTexture.insert(textureFunction);
1438 return textureFunction.name();
1439}
1440
Geoff Lang1fe74c72016-08-25 13:23:01 -04001441void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1442 const ShShaderOutput outputType,
1443 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001444{
1445 for (const TextureFunction &textureFunction : mUsesTexture)
1446 {
1447 // Function header
1448 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1449
1450 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1451
1452 out << ")\n"
1453 "{\n";
1454
1455 // In some cases we use a variable to store the texture/sampler objects, but to work around
1456 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1457 // sampling we need to call the function directly on references to the texture and sampler
1458 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1459 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001460 ImmutableString textureReference("");
1461 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001462 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1463
1464 if (textureFunction.method == TextureFunction::SIZE)
1465 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001466 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1467 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001468 }
1469 else
1470 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001471 ImmutableString texCoordX("t.x");
1472 ImmutableString texCoordY("t.y");
1473 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001474 if (textureFunction.method == TextureFunction::GATHER)
1475 {
1476 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1477 samplerReference, texCoordX, texCoordY, texCoordZ);
1478 }
1479 else
1480 {
1481 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
Anders Leinof6cbe442019-04-18 15:32:07 +03001482 OutputIntegerTextureSampleFunctionComputations(
1483 out, textureFunction, outputType, textureReference, &texCoordX, &texCoordY,
1484 &texCoordZ, getDimensionsIgnoresBaseLevel);
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001485 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1486 textureReference, samplerReference,
1487 texCoordX, texCoordY, texCoordZ);
1488 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001489 }
1490
1491 out << "}\n"
1492 "\n";
1493 }
1494}
1495
1496} // namespace sh