1 //
2 // Copyright (c) 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/UtilsHLSL.h"
11 
12 namespace sh
13 {
14 
15 // static
OutputImageFunctionArgumentList(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction)16 void ImageFunctionHLSL::OutputImageFunctionArgumentList(
17     TInfoSinkBase &out,
18     const ImageFunctionHLSL::ImageFunction &imageFunction)
19 {
20     if (imageFunction.readonly)
21     {
22         out << TextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex";
23     }
24     else
25     {
26         out << RWTextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex";
27     }
28 
29     if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD ||
30         imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
31     {
32         switch (imageFunction.image)
33         {
34             case EbtImage2D:
35             case EbtIImage2D:
36             case EbtUImage2D:
37                 out << ", int2 p";
38                 break;
39             case EbtImage3D:
40             case EbtIImage3D:
41             case EbtUImage3D:
42             case EbtImageCube:
43             case EbtIImageCube:
44             case EbtUImageCube:
45             case EbtImage2DArray:
46             case EbtIImage2DArray:
47             case EbtUImage2DArray:
48                 out << ", int3 p";
49                 break;
50             default:
51                 UNREACHABLE();
52         }
53 
54         if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
55         {
56             switch (imageFunction.image)
57             {
58                 case EbtImage2D:
59                 case EbtImage3D:
60                 case EbtImageCube:
61                 case EbtImage2DArray:
62                     out << ", float4 data";
63                     break;
64                 case EbtIImage2D:
65                 case EbtIImage3D:
66                 case EbtIImageCube:
67                 case EbtIImage2DArray:
68                     out << ", int4 data";
69                     break;
70                 case EbtUImage2D:
71                 case EbtUImage3D:
72                 case EbtUImageCube:
73                 case EbtUImage2DArray:
74                     out << ", uint4 data";
75                     break;
76                 default:
77                     UNREACHABLE();
78             }
79         }
80     }
81 }
82 
83 // static
OutputImageSizeFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const TString & imageReference)84 void ImageFunctionHLSL::OutputImageSizeFunctionBody(
85     TInfoSinkBase &out,
86     const ImageFunctionHLSL::ImageFunction &imageFunction,
87     const TString &imageReference)
88 {
89     if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
90         IsImageCube(imageFunction.image))
91     {
92         // "depth" stores either the number of layers in an array texture or 3D depth
93         out << "    uint width; uint height; uint depth;\n"
94             << "    " << imageReference << ".GetDimensions(width, height, depth);\n";
95     }
96     else if (IsImage2D(imageFunction.image))
97     {
98         out << "    uint width; uint height;\n"
99             << "    " << imageReference << ".GetDimensions(width, height);\n";
100     }
101     else
102         UNREACHABLE();
103 
104     if (strcmp(imageFunction.getReturnType(), "int3") == 0)
105     {
106         out << "    return int3(width, height, depth);\n";
107     }
108     else
109     {
110         out << "    return int2(width, height);\n";
111     }
112 }
113 
114 // static
OutputImageLoadFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const TString & imageReference)115 void ImageFunctionHLSL::OutputImageLoadFunctionBody(
116     TInfoSinkBase &out,
117     const ImageFunctionHLSL::ImageFunction &imageFunction,
118     const TString &imageReference)
119 {
120     if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
121         IsImageCube(imageFunction.image))
122     {
123         out << "    return " << imageReference << "[uint3(p.x, p.y, p.z)];\n";
124     }
125     else if (IsImage2D(imageFunction.image))
126     {
127         out << "    return " << imageReference << "[uint2(p.x, p.y)];\n";
128     }
129     else
130         UNREACHABLE();
131 }
132 
133 // static
OutputImageStoreFunctionBody(TInfoSinkBase & out,const ImageFunctionHLSL::ImageFunction & imageFunction,const TString & imageReference)134 void ImageFunctionHLSL::OutputImageStoreFunctionBody(
135     TInfoSinkBase &out,
136     const ImageFunctionHLSL::ImageFunction &imageFunction,
137     const TString &imageReference)
138 {
139     if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
140         IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image))
141     {
142         out << "    " << imageReference << "[p] = data;\n";
143     }
144     else
145         UNREACHABLE();
146 }
147 
name() const148 TString ImageFunctionHLSL::ImageFunction::name() const
149 {
150     TString name = "gl_image";
151     if (readonly)
152     {
153         name += TextureTypeSuffix(image, imageInternalFormat);
154     }
155     else
156     {
157         name += RWTextureTypeSuffix(image, imageInternalFormat);
158     }
159 
160     switch (method)
161     {
162         case Method::SIZE:
163             name += "Size";
164             break;
165         case Method::LOAD:
166             name += "Load";
167             break;
168         case Method::STORE:
169             name += "Store";
170             break;
171         default:
172             UNREACHABLE();
173     }
174 
175     return name;
176 }
177 
getReturnType() const178 const char *ImageFunctionHLSL::ImageFunction::getReturnType() const
179 {
180     if (method == ImageFunction::Method::SIZE)
181     {
182         switch (image)
183         {
184             case EbtImage2D:
185             case EbtIImage2D:
186             case EbtUImage2D:
187             case EbtImageCube:
188             case EbtIImageCube:
189             case EbtUImageCube:
190                 return "int2";
191             case EbtImage3D:
192             case EbtIImage3D:
193             case EbtUImage3D:
194             case EbtImage2DArray:
195             case EbtIImage2DArray:
196             case EbtUImage2DArray:
197                 return "int3";
198             default:
199                 UNREACHABLE();
200         }
201     }
202     else if (method == ImageFunction::Method::LOAD)
203     {
204         switch (image)
205         {
206             case EbtImage2D:
207             case EbtImage3D:
208             case EbtImageCube:
209             case EbtImage2DArray:
210                 return "float4";
211             case EbtIImage2D:
212             case EbtIImage3D:
213             case EbtIImageCube:
214             case EbtIImage2DArray:
215                 return "int4";
216             case EbtUImage2D:
217             case EbtUImage3D:
218             case EbtUImageCube:
219             case EbtUImage2DArray:
220                 return "uint4";
221             default:
222                 UNREACHABLE();
223         }
224     }
225     else if (method == ImageFunction::Method::STORE)
226     {
227         return "void";
228     }
229     else
230     {
231         UNREACHABLE();
232     }
233     return "";
234 }
235 
operator <(const ImageFunction & rhs) const236 bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const
237 {
238     return std::tie(image, imageInternalFormat, readonly, method) <
239            std::tie(rhs.image, rhs.imageInternalFormat, rhs.readonly, rhs.method);
240 }
241 
useImageFunction(const TString & name,const TBasicType & type,TLayoutImageInternalFormat imageInternalFormat,bool readonly)242 TString ImageFunctionHLSL::useImageFunction(const TString &name,
243                                             const TBasicType &type,
244                                             TLayoutImageInternalFormat imageInternalFormat,
245                                             bool readonly)
246 {
247     ASSERT(IsImage(type));
248     ImageFunction imageFunction;
249     imageFunction.image               = type;
250     imageFunction.imageInternalFormat = imageInternalFormat;
251     imageFunction.readonly            = readonly;
252 
253     if (name == "imageSize")
254     {
255         imageFunction.method = ImageFunction::Method::SIZE;
256     }
257     else if (name == "imageLoad")
258     {
259         imageFunction.method = ImageFunction::Method::LOAD;
260     }
261     else if (name == "imageStore")
262     {
263         imageFunction.method = ImageFunction::Method::STORE;
264     }
265     else
266         UNREACHABLE();
267 
268     mUsesImage.insert(imageFunction);
269     return imageFunction.name();
270 }
271 
imageFunctionHeader(TInfoSinkBase & out)272 void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out)
273 {
274     for (const ImageFunction &imageFunction : mUsesImage)
275     {
276         // Function header
277         out << imageFunction.getReturnType() << " " << imageFunction.name() << "(";
278 
279         OutputImageFunctionArgumentList(out, imageFunction);
280 
281         out << ")\n"
282                "{\n";
283 
284         TString imageReference("tex");
285 
286         if (imageFunction.method == ImageFunction::Method::SIZE)
287         {
288             OutputImageSizeFunctionBody(out, imageFunction, imageReference);
289         }
290         else if (imageFunction.method == ImageFunction::Method::LOAD)
291         {
292             OutputImageLoadFunctionBody(out, imageFunction, imageReference);
293         }
294         else
295         {
296             OutputImageStoreFunctionBody(out, imageFunction, imageReference);
297         }
298 
299         out << "}\n"
300                "\n";
301     }
302 }
303 
304 }  // namespace sh
305