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/ImageFunctionHLSL.h"
10 #include "compiler/translator/ImmutableStringBuilder.h"
11 #include "compiler/translator/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 default:
75 UNREACHABLE();
76 }
77
78 if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
79 {
80 switch (imageFunction.image)
81 {
82 case EbtImage2D:
83 case EbtImage3D:
84 case EbtImageCube:
85 case EbtImage2DArray:
86 out << ", float4 data";
87 break;
88 case EbtIImage2D:
89 case EbtIImage3D:
90 case EbtIImageCube:
91 case EbtIImage2DArray:
92 out << ", int4 data";
93 break;
94 case EbtUImage2D:
95 case EbtUImage3D:
96 case EbtUImageCube:
97 case EbtUImage2DArray:
98 out << ", uint4 data";
99 break;
100 default:
101 UNREACHABLE();
102 }
103 }
104 }
105 }
106
107 // static
OutputImageSizeFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)108 void ImageFunctionHLSL::OutputImageSizeFunctionBody(
109 TInfoSinkBase &out,
110 const ImageFunctionHLSL::ImageFunction &imageFunction,
111 const ImmutableString &imageReference)
112 {
113 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
114 IsImageCube(imageFunction.image))
115 {
116 // "depth" stores either the number of layers in an array texture or 3D depth
117 out << " uint width; uint height; uint depth;\n"
118 << " " << imageReference << ".GetDimensions(width, height, depth);\n";
119 }
120 else if (IsImage2D(imageFunction.image))
121 {
122 out << " uint width; uint height;\n"
123 << " " << imageReference << ".GetDimensions(width, height);\n";
124 }
125 else
126 UNREACHABLE();
127
128 if (strcmp(imageFunction.getReturnType(), "int3") == 0)
129 {
130 out << " return int3(width, height, depth);\n";
131 }
132 else
133 {
134 out << " return int2(width, height);\n";
135 }
136 }
137
138 // static
OutputImageLoadFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)139 void ImageFunctionHLSL::OutputImageLoadFunctionBody(
140 TInfoSinkBase &out,
141 const ImageFunctionHLSL::ImageFunction &imageFunction,
142 const ImmutableString &imageReference)
143 {
144 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
145 IsImageCube(imageFunction.image))
146 {
147 out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n";
148 }
149 else if (IsImage2D(imageFunction.image))
150 {
151 out << " return " << imageReference << "[uint2(p.x, p.y)];\n";
152 }
153 else
154 UNREACHABLE();
155 }
156
157 // static
OutputImageStoreFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const ImmutableString & imageReference)158 void ImageFunctionHLSL::OutputImageStoreFunctionBody(
159 TInfoSinkBase &out,
160 const ImageFunctionHLSL::ImageFunction &imageFunction,
161 const ImmutableString &imageReference)
162 {
163 if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
164 IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image))
165 {
166 out << " " << imageReference << "[p] = data;\n";
167 }
168 else
169 UNREACHABLE();
170 }
171
name() const172 ImmutableString ImageFunctionHLSL::ImageFunction::name() const
173 {
174 static const ImmutableString kGlImageName("gl_image");
175
176 ImmutableString suffix(nullptr);
177 if (readonly)
178 {
179 suffix = ImmutableString(TextureTypeSuffix(image, imageInternalFormat));
180 }
181 else
182 {
183 suffix = ImmutableString(RWTextureTypeSuffix(image, imageInternalFormat));
184 }
185
186 ImmutableStringBuilder name(kGlImageName.length() + suffix.length() + 5u);
187
188 name << kGlImageName << suffix;
189
190 switch (method)
191 {
192 case Method::SIZE:
193 name << "Size";
194 break;
195 case Method::LOAD:
196 name << "Load";
197 break;
198 case Method::STORE:
199 name << "Store";
200 break;
201 default:
202 UNREACHABLE();
203 }
204
205 return name;
206 }
207
getDataType(TLayoutImageInternalFormat format) const208 ImageFunctionHLSL::ImageFunction::DataType ImageFunctionHLSL::ImageFunction::getDataType(
209 TLayoutImageInternalFormat format) const
210 {
211 switch (format)
212 {
213 case EiifRGBA32F:
214 case EiifRGBA16F:
215 case EiifR32F:
216 return ImageFunction::DataType::FLOAT4;
217 case EiifRGBA32UI:
218 case EiifRGBA16UI:
219 case EiifRGBA8UI:
220 case EiifR32UI:
221 return ImageFunction::DataType::UINT4;
222 case EiifRGBA32I:
223 case EiifRGBA16I:
224 case EiifRGBA8I:
225 case EiifR32I:
226 return ImageFunction::DataType::INT4;
227 case EiifRGBA8:
228 return ImageFunction::DataType::UNORM_FLOAT4;
229 case EiifRGBA8_SNORM:
230 return ImageFunction::DataType::SNORM_FLOAT4;
231 default:
232 UNREACHABLE();
233 }
234
235 return ImageFunction::DataType::NONE;
236 }
237
getReturnType() const238 const char *ImageFunctionHLSL::ImageFunction::getReturnType() const
239 {
240 if (method == ImageFunction::Method::SIZE)
241 {
242 switch (image)
243 {
244 case EbtImage2D:
245 case EbtIImage2D:
246 case EbtUImage2D:
247 case EbtImageCube:
248 case EbtIImageCube:
249 case EbtUImageCube:
250 return "int2";
251 case EbtImage3D:
252 case EbtIImage3D:
253 case EbtUImage3D:
254 case EbtImage2DArray:
255 case EbtIImage2DArray:
256 case EbtUImage2DArray:
257 return "int3";
258 default:
259 UNREACHABLE();
260 }
261 }
262 else if (method == ImageFunction::Method::LOAD)
263 {
264 switch (image)
265 {
266 case EbtImage2D:
267 case EbtImage3D:
268 case EbtImageCube:
269 case EbtImage2DArray:
270 return "float4";
271 case EbtIImage2D:
272 case EbtIImage3D:
273 case EbtIImageCube:
274 case EbtIImage2DArray:
275 return "int4";
276 case EbtUImage2D:
277 case EbtUImage3D:
278 case EbtUImageCube:
279 case EbtUImage2DArray:
280 return "uint4";
281 default:
282 UNREACHABLE();
283 }
284 }
285 else if (method == ImageFunction::Method::STORE)
286 {
287 return "void";
288 }
289 else
290 {
291 UNREACHABLE();
292 }
293 return "";
294 }
295
operator <(const ImageFunction & rhs) const296 bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const
297 {
298 return std::tie(image, type, method, readonly) <
299 std::tie(rhs.image, rhs.type, rhs.method, rhs.readonly);
300 }
301
useImageFunction(const ImmutableString & name,const TBasicType & type,TLayoutImageInternalFormat imageInternalFormat,bool readonly)302 ImmutableString ImageFunctionHLSL::useImageFunction(const ImmutableString &name,
303 const TBasicType &type,
304 TLayoutImageInternalFormat imageInternalFormat,
305 bool readonly)
306 {
307 ASSERT(IsImage(type));
308 ImageFunction imageFunction;
309 imageFunction.image = type;
310 imageFunction.imageInternalFormat = imageInternalFormat;
311 imageFunction.readonly = readonly;
312 imageFunction.type = imageFunction.getDataType(imageInternalFormat);
313
314 if (name == "imageSize")
315 {
316 imageFunction.method = ImageFunction::Method::SIZE;
317 }
318 else if (name == "imageLoad")
319 {
320 imageFunction.method = ImageFunction::Method::LOAD;
321 }
322 else if (name == "imageStore")
323 {
324 imageFunction.method = ImageFunction::Method::STORE;
325 }
326 else
327 UNREACHABLE();
328
329 mUsesImage.insert(imageFunction);
330 return imageFunction.name();
331 }
332
imageFunctionHeader(TInfoSinkBase & out)333 void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out)
334 {
335 for (const ImageFunction &imageFunction : mUsesImage)
336 {
337 // Skip to generate image2D functions here, dynamically generate these
338 // functions when linking, or after dispatch or draw.
339 if (IsImage2D(imageFunction.image))
340 {
341 mUsedImage2DFunctionNames.insert(imageFunction.name().data());
342 continue;
343 }
344 // Function header
345 out << imageFunction.getReturnType() << " " << imageFunction.name() << "(";
346
347 OutputImageFunctionArgumentList(out, imageFunction);
348
349 out << ")\n"
350 "{\n";
351
352 ImmutableString imageReference = GetImageReference(out, imageFunction);
353 if (imageFunction.method == ImageFunction::Method::SIZE)
354 {
355 OutputImageSizeFunctionBody(out, imageFunction, imageReference);
356 }
357 else if (imageFunction.method == ImageFunction::Method::LOAD)
358 {
359 OutputImageLoadFunctionBody(out, imageFunction, imageReference);
360 }
361 else
362 {
363 OutputImageStoreFunctionBody(out, imageFunction, imageReference);
364 }
365
366 out << "}\n"
367 "\n";
368 }
369 }
370
371 } // namespace sh
372