Flutter Impeller
device_buffer_gles.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 
6 
7 #include <cstring>
8 #include <memory>
9 
11 #include "impeller/base/config.h"
12 
13 namespace impeller {
14 
16  std::shared_ptr<ReactorGLES> reactor,
17  std::unique_ptr<Allocation> backing_store)
18  : DeviceBuffer(desc),
19  reactor_(std::move(reactor)),
20  backing_store_(std::move(backing_store)) {}
21 
22 // |DeviceBuffer|
24  if (handle_.has_value() && !handle_->IsDead()) {
25  reactor_->CollectHandle(*handle_);
26  }
27 }
28 
29 // |DeviceBuffer|
30 uint8_t* DeviceBufferGLES::OnGetContents() const {
31  if (!reactor_) {
32  return nullptr;
33  }
34  return backing_store_->GetBuffer();
35 }
36 
37 // |DeviceBuffer|
38 bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source,
39  Range source_range,
40  size_t offset) {
41  if (!reactor_) {
42  return false;
43  }
44 
45  if (offset + source_range.length >
46  backing_store_->GetLength().GetByteSize()) {
47  return false;
48  }
49 
50  std::memmove(backing_store_->GetBuffer() + offset,
51  source + source_range.offset, source_range.length);
52  Flush(Range{offset, source_range.length});
53 
54  return true;
55 }
56 
57 std::optional<GLuint> DeviceBufferGLES::GetHandle() const {
58  if (handle_.has_value()) {
59  return reactor_->GetGLHandle(*handle_);
60  } else {
61  return std::nullopt;
62  }
63 }
64 
65 void DeviceBufferGLES::Flush(std::optional<Range> range) const {
66  Lock lock(dirty_range_mutex_);
67  if (!range.has_value()) {
68  dirty_range_ = Range{
69  0, static_cast<size_t>(backing_store_->GetLength().GetByteSize())};
70  } else {
71  if (dirty_range_.has_value()) {
72  dirty_range_ = dirty_range_->Merge(range.value());
73  } else {
74  dirty_range_ = range.value();
75  }
76  }
77 }
78 
80  switch (type) {
82  return GL_ARRAY_BUFFER;
84  return GL_ELEMENT_ARRAY_BUFFER;
86  return GL_UNIFORM_BUFFER;
87  }
88  FML_UNREACHABLE();
89 }
90 
92  if (!reactor_) {
93  return false;
94  }
95 
96  if (!handle_.has_value()) {
97  handle_ = reactor_->CreateUntrackedHandle(HandleType::kBuffer);
98 #ifdef IMPELLER_DEBUG
99  if (handle_.has_value() && label_.has_value()) {
100  reactor_->SetDebugLabel(*handle_, *label_);
101  }
102 #endif
103  }
104 
105  auto buffer = reactor_->GetGLHandle(*handle_);
106  if (!buffer.has_value()) {
107  return false;
108  }
109 
110  const auto target_type = ToTarget(type);
111  const auto& gl = reactor_->GetProcTable();
112 
113  gl.BindBuffer(target_type, buffer.value());
114  if (!initialized_) {
115  gl.BufferData(target_type, backing_store_->GetLength().GetByteSize(),
116  nullptr, GL_DYNAMIC_DRAW);
117  initialized_ = true;
118  }
119 
120  // Take and clear the dirty range BEFORE uploading. A Flush() from another
121  // thread during the upload then merges into a fresh dirty range that the
122  // next bind uploads, instead of being silently discarded by a clear that
123  // runs after the upload.
124  std::optional<Range> dirty;
125  {
126  Lock lock(dirty_range_mutex_);
127  std::swap(dirty_range_, dirty);
128  }
129  if (dirty.has_value()) {
130  gl.BufferSubData(target_type, dirty->offset, dirty->length,
131  backing_store_->GetBuffer() + dirty->offset);
132  }
133 
134  return true;
135 }
136 
137 // |DeviceBuffer|
138 bool DeviceBufferGLES::SetLabel(std::string_view label) {
139 #ifdef IMPELLER_DEBUG
140  label_ = label;
141  if (handle_.has_value()) {
142  reactor_->SetDebugLabel(*handle_, label);
143  }
144 #endif // IMPELLER_DEBUG
145  return true;
146 }
147 
148 // |DeviceBuffer|
149 bool DeviceBufferGLES::SetLabel(std::string_view label, Range range) {
150  // Cannot support debug label on the range. Set the label for the entire
151  // range.
152  return SetLabel(label);
153 }
154 
155 const uint8_t* DeviceBufferGLES::GetBufferData() const {
156  return backing_store_->GetBuffer();
157 }
158 
160  const std::function<void(uint8_t* data, size_t length)>&
161  update_buffer_data) {
162  if (update_buffer_data) {
163  update_buffer_data(backing_store_->GetBuffer(),
164  backing_store_->GetLength().GetByteSize());
165  Flush(Range{
166  0, static_cast<size_t>(backing_store_->GetLength().GetByteSize())});
167  }
168 }
169 
170 } // namespace impeller
void Flush(std::optional< Range > range=std::nullopt) const override
DeviceBufferGLES(DeviceBufferDescriptor desc, std::shared_ptr< ReactorGLES > reactor, std::unique_ptr< Allocation > backing_store)
void UpdateBufferData(const std::function< void(uint8_t *, size_t length)> &update_buffer_data)
bool BindAndUploadDataIfNecessary(BindingType type) const
const uint8_t * GetBufferData() const
std::optional< GLuint > GetHandle() const
static GLenum ToTarget(DeviceBufferGLES::BindingType type)
Definition: comparable.h:93
std::shared_ptr< ReactorGLES > reactor
constexpr Range Merge(const Range &other)
Create a new range that is a union of this range and other.
Definition: range.h:27