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 
6 
7 #include "flutter/fml/closure.h"
8 #include "fml/status.h"
9 #include "fml/status_or.h"
14 
15 namespace impeller {
16 
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 
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 
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 
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 
161 
163  return is_valid_;
164 }
165 
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 
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 
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>>
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 
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