1 //
2 // Copyright 2017 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 // ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output.
7 //
8
9 #include "compiler/translator/hlsl/ImageFunctionHLSL.h"
10 #include "compiler/translator/ImmutableStringBuilder.h"
11 #include "compiler/translator/hlsl/UtilsHLSL.h"
12
13 namespace sh
14 {
15
16 // static
GetImageReference(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction)17 ImmutableString ImageFunctionHLSL::GetImageReference(
18 TInfoSinkBase &out,
19 const ImageFunctionHLSL::ImageFunction &imageFunction)
20 {
21 static const ImmutableString kImageIndexStr("[index]");
22 if (imageFunction.readonly)
23 {
24 static const ImmutableString kReadonlyImagesStr("readonlyImages");
25 ImmutableString suffix(
26 TextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat));
27 out << " const uint index = imageIndex - readonlyImageIndexOffset" << suffix.data()
28 << ";\n";
29 ImmutableStringBuilder imageRefBuilder(kReadonlyImagesStr.length() + suffix.length() +
30 kImageIndexStr.length());
31 imageRefBuilder << kReadonlyImagesStr << suffix << kImageIndexStr;
32 return imageRefBuilder;
33 }
34 else
35 {
36 static const ImmutableString kImagesStr("images");
37 ImmutableString suffix(
38 RWTextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat));
39 out << " const uint index = imageIndex - imageIndexOffset" << suffix.data() << ";\n";
40 ImmutableStringBuilder imageRefBuilder(kImagesStr.length() + suffix.length() +
41 kImageIndexStr.length());
42 imageRefBuilder << kImagesStr << suffix << kImageIndexStr;
43 return imageRefBuilder;
44 }
45 }
46
OutputImageFunctionArgumentList(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction)47 void ImageFunctionHLSL::OutputImageFunctionArgumentList(
48 TInfoSinkBase &out,
49 const ImageFunctionHLSL::ImageFunction &imageFunction)
50 {
51 out << "uint imageIndex";
52
53 if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD ||
54 imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
55 {
56 switch (imageFunction.image)
57 {
58 case EbtImage2D:
59 case EbtIImage2D:
60 case EbtUImage2D:
61 out << ", int2 p";
62 break;
63 case EbtImage3D:
64 case EbtIImage3D:
65 case EbtUImage3D:
66 case EbtImageCube:
67 case EbtIImageCube:
68 case EbtUImageCube:
69 case EbtImage2DArray:
70 case EbtIImage2DArray:
71 case EbtUImage2DArray:
72 out << ", int3 p";
73 break;
74 case EbtUImageBuffer:
75 case EbtIImageBuffer:
76 case EbtImageBuffer:
77 out << ", int p";
78 break;
79
80 default:
81 UNREACHABLE();
82 }
83
84 if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
85 {
86 switch (imageFunction.image)
87 {
88 case EbtImage2D:
89 case EbtImage3D:
90 case EbtImageCube:
91 case EbtImage2DArray:
92 case EbtImageBuffer:
93 out << ", float4 data";
94 break;
95 case EbtIImage2D:
96 case EbtIImage3D:
97 case EbtIImageCube:
98 case EbtIImage2DArray:
99 case EbtIImageBuffer:
100 out << ", int4 data";
101 break;
102 case EbtUImage2D:
103 case EbtUImage3D:
104 case EbtUImageCube:
105 case EbtUImage2DArray:
106 case EbtUImageBuffer:
107 out << ", uint4 data";
108 break;
109 default:
110 UNREACHABLE();
111 }
112 }
113 }
114 }
115
116 // static
OutputImageSizeFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)117 void ImageFunctionHLSL::OutputImageSizeFunctionBody(
118 TInfoSinkBase &out,
119 const ImageFunctionHLSL::ImageFunction &imageFunction,
120 const ImmutableString &imageReference)
121 {
122 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
123 IsImageCube(imageFunction.image))
124 {
125 // "depth" stores either the number of layers in an array texture or 3D depth
126 out << " uint width; uint height; uint depth;\n"
127 << " " << imageReference << ".GetDimensions(width, height, depth);\n";
128 }
129 else if (IsImage2D(imageFunction.image))
130 {
131 out << " uint width; uint height;\n"
132 << " " << imageReference << ".GetDimensions(width, height);\n";
133 }
134 else if (IsImageBuffer(imageFunction.image))
135 {
136 out << " uint width;\n"
137 << " " << imageReference << ".GetDimensions(width);\n";
138 }
139 else
140 UNREACHABLE();
141
142 if (strcmp(imageFunction.getReturnType(), "int3") == 0)
143 {
144 out << " return int3(width, height, depth);\n";
145 }
146 else if (strcmp(imageFunction.getReturnType(), "int2") == 0)
147 {
148 out << " return int2(width, height);\n";
149 }
150 else if (strcmp(imageFunction.getReturnType(), "int") == 0)
151 out << " return int(width);\n";
152 else
153 UNREACHABLE();
154 }
155
156 // static
OutputImageLoadFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)157 void ImageFunctionHLSL::OutputImageLoadFunctionBody(
158 TInfoSinkBase &out,
159 const ImageFunctionHLSL::ImageFunction &imageFunction,
160 const ImmutableString &imageReference)
161 {
162 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
163 IsImageCube(imageFunction.image))
164 {
165 out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n";
166 }
167 else if (IsImage2D(imageFunction.image))
168 {
169 out << " return " << imageReference << "[uint2(p.x, p.y)];\n";
170 }
171 else if (IsImageBuffer(imageFunction.image))
172 {
173 out << " return " << imageReference << "[uint(p.x)];\n";
174 }
175 else
176 UNREACHABLE();
177 }
178
179 // static
OutputImageStoreFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)180 void ImageFunctionHLSL::OutputImageStoreFunctionBody(
181 TInfoSinkBase &out,
182 const ImageFunctionHLSL::ImageFunction &imageFunction,
183 const ImmutableString &imageReference)
184 {
185 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
186 IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image) ||
187 IsImageBuffer(imageFunction.image))
188 {
189 out << " " << imageReference << "[p] = data;\n";
190 }
191 else
192 UNREACHABLE();
193 }
194
name() const195 ImmutableString ImageFunctionHLSL::ImageFunction::name() const
196 {
197 static const ImmutableString kGlImageName("gl_image");
198
199 ImmutableString suffix(nullptr);
200 if (readonly)
201 {
202 suffix = ImmutableString(TextureTypeSuffix(image, imageInternalFormat));
203 }
204 else
205 {
206 suffix = ImmutableString(RWTextureTypeSuffix(image, imageInternalFormat));
207 }
208
209 ImmutableStringBuilder name(kGlImageName.length() + suffix.length() + 5u);
210
211 name << kGlImageName << suffix;
212
213 switch (method)
214 {
215 case Method::SIZE:
216 name << "Size";
217 break;
218 case Method::LOAD:
219 name << "Load";
220 break;
221 case Method::STORE:
222 name << "Store";
223 break;
224 default:
225 UNREACHABLE();
226 }
227
228 return name;
229 }
230
getDataType(TLayoutImageInternalFormat format) const231 ImageFunctionHLSL::ImageFunction::DataType ImageFunctionHLSL::ImageFunction::getDataType(
232 TLayoutImageInternalFormat format) const
233 {
234 switch (format)
235 {
236 case EiifRGBA32F:
237 case EiifRGBA16F:
238 case EiifR32F:
239 return ImageFunction::DataType::FLOAT4;
240 case EiifRGBA32UI:
241 case EiifRGBA16UI:
242 case EiifRGBA8UI:
243 case EiifR32UI:
244 return ImageFunction::DataType::UINT4;
245 case EiifRGBA32I:
246 case EiifRGBA16I:
247 case EiifRGBA8I:
248 case EiifR32I:
249 return ImageFunction::DataType::INT4;
250 case EiifRGBA8:
251 return ImageFunction::DataType::UNORM_FLOAT4;
252 case EiifRGBA8_SNORM:
253 return ImageFunction::DataType::SNORM_FLOAT4;
254 default:
255 UNREACHABLE();
256 }
257
258 return ImageFunction::DataType::NONE;
259 }
260
getReturnType() const261 const char *ImageFunctionHLSL::ImageFunction::getReturnType() const
262 {
263 if (method == ImageFunction::Method::SIZE)
264 {
265 switch (image)
266 {
267 case EbtImage2D:
268 case EbtIImage2D:
269 case EbtUImage2D:
270 case EbtImageCube:
271 case EbtIImageCube:
272 case EbtUImageCube:
273 return "int2";
274 case EbtImage3D:
275 case EbtIImage3D:
276 case EbtUImage3D:
277 case EbtImage2DArray:
278 case EbtIImage2DArray:
279 case EbtUImage2DArray:
280 return "int3";
281 case EbtImageBuffer:
282 case EbtIImageBuffer:
283 case EbtUImageBuffer:
284 return "int";
285 default:
286 UNREACHABLE();
287 }
288 }
289 else if (method == ImageFunction::Method::LOAD)
290 {
291 switch (image)
292 {
293 case EbtImageBuffer:
294 case EbtImage2D:
295 case EbtImage3D:
296 case EbtImageCube:
297 case EbtImage2DArray:
298 return "float4";
299 case EbtIImageBuffer:
300 case EbtIImage2D:
301 case EbtIImage3D:
302 case EbtIImageCube:
303 case EbtIImage2DArray:
304 return "int4";
305 case EbtUImageBuffer:
306 case EbtUImage2D:
307 case EbtUImage3D:
308 case EbtUImageCube:
309 case EbtUImage2DArray:
310 return "uint4";
311 default:
312 UNREACHABLE();
313 }
314 }
315 else if (method == ImageFunction::Method::STORE)
316 {
317 return "void";
318 }
319 else
320 {
321 UNREACHABLE();
322 }
323 return "";
324 }
325
operator <(const ImageFunction & rhs) const326 bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const
327 {
328 return std::tie(image, type, method, readonly) <
329 std::tie(rhs.image, rhs.type, rhs.method, rhs.readonly);
330 }
331
useImageFunction(const ImmutableString & name,const TBasicType & type,TLayoutImageInternalFormat imageInternalFormat,bool readonly)332 ImmutableString ImageFunctionHLSL::useImageFunction(const ImmutableString &name,
333 const TBasicType &type,
334 TLayoutImageInternalFormat imageInternalFormat,
335 bool readonly)
336 {
337 ASSERT(IsImage(type));
338 ImageFunction imageFunction;
339 imageFunction.image = type;
340 imageFunction.imageInternalFormat = imageInternalFormat;
341 imageFunction.readonly = readonly;
342 imageFunction.type = imageFunction.getDataType(imageInternalFormat);
343
344 if (name == "imageSize")
345 {
346 imageFunction.method = ImageFunction::Method::SIZE;
347 }
348 else if (name == "imageLoad")
349 {
350 imageFunction.method = ImageFunction::Method::LOAD;
351 }
352 else if (name == "imageStore")
353 {
354 imageFunction.method = ImageFunction::Method::STORE;
355 }
356 else
357 UNREACHABLE();
358
359 mUsesImage.insert(imageFunction);
360 return imageFunction.name();
361 }
362
imageFunctionHeader(TInfoSinkBase & out)363 void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out)
364 {
365 for (const ImageFunction &imageFunction : mUsesImage)
366 {
367 // Skip to generate image2D functions here, dynamically generate these
368 // functions when linking, or after dispatch or draw.
369 if (IsImage2D(imageFunction.image))
370 {
371 mUsedImage2DFunctionNames.insert(imageFunction.name().data());
372 continue;
373 }
374 // Function header
375 out << imageFunction.getReturnType() << " " << imageFunction.name() << "(";
376
377 OutputImageFunctionArgumentList(out, imageFunction);
378
379 out << ")\n"
380 "{\n";
381
382 ImmutableString imageReference = GetImageReference(out, imageFunction);
383 if (imageFunction.method == ImageFunction::Method::SIZE)
384 {
385 OutputImageSizeFunctionBody(out, imageFunction, imageReference);
386 }
387 else if (imageFunction.method == ImageFunction::Method::LOAD)
388 {
389 OutputImageLoadFunctionBody(out, imageFunction, imageReference);
390 }
391 else
392 {
393 OutputImageStoreFunctionBody(out, imageFunction, imageReference);
394 }
395
396 out << "}\n"
397 "\n";
398 }
399 }
400
401 } // namespace sh
402