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