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