1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/lite/delegates/gpu/common/task/storage_type_util.h"
17
18 #include "absl/strings/str_cat.h"
19 #include "tensorflow/lite/delegates/gpu/common/data_type.h"
20 #include "tensorflow/lite/delegates/gpu/common/shape.h"
21 #include "tensorflow/lite/delegates/gpu/common/task/tensor_desc.h"
22 #include "tensorflow/lite/delegates/gpu/common/util.h"
23
24 namespace tflite {
25 namespace gpu {
26
CanCreateTensorWithShape(const GpuInfo & gpu_info,const BHWDC & shape,const TensorDescriptor & descriptor)27 absl::Status CanCreateTensorWithShape(const GpuInfo& gpu_info,
28 const BHWDC& shape,
29 const TensorDescriptor& descriptor) {
30 const int slices = DivideRoundUp(shape.c, 4);
31 const uint64_t flt_size = descriptor.data_type == DataType::FLOAT32 ? 4 : 2;
32 const uint64_t channels =
33 descriptor.storage_type == TensorStorageType::SINGLE_TEXTURE_2D
34 ? shape.c
35 : slices * 4;
36 const uint64_t allocation_size =
37 flt_size * channels * shape.b * shape.w * shape.h * shape.d;
38 const std::string common_desc = "Shape - " + ToString(shape) +
39 ", data type - " +
40 ToString(descriptor.data_type) + ".";
41 if (allocation_size > gpu_info.GetMaxMemoryAllocationSize()) {
42 return absl::ResourceExhaustedError(absl::StrCat(
43 "Requested allocation size - ", allocation_size,
44 " bytes. Max allocation size for this GPU - ",
45 gpu_info.GetMaxMemoryAllocationSize(), " bytes. ", common_desc));
46 }
47 switch (descriptor.storage_type) {
48 case TensorStorageType::BUFFER: {
49 const uint64_t flt4_size =
50 4 * (descriptor.data_type == DataType::FLOAT32 ? 4 : 2);
51 const uint64_t buffer_size =
52 flt4_size * shape.b * shape.w * shape.h * shape.d * slices;
53 if (buffer_size > gpu_info.GetMaxBufferSize()) {
54 return absl::ResourceExhaustedError(absl::StrCat(
55 "Buffer with size - ", buffer_size,
56 " bytes can not be created. Max buffer size for this GPU - ",
57 gpu_info.GetMaxBufferSize(), " bytes. ", common_desc));
58 } else {
59 return absl::OkStatus();
60 }
61 }
62 case TensorStorageType::IMAGE_BUFFER: {
63 const uint64_t flt4_size =
64 4 * (descriptor.data_type == DataType::FLOAT32 ? 4 : 2);
65 const uint64_t buffer_size =
66 flt4_size * shape.b * shape.w * shape.h * shape.d * slices;
67 const uint64_t image_width = buffer_size / flt4_size;
68 if (image_width > gpu_info.GetMaxImageBufferWidth()) {
69 return absl::ResourceExhaustedError(absl::StrCat(
70 "Image buffer with width - ", image_width,
71 " can not be created. Max image buffer width for this GPU - ",
72 gpu_info.GetMaxImageBufferWidth(), ". ", common_desc));
73 } else if (buffer_size > gpu_info.GetMaxBufferSize()) {
74 return absl::ResourceExhaustedError(absl::StrCat(
75 "Buffer with size - ", buffer_size,
76 " bytes can not be created. Max buffer size for this GPU - ",
77 gpu_info.GetMaxBufferSize(), " bytes. ", common_desc));
78 } else {
79 return absl::OkStatus();
80 }
81 }
82 case TensorStorageType::TEXTURE_3D: {
83 if (gpu_info.opencl_info.cl_version < OpenClVersion::kCl1_2 &&
84 slices == 1) {
85 return absl::InternalError(
86 "clCreateImage3D (that used in CL 1.0/1.1) can not create image "
87 "with depth = 1 by specification.");
88 }
89 const int image_width = shape.w * shape.b;
90 const int image_height = shape.h;
91 const int image_depth = slices * shape.d;
92 if (image_width > gpu_info.GetMaxImage3DWidth()) {
93 return absl::ResourceExhaustedError(absl::StrCat(
94 "Image3D with width - ", image_width,
95 " can not be created. Max Image3D width for this GPU - ",
96 gpu_info.GetMaxImage3DWidth(), ". ", common_desc));
97 } else if (image_height > gpu_info.GetMaxImage3DHeight()) {
98 return absl::ResourceExhaustedError(absl::StrCat(
99 "Image3D with height - ", image_height,
100 " can not be created. Max Image3D height for this GPU - ",
101 gpu_info.GetMaxImage3DHeight(), ". ", common_desc));
102 } else if (image_depth > gpu_info.GetMaxImage3DDepth()) {
103 return absl::ResourceExhaustedError(absl::StrCat(
104 "Image3D with depth - ", image_depth,
105 " can not be created. Max Image3D depth for this GPU - ",
106 gpu_info.GetMaxImage3DDepth(), ". ", common_desc));
107 } else {
108 return absl::OkStatus();
109 }
110 }
111 case TensorStorageType::TEXTURE_ARRAY: {
112 // Bug on some Adreno. b/131099086
113 if (slices == 1 && gpu_info.IsAdreno() &&
114 !gpu_info.adreno_info.support_one_layer_texture_array) {
115 return absl::InternalError(
116 "Image2DArray with layer = 1 works incorrect on some Adreno. Can "
117 "not be created.");
118 }
119 const int image_width = shape.w * shape.b;
120 const int image_height = shape.h;
121 const int image_layers = slices * shape.d;
122 if (image_width > gpu_info.GetMaxImage2DWidth()) {
123 return absl::ResourceExhaustedError(absl::StrCat(
124 "Image2DArray with width - ", image_width,
125 " can not be created. Max Image2DArray width for this GPU - ",
126 gpu_info.GetMaxImage2DWidth(), ". ", common_desc));
127 } else if (image_height > gpu_info.GetMaxImage2DHeight()) {
128 return absl::ResourceExhaustedError(absl::StrCat(
129 "Image2DArray with height - ", image_height,
130 " can not be created. Max Image2DArray height for this GPU - ",
131 gpu_info.GetMaxImage2DHeight(), ". ", common_desc));
132 } else if (image_layers > gpu_info.GetMaxImage2DArrayLayers()) {
133 return absl::ResourceExhaustedError(absl::StrCat(
134 "Image2DArray with layers - ", image_layers,
135 " can not be created. Max Image2DArray layers for this GPU - ",
136 gpu_info.GetMaxImage2DArrayLayers(), ". ", common_desc));
137 } else {
138 return absl::OkStatus();
139 }
140 }
141 case TensorStorageType::TEXTURE_2D: {
142 const int image_width = shape.w * shape.b * shape.d;
143 const int image_height = shape.h * slices;
144 if (image_width > gpu_info.GetMaxImage2DWidth()) {
145 return absl::ResourceExhaustedError(absl::StrCat(
146 "Image2D with width - ", image_width,
147 " can not be created. Max Image2D width for this GPU - ",
148 gpu_info.GetMaxImage2DWidth(), ". ", common_desc));
149 } else if (image_height > gpu_info.GetMaxImage2DHeight()) {
150 return absl::ResourceExhaustedError(absl::StrCat(
151 "Image2D with height - ", image_height,
152 " can not be created. Max Image2D height for this GPU - ",
153 gpu_info.GetMaxImage2DHeight(), ". ", common_desc));
154 } else {
155 return absl::OkStatus();
156 }
157 }
158 case TensorStorageType::SINGLE_TEXTURE_2D: {
159 const int image_width = shape.w * shape.b * shape.d;
160 const int image_height = shape.h;
161 if (shape.c > 4) {
162 return absl::ResourceExhaustedError(absl::StrCat(
163 "Image2D with channels - ", shape.c, " can not be created."));
164 } else if (!gpu_info.SupportsFloatImage2D(descriptor.data_type,
165 shape.c)) {
166 return absl::ResourceExhaustedError(
167 "Image2D doesn't support this pixel layout.");
168 } else if (image_width > gpu_info.GetMaxImage2DWidth()) {
169 return absl::ResourceExhaustedError(absl::StrCat(
170 "Image2D with width - ", image_width,
171 " can not be created. Max Image2D width for this GPU - ",
172 gpu_info.GetMaxImage2DWidth(), ". ", common_desc));
173 } else if (image_height > gpu_info.GetMaxImage2DHeight()) {
174 return absl::ResourceExhaustedError(absl::StrCat(
175 "Image2D with height - ", image_height,
176 " can not be created. Max Image2D height for this GPU - ",
177 gpu_info.GetMaxImage2DHeight(), ". ", common_desc));
178 } else {
179 return absl::OkStatus();
180 }
181 }
182 default:
183 return absl::UnimplementedError(
184 "Can not create resources for unknown storage type.");
185 }
186 }
187
CanCreateTensorWithShape(const GpuInfo & gpu_info,const BHWC & shape,const TensorDescriptor & descriptor)188 absl::Status CanCreateTensorWithShape(const GpuInfo& gpu_info,
189 const BHWC& shape,
190 const TensorDescriptor& descriptor) {
191 const BHWDC shape5D(shape.b, shape.h, shape.w, 1, shape.c);
192 return CanCreateTensorWithShape(gpu_info, shape5D, descriptor);
193 }
194
SelectBestStorageType(const GpuInfo & gpu_info,const BHWC & shape,TensorStorageType desired,DataType data_type,Layout layout,TensorStorageType * result)195 absl::Status SelectBestStorageType(const GpuInfo& gpu_info, const BHWC& shape,
196 TensorStorageType desired,
197 DataType data_type, Layout layout,
198 TensorStorageType* result) {
199 if (CanCreateTensorWithShape(gpu_info, shape,
200 TensorDescriptor{data_type, desired, layout})
201 .ok()) {
202 *result = desired;
203 return absl::OkStatus();
204 }
205 if (gpu_info.IsApiMetal()) {
206 *result = TensorStorageType::BUFFER;
207 return CanCreateTensorWithShape(
208 gpu_info, shape,
209 TensorDescriptor{data_type, TensorStorageType::BUFFER, layout});
210 }
211 auto GetBestTypeAfterTexture2D = [&]() {
212 if (gpu_info.SupportsImageBuffer() &&
213 CanCreateTensorWithShape(
214 gpu_info, shape,
215 TensorDescriptor{data_type, TensorStorageType::IMAGE_BUFFER,
216 layout})
217 .ok()) {
218 *result = TensorStorageType::IMAGE_BUFFER;
219 return absl::OkStatus();
220 } else {
221 *result = TensorStorageType::BUFFER;
222 return CanCreateTensorWithShape(
223 gpu_info, shape,
224 TensorDescriptor{data_type, TensorStorageType::BUFFER, layout});
225 }
226 };
227 auto GetBestTypeAfterTextureArray = [&]() {
228 if (gpu_info.SupportsImageBuffer() &&
229 CanCreateTensorWithShape(
230 gpu_info, shape,
231 TensorDescriptor{data_type, TensorStorageType::IMAGE_BUFFER,
232 layout})
233 .ok()) {
234 *result = TensorStorageType::IMAGE_BUFFER;
235 return absl::OkStatus();
236 } else {
237 *result = TensorStorageType::BUFFER;
238 return CanCreateTensorWithShape(
239 gpu_info, shape,
240 TensorDescriptor{data_type, TensorStorageType::BUFFER, layout});
241 }
242 };
243 auto GetBestTypeAfterTexture3D = [&]() {
244 if (CanCreateTensorWithShape(
245 gpu_info, shape,
246 TensorDescriptor{data_type, TensorStorageType::TEXTURE_2D, layout})
247 .ok()) {
248 *result = TensorStorageType::TEXTURE_2D;
249 return absl::OkStatus();
250 } else {
251 return GetBestTypeAfterTextureArray();
252 }
253 };
254 switch (desired) {
255 case TensorStorageType::TEXTURE_2D:
256 case TensorStorageType::SINGLE_TEXTURE_2D:
257 return GetBestTypeAfterTexture2D();
258 case TensorStorageType::TEXTURE_ARRAY:
259 return GetBestTypeAfterTextureArray();
260 case TensorStorageType::TEXTURE_3D:
261 return GetBestTypeAfterTexture3D();
262 case TensorStorageType::IMAGE_BUFFER: {
263 if (CanCreateTensorWithShape(
264 gpu_info, shape,
265 TensorDescriptor{data_type, TensorStorageType::IMAGE_BUFFER,
266 layout})
267 .ok()) {
268 *result = TensorStorageType::IMAGE_BUFFER;
269 return absl::OkStatus();
270 } else {
271 *result = TensorStorageType::BUFFER;
272 return CanCreateTensorWithShape(
273 gpu_info, shape,
274 TensorDescriptor{data_type, TensorStorageType::BUFFER, layout});
275 }
276 }
277 case TensorStorageType::BUFFER: {
278 *result = TensorStorageType::BUFFER;
279 return CanCreateTensorWithShape(
280 gpu_info, shape,
281 TensorDescriptor{data_type, TensorStorageType::BUFFER, layout});
282 }
283 default:
284 return absl::UnimplementedError(absl::StrCat(
285 "No support of this storage type - ", ToString(desired)));
286 }
287 }
288
DeduceLinearStorageType(TensorStorageType tensor_storage_type)289 LinearStorageType DeduceLinearStorageType(
290 TensorStorageType tensor_storage_type) {
291 if (tensor_storage_type == TensorStorageType::BUFFER) {
292 return LinearStorageType::BUFFER;
293 } else {
294 return LinearStorageType::TEXTURE_2D;
295 }
296 }
297
298 } // namespace gpu
299 } // namespace tflite
300