Flutter Impeller
host_buffer.h
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 #ifndef FLUTTER_IMPELLER_CORE_HOST_BUFFER_H_
6 #define FLUTTER_IMPELLER_CORE_HOST_BUFFER_H_
7 
8 #include <algorithm>
9 #include <array>
10 #include <functional>
11 #include <memory>
12 #include <string>
13 #include <type_traits>
14 
17 #include "impeller/core/platform.h"
18 
19 namespace impeller {
20 
21 /// Approximately the same size as the max frames in flight.
22 static const constexpr size_t kHostBufferArenaSize = 4u;
23 
24 /// The host buffer class manages one more 1024 Kb blocks of device buffer
25 /// allocations.
26 ///
27 /// These are reset per-frame.
28 class HostBuffer {
29  public:
30  static std::shared_ptr<HostBuffer> Create(
31  const std::shared_ptr<Allocator>& allocator,
32  const std::shared_ptr<const IdleWaiter>& idle_waiter);
33 
34  ~HostBuffer();
35 
36  //----------------------------------------------------------------------------
37  /// @brief Emplace uniform data onto the host buffer. Ensure that backend
38  /// specific uniform alignment requirements are respected.
39  ///
40  /// @param[in] uniform The uniform struct to emplace onto the buffer.
41  ///
42  /// @tparam UniformType The type of the uniform struct.
43  ///
44  /// @return The buffer view.
45  ///
46  template <class UniformType,
47  class = std::enable_if_t<std::is_standard_layout_v<UniformType>>>
48  [[nodiscard]] BufferView EmplaceUniform(const UniformType& uniform) {
49  const auto alignment =
50  std::max(alignof(UniformType), DefaultUniformAlignment());
51  return Emplace(reinterpret_cast<const void*>(&uniform), // buffer
52  sizeof(UniformType), // size
53  alignment // alignment
54  );
55  }
56 
57  //----------------------------------------------------------------------------
58  /// @brief Emplace storage buffer data onto the host buffer. Ensure that
59  /// backend specific uniform alignment requirements are respected.
60  ///
61  /// @param[in] uniform The storage buffer to emplace onto the buffer.
62  ///
63  /// @tparam StorageBufferType The type of the shader storage buffer.
64  ///
65  /// @return The buffer view.
66  ///
67  template <
68  class StorageBufferType,
69  class = std::enable_if_t<std::is_standard_layout_v<StorageBufferType>>>
71  const StorageBufferType& buffer) {
72  const auto alignment =
73  std::max(alignof(StorageBufferType), DefaultUniformAlignment());
74  return Emplace(&buffer, // buffer
75  sizeof(StorageBufferType), // size
76  alignment // alignment
77  );
78  }
79 
80  //----------------------------------------------------------------------------
81  /// @brief Emplace non-uniform data (like contiguous vertices) onto the
82  /// host buffer.
83  ///
84  /// @param[in] buffer The buffer data.
85  /// @param[in] alignment Minimum alignment of the data being emplaced.
86  ///
87  /// @tparam BufferType The type of the buffer data.
88  ///
89  /// @return The buffer view.
90  ///
91  template <class BufferType,
92  class = std::enable_if_t<std::is_standard_layout_v<BufferType>>>
93  [[nodiscard]] BufferView Emplace(const BufferType& buffer,
94  size_t alignment = 0) {
95  return Emplace(reinterpret_cast<const void*>(&buffer), // buffer
96  sizeof(BufferType), // size
97  std::max(alignment, alignof(BufferType)) // alignment
98  );
99  }
100 
101  [[nodiscard]] BufferView Emplace(const void* buffer,
102  size_t length,
103  size_t align);
104 
105  using EmplaceProc = std::function<void(uint8_t* buffer)>;
106 
107  //----------------------------------------------------------------------------
108  /// @brief Emplaces undefined data onto the managed buffer and gives the
109  /// caller a chance to update it using the specified callback. The
110  /// buffer is guaranteed to have enough space for length bytes. It
111  /// is the responsibility of the caller to not exceed the bounds
112  /// of the buffer returned in the EmplaceProc.
113  ///
114  /// @param[in] cb A callback that will be passed a ptr to the
115  /// underlying host buffer.
116  ///
117  /// @return The buffer view.
118  ///
119  BufferView Emplace(size_t length, size_t align, const EmplaceProc& cb);
120 
121  //----------------------------------------------------------------------------
122  /// @brief Resets the contents of the HostBuffer to nothing so it can be
123  /// reused.
124  void Reset();
125 
126  /// Test only internal state.
127  struct TestStateQuery {
131  };
132 
133  /// @brief Retrieve internal buffer state for test expectations.
135 
136  private:
137  [[nodiscard]] std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
138  EmplaceInternal(const void* buffer, size_t length);
139 
140  std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
141  EmplaceInternal(size_t length, size_t align, const EmplaceProc& cb);
142 
143  std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
144  EmplaceInternal(const void* buffer, size_t length, size_t align);
145 
146  size_t GetLength() const { return offset_; }
147 
148  /// Attempt to create a new internal buffer if the existing capacity is not
149  /// sufficient.
150  ///
151  /// A false return value indicates an unrecoverable allocation failure.
152  [[nodiscard]] bool MaybeCreateNewBuffer();
153 
154  const std::shared_ptr<DeviceBuffer>& GetCurrentBuffer() const;
155 
156  [[nodiscard]] BufferView Emplace(const void* buffer, size_t length);
157 
158  explicit HostBuffer(const std::shared_ptr<Allocator>& allocator,
159  const std::shared_ptr<const IdleWaiter>& idle_waiter);
160 
161  HostBuffer(const HostBuffer&) = delete;
162 
163  HostBuffer& operator=(const HostBuffer&) = delete;
164 
165  std::shared_ptr<Allocator> allocator_;
166  std::shared_ptr<const IdleWaiter> idle_waiter_;
167  std::array<std::vector<std::shared_ptr<DeviceBuffer>>, kHostBufferArenaSize>
168  device_buffers_;
169  size_t current_buffer_ = 0u;
170  size_t offset_ = 0u;
171  size_t frame_index_ = 0u;
172 };
173 
174 } // namespace impeller
175 
176 #endif // FLUTTER_IMPELLER_CORE_HOST_BUFFER_H_
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:93
TestStateQuery GetStateForTest()
Retrieve internal buffer state for test expectations.
Definition: host_buffer.cc:88
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:48
BufferView EmplaceStorageBuffer(const StorageBufferType &buffer)
Emplace storage buffer data onto the host buffer. Ensure that backend specific uniform alignment requ...
Definition: host_buffer.h:70
std::function< void(uint8_t *buffer)> EmplaceProc
Definition: host_buffer.h:105
void Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
Definition: host_buffer.cc:224
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter)
Definition: host_buffer.cc:21
static constexpr const size_t kHostBufferArenaSize
Approximately the same size as the max frames in flight.
Definition: host_buffer.h:22
constexpr size_t DefaultUniformAlignment()
Definition: platform.h:14
Test only internal state.
Definition: host_buffer.h:127