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