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