1 /* Copyright 2019 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/gl/compiler/object_accessor.h"
17
18 #include <string>
19 #include <vector>
20
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include "absl/types/variant.h"
24 #include "tensorflow/lite/delegates/gpu/common/types.h"
25 #include "tensorflow/lite/delegates/gpu/gl/compiler/variable_accessor.h"
26 #include "tensorflow/lite/delegates/gpu/gl/variable.h"
27
28 namespace tflite {
29 namespace gpu {
30 namespace gl {
31
32 struct ParameterComparator {
33 template <typename T>
operator ()tflite::gpu::gl::ParameterComparator34 bool operator()(const T& t) const {
35 const T* v = absl::get_if<T>(&p.value);
36 return v && t == *v;
37 }
38 const Variable& p;
39 };
40
41 // partially equal
operator ==(const Variable & l,const Variable & r)42 bool operator==(const Variable& l, const Variable& r) {
43 return l.name == r.name && absl::visit(ParameterComparator{l}, r.value);
44 }
45
46 namespace {
47
TEST(Preprocessor,CornerCases)48 TEST(Preprocessor, CornerCases) {
49 VariableAccessor variable_accessor(/*inline_values=*/false);
50 ObjectAccessor accessor(false, &variable_accessor);
51 std::string result;
52 ASSERT_EQ(accessor.Rewrite("", &result), RewriteStatus::NOT_RECOGNIZED);
53 ASSERT_EQ(accessor.Rewrite("=", &result), RewriteStatus::NOT_RECOGNIZED);
54 }
55
TEST(Preprocessor,ReadFromBuffer)56 TEST(Preprocessor, ReadFromBuffer) {
57 VariableAccessor variable_accessor(/*inline_values=*/false);
58 ObjectAccessor accessor(false, &variable_accessor);
59 ASSERT_TRUE(
60 accessor.AddObject("obj", MakeReadonlyBuffer(std::vector<float>{1.0})));
61 std::string result;
62 EXPECT_EQ(accessor.Rewrite("obj[i]", &result), RewriteStatus::SUCCESS);
63 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
64 ASSERT_EQ(result, "obj.data[i]");
65 }
66
TEST(Preprocessor,ReadFromBufferLinear)67 TEST(Preprocessor, ReadFromBufferLinear) {
68 VariableAccessor variable_accessor(/*inline_values=*/false);
69 ObjectAccessor accessor(false, &variable_accessor);
70 ASSERT_TRUE(accessor.AddObject(
71 "obj", MakeReadonlyBuffer(uint3(1, 2, 3), std::vector<float>{1.0})));
72 std::string result;
73 EXPECT_EQ(accessor.Rewrite("obj[i]", &result), RewriteStatus::SUCCESS);
74 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
75 ASSERT_EQ(result, "obj.data[i]");
76 }
77
TEST(Preprocessor,ReadFromBufferByIndex)78 TEST(Preprocessor, ReadFromBufferByIndex) {
79 VariableAccessor variable_accessor(/*inline_values=*/false);
80 ObjectAccessor accessor(false, &variable_accessor);
81 ASSERT_TRUE(accessor.AddObject(
82 "obj", MakeReadonlyBuffer(uint3(1, 2, 3), std::vector<float>{1.0})));
83 std::string result;
84 EXPECT_EQ(accessor.Rewrite("obj[x,y + 5,z]", &result),
85 RewriteStatus::SUCCESS);
86 EXPECT_THAT(variable_accessor.GetUniformParameters(),
87 testing::UnorderedElementsAre(Variable{"obj_w", 1},
88 Variable{"obj_h", 2}));
89 ASSERT_EQ(result, "obj.data[x + $obj_w$ * (y + 5 + $obj_h$ * (z))]");
90 }
91
TEST(Preprocessor,ReadFromTexture)92 TEST(Preprocessor, ReadFromTexture) {
93 VariableAccessor variable_accessor(/*inline_values=*/false);
94 ObjectAccessor accessor(false, &variable_accessor);
95 ASSERT_TRUE(accessor.AddObject(
96 "obj", MakeReadonlyTexture(uint3(1, 2, 3), {1.0, 2.0, 3.0, 4.0})));
97 std::string result;
98 EXPECT_EQ(accessor.Rewrite("obj[i,j,k]", &result), RewriteStatus::SUCCESS);
99 // textures don't need extra variables to be stored for indexed access
100 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
101 ASSERT_EQ(result, "imageLoad(obj, ivec3(i, j, k))");
102 }
103
TEST(Preprocessor,ReadFromTexture1D)104 TEST(Preprocessor, ReadFromTexture1D) {
105 VariableAccessor variable_accessor(/*inline_values=*/false);
106 ObjectAccessor accessor(false, &variable_accessor);
107 ASSERT_TRUE(
108 accessor.AddObject("obj", MakeReadonlyTexture({1.0, 2.0, 3.0, 4.0})));
109 std::string result;
110 EXPECT_EQ(accessor.Rewrite("obj[i]", &result), RewriteStatus::SUCCESS);
111 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
112 ASSERT_EQ(result, "imageLoad(obj, ivec2(i, 0))");
113 }
114
TEST(Preprocessor,WriteToBuffer)115 TEST(Preprocessor, WriteToBuffer) {
116 VariableAccessor variable_accessor(/*inline_values=*/false);
117 ObjectAccessor accessor(false, &variable_accessor);
118 ASSERT_TRUE(
119 accessor.AddObject("obj", MakeReadonlyBuffer(std::vector<float>{1.0})));
120 std::string result;
121 EXPECT_EQ(accessor.Rewrite(" obj[i] =value", &result),
122 RewriteStatus::SUCCESS);
123 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
124 ASSERT_EQ(result, "obj.data[i] = value");
125 }
126
TEST(Preprocessor,WriteToBufferByIndex)127 TEST(Preprocessor, WriteToBufferByIndex) {
128 VariableAccessor variable_accessor(/*inline_values=*/false);
129 ObjectAccessor accessor(false, &variable_accessor);
130 ASSERT_TRUE(accessor.AddObject(
131 "obj", MakeReadonlyBuffer(uint3(1, 2, 3), {1.0, 2.0, 3.0, 4.0})));
132 std::string result;
133 EXPECT_EQ(accessor.Rewrite(" obj[i,j,k] =value", &result),
134 RewriteStatus::SUCCESS);
135 EXPECT_THAT(variable_accessor.GetUniformParameters(),
136 testing::UnorderedElementsAre(Variable{"obj_w", 1},
137 Variable{"obj_h", 2}));
138 ASSERT_EQ(result, "obj.data[i + $obj_w$ * (j + $obj_h$ * (k))] = value");
139 }
140
TEST(Preprocessor,WriteToTexture)141 TEST(Preprocessor, WriteToTexture) {
142 VariableAccessor variable_accessor(/*inline_values=*/false);
143 ObjectAccessor accessor(false, &variable_accessor);
144 ASSERT_TRUE(accessor.AddObject(
145 "obj", MakeReadonlyTexture(uint3(1, 1, 1), {1.0, 2.0, 3.0, 4.0})));
146 std::string result;
147 EXPECT_EQ(accessor.Rewrite("obj[i,j,k]= value ", &result),
148 RewriteStatus::SUCCESS);
149 ASSERT_EQ(result, "imageStore(obj, ivec3(i, j, k), value)");
150 }
151
TEST(Preprocessor,WriteToTexture1D)152 TEST(Preprocessor, WriteToTexture1D) {
153 VariableAccessor variable_accessor(/*inline_values=*/false);
154 ObjectAccessor accessor(false, &variable_accessor);
155 ASSERT_TRUE(
156 accessor.AddObject("obj", MakeReadonlyTexture({1.0, 2.0, 3.0, 4.0})));
157 std::string result;
158 EXPECT_EQ(accessor.Rewrite("obj[i]= value ", &result),
159 RewriteStatus::SUCCESS);
160 EXPECT_TRUE(variable_accessor.GetUniformParameters().empty());
161 ASSERT_EQ(result, "imageStore(obj, ivec2(i, 0), value)");
162 }
163
TEST(Preprocessor,FailedWriteToBuffer)164 TEST(Preprocessor, FailedWriteToBuffer) {
165 VariableAccessor variable_accessor(/*inline_values=*/false);
166 ObjectAccessor accessor(false, &variable_accessor);
167 ASSERT_TRUE(
168 accessor.AddObject("obj", MakeReadonlyBuffer(std::vector<float>{1.0})));
169 std::string result;
170 EXPECT_EQ(accessor.Rewrite(" obj[i,j] =value", &result),
171 RewriteStatus::ERROR);
172 ASSERT_EQ(result, "WRONG_NUMBER_OF_INDICES");
173 }
174
TEST(Preprocessor,FailedWriteToTexture)175 TEST(Preprocessor, FailedWriteToTexture) {
176 VariableAccessor variable_accessor(/*inline_values=*/false);
177 ObjectAccessor accessor(false, &variable_accessor);
178 ASSERT_TRUE(accessor.AddObject(
179 "obj", MakeReadonlyTexture(uint3(1, 1, 1), {1.0, 2.0, 3.0, 4.0})));
180 std::string result;
181 EXPECT_EQ(accessor.Rewrite("obj[i]= value ", &result), RewriteStatus::ERROR);
182 ASSERT_EQ(result, "WRONG_NUMBER_OF_INDICES");
183 }
184
TEST(Preprocessor,DeclareTexture)185 TEST(Preprocessor, DeclareTexture) {
186 VariableAccessor variable_accessor(/*inline_values=*/false);
187 ObjectAccessor accessor(false, &variable_accessor);
188 ASSERT_TRUE(accessor.AddObject(
189 "obj", MakeReadonlyTexture(uint3(1, 1, 1), {1.0, 2.0, 3.0, 4.0})));
190 ASSERT_EQ(accessor.GetObjectDeclarations(),
191 "layout(rgba32f, binding = 0) readonly uniform highp image2DArray "
192 "obj;\n");
193 }
194
TEST(Preprocessor,DeclareBuffer)195 TEST(Preprocessor, DeclareBuffer) {
196 VariableAccessor variable_accessor(/*inline_values=*/false);
197 ObjectAccessor accessor(true, &variable_accessor);
198 ASSERT_TRUE(
199 accessor.AddObject("obj", MakeReadonlyBuffer(std::vector<float>{1.0})));
200 ASSERT_EQ(accessor.GetObjectDeclarations(),
201 "layout(binding = 0) buffer B0 { vec4 data[]; } obj;\n");
202 }
203
204 } // namespace
205 } // namespace gl
206 } // namespace gpu
207 } // namespace tflite
208