blob: 36898ffbede866064bb328a211bad18422ab2f25 [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 Etuahoc13bda82018-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,
26 const TString &texCoord,
27 const TString &texCoordOffset,
28 const char *texCoordOutName)
29{
30 // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
31 // but rather use equivalent formulas that map better to HLSL.
32 out << "int " << texCoordOutName << ";\n";
33 out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
34 << ") / " << size << ";\n";
35
36 // CLAMP_TO_EDGE
37 out << "if (" << wrapMode << " == 1)\n";
38 out << "{\n";
39 out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
40 << "Offset)), 0, int(" << size << ") - 1);\n";
41 out << "}\n";
42
43 // MIRRORED_REPEAT
44 out << "else if (" << wrapMode << " == 3)\n";
45 out << "{\n";
46 out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
47 << "Offset) * 0.5) * 2.0 - 1.0);\n";
48 out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
49 out << "}\n";
50
51 // REPEAT
52 out << "else\n";
53 out << "{\n";
54 out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
55 << "Offset)));\n";
56 out << "}\n";
57}
58
59void OutputIntTexCoordWraps(TInfoSinkBase &out,
60 const TextureFunctionHLSL::TextureFunction &textureFunction,
61 TString *texCoordX,
62 TString *texCoordY,
63 TString *texCoordZ)
64{
65 // Convert from normalized floating-point to integer
66 out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
67 if (textureFunction.offset)
68 {
69 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix");
70 }
71 else
72 {
73 OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix");
74 }
75 *texCoordX = "tix";
76 out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
77 if (textureFunction.offset)
78 {
79 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy");
80 }
81 else
82 {
83 OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy");
84 }
85 *texCoordY = "tiy";
86
87 if (IsSamplerArray(textureFunction.sampler))
88 {
89 *texCoordZ = "int(max(0, min(layers - 1, floor(0.5 + t.z))))";
90 }
91 else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler))
92 {
93 out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
94 if (textureFunction.offset)
95 {
96 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz");
97 }
98 else
99 {
100 OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz");
101 }
102 *texCoordZ = "tiz";
103 }
104}
105
106void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
107 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahoc13bda82018-01-25 12:22:33 +0200108 const ImmutableString &textureReference,
109 const ImmutableString &samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300110{
111 out << textureReference;
112 if (IsIntegerSampler(textureFunction.sampler) ||
113 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
114 {
115 out << ".Load(";
116 return;
117 }
118
119 if (IsShadowSampler(textureFunction.sampler))
120 {
121 switch (textureFunction.method)
122 {
123 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
124 case TextureFunctionHLSL::TextureFunction::BIAS:
125 case TextureFunctionHLSL::TextureFunction::LOD:
126 out << ".SampleCmp(";
127 break;
128 case TextureFunctionHLSL::TextureFunction::LOD0:
129 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
130 case TextureFunctionHLSL::TextureFunction::GRAD:
131 out << ".SampleCmpLevelZero(";
132 break;
133 default:
134 UNREACHABLE();
135 }
136 }
137 else
138 {
139 switch (textureFunction.method)
140 {
141 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
142 out << ".Sample(";
143 break;
144 case TextureFunctionHLSL::TextureFunction::BIAS:
145 out << ".SampleBias(";
146 break;
147 case TextureFunctionHLSL::TextureFunction::LOD:
148 case TextureFunctionHLSL::TextureFunction::LOD0:
149 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
150 out << ".SampleLevel(";
151 break;
152 case TextureFunctionHLSL::TextureFunction::GRAD:
153 out << ".SampleGrad(";
154 break;
155 default:
156 UNREACHABLE();
157 }
158 }
159 out << samplerReference << ", ";
160}
161
162const char *GetSamplerCoordinateTypeString(
163 const TextureFunctionHLSL::TextureFunction &textureFunction,
164 int hlslCoords)
165{
166 if (IsIntegerSampler(textureFunction.sampler) ||
167 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
168 {
169 switch (hlslCoords)
170 {
171 case 2:
JiangYizhou5b03f472017-01-09 10:22:53 +0800172 if (textureFunction.sampler == EbtSampler2DMS ||
173 textureFunction.sampler == EbtISampler2DMS ||
174 textureFunction.sampler == EbtUSampler2DMS)
175 return "int2";
176 else
177 return "int3";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300178 case 3:
179 return "int4";
180 default:
181 UNREACHABLE();
182 }
183 }
184 else
185 {
186 switch (hlslCoords)
187 {
188 case 2:
189 return "float2";
190 case 3:
191 return "float3";
192 case 4:
193 return "float4";
194 default:
195 UNREACHABLE();
196 }
197 }
198 return "";
199}
200
201int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction,
202 ShShaderOutput outputType)
203{
204 if (outputType == SH_HLSL_3_0_OUTPUT)
205 {
206 int hlslCoords = 2;
207 switch (textureFunction.sampler)
208 {
209 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400210 case EbtSamplerExternalOES:
JiangYizhou5b03f472017-01-09 10:22:53 +0800211 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300212 hlslCoords = 2;
213 break;
214 case EbtSamplerCube:
215 hlslCoords = 3;
216 break;
217 default:
218 UNREACHABLE();
219 }
220
221 switch (textureFunction.method)
222 {
223 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
Geoff Langba992ab2017-04-19 11:18:14 -0400224 case TextureFunctionHLSL::TextureFunction::GRAD:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300225 return hlslCoords;
226 case TextureFunctionHLSL::TextureFunction::BIAS:
227 case TextureFunctionHLSL::TextureFunction::LOD:
228 case TextureFunctionHLSL::TextureFunction::LOD0:
229 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
230 return 4;
231 default:
232 UNREACHABLE();
233 }
234 }
235 else
236 {
237 switch (textureFunction.sampler)
238 {
239 case EbtSampler2D:
240 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800241 case EbtSampler2DMS:
242 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300243 case EbtSampler3D:
244 return 3;
245 case EbtSamplerCube:
246 return 3;
247 case EbtSampler2DArray:
248 return 3;
Ian Ewellbda75592016-04-18 17:25:54 -0400249 case EbtSamplerExternalOES:
250 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300251 case EbtISampler2D:
252 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800253 case EbtISampler2DMS:
254 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300255 case EbtISampler3D:
256 return 3;
257 case EbtISamplerCube:
258 return 3;
259 case EbtISampler2DArray:
260 return 3;
261 case EbtUSampler2D:
262 return 2;
JiangYizhou34bc3152017-03-29 14:56:01 +0800263 case EbtUSampler2DMS:
264 return 2;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300265 case EbtUSampler3D:
266 return 3;
267 case EbtUSamplerCube:
268 return 3;
269 case EbtUSampler2DArray:
270 return 3;
271 case EbtSampler2DShadow:
272 return 2;
273 case EbtSamplerCubeShadow:
274 return 3;
275 case EbtSampler2DArrayShadow:
276 return 3;
277 default:
278 UNREACHABLE();
279 }
280 }
281 return 0;
282}
283
284void OutputTextureFunctionArgumentList(TInfoSinkBase &out,
285 const TextureFunctionHLSL::TextureFunction &textureFunction,
286 const ShShaderOutput outputType)
287{
288 if (outputType == SH_HLSL_3_0_OUTPUT)
289 {
290 switch (textureFunction.sampler)
291 {
292 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400293 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300294 out << "sampler2D s";
295 break;
296 case EbtSamplerCube:
297 out << "samplerCUBE s";
298 break;
299 default:
300 UNREACHABLE();
301 }
302 }
303 else
304 {
305 if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
306 {
307 out << TextureString(textureFunction.sampler) << " x, "
308 << SamplerString(textureFunction.sampler) << " s";
309 }
310 else
311 {
312 ASSERT(outputType == SH_HLSL_4_1_OUTPUT);
Jamie Madill8aeeed62017-03-15 18:09:26 -0400313 // A bug in the D3D compiler causes some nested sampling operations to fail.
314 // See http://anglebug.com/1923
315 // TODO(jmadill): Reinstate the const keyword when possible.
316 out << /*"const"*/ "uint samplerIndex";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300317 }
318 }
319
320 if (textureFunction.method ==
321 TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates
322 {
323 switch (textureFunction.coords)
324 {
325 case 2:
326 out << ", int2 t";
327 break;
328 case 3:
329 out << ", int3 t";
330 break;
331 default:
332 UNREACHABLE();
333 }
334 }
335 else // Floating-point coordinates (except textureSize)
336 {
337 switch (textureFunction.coords)
338 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000339 case 0:
340 break; // textureSize(gSampler2DMS sampler)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300341 case 1:
342 out << ", int lod";
343 break; // textureSize()
344 case 2:
345 out << ", float2 t";
346 break;
347 case 3:
348 out << ", float3 t";
349 break;
350 case 4:
351 out << ", float4 t";
352 break;
353 default:
354 UNREACHABLE();
355 }
356 }
357
358 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
359 {
360 switch (textureFunction.sampler)
361 {
362 case EbtSampler2D:
363 case EbtISampler2D:
364 case EbtUSampler2D:
365 case EbtSampler2DArray:
366 case EbtISampler2DArray:
367 case EbtUSampler2DArray:
368 case EbtSampler2DShadow:
369 case EbtSampler2DArrayShadow:
Ian Ewellbda75592016-04-18 17:25:54 -0400370 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300371 out << ", float2 ddx, float2 ddy";
372 break;
373 case EbtSampler3D:
374 case EbtISampler3D:
375 case EbtUSampler3D:
376 case EbtSamplerCube:
377 case EbtISamplerCube:
378 case EbtUSamplerCube:
379 case EbtSamplerCubeShadow:
380 out << ", float3 ddx, float3 ddy";
381 break;
382 default:
383 UNREACHABLE();
384 }
385 }
386
387 switch (textureFunction.method)
388 {
389 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
390 break;
391 case TextureFunctionHLSL::TextureFunction::BIAS:
392 break; // Comes after the offset parameter
393 case TextureFunctionHLSL::TextureFunction::LOD:
394 out << ", float lod";
395 break;
396 case TextureFunctionHLSL::TextureFunction::LOD0:
397 break;
398 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
399 break; // Comes after the offset parameter
400 case TextureFunctionHLSL::TextureFunction::SIZE:
401 break;
402 case TextureFunctionHLSL::TextureFunction::FETCH:
JiangYizhou5b03f472017-01-09 10:22:53 +0800403 if (textureFunction.sampler == EbtSampler2DMS ||
404 textureFunction.sampler == EbtISampler2DMS ||
405 textureFunction.sampler == EbtUSampler2DMS)
406 out << ", int index";
407 else
408 out << ", int mip";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300409 break;
410 case TextureFunctionHLSL::TextureFunction::GRAD:
411 break;
412 default:
413 UNREACHABLE();
414 }
415
416 if (textureFunction.offset)
417 {
418 switch (textureFunction.sampler)
419 {
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300420 case EbtSampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300421 case EbtISampler3D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300422 case EbtUSampler3D:
423 out << ", int3 offset";
424 break;
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300425 case EbtSampler2D:
426 case EbtSampler2DArray:
427 case EbtISampler2D:
428 case EbtISampler2DArray:
429 case EbtUSampler2D:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300430 case EbtUSampler2DArray:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300431 case EbtSampler2DShadow:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300432 case EbtSampler2DArrayShadow:
JiangYizhou5b03f472017-01-09 10:22:53 +0800433 case EbtSampler2DMS:
434 case EbtISampler2DMS:
435 case EbtUSampler2DMS:
Ian Ewellbda75592016-04-18 17:25:54 -0400436 case EbtSamplerExternalOES:
437 out << ", int2 offset";
Andi-Bogdan Postelnicu9e77ce32016-09-27 17:05:44 +0300438 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300439 default:
440 UNREACHABLE();
441 }
442 }
443
444 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS ||
445 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
446 {
447 out << ", float bias";
448 }
449}
450
451void GetTextureReference(TInfoSinkBase &out,
452 const TextureFunctionHLSL::TextureFunction &textureFunction,
453 const ShShaderOutput outputType,
Olli Etuahoc13bda82018-01-25 12:22:33 +0200454 ImmutableString *textureReference,
455 ImmutableString *samplerReference)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300456{
457 if (outputType == SH_HLSL_4_1_OUTPUT)
458 {
Olli Etuahoc13bda82018-01-25 12:22:33 +0200459 static const ImmutableString kTexturesStr("textures");
460 static const ImmutableString kSamplersStr("samplers");
461 static const ImmutableString kSamplerIndexStr("[samplerIndex]");
462 static const ImmutableString kTextureIndexStr("[textureIndex]");
463 static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
464 ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
465
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300466 if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
467 {
Olli Etuahoc13bda82018-01-25 12:22:33 +0200468 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
469 kSamplerIndexStr.length());
470 textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
471 *textureReference = textureRefBuilder;
472 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
473 kSamplerIndexStr.length());
474 samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
475 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300476 }
477 else
478 {
Olli Etuahoc13bda82018-01-25 12:22:33 +0200479 out << " const uint textureIndex = samplerIndex - textureIndexOffset"
480 << suffix.data() << ";\n";
481 ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
482 kTextureIndexStr.length());
483 textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
484 *textureReference = textureRefBuilder;
485
486 out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
487 << suffix.data() << ";\n";
488 ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
489 kSamplerArrayIndexStr.length());
490 samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
491 *samplerReference = samplerRefBuilder;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300492 }
493 }
494 else
495 {
Olli Etuahoc13bda82018-01-25 12:22:33 +0200496 *textureReference = ImmutableString("x");
497 *samplerReference = ImmutableString("s");
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300498 }
499}
500
501void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
502 const TextureFunctionHLSL::TextureFunction &textureFunction,
Olli Etuahoc13bda82018-01-25 12:22:33 +0200503 const ImmutableString &textureReference,
Geoff Lang1fe74c72016-08-25 13:23:01 -0400504 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300505{
Olli Etuaho92db39e2017-02-15 12:11:04 +0000506 if (IsSampler2DMS(textureFunction.sampler))
Geoff Lang1fe74c72016-08-25 13:23:01 -0400507 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000508 out << " uint width; uint height; uint samples;\n"
509 << " " << textureReference << ".GetDimensions(width, height, samples);\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400510 }
511 else
512 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000513 if (getDimensionsIgnoresBaseLevel)
Geoff Lang1fe74c72016-08-25 13:23:01 -0400514 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000515 out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
Geoff Lang1fe74c72016-08-25 13:23:01 -0400516 }
Olli Etuaho92db39e2017-02-15 12:11:04 +0000517 else
518 {
519 out << " int baseLevel = 0;\n";
520 }
521
522 if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) ||
523 (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler)))
524 {
525 // "depth" stores either the number of layers in an array texture or 3D depth
526 out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
527 << " " << textureReference
528 << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n"
529 << " width = max(width >> lod, 1);\n"
530 << " height = max(height >> lod, 1);\n";
531
532 if (!IsSamplerArray(textureFunction.sampler))
533 {
534 out << " depth = max(depth >> lod, 1);\n";
535 }
536 }
537 else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler))
538 {
539 out << " uint width; uint height; uint numberOfLevels;\n"
540 << " " << textureReference
541 << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n"
542 << " width = max(width >> lod, 1);\n"
543 << " height = max(height >> lod, 1);\n";
544 }
545 else
546 UNREACHABLE();
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300547 }
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300548
549 if (strcmp(textureFunction.getReturnType(), "int3") == 0)
550 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000551 out << " return int3(width, height, depth);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300552 }
553 else
554 {
Olli Etuaho92db39e2017-02-15 12:11:04 +0000555 out << " return int2(width, height);\n";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300556 }
557}
558
559void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction,
560 TString *texCoordX,
561 TString *texCoordY,
562 TString *texCoordZ)
563{
564 if (textureFunction.proj)
565 {
566 TString proj("");
567 switch (textureFunction.coords)
568 {
569 case 3:
570 proj = " / t.z";
571 break;
572 case 4:
573 proj = " / t.w";
574 break;
575 default:
576 UNREACHABLE();
577 }
578 *texCoordX = "(" + *texCoordX + proj + ")";
579 *texCoordY = "(" + *texCoordY + proj + ")";
580 *texCoordZ = "(" + *texCoordZ + proj + ")";
581 }
582}
583
584void OutputIntegerTextureSampleFunctionComputations(
585 TInfoSinkBase &out,
586 const TextureFunctionHLSL::TextureFunction &textureFunction,
587 const ShShaderOutput outputType,
Olli Etuahoc13bda82018-01-25 12:22:33 +0200588 const ImmutableString &textureReference,
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300589 TString *texCoordX,
590 TString *texCoordY,
591 TString *texCoordZ)
592{
593 if (!IsIntegerSampler(textureFunction.sampler))
594 {
595 return;
596 }
597 if (IsSamplerCube(textureFunction.sampler))
598 {
599 out << " float width; float height; float layers; float levels;\n";
600
601 out << " uint mip = 0;\n";
602
603 out << " " << textureReference
604 << ".GetDimensions(mip, width, height, layers, levels);\n";
605
606 out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
607 out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
608 out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
609 out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || "
610 "(zMajor && t.z < 0.0f);\n";
611
612 // FACE_POSITIVE_X = 000b
613 // FACE_NEGATIVE_X = 001b
614 // FACE_POSITIVE_Y = 010b
615 // FACE_NEGATIVE_Y = 011b
616 // FACE_POSITIVE_Z = 100b
617 // FACE_NEGATIVE_Z = 101b
618 out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
619
620 out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
621 out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
622 out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
623
624 out << " t.x = (u * 0.5f / m) + 0.5f;\n";
625 out << " t.y = (v * 0.5f / m) + 0.5f;\n";
626
627 // Mip level computation.
628 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
629 textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD ||
630 textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
631 {
632 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT)
633 {
634 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
635 " float2 dx = ddx(tSized);\n"
636 " float2 dy = ddy(tSized);\n"
637 " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n";
638 }
639 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
640 {
641 // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial
642 // derivatives of P are assumed to be in the coordinate system used before
643 // texture coordinates are projected onto the appropriate cube face."
644 // ddx[0] and ddy[0] are the derivatives of t.x passed into the function
645 // ddx[1] and ddy[1] are the derivatives of t.y passed into the function
646 // ddx[2] and ddy[2] are the derivatives of t.z passed into the function
647 // Determine the derivatives of u, v and m
648 out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] "
649 ": ddx[0]);\n"
650 " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] "
651 ": ddy[0]);\n"
652 " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n"
653 " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n"
654 " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n"
655 " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n";
656 // Now determine the derivatives of the face coordinates, using the
657 // derivatives calculated above.
658 // d / dx (u(x) * 0.5 / m(x) + 0.5)
659 // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2
660 out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n"
661 " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n"
662 " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n"
663 " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n"
664 " float2 sizeVec = float2(width, height);\n"
665 " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n"
666 " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n";
667 // Optimization: instead of: log2(max(length(faceddx), length(faceddy)))
668 // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2
669 out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n"
670 " float lengthfaceddy2 = dot(faceddy, faceddy);\n"
671 " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n";
672 }
673 out << " mip = uint(min(max(round(lod), 0), levels - 1));\n"
674 << " " << textureReference
675 << ".GetDimensions(mip, width, height, layers, levels);\n";
676 }
677
678 // Convert from normalized floating-point to integer
679 *texCoordX = "int(floor(width * frac(" + *texCoordX + ")))";
680 *texCoordY = "int(floor(height * frac(" + *texCoordY + ")))";
681 *texCoordZ = "face";
682 }
683 else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH)
684 {
685 if (IsSampler2D(textureFunction.sampler))
686 {
687 if (IsSamplerArray(textureFunction.sampler))
688 {
689 out << " float width; float height; float layers; float levels;\n";
690
691 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
692 {
693 out << " uint mip = 0;\n";
694 }
695 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
696 {
697 out << " uint mip = bias;\n";
698 }
699 else
700 {
701
702 out << " " << textureReference
703 << ".GetDimensions(0, width, height, layers, levels);\n";
704 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
705 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
706 {
707 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
708 " float dx = length(ddx(tSized));\n"
709 " float dy = length(ddy(tSized));\n"
710 " float lod = log2(max(dx, dy));\n";
711
712 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
713 {
714 out << " lod += bias;\n";
715 }
716 }
717 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
718 {
719 out << " float2 sizeVec = float2(width, height);\n"
720 " float2 sizeDdx = ddx * sizeVec;\n"
721 " float2 sizeDdy = ddy * sizeVec;\n"
722 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
723 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
724 }
725
726 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
727 }
728
729 out << " " << textureReference
730 << ".GetDimensions(mip, width, height, layers, levels);\n";
731 }
732 else
733 {
734 out << " float width; float height; float levels;\n";
735
736 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
737 {
738 out << " uint mip = 0;\n";
739 }
740 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
741 {
742 out << " uint mip = bias;\n";
743 }
744 else
745 {
746 out << " " << textureReference
747 << ".GetDimensions(0, width, height, levels);\n";
748
749 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
750 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
751 {
752 out << " float2 tSized = float2(t.x * width, t.y * height);\n"
753 " float dx = length(ddx(tSized));\n"
754 " float dy = length(ddy(tSized));\n"
755 " float lod = log2(max(dx, dy));\n";
756
757 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
758 {
759 out << " lod += bias;\n";
760 }
761 }
762 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
763 {
764 out << " float2 sizeVec = float2(width, height);\n"
765 " float2 sizeDdx = ddx * sizeVec;\n"
766 " float2 sizeDdy = ddy * sizeVec;\n"
767 " float lod = log2(max(dot(sizeDdx, sizeDdx), "
768 "dot(sizeDdy, sizeDdy))) * 0.5f;\n";
769 }
770
771 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
772 }
773
774 out << " " << textureReference
775 << ".GetDimensions(mip, width, height, levels);\n";
776 }
777 }
778 else if (IsSampler3D(textureFunction.sampler))
779 {
780 out << " float width; float height; float depth; float levels;\n";
781
782 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0)
783 {
784 out << " uint mip = 0;\n";
785 }
786 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS)
787 {
788 out << " uint mip = bias;\n";
789 }
790 else
791 {
792 out << " " << textureReference
793 << ".GetDimensions(0, width, height, depth, levels);\n";
794
795 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT ||
796 textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
797 {
798 out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
799 " float dx = length(ddx(tSized));\n"
800 " float dy = length(ddy(tSized));\n"
801 " float lod = log2(max(dx, dy));\n";
802
803 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS)
804 {
805 out << " lod += bias;\n";
806 }
807 }
808 else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
809 {
810 out << " float3 sizeVec = float3(width, height, depth);\n"
811 " float3 sizeDdx = ddx * sizeVec;\n"
812 " float3 sizeDdy = ddy * sizeVec;\n"
813 " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, "
814 "sizeDdy))) * 0.5f;\n";
815 }
816
817 out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
818 }
819
820 out << " " << textureReference
821 << ".GetDimensions(mip, width, height, depth, levels);\n";
822 }
823 else
824 UNREACHABLE();
825
826 OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ);
827 }
828}
829
830void OutputTextureSampleFunctionReturnStatement(
831 TInfoSinkBase &out,
832 const TextureFunctionHLSL::TextureFunction &textureFunction,
833 const ShShaderOutput outputType,
Olli Etuahoc13bda82018-01-25 12:22:33 +0200834 const ImmutableString &textureReference,
835 const ImmutableString &samplerReference,
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300836 const TString &texCoordX,
837 const TString &texCoordY,
838 const TString &texCoordZ)
839{
840 out << " return ";
841
842 // HLSL intrinsic
843 if (outputType == SH_HLSL_3_0_OUTPUT)
844 {
845 switch (textureFunction.sampler)
846 {
847 case EbtSampler2D:
Geoff Langb66a9092016-05-16 15:59:14 -0400848 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300849 out << "tex2D";
850 break;
851 case EbtSamplerCube:
852 out << "texCUBE";
853 break;
854 default:
855 UNREACHABLE();
856 }
857
858 switch (textureFunction.method)
859 {
860 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
861 out << "(" << samplerReference << ", ";
862 break;
863 case TextureFunctionHLSL::TextureFunction::BIAS:
864 out << "bias(" << samplerReference << ", ";
865 break;
866 case TextureFunctionHLSL::TextureFunction::LOD:
867 out << "lod(" << samplerReference << ", ";
868 break;
869 case TextureFunctionHLSL::TextureFunction::LOD0:
870 out << "lod(" << samplerReference << ", ";
871 break;
872 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
873 out << "lod(" << samplerReference << ", ";
874 break;
Geoff Langba992ab2017-04-19 11:18:14 -0400875 case TextureFunctionHLSL::TextureFunction::GRAD:
876 out << "grad(" << samplerReference << ", ";
877 break;
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300878 default:
879 UNREACHABLE();
880 }
881 }
882 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
883 {
884 OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference);
885 }
886 else
887 UNREACHABLE();
888
889 const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType);
890
891 out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", "
892 << texCoordY;
893
894 if (outputType == SH_HLSL_3_0_OUTPUT)
895 {
896 if (hlslCoords >= 3)
897 {
898 if (textureFunction.coords < 3)
899 {
900 out << ", 0";
901 }
902 else
903 {
904 out << ", " << texCoordZ;
905 }
906 }
907
908 if (hlslCoords == 4)
909 {
910 switch (textureFunction.method)
911 {
912 case TextureFunctionHLSL::TextureFunction::BIAS:
913 out << ", bias";
914 break;
915 case TextureFunctionHLSL::TextureFunction::LOD:
916 out << ", lod";
917 break;
918 case TextureFunctionHLSL::TextureFunction::LOD0:
919 out << ", 0";
920 break;
921 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
922 out << ", bias";
923 break;
924 default:
925 UNREACHABLE();
926 }
927 }
928
929 out << ")";
930 }
931 else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
932 {
933 if (hlslCoords >= 3)
934 {
935 ASSERT(!IsIntegerSampler(textureFunction.sampler) ||
936 !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face");
937 out << ", " << texCoordZ;
938 }
939
940 if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD)
941 {
942 if (IsIntegerSampler(textureFunction.sampler))
943 {
944 out << ", mip)";
945 }
946 else if (IsShadowSampler(textureFunction.sampler))
947 {
948 // Compare value
949 if (textureFunction.proj)
950 {
951 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
952 // The resulting third component of P' in the shadow forms is used as
953 // Dref
954 out << "), " << texCoordZ;
955 }
956 else
957 {
958 switch (textureFunction.coords)
959 {
960 case 3:
961 out << "), t.z";
962 break;
963 case 4:
964 out << "), t.w";
965 break;
966 default:
967 UNREACHABLE();
968 }
969 }
970 }
971 else
972 {
973 out << "), ddx, ddy";
974 }
975 }
976 else if (IsIntegerSampler(textureFunction.sampler) ||
977 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)
978 {
JiangYizhou5b03f472017-01-09 10:22:53 +0800979 if (textureFunction.sampler == EbtSampler2DMS ||
980 textureFunction.sampler == EbtISampler2DMS ||
981 textureFunction.sampler == EbtUSampler2DMS)
982 out << "), index";
983 else
984 out << ", mip)";
Olli Etuaho5858f7e2016-04-08 13:08:46 +0300985 }
986 else if (IsShadowSampler(textureFunction.sampler))
987 {
988 // Compare value
989 if (textureFunction.proj)
990 {
991 // According to ESSL 3.00.4 sec 8.8 p95 on textureProj:
992 // The resulting third component of P' in the shadow forms is used as Dref
993 out << "), " << texCoordZ;
994 }
995 else
996 {
997 switch (textureFunction.coords)
998 {
999 case 3:
1000 out << "), t.z";
1001 break;
1002 case 4:
1003 out << "), t.w";
1004 break;
1005 default:
1006 UNREACHABLE();
1007 }
1008 }
1009 }
1010 else
1011 {
1012 switch (textureFunction.method)
1013 {
1014 case TextureFunctionHLSL::TextureFunction::IMPLICIT:
1015 out << ")";
1016 break;
1017 case TextureFunctionHLSL::TextureFunction::BIAS:
1018 out << "), bias";
1019 break;
1020 case TextureFunctionHLSL::TextureFunction::LOD:
1021 out << "), lod";
1022 break;
1023 case TextureFunctionHLSL::TextureFunction::LOD0:
1024 out << "), 0";
1025 break;
1026 case TextureFunctionHLSL::TextureFunction::LOD0BIAS:
1027 out << "), bias";
1028 break;
1029 default:
1030 UNREACHABLE();
1031 }
1032 }
1033
1034 if (textureFunction.offset &&
1035 (!IsIntegerSampler(textureFunction.sampler) ||
1036 textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH))
1037 {
1038 out << ", offset";
1039 }
1040 }
1041 else
1042 UNREACHABLE();
1043
1044 out << ");\n"; // Close the sample function call and return statement
1045}
1046
1047} // Anonymous namespace
1048
1049TString TextureFunctionHLSL::TextureFunction::name() const
1050{
1051 TString name = "gl_texture";
1052
1053 // We need to include full the sampler type in the function name to make the signature unique
1054 // on D3D11, where samplers are passed to texture functions as indices.
1055 name += TextureTypeSuffix(this->sampler);
1056
1057 if (proj)
1058 {
1059 name += "Proj";
1060 }
1061
1062 if (offset)
1063 {
1064 name += "Offset";
1065 }
1066
1067 switch (method)
1068 {
1069 case IMPLICIT:
1070 break;
1071 case BIAS:
1072 break; // Extra parameter makes the signature unique
1073 case LOD:
1074 name += "Lod";
1075 break;
1076 case LOD0:
1077 name += "Lod0";
1078 break;
1079 case LOD0BIAS:
1080 name += "Lod0";
1081 break; // Extra parameter makes the signature unique
1082 case SIZE:
1083 name += "Size";
1084 break;
1085 case FETCH:
1086 name += "Fetch";
1087 break;
1088 case GRAD:
1089 name += "Grad";
1090 break;
1091 default:
1092 UNREACHABLE();
1093 }
1094
1095 return name;
1096}
1097
1098const char *TextureFunctionHLSL::TextureFunction::getReturnType() const
1099{
1100 if (method == TextureFunction::SIZE)
1101 {
1102 switch (sampler)
1103 {
1104 case EbtSampler2D:
1105 case EbtISampler2D:
1106 case EbtUSampler2D:
1107 case EbtSampler2DShadow:
1108 case EbtSamplerCube:
1109 case EbtISamplerCube:
1110 case EbtUSamplerCube:
1111 case EbtSamplerCubeShadow:
Ian Ewellbda75592016-04-18 17:25:54 -04001112 case EbtSamplerExternalOES:
Olli Etuaho92db39e2017-02-15 12:11:04 +00001113 case EbtSampler2DMS:
1114 case EbtISampler2DMS:
1115 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001116 return "int2";
1117 case EbtSampler3D:
1118 case EbtISampler3D:
1119 case EbtUSampler3D:
1120 case EbtSampler2DArray:
1121 case EbtISampler2DArray:
1122 case EbtUSampler2DArray:
1123 case EbtSampler2DArrayShadow:
1124 return "int3";
1125 default:
1126 UNREACHABLE();
1127 }
1128 }
1129 else // Sampling function
1130 {
1131 switch (sampler)
1132 {
1133 case EbtSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001134 case EbtSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001135 case EbtSampler3D:
1136 case EbtSamplerCube:
1137 case EbtSampler2DArray:
Ian Ewellbda75592016-04-18 17:25:54 -04001138 case EbtSamplerExternalOES:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001139 return "float4";
1140 case EbtISampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001141 case EbtISampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001142 case EbtISampler3D:
1143 case EbtISamplerCube:
1144 case EbtISampler2DArray:
1145 return "int4";
1146 case EbtUSampler2D:
JiangYizhou34bc3152017-03-29 14:56:01 +08001147 case EbtUSampler2DMS:
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001148 case EbtUSampler3D:
1149 case EbtUSamplerCube:
1150 case EbtUSampler2DArray:
1151 return "uint4";
1152 case EbtSampler2DShadow:
1153 case EbtSamplerCubeShadow:
1154 case EbtSampler2DArrayShadow:
1155 return "float";
1156 default:
1157 UNREACHABLE();
1158 }
1159 }
1160 return "";
1161}
1162
1163bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
1164{
Geoff Lang28a97ee2016-09-22 13:01:26 -04001165 return std::tie(sampler, coords, proj, offset, method) <
1166 std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001167}
1168
1169TString TextureFunctionHLSL::useTextureFunction(const TString &name,
1170 TBasicType samplerType,
1171 int coords,
1172 size_t argumentCount,
1173 bool lod0,
1174 sh::GLenum shaderType)
1175{
1176 TextureFunction textureFunction;
1177 textureFunction.sampler = samplerType;
1178 textureFunction.coords = coords;
1179 textureFunction.method = TextureFunction::IMPLICIT;
1180 textureFunction.proj = false;
1181 textureFunction.offset = false;
1182
1183 if (name == "texture2D" || name == "textureCube" || name == "texture")
1184 {
1185 textureFunction.method = TextureFunction::IMPLICIT;
1186 }
1187 else if (name == "texture2DProj" || name == "textureProj")
1188 {
1189 textureFunction.method = TextureFunction::IMPLICIT;
1190 textureFunction.proj = true;
1191 }
1192 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
1193 name == "texture2DLodEXT" || name == "textureCubeLodEXT")
1194 {
1195 textureFunction.method = TextureFunction::LOD;
1196 }
1197 else if (name == "texture2DProjLod" || name == "textureProjLod" ||
1198 name == "texture2DProjLodEXT")
1199 {
1200 textureFunction.method = TextureFunction::LOD;
1201 textureFunction.proj = true;
1202 }
1203 else if (name == "textureSize")
1204 {
1205 textureFunction.method = TextureFunction::SIZE;
1206 }
1207 else if (name == "textureOffset")
1208 {
1209 textureFunction.method = TextureFunction::IMPLICIT;
1210 textureFunction.offset = true;
1211 }
1212 else if (name == "textureProjOffset")
1213 {
1214 textureFunction.method = TextureFunction::IMPLICIT;
1215 textureFunction.offset = true;
1216 textureFunction.proj = true;
1217 }
1218 else if (name == "textureLodOffset")
1219 {
1220 textureFunction.method = TextureFunction::LOD;
1221 textureFunction.offset = true;
1222 }
1223 else if (name == "textureProjLodOffset")
1224 {
1225 textureFunction.method = TextureFunction::LOD;
1226 textureFunction.proj = true;
1227 textureFunction.offset = true;
1228 }
1229 else if (name == "texelFetch")
1230 {
1231 textureFunction.method = TextureFunction::FETCH;
1232 }
1233 else if (name == "texelFetchOffset")
1234 {
1235 textureFunction.method = TextureFunction::FETCH;
1236 textureFunction.offset = true;
1237 }
1238 else if (name == "textureGrad" || name == "texture2DGradEXT")
1239 {
1240 textureFunction.method = TextureFunction::GRAD;
1241 }
1242 else if (name == "textureGradOffset")
1243 {
1244 textureFunction.method = TextureFunction::GRAD;
1245 textureFunction.offset = true;
1246 }
1247 else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" ||
1248 name == "textureCubeGradEXT")
1249 {
1250 textureFunction.method = TextureFunction::GRAD;
1251 textureFunction.proj = true;
1252 }
1253 else if (name == "textureProjGradOffset")
1254 {
1255 textureFunction.method = TextureFunction::GRAD;
1256 textureFunction.proj = true;
1257 textureFunction.offset = true;
1258 }
1259 else
1260 UNREACHABLE();
1261
1262 if (textureFunction.method ==
1263 TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
1264 {
1265 size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
1266
1267 if (textureFunction.offset)
1268 {
1269 mandatoryArgumentCount++;
1270 }
1271
1272 bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional
1273
1274 if (lod0 || shaderType == GL_VERTEX_SHADER)
1275 {
1276 if (bias)
1277 {
1278 textureFunction.method = TextureFunction::LOD0BIAS;
1279 }
1280 else
1281 {
1282 textureFunction.method = TextureFunction::LOD0;
1283 }
1284 }
1285 else if (bias)
1286 {
1287 textureFunction.method = TextureFunction::BIAS;
1288 }
1289 }
1290
1291 mUsesTexture.insert(textureFunction);
1292 return textureFunction.name();
1293}
1294
Geoff Lang1fe74c72016-08-25 13:23:01 -04001295void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out,
1296 const ShShaderOutput outputType,
1297 bool getDimensionsIgnoresBaseLevel)
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001298{
1299 for (const TextureFunction &textureFunction : mUsesTexture)
1300 {
1301 // Function header
1302 out << textureFunction.getReturnType() << " " << textureFunction.name() << "(";
1303
1304 OutputTextureFunctionArgumentList(out, textureFunction, outputType);
1305
1306 out << ")\n"
1307 "{\n";
1308
1309 // In some cases we use a variable to store the texture/sampler objects, but to work around
1310 // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
1311 // sampling we need to call the function directly on references to the texture and sampler
1312 // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
1313 // tests.
Olli Etuahoc13bda82018-01-25 12:22:33 +02001314 ImmutableString textureReference("");
1315 ImmutableString samplerReference("");
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001316 GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
1317
1318 if (textureFunction.method == TextureFunction::SIZE)
1319 {
Geoff Lang1fe74c72016-08-25 13:23:01 -04001320 OutputTextureSizeFunctionBody(out, textureFunction, textureReference,
1321 getDimensionsIgnoresBaseLevel);
Olli Etuaho5858f7e2016-04-08 13:08:46 +03001322 }
1323 else
1324 {
1325 TString texCoordX("t.x");
1326 TString texCoordY("t.y");
1327 TString texCoordZ("t.z");
1328 ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ);
1329 OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType,
1330 textureReference, &texCoordX, &texCoordY,
1331 &texCoordZ);
1332 OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType,
1333 textureReference, samplerReference,
1334 texCoordX, texCoordY, texCoordZ);
1335 }
1336
1337 out << "}\n"
1338 "\n";
1339 }
1340}
1341
1342} // namespace sh