11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/trace_event.h"
27 #include "vulkan/vulkan_to_string.hpp"
33 const std::shared_ptr<Texture>
Attachment::*texture_ptr) {
34 const auto& texture = attachment.*texture_ptr;
39 const auto& desc = texture->GetTextureDescriptor();
40 auto current_layout = texture_vk.GetLayout();
45 if (current_layout == vk::ImageLayout::eUndefined) {
55 if (current_layout != vk::ImageLayout::ePresentSrcKHR &&
56 current_layout != vk::ImageLayout::eUndefined) {
58 current_layout = vk::ImageLayout::eGeneral;
71 const vk::AttachmentDescription& attachment_desc,
72 const std::shared_ptr<CommandBufferVK>& command_buffer,
73 const std::shared_ptr<Texture>
Attachment::*texture_ptr) {
74 const auto& texture = attachment.*texture_ptr;
80 if (attachment_desc.initialLayout == vk::ImageLayout::eGeneral) {
82 barrier.
new_layout = vk::ImageLayout::eGeneral;
83 barrier.
cmd_buffer = command_buffer->GetEncoder()->GetCommandBuffer();
84 barrier.
src_access = vk::AccessFlagBits::eShaderRead;
85 barrier.
src_stage = vk::PipelineStageFlagBits::eFragmentShader;
86 barrier.
dst_access = vk::AccessFlagBits::eColorAttachmentWrite |
87 vk::AccessFlagBits::eTransferWrite;
88 barrier.
dst_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
89 vk::PipelineStageFlagBits::eTransfer;
91 texture_vk.SetLayout(barrier);
96 texture_vk.SetLayoutWithoutEncoding(attachment_desc.finalLayout);
99 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
100 const ContextVK& context,
101 const std::shared_ptr<CommandBufferVK>& command_buffer)
const {
102 std::vector<vk::AttachmentDescription> attachments;
104 std::vector<vk::AttachmentReference> color_refs;
105 std::vector<vk::AttachmentReference> resolve_refs;
122 color_refs[bind_point] =
123 vk::AttachmentReference{
static_cast<uint32_t
>(attachments.size()),
124 vk::ImageLayout::eColorAttachmentOptimal};
125 attachments.emplace_back(
129 if (color.resolve_texture) {
130 resolve_refs[bind_point] = vk::AttachmentReference{
131 static_cast<uint32_t
>(attachments.size()), vk::ImageLayout::eGeneral};
132 attachments.emplace_back(
140 depth_stencil_ref = vk::AttachmentReference{
141 static_cast<uint32_t
>(attachments.size()),
142 vk::ImageLayout::eDepthStencilAttachmentOptimal};
143 attachments.emplace_back(
150 stencil.has_value()) {
151 depth_stencil_ref = vk::AttachmentReference{
152 static_cast<uint32_t
>(attachments.size()),
153 vk::ImageLayout::eDepthStencilAttachmentOptimal};
154 attachments.emplace_back(
160 vk::SubpassDescription subpass_desc;
161 subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
162 subpass_desc.setColorAttachments(color_refs);
163 subpass_desc.setResolveAttachments(resolve_refs);
164 subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);
166 vk::RenderPassCreateInfo render_pass_desc;
167 render_pass_desc.setAttachments(attachments);
168 render_pass_desc.setPSubpasses(&subpass_desc);
169 render_pass_desc.setSubpassCount(1u);
171 auto [result, pass] =
172 context.GetDevice().createRenderPassUnique(render_pass_desc);
173 if (result != vk::Result::eSuccess) {
174 VALIDATION_LOG <<
"Failed to create render pass: " << vk::to_string(result);
177 context.SetDebugName(pass.get(), debug_label_.c_str());
181 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
182 const RenderTarget& target,
183 std::weak_ptr<CommandBufferVK> command_buffer)
184 : RenderPass(context, target), command_buffer_(
std::move(command_buffer)) {
188 RenderPassVK::~RenderPassVK() =
default;
190 bool RenderPassVK::IsValid()
const {
194 void RenderPassVK::OnSetLabel(std::string label) {
195 debug_label_ = std::move(label);
199 vk::ClearColorValue value;
207 vk::ClearDepthStencilValue value;
209 value.stencil = stencil;
215 std::vector<vk::ClearValue> clears;
219 if (color.resolve_texture) {
227 if (depth.has_value()) {
229 stencil ? stencil->clear_stencil : 0u, depth->clear_depth));
232 if (stencil.has_value()) {
234 stencil->clear_stencil, depth ? depth->clear_depth : 0.0f));
240 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
241 const ContextVK& context,
242 const vk::RenderPass& pass)
const {
243 vk::FramebufferCreateInfo fb_info;
245 fb_info.renderPass = pass;
247 const auto target_size = render_target_.GetRenderTargetSize();
248 fb_info.width = target_size.width;
249 fb_info.height = target_size.height;
253 std::vector<vk::ImageView> attachments;
257 for (
const auto& [_, color] : render_target_.GetColorAttachments()) {
260 attachments.emplace_back(TextureVK::Cast(*color.texture).GetImageView());
261 if (color.resolve_texture) {
262 attachments.emplace_back(
263 TextureVK::Cast(*color.resolve_texture).GetImageView());
266 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
267 attachments.emplace_back(TextureVK::Cast(*depth->texture).GetImageView());
269 if (
auto stencil = render_target_.GetStencilAttachment();
270 stencil.has_value()) {
271 attachments.emplace_back(TextureVK::Cast(*stencil->texture).GetImageView());
274 fb_info.setAttachments(attachments);
276 auto [result, framebuffer] =
277 context.GetDevice().createFramebufferUnique(fb_info);
279 if (result != vk::Result::eSuccess) {
280 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
288 const vk::CommandBuffer& buffer) {
293 barrier.
src_access = vk::AccessFlagBits::eColorAttachmentWrite |
294 vk::AccessFlagBits::eTransferWrite;
295 barrier.
src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
296 vk::PipelineStageFlagBits::eTransfer;
297 barrier.
dst_access = vk::AccessFlagBits::eShaderRead;
298 barrier.
dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
300 barrier.
new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
303 if (!TextureVK::Cast(*data.texture.resource).SetLayout(barrier)) {
311 const vk::CommandBuffer& buffer) {
317 const vk::CommandBuffer& buffer) {
318 for (
const auto& command : commands) {
330 size_t command_count) {
341 std::vector<vk::DescriptorImageInfo> images;
342 std::vector<vk::DescriptorBufferInfo> buffers;
343 std::vector<vk::WriteDescriptorSet> writes;
351 auto bind_images = [&encoder,
355 ](
const Bindings& bindings) ->
bool {
356 for (
const auto& [index, data] : bindings.sampled_images) {
357 auto texture = data.texture.resource;
358 const auto& texture_vk = TextureVK::Cast(*texture);
359 const SamplerVK& sampler = SamplerVK::Cast(*data.sampler.resource);
361 if (!encoder.
Track(texture) ||
368 vk::DescriptorImageInfo image_info;
369 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
371 image_info.imageView = texture_vk.GetImageView();
372 images.push_back(image_info);
374 vk::WriteDescriptorSet write_set;
375 write_set.dstSet = vk_desc_set.value();
376 write_set.dstBinding = slot.
binding;
377 write_set.descriptorCount = 1u;
378 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
379 write_set.pImageInfo = &images.back();
381 writes.push_back(write_set);
387 auto bind_buffers = [&allocator,
393 ](
const Bindings& bindings) ->
bool {
394 for (
const auto& [buffer_index, data] : bindings.buffers) {
395 const auto& buffer_view = data.view.resource.buffer;
397 auto device_buffer = buffer_view->GetDeviceBuffer(allocator);
398 if (!device_buffer) {
399 VALIDATION_LOG <<
"Failed to get device buffer for vertex binding";
403 auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
408 if (!encoder.Track(device_buffer)) {
412 uint32_t offset = data.view.resource.range.offset;
414 vk::DescriptorBufferInfo buffer_info;
415 buffer_info.buffer = buffer;
416 buffer_info.offset = offset;
417 buffer_info.range = data.view.resource.range.length;
418 buffers.push_back(buffer_info);
421 auto layout_it = std::find_if(desc_set.begin(), desc_set.end(),
423 return layout.binding == uniform.binding;
425 if (layout_it == desc_set.end()) {
426 VALIDATION_LOG <<
"Failed to get descriptor set layout for binding "
430 auto layout = *layout_it;
432 vk::WriteDescriptorSet write_set;
433 write_set.dstSet = vk_desc_set.value();
434 write_set.dstBinding = uniform.
binding;
435 write_set.descriptorCount = 1u;
437 write_set.pBufferInfo = &buffers.back();
439 writes.push_back(write_set);
450 context.
GetDevice().updateDescriptorSets(writes, {});
452 encoder.GetCommandBuffer().bindDescriptorSets(
453 vk::PipelineBindPoint::eGraphics,
456 {vk::DescriptorSet{*vk_desc_set}},
463 const vk::CommandBuffer& cmd_buffer,
465 const ISize& target_size) {
468 {.rect = Rect::MakeSize(target_size)});
469 vk::Viewport viewport = vk::Viewport()
470 .setWidth(vp.rect.size.width)
471 .setHeight(-vp.rect.size.height)
472 .setY(vp.rect.size.height)
475 cmd_buffer_cache.
SetViewport(cmd_buffer, 0, 1, &viewport);
478 const auto& sc = command.
scissor.value_or(IRect::MakeSize(target_size));
481 .setOffset(vk::Offset2D(sc.origin.x, sc.origin.y))
482 .setExtent(vk::Extent2D(sc.size.width, sc.size.height));
483 cmd_buffer_cache.
SetScissor(cmd_buffer, 0, 1, &scissor);
490 const ISize& target_size,
491 size_t command_count) {
496 #ifdef IMPELLER_DEBUG
497 fml::ScopedCleanupClosure pop_marker(
499 if (!command.label.empty()) {
502 pop_marker.Release();
504 #endif // IMPELLER_DEBUG
508 const auto& pipeline_vk = PipelineVK::Cast(*command.
pipeline);
520 cmd_buffer, vk::PipelineBindPoint::eGraphics, pipeline_vk.GetPipeline());
527 cmd_buffer, vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
533 if (!vertex_buffer_view) {
539 auto vertex_buffer = vertex_buffer_view.buffer->GetDeviceBuffer(allocator);
541 if (!vertex_buffer) {
543 <<
" for vertex buffer view";
547 if (!encoder.
Track(vertex_buffer)) {
552 auto vertex_buffer_handle = DeviceBufferVK::Cast(*vertex_buffer).GetBuffer();
553 vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
554 vk::DeviceSize vertex_buffer_offsets[] = {vertex_buffer_view.range.offset};
555 cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets);
560 if (!index_buffer_view) {
564 auto index_buffer = index_buffer_view.
buffer->GetDeviceBuffer(allocator);
567 <<
" for index buffer view";
571 if (!encoder.
Track(index_buffer)) {
575 auto index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetBuffer();
576 cmd_buffer.bindIndexBuffer(index_buffer_handle,
577 index_buffer_view.range.offset,
597 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
598 TRACE_EVENT0(
"impeller",
"RenderPassVK::OnEncodeCommands");
603 const auto& vk_context = ContextVK::Cast(context);
605 auto command_buffer = command_buffer_.lock();
606 if (!command_buffer) {
607 VALIDATION_LOG <<
"Command buffer died before commands could be encoded.";
610 auto encoder = command_buffer->GetEncoder();
615 fml::ScopedCleanupClosure pop_marker(
616 [&encoder]() { encoder->PopDebugGroup(); });
617 if (!debug_label_.empty()) {
618 encoder->PushDebugGroup(debug_label_.c_str());
620 pop_marker.Release();
623 auto cmd_buffer = encoder->GetCommandBuffer();
629 render_target_.IterateAllAttachments(
630 [&encoder](
const auto& attachment) ->
bool {
631 encoder->Track(attachment.texture);
632 encoder->Track(attachment.resolve_texture);
636 const auto& target_size = render_target_.GetRenderTargetSize();
638 auto render_pass = CreateVKRenderPass(vk_context, command_buffer);
644 auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass);
650 if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) {
656 vk::RenderPassBeginInfo pass_info;
657 pass_info.renderPass = *render_pass;
658 pass_info.framebuffer = *framebuffer;
659 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
660 pass_info.renderArea.extent.height =
661 static_cast<uint32_t
>(target_size.height);
662 pass_info.setClearValues(clear_values);
665 TRACE_EVENT0(
"impeller",
"EncodeRenderPassCommands");
666 cmd_buffer.beginRenderPass(pass_info, vk::SubpassContents::eInline);
668 fml::ScopedCleanupClosure end_render_pass(
669 [cmd_buffer]() { cmd_buffer.endRenderPass(); });
671 for (
const auto& command : commands_) {
672 if (!command.pipeline) {
676 if (!
EncodeCommand(context, command, *encoder, pass_bindings_cache_,
677 target_size, commands_.size())) {