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 "tensorflow/lite/delegates/gpu/common/data_type.h"
19 #include "tensorflow/lite/delegates/gpu/common/shape.h"
20 #include "tensorflow/lite/delegates/gpu/common/task/tensor_desc.h"
21 #include "tensorflow/lite/delegates/gpu/common/util.h"
22
23 namespace tflite {
24 namespace gpu {
25
CanCreateTensorWithShape(const GpuInfo & gpu_info,const BHWDC & shape,const TensorDescriptor & descriptor)26 bool CanCreateTensorWithShape(const GpuInfo& gpu_info, const BHWDC& shape,
27 const TensorDescriptor& descriptor) {
28 const int slices = DivideRoundUp(shape.c, 4);
29 switch (descriptor.storage_type) {
30 case TensorStorageType::BUFFER: {
31 const int flt4_size =
32 4 * (descriptor.data_type == DataType::FLOAT32 ? 4 : 2);
33 const int buffer_size =
34 shape.b * shape.w * shape.h * shape.d * slices * flt4_size;
35 return buffer_size <= gpu_info.GetMaxBufferSize();
36 }
37 case TensorStorageType::IMAGE_BUFFER:
38 return shape.b * shape.w * shape.h * shape.d * slices <=
39 gpu_info.GetMaxImageBufferWidth();
40 case TensorStorageType::TEXTURE_3D:
41 if (gpu_info.opencl_info.cl_version < OpenClVersion::kCl1_2 &&
42 slices == 1) {
43 // clCreateImage3D (that used in CL 1.0/1.1) can not create image with
44 // depth = 1 by specification;
45 return false;
46 }
47 return shape.w * shape.b <= gpu_info.GetMaxImage3DWidth() &&
48 shape.h <= gpu_info.GetMaxImage3DHeight() &&
49 slices * shape.d <= gpu_info.GetMaxImage3DDepth();
50 case TensorStorageType::TEXTURE_ARRAY:
51 // Bug on some Adreno. b/131099086
52 if (slices == 1 && gpu_info.IsAdreno() &&
53 !gpu_info.adreno_info.support_one_layer_texture_array) {
54 return false;
55 }
56 return shape.w * shape.b <= gpu_info.GetMaxImage2DWidth() &&
57 shape.h <= gpu_info.GetMaxImage2DHeight() &&
58 slices * shape.d <= gpu_info.GetMaxImage2DArrayLayers();
59 case TensorStorageType::TEXTURE_2D:
60 return shape.w * shape.b * shape.d <= gpu_info.GetMaxImage2DWidth() &&
61 shape.h * slices <= gpu_info.GetMaxImage2DHeight();
62 case TensorStorageType::SINGLE_TEXTURE_2D:
63 return shape.c <= 4 &&
64 gpu_info.SupportsFloatImage2D(descriptor.data_type, shape.c) &&
65 shape.w * shape.b * shape.d <= gpu_info.GetMaxImage2DWidth() &&
66 shape.h <= gpu_info.GetMaxImage2DHeight();
67 default:
68 return false;
69 }
70 }
71
CanCreateTensorWithShape(const GpuInfo & gpu_info,const BHWC & shape,const TensorDescriptor & descriptor)72 bool CanCreateTensorWithShape(const GpuInfo& gpu_info, const BHWC& shape,
73 const TensorDescriptor& descriptor) {
74 const BHWDC shape5D(shape.b, shape.h, shape.w, 1, shape.c);
75 return CanCreateTensorWithShape(gpu_info, shape5D, descriptor);
76 }
77
SelectBestStorageType(const GpuInfo & gpu_info,const BHWC & shape,const TensorStorageType & desired,const DataType & data_type,const Layout & layout)78 TensorStorageType SelectBestStorageType(const GpuInfo& gpu_info,
79 const BHWC& shape,
80 const TensorStorageType& desired,
81 const DataType& data_type,
82 const Layout& layout) {
83 if (CanCreateTensorWithShape(gpu_info, shape,
84 TensorDescriptor{data_type, desired, layout})) {
85 return desired;
86 }
87 if (gpu_info.IsApiMetal()) {
88 return TensorStorageType::BUFFER;
89 }
90 auto GetBestTypeAfterTextureArray = [&]() {
91 if (gpu_info.SupportsImageBuffer() &&
92 CanCreateTensorWithShape(
93 gpu_info, shape,
94 TensorDescriptor{data_type, TensorStorageType::IMAGE_BUFFER,
95 layout})) {
96 return TensorStorageType::IMAGE_BUFFER;
97 } else {
98 return TensorStorageType::BUFFER;
99 }
100 };
101 auto GetBestTypeAfterTexture2D = [&]() {
102 if (gpu_info.SupportsTextureArray() &&
103 CanCreateTensorWithShape(
104 gpu_info, shape,
105 TensorDescriptor{data_type, TensorStorageType::TEXTURE_ARRAY,
106 layout})) {
107 return TensorStorageType::TEXTURE_ARRAY;
108 } else {
109 return GetBestTypeAfterTextureArray();
110 }
111 };
112 auto GetBestTypeAfterTexture3D = [&]() {
113 if (CanCreateTensorWithShape(
114 gpu_info, shape,
115 TensorDescriptor{data_type, TensorStorageType::TEXTURE_2D,
116 layout})) {
117 return TensorStorageType::TEXTURE_2D;
118 } else {
119 return GetBestTypeAfterTexture2D();
120 }
121 };
122 switch (desired) {
123 case TensorStorageType::TEXTURE_2D:
124 case TensorStorageType::SINGLE_TEXTURE_2D:
125 return GetBestTypeAfterTexture2D();
126 case TensorStorageType::TEXTURE_ARRAY:
127 return GetBestTypeAfterTextureArray();
128 case TensorStorageType::TEXTURE_3D:
129 return GetBestTypeAfterTexture3D();
130 case TensorStorageType::IMAGE_BUFFER:
131 case TensorStorageType::BUFFER:
132 return TensorStorageType::BUFFER;
133 default:
134 return TensorStorageType::BUFFER;
135 }
136 }
137
DeduceLinearStorageType(TensorStorageType tensor_storage_type)138 LinearStorageType DeduceLinearStorageType(
139 TensorStorageType tensor_storage_type) {
140 if (tensor_storage_type == TensorStorageType::BUFFER) {
141 return LinearStorageType::BUFFER;
142 } else {
143 return LinearStorageType::TEXTURE_2D;
144 }
145 }
146
147 } // namespace gpu
148 } // namespace tflite
149