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"
15 
16 namespace impeller {
17 namespace testing {
18 
19 class MockIdleWaiter : public IdleWaiter {
20  public:
21  MOCK_METHOD(void, WaitIdle, (), (const, override));
22 };
23 
26 
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 
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  return delegate_->CreateTexture(desc);
211  }
212 
214  return delegate_->GetMaxTextureSizeSupported();
215  }
216 
217  private:
218  std::shared_ptr<Allocator> delegate_;
219 };
220 
221 TEST_P(HostBufferTest, EmplaceWithFailingAllocationDoesntCrash) {
222  ScopedValidationDisable disable;
223  std::shared_ptr<FailingAllocator> allocator =
224  std::make_shared<FailingAllocator>(GetContext()->GetResourceAllocator());
225  auto buffer =
226  HostBuffer::Create(allocator, GetContext()->GetIdleWaiter(), 256);
227 
228  auto view = buffer->Emplace(nullptr, kMagicFailingAllocation, 0);
229 
230  EXPECT_EQ(view.GetBuffer(), nullptr);
231  EXPECT_EQ(view.GetRange().offset, 0u);
232  EXPECT_EQ(view.GetRange().length, 0u);
233 }
234 
235 } // namespace testing
236 } // namespace impeller
BufferView buffer_view
An object that allocates device memory.
Definition: allocator.h:24
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
virtual void WaitIdle() const =0
std::shared_ptr< DeviceBuffer > OnCreateBuffer(const DeviceBufferDescriptor &desc)
std::shared_ptr< Texture > OnCreateTexture(const TextureDescriptor &desc)
ISize GetMaxTextureSizeSupported() const override
FailingAllocator(std::shared_ptr< Allocator > delegate)
MOCK_METHOD(void, WaitIdle,(),(const, override))
static constexpr const size_t kMagicFailingAllocation
TEST_P(AiksTest, DrawAtlasNoColor)
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
Definition: comparable.h:95
Range GetRange() const
Definition: buffer_view.h:27
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:68