xref: /aosp_15_r20/external/angle/src/compiler/translator/hlsl/ImageFunctionHLSL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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