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 #include "tensorflow/lite/experimental/acceleration/compatibility/gpu_compatibility.h"
16
17 #include <cctype>
18 #include <map>
19 #include <memory>
20 #include <string>
21
22 #include "absl/strings/string_view.h"
23 #include "flatbuffers/flatbuffers.h" // from @flatbuffers
24 #include "tensorflow/lite/experimental/acceleration/compatibility/database_generated.h"
25 #include "tensorflow/lite/experimental/acceleration/compatibility/devicedb.h"
26 #include "tensorflow/lite/experimental/acceleration/compatibility/gpu_compatibility_binary.h"
27 #include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
28
29 namespace tflite {
30 namespace acceleration {
31 namespace {
32
CanonicalizeValue(absl::string_view input)33 std::string CanonicalizeValue(absl::string_view input) {
34 // This assumes ASCII, which holds for all values we have in the list.
35 std::string output(input);
36 for (int i = 0; i < output.size(); i++) {
37 char c = output[i];
38 if (c == ' ' || c == '-') {
39 output[i] = '_';
40 } else if (isalpha(c)) {
41 output[i] = tolower(c);
42 }
43 }
44 return output;
45 }
46
CanonicalizeValues(std::map<std::string,std::string> * variable_values)47 void CanonicalizeValues(std::map<std::string, std::string>* variable_values) {
48 for (auto& i : *variable_values) {
49 i.second = CanonicalizeValue(i.second);
50 }
51 }
52
53 } // namespace
54
GPUCompatibilityList(const unsigned char * compatibility_list_flatbuffer)55 GPUCompatibilityList::GPUCompatibilityList(
56 const unsigned char* compatibility_list_flatbuffer) {
57 if (!compatibility_list_flatbuffer) return;
58 database_ =
59 flatbuffers::GetRoot<DeviceDatabase>(compatibility_list_flatbuffer);
60 }
61
Create()62 std::unique_ptr<GPUCompatibilityList> GPUCompatibilityList::Create() {
63 return Create(g_tflite_acceleration_gpu_compatibility_binary,
64 g_tflite_acceleration_gpu_compatibility_binary_len);
65 }
66
Create(const unsigned char * compatibility_list_flatbuffer,int length)67 std::unique_ptr<GPUCompatibilityList> GPUCompatibilityList::Create(
68 const unsigned char* compatibility_list_flatbuffer, int length) {
69 if (!compatibility_list_flatbuffer ||
70 !IsValidFlatbuffer(compatibility_list_flatbuffer, length)) {
71 return nullptr;
72 }
73 return std::unique_ptr<GPUCompatibilityList>(
74 new GPUCompatibilityList(compatibility_list_flatbuffer));
75 }
76
CalculateVariables(const AndroidInfo & android_info,const::tflite::gpu::GpuInfo & gpu_info) const77 std::map<std::string, std::string> GPUCompatibilityList::CalculateVariables(
78 const AndroidInfo& android_info,
79 const ::tflite::gpu::GpuInfo& gpu_info) const {
80 std::map<std::string, std::string> variables;
81
82 variables[kAndroidSdkVersion] = android_info.android_sdk_version;
83 variables[kDeviceModel] = android_info.model;
84 variables[kDeviceName] = android_info.device;
85 variables[kManufacturer] = android_info.manufacturer;
86 const auto& gl_info = gpu_info.opengl_info;
87 variables[kGPUModel] = gl_info.renderer_name;
88 char buffer[128];
89 int len = snprintf(buffer, 128 - 1, "%d.%d", gl_info.major_version,
90 gl_info.minor_version);
91 buffer[len] = '\0';
92 variables[kOpenGLESVersion] = std::string(buffer);
93 CanonicalizeValues(&variables);
94 if (!database_) return variables;
95 UpdateVariablesFromDatabase(&variables, *database_);
96 return variables;
97 }
98
Includes(const AndroidInfo & android_info,const::tflite::gpu::GpuInfo & gpu_info) const99 bool GPUCompatibilityList::Includes(
100 const AndroidInfo& android_info,
101 const ::tflite::gpu::GpuInfo& gpu_info) const {
102 auto variables = CalculateVariables(android_info, gpu_info);
103 return variables[gpu::kStatus] == std::string(gpu::kStatusSupported);
104 }
105
GetBestOptionsFor(const AndroidInfo &,const::tflite::gpu::GpuInfo &) const106 TfLiteGpuDelegateOptionsV2 GPUCompatibilityList::GetBestOptionsFor(
107 const AndroidInfo& /* android_info */,
108 const ::tflite::gpu::GpuInfo& /* gpu_info */) const {
109 // This method is for forwards-compatibility: the list may later include
110 // information about which backend to choose (OpenGL/OpenCL/Vulkan) or other
111 // options.
112 return TfLiteGpuDelegateOptionsV2Default();
113 }
114
115 // static
IsValidFlatbuffer(const unsigned char * data,int len)116 bool GPUCompatibilityList::IsValidFlatbuffer(const unsigned char* data,
117 int len) {
118 // Verify opensource db.
119 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(data), len);
120 return tflite::acceleration::VerifyDeviceDatabaseBuffer(verifier);
121 }
122
123 } // namespace acceleration
124 } // namespace tflite
125