Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
command_buffer.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 "dart_api.h"
8#include "fml/make_copyable.h"
14
15namespace flutter {
16namespace gpu {
17
19
21 std::shared_ptr<impeller::Context> context,
22 std::shared_ptr<impeller::CommandBuffer> command_buffer)
23 : context_(std::move(context)),
24 command_buffer_(std::move(command_buffer)) {}
25
27
28bool CommandBuffer::Encodable::EncodeCommands() const {
29 if (render_pass) {
30 return render_pass->EncodeCommands();
31 }
32 if (blit_pass) {
33 return blit_pass->EncodeCommands();
34 }
35 return false;
36}
37
38std::shared_ptr<impeller::CommandBuffer> CommandBuffer::GetCommandBuffer() {
39 return command_buffer_;
40}
41
43 std::shared_ptr<impeller::RenderPass> render_pass) {
44 Encodable encodable;
45 encodable.render_pass = std::move(render_pass);
46 encodables_.push_back(std::move(encodable));
47}
48
49std::shared_ptr<impeller::BlitPass> CommandBuffer::GetOrCreateBlitPass() {
50 if (!encodables_.empty() && encodables_.back().blit_pass) {
51 return encodables_.back().blit_pass;
52 }
53 auto blit_pass = command_buffer_->CreateBlitPass();
54 if (!blit_pass) {
55 return nullptr;
56 }
57 Encodable encodable;
58 encodable.blit_pass = blit_pass;
59 encodables_.push_back(std::move(encodable));
60 return blit_pass;
61}
62
64 size_t source_offset,
65 size_t source_length,
66 Texture& destination,
67 impeller::IRect destination_region,
68 uint32_t mip_level,
69 uint32_t slice) {
70 auto blit_pass = GetOrCreateBlitPass();
71 if (!blit_pass) {
72 return false;
73 }
74 impeller::BufferView source_view(
75 source.GetBuffer(), impeller::Range(source_offset, source_length));
76 return blit_pass->AddCopy(
77 std::move(source_view), destination.GetTexture(), destination_region,
78 /*label=*/"CommandBuffer.copyBufferToTexture", mip_level, slice);
79}
80
82 impeller::IRect source_region,
83 DeviceBuffer& destination,
84 size_t destination_offset) {
85 auto blit_pass = GetOrCreateBlitPass();
86 if (!blit_pass) {
87 return false;
88 }
89 return blit_pass->AddCopy(source.GetTexture(), destination.GetBuffer(),
90 source_region, destination_offset,
91 "CommandBuffer.copyTextureToBuffer");
92}
93
95 Texture& destination,
96 impeller::IRect source_region,
97 impeller::IPoint destination_origin) {
98 auto blit_pass = GetOrCreateBlitPass();
99 if (!blit_pass) {
100 return false;
101 }
102 return blit_pass->AddCopy(source.GetTexture(), destination.GetTexture(),
103 source_region, destination_origin,
104 "CommandBuffer.copyTextureToTexture");
105}
106
109 if (submitted_) {
110 return false;
111 }
112 if (completion_callback) {
113 completion_callbacks_.push_back(std::move(completion_callback));
114 }
115 return true;
116}
117
119 return CommandBuffer::Submit({});
120}
121
123 const impeller::CommandBuffer::CompletionCallback& completion_callback) {
124 if (submitted_) {
125 return false;
126 }
127 submitted_ = true;
128
129 std::vector<impeller::CommandBuffer::CompletionCallback> callbacks =
130 std::move(completion_callbacks_);
131 if (completion_callback) {
132 callbacks.push_back(completion_callback);
133 }
134 impeller::CommandBuffer::CompletionCallback combined_completion_callback;
135 if (!callbacks.empty()) {
136 combined_completion_callback =
137 [callbacks = std::move(callbacks)](
138 impeller::CommandBuffer::Status status) mutable {
139 for (auto& callback : callbacks) {
140 callback(status);
141 }
142 };
143 }
144
145 // For the GLES backend, command queue submission just flushes the reactor,
146 // which needs to happen on the raster thread.
147 if (context_->GetBackendType() == impeller::Context::BackendType::kOpenGLES) {
148 auto dart_state = flutter::UIDartState::Current();
149 auto& task_runners = dart_state->GetTaskRunners();
150
151 task_runners.GetRasterTaskRunner()->PostTask(
152 fml::MakeCopyable([context = context_, command_buffer = command_buffer_,
153 completion_callback = combined_completion_callback,
154 encodables = encodables_]() mutable {
155 for (auto& encodable : encodables) {
156 if (!encodable.EncodeCommands()) {
157 if (completion_callback) {
158 completion_callback(impeller::CommandBuffer::Status::kError);
159 }
160 context->DisposeThreadLocalCachedResources();
161 return;
162 }
163 }
164
165 auto status = context->GetCommandQueue()->Submit({command_buffer},
166 completion_callback);
167 if (!status.ok() && completion_callback) {
168 completion_callback(impeller::CommandBuffer::Status::kError);
169 }
170 context->DisposeThreadLocalCachedResources();
171 }));
172 return true;
173 }
174
175 for (auto& encodable : encodables_) {
176 if (!encodable.EncodeCommands()) {
177 return false;
178 }
179 }
180
181 auto status = context_->GetCommandQueue()->Submit(
182 {command_buffer_}, combined_completion_callback);
183 context_->DisposeThreadLocalCachedResources();
184 if (!status.ok() && combined_completion_callback) {
185 combined_completion_callback(impeller::CommandBuffer::Status::kError);
186 }
187 return status.ok();
188}
189
190} // namespace gpu
191} // namespace flutter
192
193//----------------------------------------------------------------------------
194/// Exports
195///
196
198 Dart_Handle wrapper,
199 flutter::gpu::Context* contextWrapper) {
200 auto res = fml::MakeRefCounted<flutter::gpu::CommandBuffer>(
201 contextWrapper->GetContextShared(),
202 contextWrapper->GetContext().CreateCommandBuffer());
203 res->AssociateWithDartWrapper(wrapper);
204
205 return true;
206}
207
210 Dart_Handle completion_callback) {
211 if (Dart_IsNull(completion_callback)) {
212 bool success = wrapper->Submit();
213 if (!success) {
214 return tonic::ToDart("Failed to submit CommandBuffer");
215 }
216 return Dart_Null();
217 }
218
219 if (!Dart_IsClosure(completion_callback)) {
220 return tonic::ToDart("Completion callback must be a function");
221 }
222
223 auto dart_state = flutter::UIDartState::Current();
224 auto& task_runners = dart_state->GetTaskRunners();
225
226 auto persistent_completion_callback =
227 std::make_unique<tonic::DartPersistentValue>(dart_state,
228 completion_callback);
229
230 auto ui_task_completion_callback = fml::MakeCopyable(
231 [callback = std::move(persistent_completion_callback),
232 task_runners](impeller::CommandBuffer::Status status) mutable {
233 bool success = status != impeller::CommandBuffer::Status::kError;
234
235 auto ui_completion_task = fml::MakeCopyable(
236 [callback = std::move(callback), success]() mutable {
237 auto dart_state = callback->dart_state().lock();
238 if (!dart_state) {
239 // The root isolate could have died in the meantime.
240 return;
241 }
242 tonic::DartState::Scope scope(dart_state);
243
244 tonic::DartInvoke(callback->Get(), {tonic::ToDart(success)});
245
246 // callback is associated with the Dart isolate and must be
247 // deleted on the UI thread.
248 callback.reset();
249 });
250 task_runners.GetUITaskRunner()->PostTask(ui_completion_task);
251 });
252 bool success = wrapper->Submit(ui_task_completion_callback);
253 if (!success) {
254 return tonic::ToDart("Failed to submit CommandBuffer");
255 }
256 return Dart_Null();
257}
258
262 int source_offset_in_bytes,
263 int source_length_in_bytes,
264 flutter::gpu::Texture* destination,
265 int destination_x,
266 int destination_y,
267 int destination_width,
268 int destination_height,
269 int mip_level,
270 int slice) {
271 if (!command_buffer->CopyBufferToTexture(
272 *source, static_cast<size_t>(source_offset_in_bytes),
273 static_cast<size_t>(source_length_in_bytes), *destination,
274 impeller::IRect::MakeXYWH(destination_x, destination_y,
275 destination_width, destination_height),
276 static_cast<uint32_t>(mip_level), static_cast<uint32_t>(slice))) {
277 return tonic::ToDart("Failed to append copyBufferToTexture");
278 }
279 return Dart_Null();
280}
281
284 flutter::gpu::Texture* source,
285 int source_x,
286 int source_y,
287 int source_width,
288 int source_height,
289 flutter::gpu::DeviceBuffer* destination,
290 int destination_offset_in_bytes) {
291 if (!command_buffer->CopyTextureToBuffer(
292 *source,
293 impeller::IRect::MakeXYWH(source_x, source_y, source_width,
294 source_height),
295 *destination, static_cast<size_t>(destination_offset_in_bytes))) {
296 return tonic::ToDart("Failed to append copyTextureToBuffer");
297 }
298 return Dart_Null();
299}
300
303 flutter::gpu::Texture* source,
304 flutter::gpu::Texture* destination,
305 int source_x,
306 int source_y,
307 int source_width,
308 int source_height,
309 int destination_x,
310 int destination_y) {
311 if (!command_buffer->CopyTextureToTexture(
312 *source, *destination,
313 impeller::IRect::MakeXYWH(source_x, source_y, source_width,
314 source_height),
315 impeller::IPoint(destination_x, destination_y))) {
316 return tonic::ToDart("Failed to append copyTextureToTexture");
317 }
318 return Dart_Null();
319}
static UIDartState * Current()
CommandBuffer(std::shared_ptr< impeller::Context > context, std::shared_ptr< impeller::CommandBuffer > command_buffer)
bool CopyBufferToTexture(DeviceBuffer &source, size_t source_offset, size_t source_length, Texture &destination, impeller::IRect destination_region, uint32_t mip_level, uint32_t slice)
std::shared_ptr< impeller::CommandBuffer > GetCommandBuffer()
bool CopyTextureToTexture(Texture &source, Texture &destination, impeller::IRect source_region, impeller::IPoint destination_origin)
void AddRenderPass(std::shared_ptr< impeller::RenderPass > render_pass)
bool AddCompletionCallback(impeller::CommandBuffer::CompletionCallback completion_callback)
bool CopyTextureToBuffer(Texture &source, impeller::IRect source_region, DeviceBuffer &destination, size_t destination_offset)
std::shared_ptr< impeller::Context > & GetContextShared()
Definition context.cc:91
impeller::Context & GetContext()
Definition context.cc:87
std::shared_ptr< impeller::DeviceBuffer > GetBuffer()
std::shared_ptr< impeller::Texture > GetTexture()
Definition texture.cc:38
std::function< void(Status)> CompletionCallback
virtual std::shared_ptr< CommandBuffer > CreateCommandBuffer() const =0
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
FlutterDesktopBinaryReply callback
Dart_Handle InternalFlutterGpu_CommandBuffer_CopyBufferToTexture(flutter::gpu::CommandBuffer *command_buffer, flutter::gpu::DeviceBuffer *source, int source_offset_in_bytes, int source_length_in_bytes, flutter::gpu::Texture *destination, int destination_x, int destination_y, int destination_width, int destination_height, int mip_level, int slice)
Dart_Handle InternalFlutterGpu_CommandBuffer_CopyTextureToTexture(flutter::gpu::CommandBuffer *command_buffer, flutter::gpu::Texture *source, flutter::gpu::Texture *destination, int source_x, int source_y, int source_width, int source_height, int destination_x, int destination_y)
Dart_Handle InternalFlutterGpu_CommandBuffer_Submit(flutter::gpu::CommandBuffer *wrapper, Dart_Handle completion_callback)
bool InternalFlutterGpu_CommandBuffer_Initialize(Dart_Handle wrapper, flutter::gpu::Context *contextWrapper)
Dart_Handle InternalFlutterGpu_CommandBuffer_CopyTextureToBuffer(flutter::gpu::CommandBuffer *command_buffer, flutter::gpu::Texture *source, int source_x, int source_y, int source_width, int source_height, flutter::gpu::DeviceBuffer *destination, int destination_offset_in_bytes)
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition ref_ptr.h:261
Dart_Handle ToDart(const T &object)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< CommandBuffer > command_buffer
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136