| Flutter Impeller |

command_encoder_vk.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 "impeller/renderer/backend/vulkan/command_encoder_vk.h"
6
7 #include "flutter/fml/closure.h"
8 #include "impeller/renderer/backend/vulkan/context_vk.h"
9 #include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
10 #include "impeller/renderer/backend/vulkan/texture_vk.h"
11
12 namespace impeller {
13
14 class TrackedObjectsVK {
15 public:
16 explicit TrackedObjectsVK(
17 const std::weak_ptr<const DeviceHolder>& device_holder,
18 const std::shared_ptr<CommandPoolVK>& pool)
19 : desc_pool_(device_holder) {
20 if (!pool) {
21 return;
22 }
23 auto buffer = pool->CreateCommandBuffer();
24 if (!buffer) {
25 return;
26 }
27 pool_ = pool;
28 buffer_ = std::move(buffer);
29 is_valid_ = true;
30 }
31
32 ~TrackedObjectsVK() {
33 if (!buffer_) {
34 return;
35 }
36 pool_->CollectCommandBuffer(std::move(buffer_));
37 }
38
39 bool IsValid() const { return is_valid_; }
40
41 void Track(std::shared_ptr<SharedObjectVK> object) {
42 if (!object) {
43 return;
44 }
45 tracked_objects_.insert(std::move(object));
46 }
47
48 void Track(std::shared_ptr<const Buffer> buffer) {
49 if (!buffer) {
50 return;
51 }
52 tracked_buffers_.insert(std::move(buffer));
53 }
54
55 bool IsTracking(const std::shared_ptr<const Buffer>& buffer) const {
56 if (!buffer) {
57 return false;
58 }
59 return tracked_buffers_.find(buffer) != tracked_buffers_.end();
60 }
61
62 void Track(std::shared_ptr<const TextureSourceVK> texture) {
63 if (!texture) {
64 return;
65 }
66 tracked_textures_.insert(std::move(texture));
67 }
68
69 bool IsTracking(const std::shared_ptr<const TextureSourceVK>& texture) const {
70 if (!texture) {
71 return false;
72 }
73 return tracked_textures_.find(texture) != tracked_textures_.end();
74 }
75
76 vk::CommandBuffer GetCommandBuffer() const { return *buffer_; }
77
78 DescriptorPoolVK& GetDescriptorPool() { return desc_pool_; }
79
80 private:
81 DescriptorPoolVK desc_pool_;
82 // `shared_ptr` since command buffers have a link to the command pool.
83 std::shared_ptr<CommandPoolVK> pool_;
84 vk::UniqueCommandBuffer buffer_;
85 std::set<std::shared_ptr<SharedObjectVK>> tracked_objects_;
86 std::set<std::shared_ptr<const Buffer>> tracked_buffers_;
87 std::set<std::shared_ptr<const TextureSourceVK>> tracked_textures_;
88 bool is_valid_ = false;
89
90 FML_DISALLOW_COPY_AND_ASSIGN(TrackedObjectsVK);
91 };
92
93 CommandEncoderFactoryVK::CommandEncoderFactoryVK(
94 const std::weak_ptr<const ContextVK>& context)
95 : context_(context) {}
96
97 void CommandEncoderFactoryVK::SetLabel(const std::string& label) {
98 label_ = label;
99 }
100
101 std::shared_ptr<CommandEncoderVK> CommandEncoderFactoryVK::Create() {
102 auto context = context_.lock();
103 if (!context) {
104 return nullptr;
105 }
106 auto& context_vk = ContextVK::Cast(*context);
107 auto recycler = context_vk.GetCommandPoolRecycler();
108 if (!recycler) {
109 return nullptr;
110 }
111 auto tls_pool = recycler->Get();
112 if (!tls_pool) {
113 return nullptr;
114 }
115
116 auto tracked_objects = std::make_shared<TrackedObjectsVK>(
117 context_vk.GetDeviceHolder(), tls_pool);
118 auto queue = context_vk.GetGraphicsQueue();
119
120 if (!tracked_objects || !tracked_objects->IsValid() || !queue) {
121 return nullptr;
122 }
123
124 vk::CommandBufferBeginInfo begin_info;
125 begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
126 if (tracked_objects->GetCommandBuffer().begin(begin_info) !=
127 vk::Result::eSuccess) {
128 VALIDATION_LOG << "Could not begin command buffer.";
129 return nullptr;
130 }
131
132 if (label_.has_value()) {
133 context_vk.SetDebugName(tracked_objects->GetCommandBuffer(),
134 label_.value());
135 }
136
137 return std::make_shared<CommandEncoderVK>(context_vk.GetDeviceHolder(),
138 tracked_objects, queue,
139 context_vk.GetFenceWaiter());
140 }
141
142 CommandEncoderVK::CommandEncoderVK(
143 std::weak_ptr<const DeviceHolder> device_holder,
144 std::shared_ptr<TrackedObjectsVK> tracked_objects,
145 const std::shared_ptr<QueueVK>& queue,
146 std::shared_ptr<FenceWaiterVK> fence_waiter)
147 : device_holder_(std::move(device_holder)),
148 tracked_objects_(std::move(tracked_objects)),
149 queue_(queue),
150 fence_waiter_(std::move(fence_waiter)) {}
151
152 CommandEncoderVK::~CommandEncoderVK() = default;
153
154 bool CommandEncoderVK::IsValid() const {
155 return is_valid_;
156 }
157
158 bool CommandEncoderVK::Submit(SubmitCallback callback) {
159 // Make sure to call callback with `false` if anything returns early.
160 bool fail_callback = !!callback;
161 if (!IsValid()) {
162 VALIDATION_LOG << "Cannot submit invalid CommandEncoderVK.";
163 if (fail_callback) {
164 callback(false);
165 }
166 return false;
167 }
168
169 // Success or failure, you only get to submit once.
170 fml::ScopedCleanupClosure reset([&]() {
171 if (fail_callback) {
172 callback(false);
173 }
174 Reset();
175 });
176
177 InsertDebugMarker("QueueSubmit");
178
179 auto command_buffer = GetCommandBuffer();
180
181 auto status = command_buffer.end();
182 if (status != vk::Result::eSuccess) {
183 VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(status);
184 return false;
185 }
186 std::shared_ptr<const DeviceHolder> strong_device = device_holder_.lock();
187 if (!strong_device) {
188 VALIDATION_LOG << "Device lost.";
189 return false;
190 }
191 auto [fence_result, fence] = strong_device->GetDevice().createFenceUnique({});
192 if (fence_result != vk::Result::eSuccess) {
193 VALIDATION_LOG << "Failed to create fence: " << vk::to_string(fence_result);
194 return false;
195 }
196
197 vk::SubmitInfo submit_info;
198 std::vector<vk::CommandBuffer> buffers = {command_buffer};
199 submit_info.setCommandBuffers(buffers);
200 status = queue_->Submit(submit_info, *fence);
201 if (status != vk::Result::eSuccess) {
202 VALIDATION_LOG << "Failed to submit queue: " << vk::to_string(status);
203 return false;
204 }
205
206 // Submit will proceed, call callback with true when it is done and do not
207 // call when `reset` is collected.
208 fail_callback = false;
209 return fence_waiter_->AddFence(
210 std::move(fence),
211 [callback, tracked_objects = std::move(tracked_objects_)] {
212 if (callback) {
213 callback(true);
214 }
215 });
216 }
217
218 vk::CommandBuffer CommandEncoderVK::GetCommandBuffer() const {
219 if (tracked_objects_) {
220 return tracked_objects_->GetCommandBuffer();
221 }
222 return {};
223 }
224
225 void CommandEncoderVK::Reset() {
226 tracked_objects_.reset();
227
228 queue_ = nullptr;
229 is_valid_ = false;
230 }
231
232 bool CommandEncoderVK::Track(std::shared_ptr<SharedObjectVK> object) {
233 if (!IsValid()) {
234 return false;
235 }
236 tracked_objects_->Track(std::move(object));
237 return true;
238 }
239
240 bool CommandEncoderVK::Track(std::shared_ptr<const Buffer> buffer) {
241 if (!IsValid()) {
242 return false;
243 }
244 tracked_objects_->Track(std::move(buffer));
245 return true;
246 }
247
248 bool CommandEncoderVK::IsTracking(
249 const std::shared_ptr<const Buffer>& buffer) const {
250 if (!IsValid()) {
251 return false;
252 }
253 return tracked_objects_->IsTracking(buffer);
254 }
255
256 bool CommandEncoderVK::Track(std::shared_ptr<const TextureSourceVK> texture) {
257 if (!IsValid()) {
258 return false;
259 }
260 tracked_objects_->Track(std::move(texture));
261 return true;
262 }
263
264 bool CommandEncoderVK::Track(const std::shared_ptr<const Texture>& texture) {
265 if (!IsValid()) {
266 return false;
267 }
268 if (!texture) {
269 return true;
270 }
271 return Track(TextureVK::Cast(*texture).GetTextureSource());
272 }
273
274 bool CommandEncoderVK::IsTracking(
275 const std::shared_ptr<const Texture>& texture) const {
276 if (!IsValid()) {
277 return false;
278 }
279 std::shared_ptr<const TextureSourceVK> source =
280 TextureVK::Cast(*texture).GetTextureSource();
281 return tracked_objects_->IsTracking(source);
282 }
283
284 std::optional<vk::DescriptorSet> CommandEncoderVK::AllocateDescriptorSet(
285 const vk::DescriptorSetLayout& layout,
286 size_t command_count) {
287 if (!IsValid()) {
288 return std::nullopt;
289 }
290
291 return tracked_objects_->GetDescriptorPool().AllocateDescriptorSet(
292 layout, command_count);
293 }
294
295 void CommandEncoderVK::PushDebugGroup(const char* label) const {
296 if (!HasValidationLayers()) {
297 return;
298 }
299 vk::DebugUtilsLabelEXT label_info;
300 label_info.pLabelName = label;
301 if (auto command_buffer = GetCommandBuffer()) {
302 command_buffer.beginDebugUtilsLabelEXT(label_info);
303 }
304 }
305
306 void CommandEncoderVK::PopDebugGroup() const {
307 if (!HasValidationLayers()) {
308 return;
309 }
310 if (auto command_buffer = GetCommandBuffer()) {
311 command_buffer.endDebugUtilsLabelEXT();
312 }
313 }
314
315 void CommandEncoderVK::InsertDebugMarker(const char* label) const {
316 if (!HasValidationLayers()) {
317 return;
318 }
319 vk::DebugUtilsLabelEXT label_info;
320 label_info.pLabelName = label;
321 if (auto command_buffer = GetCommandBuffer()) {
322 command_buffer.insertDebugUtilsLabelEXT(label_info);
323 }
324 if (queue_) {
325 queue_->InsertDebugMarker(label);
326 }
327 }
328
329 } // namespace impeller
impeller::CommandEncoderVK::Submit
bool Submit(SubmitCallback callback={})
Definition: command_encoder_vk.cc:158
fence_waiter_vk.h
impeller::CommandEncoderVK::PushDebugGroup
void PushDebugGroup(const char *label) const
Definition: command_encoder_vk.cc:295
impeller::TrackedObjectsVK
Definition: command_encoder_vk.cc:14
command_encoder_vk.h
impeller::TrackedObjectsVK::TrackedObjectsVK
TrackedObjectsVK(const std::weak_ptr< const DeviceHolder > &device_holder, const std::shared_ptr< CommandPoolVK > &pool)
Definition: command_encoder_vk.cc:16
impeller::TrackedObjectsVK::IsTracking
bool IsTracking(const std::shared_ptr< const Buffer > &buffer) const
Definition: command_encoder_vk.cc:55
impeller::TrackedObjectsVK::~TrackedObjectsVK
~TrackedObjectsVK()
Definition: command_encoder_vk.cc:32
impeller::TrackedObjectsVK::IsTracking
bool IsTracking(const std::shared_ptr< const TextureSourceVK > &texture) const
Definition: command_encoder_vk.cc:69
impeller::TextureVK::GetTextureSource
std::shared_ptr< const TextureSourceVK > GetTextureSource() const
Definition: texture_vk.cc:136
impeller::CommandEncoderVK::CommandEncoderVK
CommandEncoderVK(std::weak_ptr< const DeviceHolder > device_holder, std::shared_ptr< TrackedObjectsVK > tracked_objects, const std::shared_ptr< QueueVK > &queue, std::shared_ptr< FenceWaiterVK > fence_waiter)
Definition: command_encoder_vk.cc:142
impeller::CommandEncoderVK::AllocateDescriptorSet
std::optional< vk::DescriptorSet > AllocateDescriptorSet(const vk::DescriptorSetLayout &layout, size_t command_count)
Definition: command_encoder_vk.cc:284
impeller::CommandEncoderFactoryVK::SetLabel
void SetLabel(const std::string &label)
Definition: command_encoder_vk.cc:97
impeller::TrackedObjectsVK::GetDescriptorPool
DescriptorPoolVK & GetDescriptorPool()
Definition: command_encoder_vk.cc:78
impeller::TrackedObjectsVK::IsValid
bool IsValid() const
Definition: command_encoder_vk.cc:39
impeller::CommandEncoderVK::SubmitCallback
std::function< void(bool)> SubmitCallback
Definition: command_encoder_vk.h:47
impeller::CommandEncoderVK::Track
bool Track(std::shared_ptr< SharedObjectVK > object)
Definition: command_encoder_vk.cc:232
impeller::DescriptorPoolVK
A short-lived dynamically-sized descriptor pool. Descriptors from this pool don't need to be freed in...
Definition: descriptor_pool_vk.h:28
impeller::TrackedObjectsVK::GetCommandBuffer
vk::CommandBuffer GetCommandBuffer() const
Definition: command_encoder_vk.cc:76
impeller::CommandEncoderFactoryVK::CommandEncoderFactoryVK
CommandEncoderFactoryVK(const std::weak_ptr< const ContextVK > &context)
Definition: command_encoder_vk.cc:93
impeller::TrackedObjectsVK::Track
void Track(std::shared_ptr< const TextureSourceVK > texture)
Definition: command_encoder_vk.cc:62
impeller::CommandEncoderVK::InsertDebugMarker
void InsertDebugMarker(const char *label) const
Definition: command_encoder_vk.cc:315
impeller::CommandEncoderVK::PopDebugGroup
void PopDebugGroup() const
Definition: command_encoder_vk.cc:306
texture_vk.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::CommandEncoderVK::~CommandEncoderVK
~CommandEncoderVK()
std
Definition: comparable.h:98
impeller::BackendCast< ContextVK, Context >::Cast
static ContextVK & Cast(Context &base)
Definition: backend_cast.h:14
impeller::CommandEncoderVK::IsTracking
bool IsTracking(const std::shared_ptr< const Buffer > &texture) const
Definition: command_encoder_vk.cc:248
context_vk.h
impeller::TrackedObjectsVK::Track
void Track(std::shared_ptr< SharedObjectVK > object)
Definition: command_encoder_vk.cc:41
impeller::HasValidationLayers
bool HasValidationLayers()
Definition: context_vk.cc:40
impeller::CommandEncoderVK::IsValid
bool IsValid() const
Definition: command_encoder_vk.cc:154
impeller
Definition: aiks_context.cc:10
impeller::CommandEncoderVK::GetCommandBuffer
vk::CommandBuffer GetCommandBuffer() const
Definition: command_encoder_vk.cc:218
impeller::TrackedObjectsVK::Track
void Track(std::shared_ptr< const Buffer > buffer)
Definition: command_encoder_vk.cc:48
impeller::CommandEncoderFactoryVK::Create
std::shared_ptr< CommandEncoderVK > Create()
Definition: command_encoder_vk.cc:101