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 ImmutableString & name,const TBasicType & type,TLayoutImageInternalFormat imageInternalFormat,bool readonly)242 TString ImageFunctionHLSL::useImageFunction(const ImmutableString &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