blob: c3bd27a64120e942489b37f6eddccf0f569a2609 [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";
49 out << " " << texCoordOutName << "UseBorderColor = (texCoordInt != " << texCoordOutName << ");\n";
50 out << "}\n";
51
52 // MIRRORED_REPEAT
53 out << "else if (" << wrapMode << " == 2)\n";
54 out << "{\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +030055 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
56 << "Offset) * 0.5) * 2.0 - 1.0);\n";
57 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
58 out << "}\n";
59
60 // REPEAT
61 out << "else\n";
62 out << "{\n";
63 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
64 << "Offset)));\n";
65 out << "}\n";
66}
67
68void OutputIntTexCoordWraps(TInfoSinkBase &out,
69 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +020070 ImmutableString *texCoordX,
71 ImmutableString *texCoordY,
72 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +030073{
74 // Convert from normalized floating-point to integer
75 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
76 if (textureFunction.offset)
77 {
78 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
79 }
80 else
81 {
82 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
83 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020084 *texCoordX = ImmutableString("tix");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030085 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
86 if (textureFunction.offset)
87 {
88 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
89 }
90 else
91 {
92 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
93 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +020094 *texCoordY = ImmutableString("tiy");
Olli Etuaho5858f7e2016-04-08 13:08:46 +030095
Till Rathmannb8543632018-10-02 19:46:14 +020096 bool tizAvailable = false;
97
Olli Etuaho5858f7e2016-04-08 13:08:46 +030098 if (IsSamplerArray(textureFunction.sampler))
99 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200100 *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300101 }
102 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
103 {
104 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
105 if (textureFunction.offset)
106 {
107 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
108 }
109 else
110 {
111 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
112 }
Till Rathmannb8543632018-10-02 19:46:14 +0200113 *texCoordZ = ImmutableString("tiz");
114 tizAvailable = true;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300115 }
Till Rathmannb8543632018-10-02 19:46:14 +0200116
117 out << "bool useBorderColor = tixUseBorderColor || tiyUseBorderColor"
118 << (tizAvailable ? " || tizUseBorderColor" : "") << ";\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300119}
120
121void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
122 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200123 const ImmutableString &textureReference,
124 const ImmutableString &samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300125{
126 out << textureReference;
127 if (IsIntegerSampler(textureFunction.sampler) ||
128 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
129 {
130 out << ".Load(";
131 return;
132 }
133
134 if (IsShadowSampler(textureFunction.sampler))
135 {
136 switch (textureFunction.method)
137 {
138 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
139 case TextureFunctionHLSL::TextureFunction::BIAS:
140 case TextureFunctionHLSL::TextureFunction::LOD:
141 out << ".SampleCmp(";
142 break;
143 case TextureFunctionHLSL::TextureFunction::LOD0:
144 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
145 case TextureFunctionHLSL::TextureFunction::GRAD:
146 out << ".SampleCmpLevelZero(";
147 break;
148 default:
149 UNREACHABLE();
150 }
151 }
152 else
153 {
154 switch (textureFunction.method)
155 {
156 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
157 out << ".Sample(";
158 break;
159 case TextureFunctionHLSL::TextureFunction::BIAS:
160 out << ".SampleBias(";
161 break;
162 case TextureFunctionHLSL::TextureFunction::LOD:
163 case TextureFunctionHLSL::TextureFunction::LOD0:
164 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
165 out << ".SampleLevel(";
166 break;
167 case TextureFunctionHLSL::TextureFunction::GRAD:
168 out << ".SampleGrad(";
169 break;
170 default:
171 UNREACHABLE();
172 }
173 }
174 out << samplerReference << ", ";
175}
176
177const char *GetSamplerCoordinateTypeString(
178 const TextureFunctionHLSL::TextureFunction &textureFunction,
179 int hlslCoords)
180{
Jiawei Shaoa1ac3fe2018-10-10 12:29:31 +0800181 // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or
182 // unsigned integer formats.
183 // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather
184 if ((IsIntegerSampler(textureFunction.sampler) &&
185 textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) ||
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300186 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
187 {
188 switch (hlslCoords)
189 {
190 case 2:
Olli Etuaho2da04532018-08-24 13:59:44 +0300191 if (IsSampler2DMS(textureFunction.sampler))
192 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800193 return "int2";
Olli Etuaho2da04532018-08-24 13:59:44 +0300194 }
JiangYizhou5b03f472017-01-09 10:22:53 +0800195 else
Olli Etuaho2da04532018-08-24 13:59:44 +0300196 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800197 return "int3";
Olli Etuaho2da04532018-08-24 13:59:44 +0300198 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300199 case 3:
Olli Etuaho2da04532018-08-24 13:59:44 +0300200 if (IsSampler2DMSArray(textureFunction.sampler))
201 {
202 return "int3";
203 }
204 else
205 {
206 return "int4";
207 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300208 default:
209 UNREACHABLE();
210 }
211 }
212 else
213 {
214 switch (hlslCoords)
215 {
216 case 2:
217 return "float2";
218 case 3:
219 return "float3";
220 case 4:
221 return "float4";
222 default:
223 UNREACHABLE();
224 }
225 }
226 return "";
227}
228
229int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
230 ShShaderOutput outputType)
231{
232 if (outputType == SH_HLSL_3_0_OUTPUT)
233 {
234 int hlslCoords = 2;
235 switch (textureFunction.sampler)
236 {
237 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400238 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800239 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300240 hlslCoords = 2;
241 break;
242 case EbtSamplerCube:
243 hlslCoords = 3;
244 break;
245 default:
246 UNREACHABLE();
247 }
248
249 switch (textureFunction.method)
250 {
251 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400252 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300253 return hlslCoords;
254 case TextureFunctionHLSL::TextureFunction::BIAS:
255 case TextureFunctionHLSL::TextureFunction::LOD:
256 case TextureFunctionHLSL::TextureFunction::LOD0:
257 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
258 return 4;
259 default:
260 UNREACHABLE();
261 }
262 }
263 else
264 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300265 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
266 IsSamplerCube(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300267 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300268 return 3;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300269 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300270 ASSERT(IsSampler2D(textureFunction.sampler));
271 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300272 }
273 return 0;
274}
275
276void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
277 const TextureFunctionHLSL::TextureFunction &textureFunction,
278 const ShShaderOutput outputType)
279{
280 if (outputType == SH_HLSL_3_0_OUTPUT)
281 {
282 switch (textureFunction.sampler)
283 {
284 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400285 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300286 out << "sampler2D s";
287 break;
288 case EbtSamplerCube:
289 out << "samplerCUBE s";
290 break;
291 default:
292 UNREACHABLE();
293 }
294 }
295 else
296 {
297 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
298 {
299 out << TextureString(textureFunction.sampler) << " x, "
300 << SamplerString(textureFunction.sampler) << " s";
301 }
302 else
303 {
304 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400305 // A bug in the D3D compiler causes some nested sampling operations to fail.
306 // See http://anglebug.com/1923
307 // TODO(jmadill): Reinstate the const keyword when possible.
308 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300309 }
310 }
311
312 if (textureFunction.method ==
313 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
314 {
315 switch (textureFunction.coords)
316 {
317 case 2:
318 out << ", int2 t";
319 break;
320 case 3:
321 out << ", int3 t";
322 break;
323 default:
324 UNREACHABLE();
325 }
326 }
327 else // Floating-point coordinates (except textureSize)
328 {
329 switch (textureFunction.coords)
330 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000331 case 0:
332 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300333 case 1:
334 out << ", int lod";
335 break; // textureSize()
336 case 2:
337 out << ", float2 t";
338 break;
339 case 3:
340 out << ", float3 t";
341 break;
342 case 4:
343 out << ", float4 t";
344 break;
345 default:
346 UNREACHABLE();
347 }
348 }
349
350 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
351 {
352 switch (textureFunction.sampler)
353 {
354 case EbtSampler2D:
355 case EbtISampler2D:
356 case EbtUSampler2D:
357 case EbtSampler2DArray:
358 case EbtISampler2DArray:
359 case EbtUSampler2DArray:
360 case EbtSampler2DShadow:
361 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400362 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300363 out << ", float2 ddx, float2 ddy";
364 break;
365 case EbtSampler3D:
366 case EbtISampler3D:
367 case EbtUSampler3D:
368 case EbtSamplerCube:
369 case EbtISamplerCube:
370 case EbtUSamplerCube:
371 case EbtSamplerCubeShadow:
372 out << ", float3 ddx, float3 ddy";
373 break;
374 default:
375 UNREACHABLE();
376 }
377 }
378
379 switch (textureFunction.method)
380 {
381 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
382 break;
383 case TextureFunctionHLSL::TextureFunction::BIAS:
384 break; // Comes after the offset parameter
385 case TextureFunctionHLSL::TextureFunction::LOD:
386 out << ", float lod";
387 break;
388 case TextureFunctionHLSL::TextureFunction::LOD0:
389 break;
390 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
391 break; // Comes after the offset parameter
392 case TextureFunctionHLSL::TextureFunction::SIZE:
393 break;
394 case TextureFunctionHLSL::TextureFunction::FETCH:
Olli Etuaho2da04532018-08-24 13:59:44 +0300395 if (IsSampler2DMS(textureFunction.sampler) ||
396 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +0800397 out << ", int index";
398 else
399 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300400 break;
401 case TextureFunctionHLSL::TextureFunction::GRAD:
402 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800403 case TextureFunctionHLSL::TextureFunction::GATHER:
404 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300405 default:
406 UNREACHABLE();
407 }
408
Jiawei Shao19b51d22018-09-19 15:14:45 +0800409 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
410 IsShadowSampler(textureFunction.sampler))
411 {
412 out << ", float refZ";
413 }
414
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300415 if (textureFunction.offset)
416 {
417 switch (textureFunction.sampler)
418 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300419 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300420 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300421 case EbtUSampler3D:
422 out << ", int3 offset";
423 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300424 case EbtSampler2D:
425 case EbtSampler2DArray:
426 case EbtISampler2D:
427 case EbtISampler2DArray:
428 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300429 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300430 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300431 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400432 case EbtSamplerExternalOES:
433 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300434 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300435 default:
Olli Etuaho2da04532018-08-24 13:59:44 +0300436 // Offset is not supported for multisampled textures.
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300437 UNREACHABLE();
438 }
439 }
440
441 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
442 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
443 {
444 out << ", float bias";
445 }
Jiawei Shao19b51d22018-09-19 15:14:45 +0800446 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER &&
447 !IsShadowSampler(textureFunction.sampler))
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800448 {
449 out << ", int comp = 0";
450 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300451}
452
453void GetTextureReference(TInfoSinkBase &out,
454 const TextureFunctionHLSL::TextureFunction &textureFunction,
455 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200456 ImmutableString *textureReference,
457 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300458{
459 if (outputType == SH_HLSL_4_1_OUTPUT)
460 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200461 static const ImmutableString kTexturesStr("textures");
462 static const ImmutableString kSamplersStr("samplers");
463 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
464 static const ImmutableString kTextureIndexStr("[textureIndex]");
465 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
466 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
467
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300468 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
469 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200470 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
471 kSamplerIndexStr.length());
472 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
473 *textureReference = textureRefBuilder;
474 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
475 kSamplerIndexStr.length());
476 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
477 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300478 }
479 else
480 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200481 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
482 << suffix.data() << ";\n";
483 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
484 kTextureIndexStr.length());
485 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
486 *textureReference = textureRefBuilder;
487
488 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
489 << suffix.data() << ";\n";
490 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
491 kSamplerArrayIndexStr.length());
492 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
493 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300494 }
495 }
496 else
497 {
Olli Etuaho12c03762018-01-25 12:22:33 +0200498 *textureReference = ImmutableString("x");
499 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300500 }
501}
502
503void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
504 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuaho12c03762018-01-25 12:22:33 +0200505 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400506 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300507{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000508 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400509 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000510 out << " uint width; uint height; uint samples;\n"
511 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400512 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300513 else if (IsSampler2DMSArray(textureFunction.sampler))
514 {
515 out << " uint width; uint height; uint depth; uint samples;\n"
516 << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n";
517 }
Geoff Lang1fe74c72016-08-25 13:23:01 -0400518 else
519 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000520 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400521 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000522 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400523 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000524 else
525 {
526 out << " int baseLevel = 0;\n";
527 }
528
529 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
530 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
531 {
532 // "depth" stores either the number of layers in an array texture or 3D depth
533 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
534 << " " << textureReference
535 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
536 << " width = max(width >> lod, 1);\n"
537 << " height = max(height >> lod, 1);\n";
538
539 if (!IsSamplerArray(textureFunction.sampler))
540 {
541 out << " depth = max(depth >> lod, 1);\n";
542 }
543 }
544 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
545 {
546 out << " uint width; uint height; uint numberOfLevels;\n"
547 << " " << textureReference
548 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
549 << " width = max(width >> lod, 1);\n"
550 << " height = max(height >> lod, 1);\n";
551 }
552 else
553 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300554 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300555
556 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
557 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000558 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300559 }
560 else
561 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000562 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300563 }
564}
565
566void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200567 ImmutableString *texCoordX,
568 ImmutableString *texCoordY,
569 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300570{
571 if (textureFunction.proj)
572 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200573 ImmutableString proj("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300574 switch (textureFunction.coords)
575 {
576 case 3:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200577 proj = ImmutableString(" / t.z");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300578 break;
579 case 4:
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200580 proj = ImmutableString(" / t.w");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300581 break;
582 default:
583 UNREACHABLE();
584 }
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200585 ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u);
586 texCoordXBuilder << '(' << *texCoordX << proj << ')';
587 *texCoordX = texCoordXBuilder;
588 ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u);
589 texCoordYBuilder << '(' << *texCoordY << proj << ')';
590 *texCoordY = texCoordYBuilder;
591 ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u);
592 texCoordZBuilder << '(' << *texCoordZ << proj << ')';
593 *texCoordZ = texCoordZBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300594 }
595}
596
597void OutputIntegerTextureSampleFunctionComputations(
598 TInfoSinkBase &out,
599 const TextureFunctionHLSL::TextureFunction &textureFunction,
600 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200601 const ImmutableString &textureReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200602 ImmutableString *texCoordX,
603 ImmutableString *texCoordY,
604 ImmutableString *texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300605{
606 if (!IsIntegerSampler(textureFunction.sampler))
607 {
608 return;
609 }
610 if (IsSamplerCube(textureFunction.sampler))
611 {
612 out << " float width; float height; float layers; float levels;\n";
613
614 out << " uint mip = 0;\n";
615
616 out << " " << textureReference
617 << ".GetDimensions(mip, width, height, layers, levels);\n";
618
619 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
620 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
621 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
622 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
623 "(zMajor && t.z < 0.0f);\n";
624
625 // FACE_POSITIVE_X = 000b
626 // FACE_NEGATIVE_X = 001b
627 // FACE_POSITIVE_Y = 010b
628 // FACE_NEGATIVE_Y = 011b
629 // FACE_POSITIVE_Z = 100b
630 // FACE_NEGATIVE_Z = 101b
631 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
632
633 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
634 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
635 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
636
637 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
638 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
639
640 // Mip level computation.
641 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
642 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
643 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
644 {
645 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
646 {
647 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
648 " float2 dx = ddx(tSized);\n"
649 " float2 dy = ddy(tSized);\n"
650 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
651 }
652 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
653 {
654 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
655 // derivatives of P are assumed to be in the coordinate system used before
656 // texture coordinates are projected onto the appropriate cube face."
657 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
658 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
659 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
660 // Determine the derivatives of u, v and m
661 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
662 ": ddx[0]);\n"
663 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
664 ": ddy[0]);\n"
665 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
666 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
667 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
668 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
669 // Now determine the derivatives of the face coordinates, using the
670 // derivatives calculated above.
671 // d / dx (u(x) * 0.5 / m(x) + 0.5)
672 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
673 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
674 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
675 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
676 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
677 " float2 sizeVec = float2(width, height);\n"
678 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
679 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
680 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
681 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
682 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
683 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
684 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
685 }
686 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
687 << " " << textureReference
688 << ".GetDimensions(mip, width, height, layers, levels);\n";
689 }
690
691 // Convert from normalized floating-point to integer
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200692 static const ImmutableString kXPrefix("int(floor(width * frac(");
693 static const ImmutableString kYPrefix("int(floor(height * frac(");
694 static const ImmutableString kSuffix(")))");
695 ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() +
696 kSuffix.length());
697 texCoordXBuilder << kXPrefix << *texCoordX << kSuffix;
698 *texCoordX = texCoordXBuilder;
699 ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() +
700 kSuffix.length());
701 texCoordYBuilder << kYPrefix << *texCoordY << kSuffix;
702 *texCoordY = texCoordYBuilder;
703 *texCoordZ = ImmutableString("face");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300704 }
705 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
706 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300707 if (IsSamplerArray(textureFunction.sampler))
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300708 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300709 out << " float width; float height; float layers; float levels;\n";
710
711 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300712 {
Olli Etuaho2da04532018-08-24 13:59:44 +0300713 out << " uint mip = 0;\n";
714 }
715 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
716 {
717 out << " uint mip = bias;\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300718 }
719 else
720 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300721
722 out << " " << textureReference
Olli Etuaho2da04532018-08-24 13:59:44 +0300723 << ".GetDimensions(0, width, height, layers, levels);\n";
724 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
725 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
726 {
727 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
728 " float dx = length(ddx(tSized));\n"
729 " float dy = length(ddy(tSized));\n"
730 " float lod = log2(max(dx, dy));\n";
731
732 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
733 {
734 out << " lod += bias;\n";
735 }
736 }
737 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
738 {
739 out << " float2 sizeVec = float2(width, height);\n"
740 " float2 sizeDdx = ddx * sizeVec;\n"
741 " float2 sizeDdy = ddy * sizeVec;\n"
742 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
743 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
744 }
745
746 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300747 }
Olli Etuaho2da04532018-08-24 13:59:44 +0300748
749 out << " " << textureReference
750 << ".GetDimensions(mip, width, height, layers, levels);\n";
751 }
752 else if (IsSampler2D(textureFunction.sampler))
753 {
754 out << " float width; float height; float levels;\n";
755
756 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
757 {
758 out << " uint mip = 0;\n";
759 }
760 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
761 {
762 out << " uint mip = bias;\n";
763 }
764 else
765 {
766 out << " " << textureReference << ".GetDimensions(0, width, height, levels);\n";
767
768 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
769 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
770 {
771 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
772 " float dx = length(ddx(tSized));\n"
773 " float dy = length(ddy(tSized));\n"
774 " float lod = log2(max(dx, dy));\n";
775
776 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
777 {
778 out << " lod += bias;\n";
779 }
780 }
781 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
782 {
783 out << " float2 sizeVec = float2(width, height);\n"
784 " float2 sizeDdx = ddx * sizeVec;\n"
785 " float2 sizeDdy = ddy * sizeVec;\n"
786 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
787 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
788 }
789
790 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
791 }
792
793 out << " " << textureReference << ".GetDimensions(mip, width, height, levels);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300794 }
795 else if (IsSampler3D(textureFunction.sampler))
796 {
797 out << " float width; float height; float depth; float levels;\n";
798
799 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
800 {
801 out << " uint mip = 0;\n";
802 }
803 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
804 {
805 out << " uint mip = bias;\n";
806 }
807 else
808 {
809 out << " " << textureReference
810 << ".GetDimensions(0, width, height, depth, levels);\n";
811
812 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
813 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
814 {
815 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
816 " float dx = length(ddx(tSized));\n"
817 " float dy = length(ddy(tSized));\n"
818 " float lod = log2(max(dx, dy));\n";
819
820 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
821 {
822 out << " lod += bias;\n";
823 }
824 }
825 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
826 {
827 out << " float3 sizeVec = float3(width, height, depth);\n"
828 " float3 sizeDdx = ddx * sizeVec;\n"
829 " float3 sizeDdy = ddy * sizeVec;\n"
830 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
831 "sizeDdy))) * 0.5f;\n";
832 }
833
834 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
835 }
836
837 out << " " << textureReference
838 << ".GetDimensions(mip, width, height, depth, levels);\n";
839 }
840 else
841 UNREACHABLE();
842
843 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
844 }
845}
846
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800847void OutputTextureGatherFunctionBody(TInfoSinkBase &out,
848 const TextureFunctionHLSL::TextureFunction &textureFunction,
849 ShShaderOutput outputType,
850 const ImmutableString &textureReference,
851 const ImmutableString &samplerReference,
852 const ImmutableString &texCoordX,
853 const ImmutableString &texCoordY,
854 const ImmutableString &texCoordZ)
855{
856 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
857 ImmutableString samplerCoordTypeString(
858 GetSamplerCoordinateTypeString(textureFunction, hlslCoords));
859 ImmutableStringBuilder samplerCoordBuilder(
860 samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") +
861 texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")"));
862
863 samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY;
864 if (hlslCoords >= 3)
865 {
866 if (textureFunction.coords < 3)
867 {
868 samplerCoordBuilder << ", 0";
869 }
870 else
871 {
872 samplerCoordBuilder << ", " << texCoordZ;
873 }
874 }
875 samplerCoordBuilder << ")";
876
877 ImmutableString samplerCoordString(samplerCoordBuilder);
878
Jiawei Shao19b51d22018-09-19 15:14:45 +0800879 if (IsShadowSampler(textureFunction.sampler))
880 {
881 out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", "
882 << samplerCoordString << ", refZ";
883 if (textureFunction.offset)
884 {
885 out << ", offset";
886 }
887 out << ");\n";
888 return;
889 }
890
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800891 constexpr std::array<const char *, 4> kHLSLGatherFunctions = {
892 {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}};
893
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800894 out << " switch(comp)\n"
Jiawei Shaocf8ad762018-09-21 09:11:35 +0800895 " {\n";
896 for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component)
897 {
898 out << " case " << component << ":\n"
899 << " return " << textureReference << "." << kHLSLGatherFunctions[component]
900 << "(" << samplerReference << ", " << samplerCoordString;
901 if (textureFunction.offset)
902 {
903 out << ", offset";
904 }
905 out << ");\n";
906 }
907
908 out << " default:\n"
Jiawei Shaoa977acc2018-09-19 12:46:05 +0800909 " return float4(0.0, 0.0, 0.0, 1.0);\n"
910 " }\n";
911}
912
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300913void OutputTextureSampleFunctionReturnStatement(
914 TInfoSinkBase &out,
915 const TextureFunctionHLSL::TextureFunction &textureFunction,
916 const ShShaderOutput outputType,
Olli Etuaho12c03762018-01-25 12:22:33 +0200917 const ImmutableString &textureReference,
918 const ImmutableString &samplerReference,
Olli Etuahob4cc49f2018-01-25 14:37:06 +0200919 const ImmutableString &texCoordX,
920 const ImmutableString &texCoordY,
921 const ImmutableString &texCoordZ)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300922{
923 out << " return ";
924
Till Rathmannb8543632018-10-02 19:46:14 +0200925 if (IsIntegerSampler(textureFunction.sampler) && !IsSamplerCube(textureFunction.sampler) &&
926 textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
927 {
928 out << " useBorderColor ? ";
929 if (IsIntegerSamplerUnsigned(textureFunction.sampler))
930 {
931 out << "asuint";
932 }
933 out << "(samplerMetadata[samplerIndex].intBorderColor) : ";
934 }
935
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300936 // HLSL intrinsic
937 if (outputType == SH_HLSL_3_0_OUTPUT)
938 {
939 switch (textureFunction.sampler)
940 {
941 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400942 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300943 out << "tex2D";
944 break;
945 case EbtSamplerCube:
946 out << "texCUBE";
947 break;
948 default:
949 UNREACHABLE();
950 }
951
952 switch (textureFunction.method)
953 {
954 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
955 out << "(" << samplerReference << ", ";
956 break;
957 case TextureFunctionHLSL::TextureFunction::BIAS:
958 out << "bias(" << samplerReference << ", ";
959 break;
960 case TextureFunctionHLSL::TextureFunction::LOD:
961 out << "lod(" << samplerReference << ", ";
962 break;
963 case TextureFunctionHLSL::TextureFunction::LOD0:
964 out << "lod(" << samplerReference << ", ";
965 break;
966 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
967 out << "lod(" << samplerReference << ", ";
968 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400969 case TextureFunctionHLSL::TextureFunction::GRAD:
970 out << "grad(" << samplerReference << ", ";
971 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300972 default:
973 UNREACHABLE();
974 }
975 }
976 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
977 {
978 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
979 }
980 else
981 UNREACHABLE();
982
983 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
984
985 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
986 << texCoordY;
987
988 if (outputType == SH_HLSL_3_0_OUTPUT)
989 {
990 if (hlslCoords >= 3)
991 {
992 if (textureFunction.coords < 3)
993 {
994 out << ", 0";
995 }
996 else
997 {
998 out << ", " << texCoordZ;
999 }
1000 }
1001
1002 if (hlslCoords == 4)
1003 {
1004 switch (textureFunction.method)
1005 {
1006 case TextureFunctionHLSL::TextureFunction::BIAS:
1007 out << ", bias";
1008 break;
1009 case TextureFunctionHLSL::TextureFunction::LOD:
1010 out << ", lod";
1011 break;
1012 case TextureFunctionHLSL::TextureFunction::LOD0:
1013 out << ", 0";
1014 break;
1015 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1016 out << ", bias";
1017 break;
1018 default:
1019 UNREACHABLE();
1020 }
1021 }
1022
1023 out << ")";
1024 }
1025 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1026 {
1027 if (hlslCoords >= 3)
1028 {
1029 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
1030 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
1031 out << ", " << texCoordZ;
1032 }
1033
1034 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
1035 {
1036 if (IsIntegerSampler(textureFunction.sampler))
1037 {
1038 out << ", mip)";
1039 }
1040 else if (IsShadowSampler(textureFunction.sampler))
1041 {
1042 // Compare value
1043 if (textureFunction.proj)
1044 {
1045 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1046 // The resulting third component of P' in the shadow forms is used as
1047 // Dref
1048 out << "), " << texCoordZ;
1049 }
1050 else
1051 {
1052 switch (textureFunction.coords)
1053 {
1054 case 3:
1055 out << "), t.z";
1056 break;
1057 case 4:
1058 out << "), t.w";
1059 break;
1060 default:
1061 UNREACHABLE();
1062 }
1063 }
1064 }
1065 else
1066 {
1067 out << "), ddx, ddy";
1068 }
1069 }
1070 else if (IsIntegerSampler(textureFunction.sampler) ||
1071 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
1072 {
Olli Etuaho2da04532018-08-24 13:59:44 +03001073 if (IsSampler2DMS(textureFunction.sampler) ||
1074 IsSampler2DMSArray(textureFunction.sampler))
JiangYizhou5b03f472017-01-09 10:22:53 +08001075 out << "), index";
1076 else
1077 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001078 }
1079 else if (IsShadowSampler(textureFunction.sampler))
1080 {
1081 // Compare value
1082 if (textureFunction.proj)
1083 {
1084 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
1085 // The resulting third component of P' in the shadow forms is used as Dref
1086 out << "), " << texCoordZ;
1087 }
1088 else
1089 {
1090 switch (textureFunction.coords)
1091 {
1092 case 3:
1093 out << "), t.z";
1094 break;
1095 case 4:
1096 out << "), t.w";
1097 break;
1098 default:
1099 UNREACHABLE();
1100 }
1101 }
1102 }
1103 else
1104 {
1105 switch (textureFunction.method)
1106 {
1107 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1108 out << ")";
1109 break;
1110 case TextureFunctionHLSL::TextureFunction::BIAS:
1111 out << "), bias";
1112 break;
1113 case TextureFunctionHLSL::TextureFunction::LOD:
1114 out << "), lod";
1115 break;
1116 case TextureFunctionHLSL::TextureFunction::LOD0:
1117 out << "), 0";
1118 break;
1119 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1120 out << "), bias";
1121 break;
1122 default:
1123 UNREACHABLE();
1124 }
1125 }
1126
1127 if (textureFunction.offset &&
1128 (!IsIntegerSampler(textureFunction.sampler) ||
1129 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1130 {
1131 out << ", offset";
1132 }
1133 }
1134 else
1135 UNREACHABLE();
1136
1137 out << ");\n"; // Close the sample function call and return statement
1138}
1139
1140} // Anonymous namespace
1141
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001142ImmutableString TextureFunctionHLSL::TextureFunction::name() const
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001143{
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001144 static const ImmutableString kGlTextureName("gl_texture");
1145
1146 ImmutableString suffix(TextureTypeSuffix(this->sampler));
1147
1148 ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u);
1149
1150 name << kGlTextureName;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001151
1152 // We need to include full the sampler type in the function name to make the signature unique
1153 // on D3D11, where samplers are passed to texture functions as indices.
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001154 name << suffix;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001155
1156 if (proj)
1157 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001158 name << "Proj";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001159 }
1160
1161 if (offset)
1162 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001163 name << "Offset";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001164 }
1165
1166 switch (method)
1167 {
1168 case IMPLICIT:
1169 break;
1170 case BIAS:
1171 break; // Extra parameter makes the signature unique
1172 case LOD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001173 name << "Lod";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001174 break;
1175 case LOD0:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001176 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001177 break;
1178 case LOD0BIAS:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001179 name << "Lod0";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001180 break; // Extra parameter makes the signature unique
1181 case SIZE:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001182 name << "Size";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001183 break;
1184 case FETCH:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001185 name << "Fetch";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001186 break;
1187 case GRAD:
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001188 name << "Grad";
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001189 break;
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001190 case GATHER:
1191 name << "Gather";
1192 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001193 default:
1194 UNREACHABLE();
1195 }
1196
1197 return name;
1198}
1199
1200const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1201{
1202 if (method == TextureFunction::SIZE)
1203 {
1204 switch (sampler)
1205 {
1206 case EbtSampler2D:
1207 case EbtISampler2D:
1208 case EbtUSampler2D:
1209 case EbtSampler2DShadow:
1210 case EbtSamplerCube:
1211 case EbtISamplerCube:
1212 case EbtUSamplerCube:
1213 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001214 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001215 case EbtSampler2DMS:
1216 case EbtISampler2DMS:
1217 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001218 return "int2";
1219 case EbtSampler3D:
1220 case EbtISampler3D:
1221 case EbtUSampler3D:
1222 case EbtSampler2DArray:
1223 case EbtISampler2DArray:
1224 case EbtUSampler2DArray:
Olli Etuaho2da04532018-08-24 13:59:44 +03001225 case EbtSampler2DMSArray:
1226 case EbtISampler2DMSArray:
1227 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001228 case EbtSampler2DArrayShadow:
1229 return "int3";
1230 default:
1231 UNREACHABLE();
1232 }
1233 }
1234 else // Sampling function
1235 {
1236 switch (sampler)
1237 {
1238 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001239 case EbtSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001240 case EbtSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001241 case EbtSampler3D:
1242 case EbtSamplerCube:
1243 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001244 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001245 return "float4";
1246 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001247 case EbtISampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001248 case EbtISampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001249 case EbtISampler3D:
1250 case EbtISamplerCube:
1251 case EbtISampler2DArray:
1252 return "int4";
1253 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001254 case EbtUSampler2DMS:
Olli Etuaho2da04532018-08-24 13:59:44 +03001255 case EbtUSampler2DMSArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001256 case EbtUSampler3D:
1257 case EbtUSamplerCube:
1258 case EbtUSampler2DArray:
1259 return "uint4";
1260 case EbtSampler2DShadow:
1261 case EbtSamplerCubeShadow:
1262 case EbtSampler2DArrayShadow:
Jiawei Shao19b51d22018-09-19 15:14:45 +08001263 if (method == TextureFunctionHLSL::TextureFunction::GATHER)
1264 {
1265 return "float4";
1266 }
1267 else
1268 {
1269 return "float";
1270 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001271 default:
1272 UNREACHABLE();
1273 }
1274 }
1275 return "";
1276}
1277
1278bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1279{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001280 return std::tie(sampler, coords, proj, offset, method) <
1281 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001282}
1283
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001284ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name,
1285 TBasicType samplerType,
1286 int coords,
1287 size_t argumentCount,
1288 bool lod0,
1289 sh::GLenum shaderType)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001290{
1291 TextureFunction textureFunction;
1292 textureFunction.sampler = samplerType;
1293 textureFunction.coords = coords;
1294 textureFunction.method = TextureFunction::IMPLICIT;
1295 textureFunction.proj = false;
1296 textureFunction.offset = false;
1297
1298 if (name == "texture2D" || name == "textureCube" || name == "texture")
1299 {
1300 textureFunction.method = TextureFunction::IMPLICIT;
1301 }
1302 else if (name == "texture2DProj" || name == "textureProj")
1303 {
1304 textureFunction.method = TextureFunction::IMPLICIT;
1305 textureFunction.proj = true;
1306 }
1307 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1308 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1309 {
1310 textureFunction.method = TextureFunction::LOD;
1311 }
1312 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1313 name == "texture2DProjLodEXT")
1314 {
1315 textureFunction.method = TextureFunction::LOD;
1316 textureFunction.proj = true;
1317 }
1318 else if (name == "textureSize")
1319 {
1320 textureFunction.method = TextureFunction::SIZE;
1321 }
1322 else if (name == "textureOffset")
1323 {
1324 textureFunction.method = TextureFunction::IMPLICIT;
1325 textureFunction.offset = true;
1326 }
1327 else if (name == "textureProjOffset")
1328 {
1329 textureFunction.method = TextureFunction::IMPLICIT;
1330 textureFunction.offset = true;
1331 textureFunction.proj = true;
1332 }
1333 else if (name == "textureLodOffset")
1334 {
1335 textureFunction.method = TextureFunction::LOD;
1336 textureFunction.offset = true;
1337 }
1338 else if (name == "textureProjLodOffset")
1339 {
1340 textureFunction.method = TextureFunction::LOD;
1341 textureFunction.proj = true;
1342 textureFunction.offset = true;
1343 }
1344 else if (name == "texelFetch")
1345 {
1346 textureFunction.method = TextureFunction::FETCH;
1347 }
1348 else if (name == "texelFetchOffset")
1349 {
1350 textureFunction.method = TextureFunction::FETCH;
1351 textureFunction.offset = true;
1352 }
1353 else if (name == "textureGrad" || name == "texture2DGradEXT")
1354 {
1355 textureFunction.method = TextureFunction::GRAD;
1356 }
1357 else if (name == "textureGradOffset")
1358 {
1359 textureFunction.method = TextureFunction::GRAD;
1360 textureFunction.offset = true;
1361 }
1362 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1363 name == "textureCubeGradEXT")
1364 {
1365 textureFunction.method = TextureFunction::GRAD;
1366 textureFunction.proj = true;
1367 }
1368 else if (name == "textureProjGradOffset")
1369 {
1370 textureFunction.method = TextureFunction::GRAD;
1371 textureFunction.proj = true;
1372 textureFunction.offset = true;
1373 }
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001374 else if (name == "textureGather")
1375 {
1376 textureFunction.method = TextureFunction::GATHER;
1377 }
Jiawei Shaocf8ad762018-09-21 09:11:35 +08001378 else if (name == "textureGatherOffset")
1379 {
1380 textureFunction.method = TextureFunction::GATHER;
1381 textureFunction.offset = true;
1382 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001383 else
1384 UNREACHABLE();
1385
1386 if (textureFunction.method ==
1387 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1388 {
1389 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1390
1391 if (textureFunction.offset)
1392 {
1393 mandatoryArgumentCount++;
1394 }
1395
1396 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1397
1398 if (lod0 || shaderType == GL_VERTEX_SHADER)
1399 {
1400 if (bias)
1401 {
1402 textureFunction.method = TextureFunction::LOD0BIAS;
1403 }
1404 else
1405 {
1406 textureFunction.method = TextureFunction::LOD0;
1407 }
1408 }
1409 else if (bias)
1410 {
1411 textureFunction.method = TextureFunction::BIAS;
1412 }
1413 }
1414
1415 mUsesTexture.insert(textureFunction);
1416 return textureFunction.name();
1417}
1418
Geoff Lang1fe74c72016-08-25 13:23:01 -04001419void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1420 const ShShaderOutput outputType,
1421 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001422{
1423 for (const TextureFunction &textureFunction : mUsesTexture)
1424 {
1425 // Function header
1426 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1427
1428 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1429
1430 out << ")\n"
1431 "{\n";
1432
1433 // In some cases we use a variable to store the texture/sampler objects, but to work around
1434 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1435 // sampling we need to call the function directly on references to the texture and sampler
1436 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1437 // tests.
Olli Etuaho12c03762018-01-25 12:22:33 +02001438 ImmutableString textureReference("");
1439 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001440 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1441
1442 if (textureFunction.method == TextureFunction::SIZE)
1443 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001444 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1445 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001446 }
1447 else
1448 {
Olli Etuahob4cc49f2018-01-25 14:37:06 +02001449 ImmutableString texCoordX("t.x");
1450 ImmutableString texCoordY("t.y");
1451 ImmutableString texCoordZ("t.z");
Jiawei Shaoa977acc2018-09-19 12:46:05 +08001452 if (textureFunction.method == TextureFunction::GATHER)
1453 {
1454 OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference,
1455 samplerReference, texCoordX, texCoordY, texCoordZ);
1456 }
1457 else
1458 {
1459 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1460 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1461 textureReference, &texCoordX,
1462 &texCoordY, &texCoordZ);
1463 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1464 textureReference, samplerReference,
1465 texCoordX, texCoordY, texCoordZ);
1466 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001467 }
1468
1469 out << "}\n"
1470 "\n";
1471 }
1472}
1473
1474} // namespace sh