| Flutter Impeller |

host_buffer_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <limits>
6 #include <utility>
7
8 #include "flutter/testing/testing.h"
9 #include "gmock/gmock.h"
10 #include "impeller/base/validation.h"
11 #include "impeller/core/allocator.h"
12 #include "impeller/core/host_buffer.h"
13 #include "impeller/core/idle_waiter.h"
14 #include "impeller/entity/entity_playground.h"
15
16 namespace impeller {
17 namespace testing {
18
19 class MockIdleWaiter : public IdleWaiter {
20 public:
21 MOCK_METHOD(void, WaitIdle, (), (const, override));
22 };
23
24 using HostBufferTest = EntityPlayground;
25 INSTANTIATE_PLAYGROUND_SUITE(HostBufferTest);
26
27 TEST_P(HostBufferTest, IdleWaiter) {
28 auto mock_idle_waiter = std::make_shared<MockIdleWaiter>();
29 {
30 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
31 mock_idle_waiter, 256);
32 EXPECT_CALL(*mock_idle_waiter, WaitIdle());
33 }
34 }
35
36 TEST_P(HostBufferTest, CanEmplace) {
37 struct Length2 {
38 uint8_t pad[2];
39 };
40 static_assert(sizeof(Length2) == 2u);
41
42 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
43 GetContext()->GetIdleWaiter(), 256);
44
45 for (size_t i = 0; i < 12500; i++) {
46 auto view = buffer->Emplace(Length2{});
47 ASSERT_TRUE(view);
48 ASSERT_EQ(view.GetRange(), Range(i * sizeof(Length2), 2u));
49 }
50 }
51
52 TEST_P(HostBufferTest, CanEmplaceWithAlignment) {
53 struct Length2 {
54 uint8_t pad[2];
55 };
56 static_assert(sizeof(Length2) == 2);
57 struct alignas(16) Align16 {
58 uint8_t pad[2];
59 };
60 static_assert(alignof(Align16) == 16);
61 static_assert(sizeof(Align16) == 16);
62
63 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
64 GetContext()->GetIdleWaiter(), 256);
65 ASSERT_TRUE(buffer);
66
67 {
68 auto view = buffer->Emplace(Length2{});
69 ASSERT_TRUE(view);
70 ASSERT_EQ(view.GetRange(), Range(0u, 2u));
71 }
72
73 {
74 auto view = buffer->Emplace(Align16{});
75 ASSERT_TRUE(view);
76 ASSERT_EQ(view.GetRange().offset, 16u);
77 ASSERT_EQ(view.GetRange().length, 16u);
78 }
79 {
80 auto view = buffer->Emplace(Length2{});
81 ASSERT_TRUE(view);
82 ASSERT_EQ(view.GetRange(), Range(32u, 2u));
83 }
84
85 {
86 auto view = buffer->Emplace(Align16{});
87 ASSERT_TRUE(view);
88 ASSERT_EQ(view.GetRange().offset, 48u);
89 ASSERT_EQ(view.GetRange().length, 16u);
90 }
91 }
92
93 TEST_P(HostBufferTest, HostBufferInitialState) {
94 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
95 GetContext()->GetIdleWaiter(), 256);
96
97 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 0u);
98 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
99 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 1u);
100 }
101
102 TEST_P(HostBufferTest, ResetIncrementsFrameCounter) {
103 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
104 GetContext()->GetIdleWaiter(), 256);
105
106 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
107
108 buffer->Reset();
109 EXPECT_EQ(buffer->GetStateForTest().current_frame, 1u);
110
111 buffer->Reset();
112 EXPECT_EQ(buffer->GetStateForTest().current_frame, 2u);
113
114 buffer->Reset();
115 EXPECT_EQ(buffer->GetStateForTest().current_frame, 3u);
116
117 buffer->Reset();
118 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
119 }
120
121 TEST_P(HostBufferTest,
122 EmplacingLargerThanBlockSizeCreatesOneOffBufferCallback) {
123 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
124 GetContext()->GetIdleWaiter(), 256);
125
126 // Emplace an amount larger than the block size, to verify that the host
127 // buffer does not create a buffer.
128 auto buffer_view = buffer->Emplace(1024000 + 10, 0, [](uint8_t* data) {});
129
130 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 0u);
131 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
132 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 1u);
133 }
134
135 TEST_P(HostBufferTest, EmplacingLargerThanBlockSizeCreatesOneOffBuffer) {
136 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
137 GetContext()->GetIdleWaiter(), 256);
138
139 // Emplace an amount larger than the block size, to verify that the host
140 // buffer does not create a buffer.
141 auto buffer_view = buffer->Emplace(nullptr, 1024000 + 10, 0);
142
143 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 0u);
144 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
145 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 1u);
146 }
147
148 TEST_P(HostBufferTest, UnusedBuffersAreDiscardedWhenResetting) {
149 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
150 GetContext()->GetIdleWaiter(), 256);
151
152 // Emplace two large allocations to force the allocation of a second buffer.
153 auto buffer_view_a = buffer->Emplace(1020000, 0, [](uint8_t* data) {});
154 auto buffer_view_b = buffer->Emplace(1020000, 0, [](uint8_t* data) {});
155
156 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 1u);
157 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 2u);
158 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
159
160 // Reset until we get back to this frame.
161 for (auto i = 0; i < 4; i++) {
162 buffer->Reset();
163 }
164
165 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 0u);
166 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 2u);
167 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
168
169 // Now when we reset, the buffer should get dropped.
170 // Reset until we get back to this frame.
171 for (auto i = 0; i < 4; i++) {
172 buffer->Reset();
173 }
174
175 EXPECT_EQ(buffer->GetStateForTest().current_buffer, 0u);
176 EXPECT_EQ(buffer->GetStateForTest().total_buffer_count, 1u);
177 EXPECT_EQ(buffer->GetStateForTest().current_frame, 0u);
178 }
179
180 TEST_P(HostBufferTest, EmplaceWithProcIsAligned) {
181 auto buffer = HostBuffer::Create(GetContext()->GetResourceAllocator(),
182 GetContext()->GetIdleWaiter(), 256);
183
184 BufferView view = buffer->Emplace(std::array<char, 21>());
185 EXPECT_EQ(view.GetRange(), Range(0, 21));
186
187 view = buffer->Emplace(64, 16, [](uint8_t*) {});
188 EXPECT_EQ(view.GetRange(), Range(32, 64));
189 }
190
191 static constexpr const size_t kMagicFailingAllocation = 1024000 * 2;
192
193 class FailingAllocator : public Allocator {
194 public:
195 explicit FailingAllocator(std::shared_ptr<Allocator> delegate)
196 : Allocator(), delegate_(std::move(delegate)) {}
197
198 ~FailingAllocator() = default;
199
200 std::shared_ptr<DeviceBuffer> OnCreateBuffer(
201 const DeviceBufferDescriptor& desc) {
202 // Magic number used in test below to trigger failure.
203 if (desc.size == kMagicFailingAllocation) {
204 return nullptr;
205 }
206 return delegate_->CreateBuffer(desc);
207 }
208
209 std::shared_ptr<Texture> OnCreateTexture(const TextureDescriptor& desc,
210 bool threadsafe) {
211 return delegate_->CreateTexture(desc);
212 }
213
214 ISize GetMaxTextureSizeSupported() const override {
215 return delegate_->GetMaxTextureSizeSupported();
216 }
217
218 private:
219 std::shared_ptr<Allocator> delegate_;
220 };
221
222 TEST_P(HostBufferTest, EmplaceWithFailingAllocationDoesntCrash) {
223 ScopedValidationDisable disable;
224 std::shared_ptr<FailingAllocator> allocator =
225 std::make_shared<FailingAllocator>(GetContext()->GetResourceAllocator());
226 auto buffer =
227 HostBuffer::Create(allocator, GetContext()->GetIdleWaiter(), 256);
228
229 auto view = buffer->Emplace(nullptr, kMagicFailingAllocation, 0);
230
231 EXPECT_EQ(view.GetBuffer(), nullptr);
232 EXPECT_EQ(view.GetRange().offset, 0u);
233 EXPECT_EQ(view.GetRange().length, 0u);
234 }
235
236 } // namespace testing
237 } // namespace impeller
allocator.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:154
impeller::Allocator
An object that allocates device memory.
Definition: allocator.h:24
impeller::EntityPlayground
Definition: entity_playground.h:16
impeller::HostBuffer::Create
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment)
Definition: host_buffer.cc:21
impeller::IdleWaiter
Definition: idle_waiter.h:14
impeller::IdleWaiter::WaitIdle
virtual void WaitIdle() const =0
impeller::testing::FailingAllocator
Definition: host_buffer_unittests.cc:193
impeller::testing::FailingAllocator::~FailingAllocator
~FailingAllocator()=default
impeller::testing::FailingAllocator::OnCreateBuffer
std::shared_ptr< DeviceBuffer > OnCreateBuffer(const DeviceBufferDescriptor &desc)
Definition: host_buffer_unittests.cc:200
impeller::testing::FailingAllocator::GetMaxTextureSizeSupported
ISize GetMaxTextureSizeSupported() const override
Definition: host_buffer_unittests.cc:214
impeller::testing::FailingAllocator::OnCreateTexture
std::shared_ptr< Texture > OnCreateTexture(const TextureDescriptor &desc, bool threadsafe)
Definition: host_buffer_unittests.cc:209
impeller::testing::FailingAllocator::FailingAllocator
FailingAllocator(std::shared_ptr< Allocator > delegate)
Definition: host_buffer_unittests.cc:195
impeller::testing::MockIdleWaiter
Definition: host_buffer_unittests.cc:19
impeller::testing::MockIdleWaiter::MOCK_METHOD
MOCK_METHOD(void, WaitIdle,(),(const, override))
entity_playground.h
host_buffer.h
idle_waiter.h
impeller::testing::kMagicFailingAllocation
static constexpr const size_t kMagicFailingAllocation
Definition: host_buffer_unittests.cc:191
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:59
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
impeller
Definition: allocation.cc:12
std
Definition: comparable.h:95
impeller::BufferView
Definition: buffer_view.h:19
impeller::BufferView::GetRange
Range GetRange() const
Definition: buffer_view.h:27
impeller::DeviceBufferDescriptor
Definition: device_buffer_descriptor.h:14
impeller::DeviceBufferDescriptor::size
size_t size
Definition: device_buffer_descriptor.h:16
impeller::Range
Definition: range.h:13
impeller::ScopedValidationDisable
Definition: validation.h:56
impeller::TSize
Definition: size.h:25
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:69
validation.h