• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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