1 // Copyright 2021 The libgav1 Authors
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 "src/residual_buffer_pool.h"
16
17 #include <cstdint>
18 #include <memory>
19 #include <utility>
20
21 #include "gtest/gtest.h"
22 #include "src/utils/constants.h"
23 #include "src/utils/queue.h"
24 #include "src/utils/types.h"
25
26 namespace libgav1 {
27 namespace {
28
TEST(ResidualBufferTest,TestUsage)29 TEST(ResidualBufferTest, TestUsage) {
30 ResidualBufferPool pool(true, 1, 1, sizeof(int16_t));
31 EXPECT_EQ(pool.Size(), 0);
32 // Get one buffer.
33 std::unique_ptr<ResidualBuffer> buffer1 = pool.Get();
34 uint8_t* const buffer1_ptr = buffer1->buffer();
35 ASSERT_NE(buffer1_ptr, nullptr);
36 // Get another buffer (while holding on to the first one).
37 std::unique_ptr<ResidualBuffer> buffer2 = pool.Get();
38 uint8_t* const buffer2_ptr = buffer2->buffer();
39 ASSERT_NE(buffer2_ptr, nullptr);
40 EXPECT_NE(buffer1_ptr, buffer2_ptr);
41 // Return the second buffer.
42 pool.Release(std::move(buffer2));
43 EXPECT_EQ(pool.Size(), 1);
44 // Get another buffer (this one should be the same as the buffer2).
45 std::unique_ptr<ResidualBuffer> buffer3 = pool.Get();
46 uint8_t* const buffer3_ptr = buffer3->buffer();
47 ASSERT_NE(buffer3_ptr, nullptr);
48 EXPECT_EQ(buffer3_ptr, buffer2_ptr);
49 EXPECT_EQ(pool.Size(), 0);
50 // Get another buffer (this one will be a new buffer).
51 std::unique_ptr<ResidualBuffer> buffer4 = pool.Get();
52 uint8_t* const buffer4_ptr = buffer4->buffer();
53 ASSERT_NE(buffer4_ptr, nullptr);
54 EXPECT_NE(buffer4_ptr, buffer1_ptr);
55 EXPECT_NE(buffer4_ptr, buffer3_ptr);
56 EXPECT_EQ(pool.Size(), 0);
57 // Return all the buffers.
58 pool.Release(std::move(buffer1));
59 EXPECT_EQ(pool.Size(), 1);
60 pool.Release(std::move(buffer3));
61 EXPECT_EQ(pool.Size(), 2);
62 pool.Release(std::move(buffer4));
63 EXPECT_EQ(pool.Size(), 3);
64 // Reset the buffer with same parameters.
65 pool.Reset(true, 1, 1, sizeof(int16_t));
66 EXPECT_EQ(pool.Size(), 3);
67 // Reset the buffer size with different parameters.
68 pool.Reset(true, 0, 1, sizeof(int32_t));
69 // The existing buffers should now have been invalidated.
70 EXPECT_EQ(pool.Size(), 0);
71 // Get and return a buffer.
72 std::unique_ptr<ResidualBuffer> buffer5 = pool.Get();
73 uint8_t* const buffer5_ptr = buffer5->buffer();
74 ASSERT_NE(buffer5_ptr, nullptr);
75 pool.Release(std::move(buffer5));
76 EXPECT_EQ(pool.Size(), 1);
77 // Reset the buffer with different value for use128x128_superblock.
78 pool.Reset(false, 0, 1, sizeof(int32_t));
79 // The existing buffers should now have been invalidated.
80 EXPECT_EQ(pool.Size(), 0);
81 }
82
TEST(ResidualBufferTest,TestQueue)83 TEST(ResidualBufferTest, TestQueue) {
84 ResidualBufferPool pool(true, 1, 1, sizeof(int16_t));
85 EXPECT_EQ(pool.Size(), 0);
86 // Get one buffer.
87 std::unique_ptr<ResidualBuffer> buffer1 = pool.Get();
88 uint8_t* const buffer1_ptr = buffer1->buffer();
89 ASSERT_NE(buffer1_ptr, nullptr);
90 auto* queue1 = buffer1->transform_parameters();
91 queue1->Push(TransformParameters(kTransformTypeAdstAdst, 10));
92 EXPECT_EQ(queue1->Size(), 1);
93 EXPECT_EQ(queue1->Front().type, kTransformTypeAdstAdst);
94 EXPECT_EQ(queue1->Front().non_zero_coeff_count, 10);
95 queue1->Push(TransformParameters(kTransformTypeDctDct, 20));
96 EXPECT_EQ(queue1->Size(), 2);
97 EXPECT_EQ(queue1->Front().type, kTransformTypeAdstAdst);
98 EXPECT_EQ(queue1->Front().non_zero_coeff_count, 10);
99 queue1->Pop();
100 EXPECT_EQ(queue1->Size(), 1);
101 EXPECT_EQ(queue1->Front().type, kTransformTypeDctDct);
102 EXPECT_EQ(queue1->Front().non_zero_coeff_count, 20);
103 // Return the buffer.
104 pool.Release(std::move(buffer1));
105 EXPECT_EQ(pool.Size(), 1);
106 // Get another buffer (should be the same as buffer1).
107 std::unique_ptr<ResidualBuffer> buffer2 = pool.Get();
108 uint8_t* const buffer2_ptr = buffer2->buffer();
109 ASSERT_NE(buffer2_ptr, nullptr);
110 EXPECT_EQ(buffer1_ptr, buffer2_ptr);
111 // Releasing the buffer should've cleared the queue.
112 EXPECT_EQ(buffer2->transform_parameters()->Size(), 0);
113 }
114
TEST(ResidualBufferTest,TestStackPushPop)115 TEST(ResidualBufferTest, TestStackPushPop) {
116 ResidualBufferStack buffers;
117 EXPECT_EQ(buffers.Size(), 0);
118 EXPECT_EQ(buffers.Pop(), nullptr);
119
120 std::unique_ptr<ResidualBuffer> buffer0 = ResidualBuffer::Create(128, 128);
121 ResidualBuffer* const buffer0_ptr = buffer0.get();
122 EXPECT_NE(buffer0_ptr, nullptr);
123 std::unique_ptr<ResidualBuffer> buffer1 = ResidualBuffer::Create(128, 128);
124 ResidualBuffer* const buffer1_ptr = buffer1.get();
125 EXPECT_NE(buffer1_ptr, nullptr);
126 std::unique_ptr<ResidualBuffer> buffer2 = ResidualBuffer::Create(128, 128);
127 ResidualBuffer* const buffer2_ptr = buffer2.get();
128 EXPECT_NE(buffer2_ptr, nullptr);
129
130 // Push two buffers onto the stack.
131 buffers.Push(std::move(buffer0));
132 EXPECT_EQ(buffers.Size(), 1);
133 buffers.Push(std::move(buffer1));
134 EXPECT_EQ(buffers.Size(), 2);
135
136 // Pop one buffer off the stack.
137 std::unique_ptr<ResidualBuffer> top = buffers.Pop();
138 EXPECT_EQ(buffers.Size(), 1);
139 EXPECT_EQ(top.get(), buffer1_ptr);
140
141 // Push one buffer onto the stack.
142 buffers.Push(std::move(buffer2));
143 EXPECT_EQ(buffers.Size(), 2);
144
145 // Pop two buffers off the stack
146 top = buffers.Pop();
147 EXPECT_EQ(buffers.Size(), 1);
148 EXPECT_EQ(top.get(), buffer2_ptr);
149 top = buffers.Pop();
150 EXPECT_EQ(buffers.Size(), 0);
151 EXPECT_EQ(top.get(), buffer0_ptr);
152
153 // Try to pop a buffer off an empty stack.
154 top = buffers.Pop();
155 EXPECT_EQ(buffers.Size(), 0);
156 EXPECT_EQ(top, nullptr);
157 }
158
TEST(ResidualBufferTest,TestStackSwap)159 TEST(ResidualBufferTest, TestStackSwap) {
160 ResidualBufferStack buffers;
161 EXPECT_EQ(buffers.Size(), 0);
162 EXPECT_EQ(buffers.Pop(), nullptr);
163
164 std::unique_ptr<ResidualBuffer> buffer0 = ResidualBuffer::Create(128, 128);
165 ResidualBuffer* const buffer0_ptr = buffer0.get();
166 EXPECT_NE(buffer0_ptr, nullptr);
167 std::unique_ptr<ResidualBuffer> buffer1 = ResidualBuffer::Create(128, 128);
168 ResidualBuffer* const buffer1_ptr = buffer1.get();
169 EXPECT_NE(buffer1_ptr, nullptr);
170 std::unique_ptr<ResidualBuffer> buffer2 = ResidualBuffer::Create(128, 128);
171 ResidualBuffer* const buffer2_ptr = buffer2.get();
172 EXPECT_NE(buffer2_ptr, nullptr);
173
174 // Push three buffers onto the stack.
175 buffers.Push(std::move(buffer0));
176 EXPECT_EQ(buffers.Size(), 1);
177 buffers.Push(std::move(buffer1));
178 EXPECT_EQ(buffers.Size(), 2);
179 buffers.Push(std::move(buffer2));
180 EXPECT_EQ(buffers.Size(), 3);
181
182 // Swap the contents of the stacks.
183 ResidualBufferStack swapped;
184 swapped.Swap(&buffers);
185 EXPECT_EQ(buffers.Size(), 0);
186 EXPECT_EQ(swapped.Size(), 3);
187
188 // Pop three buffers off the swapped stack.
189 std::unique_ptr<ResidualBuffer> top = swapped.Pop();
190 EXPECT_EQ(swapped.Size(), 2);
191 EXPECT_EQ(top.get(), buffer2_ptr);
192 top = swapped.Pop();
193 EXPECT_EQ(swapped.Size(), 1);
194 EXPECT_EQ(top.get(), buffer1_ptr);
195 top = swapped.Pop();
196 EXPECT_EQ(swapped.Size(), 0);
197 EXPECT_EQ(top.get(), buffer0_ptr);
198 }
199
200 } // namespace
201 } // namespace libgav1
202