27#include "vulkan/vulkan_handles.hpp"
39 vk::ClearColorValue
value;
47 vk::ClearDepthStencilValue
value;
49 value.stencil = stencil;
55 std::vector<vk::ClearValue> clears;
57 for (
const auto& [_,
color] :
target.GetColorAttachments()) {
59 if (
color.resolve_texture) {
64 const auto& depth =
target.GetDepthAttachment();
65 const auto& stencil =
target.GetStencilAttachment();
67 if (depth.has_value()) {
69 stencil ? stencil->clear_stencil : 0u, depth->clear_depth));
70 }
else if (stencil.has_value()) {
72 stencil->clear_stencil, depth ? depth->clear_depth : 0.0f));
78SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
79 const ContextVK& context,
80 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
81 const std::shared_ptr<CommandBufferVK>& command_buffer)
const {
83 barrier.new_layout = vk::ImageLayout::eGeneral;
84 barrier.cmd_buffer = command_buffer->GetEncoder()->GetCommandBuffer();
85 barrier.src_access = vk::AccessFlagBits::eShaderRead;
86 barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader;
87 barrier.dst_access = vk::AccessFlagBits::eColorAttachmentWrite |
88 vk::AccessFlagBits::eTransferWrite;
89 barrier.dst_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
90 vk::PipelineStageFlagBits::eTransfer;
92 RenderPassBuilderVK builder;
95 builder.SetColorAttachment(
97 color.texture->GetTextureDescriptor().format,
98 color.texture->GetTextureDescriptor().sample_count,
103 if (
color.resolve_texture) {
109 builder.SetDepthStencilAttachment(
110 depth->texture->GetTextureDescriptor().format,
111 depth->texture->GetTextureDescriptor().sample_count,
116 stencil.has_value()) {
118 stencil->texture->GetTextureDescriptor().format,
119 stencil->texture->GetTextureDescriptor().sample_count,
120 stencil->load_action,
121 stencil->store_action
125 if (recycled_renderpass !=
nullptr) {
126 return recycled_renderpass;
129 auto pass =
builder.Build(context.GetDevice());
132 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
136 context.SetDebugName(pass.get(), debug_label_.c_str());
141RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
142 const RenderTarget&
target,
143 std::shared_ptr<CommandBufferVK> command_buffer)
144 : RenderPass(context,
target), command_buffer_(
std::move(command_buffer)) {
146 render_target_.GetColorAttachments().find(0u)->second.texture;
148 render_target_.GetColorAttachments().find(0u)->second.resolve_texture;
151 const std::shared_ptr<CommandEncoderVK>&
encoder =
152 command_buffer_->GetEncoder();
153 command_buffer_vk_ =
encoder->GetCommandBuffer();
154 render_target_.IterateAllAttachments(
155 [&
encoder](
const auto& attachment) ->
bool {
156 encoder->Track(attachment.texture);
157 encoder->Track(attachment.resolve_texture);
161 SharedHandleVK<vk::RenderPass> recycled_render_pass;
162 SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
163 if (resolve_image_vk_) {
164 recycled_render_pass =
166 recycled_framebuffer =
170 const auto& target_size = render_target_.GetRenderTargetSize();
173 CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
180 auto framebuffer = (recycled_framebuffer ==
nullptr)
181 ? CreateVKFramebuffer(vk_context, *render_pass_)
182 : recycled_framebuffer;
189 if (!
encoder->Track(framebuffer) || !
encoder->Track(render_pass_)) {
193 if (resolve_image_vk_) {
200 vk::RenderPassBeginInfo pass_info;
201 pass_info.renderPass = *render_pass_;
202 pass_info.framebuffer = *framebuffer;
203 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
204 pass_info.renderArea.extent.height =
205 static_cast<uint32_t
>(target_size.height);
206 pass_info.setClearValues(clear_values);
208 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
212 vk::Viewport viewport = vk::Viewport()
213 .setWidth(vp.rect.GetWidth())
214 .setHeight(-vp.rect.GetHeight())
215 .setY(vp.rect.GetHeight())
218 command_buffer_vk_.setViewport(0, 1, &viewport);
224 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
225 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
226 command_buffer_vk_.setScissor(0, 1, &scissor);
229 command_buffer_vk_.setStencilReference(
230 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
235RenderPassVK::~RenderPassVK() =
default;
237bool RenderPassVK::IsValid()
const {
241void RenderPassVK::OnSetLabel(std::string label) {
243 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(),
244 std::string(label).c_str());
250 const vk::RenderPass& pass)
const {
251 vk::FramebufferCreateInfo fb_info;
253 fb_info.renderPass = pass;
255 const auto target_size = render_target_.GetRenderTargetSize();
256 fb_info.width = target_size.width;
257 fb_info.height = target_size.height;
260 std::vector<vk::ImageView> attachments;
265 for (
const auto& [_,
color] : render_target_.GetColorAttachments()) {
268 attachments.emplace_back(
269 TextureVK::Cast(*
color.texture).GetRenderTargetView());
270 if (
color.resolve_texture) {
271 attachments.emplace_back(
272 TextureVK::Cast(*
color.resolve_texture).GetRenderTargetView());
275 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
276 attachments.emplace_back(
277 TextureVK::Cast(*depth->texture).GetRenderTargetView());
278 }
else if (
auto stencil = render_target_.GetStencilAttachment();
279 stencil.has_value()) {
280 attachments.emplace_back(
281 TextureVK::Cast(*stencil->texture).GetRenderTargetView());
284 fb_info.setAttachments(attachments);
286 auto [
result, framebuffer] =
287 context.
GetDevice().createFramebufferUnique(fb_info);
289 if (
result != vk::Result::eSuccess) {
298void RenderPassVK::SetPipeline(
300 pipeline_ = pipeline.get();
305 pipeline_uses_input_attachments_ =
306 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
308 if (pipeline_uses_input_attachments_) {
309 if (bound_image_offset_ >= kMaxBindings) {
313 vk::DescriptorImageInfo image_info;
314 image_info.imageLayout = vk::ImageLayout::eGeneral;
316 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
317 image_workspace_[bound_image_offset_++] = image_info;
319 vk::WriteDescriptorSet write_set;
321 write_set.descriptorCount = 1u;
322 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
323 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
325 write_workspace_[descriptor_write_offset_++] = write_set;
330void RenderPassVK::SetCommandLabel(std::string_view label) {
332 command_buffer_->GetEncoder()->PushDebugGroup(label);
338void RenderPassVK::SetStencilReference(uint32_t value) {
339 command_buffer_vk_.setStencilReference(
340 vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
value);
344void RenderPassVK::SetBaseVertex(uint64_t value) {
345 base_vertex_ =
value;
350 vk::Viewport viewport_vk = vk::Viewport()
356 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
360void RenderPassVK::SetScissor(
IRect scissor) {
361 vk::Rect2D scissor_vk =
363 .setOffset(vk::Offset2D(scissor.
GetX(), scissor.
GetY()))
365 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
369void RenderPassVK::SetInstanceCount(
size_t count) {
370 instance_count_ =
count;
375 vertex_count_ =
buffer.vertex_count;
376 if (
buffer.index_type == IndexType::kUnknown || !
buffer.vertex_buffer) {
380 if (!command_buffer_->GetEncoder()->Track(
buffer.vertex_buffer.buffer)) {
385 vk::Buffer vertex_buffer_handle =
386 DeviceBufferVK::Cast(*
buffer.vertex_buffer.buffer).GetBuffer();
387 vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
388 vk::DeviceSize vertex_buffer_offsets[] = {
buffer.vertex_buffer.range.offset};
390 command_buffer_vk_.bindVertexBuffers(0u, 1u, vertex_buffers,
391 vertex_buffer_offsets);
394 if (
buffer.index_type != IndexType::kNone) {
395 has_index_buffer_ =
true;
397 if (!index_buffer_view) {
401 const std::shared_ptr<const DeviceBuffer>& index_buffer =
405 <<
" for index buffer view";
409 if (!command_buffer_->GetEncoder()->Track(index_buffer)) {
413 vk::Buffer index_buffer_handle =
414 DeviceBufferVK::Cast(*index_buffer).GetBuffer();
415 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
419 has_index_buffer_ =
false;
428 "No valid pipeline is bound to the RenderPass.");
448 if (immutable_sampler_) {
449 std::shared_ptr<PipelineVK> pipeline_variant =
450 PipelineVK::Cast(*pipeline_)
451 .CreateVariantForImmutableSamplers(immutable_sampler_);
452 if (!pipeline_variant) {
455 "Could not create pipeline variant with immutable sampler.");
457 pipeline_ = pipeline_variant.get();
460 const auto& context_vk = ContextVK::Cast(*context_);
461 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
463 auto descriptor_result =
464 command_buffer_->GetEncoder()->AllocateDescriptorSets(
465 pipeline_vk.GetDescriptorSetLayout(), context_vk);
466 if (!descriptor_result.ok()) {
468 "Could not allocate descriptor sets.");
470 const auto descriptor_set = descriptor_result.value();
471 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
472 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
473 pipeline_vk.GetPipeline());
475 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
476 write_workspace_[i].dstSet = descriptor_set;
479 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
480 write_workspace_.data(), 0u, {});
482 command_buffer_vk_.bindDescriptorSets(
483 vk::PipelineBindPoint::eGraphics,
492 if (pipeline_uses_input_attachments_) {
494 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
497 if (has_index_buffer_) {
498 command_buffer_vk_.drawIndexed(vertex_count_,
505 command_buffer_vk_.draw(vertex_count_,
514 command_buffer_->GetEncoder()->PopDebugGroup();
518 has_index_buffer_ =
false;
519 bound_image_offset_ = 0u;
520 bound_buffer_offset_ = 0u;
521 descriptor_write_offset_ = 0u;
522 instance_count_ = 1u;
526 pipeline_uses_input_attachments_ =
false;
527 immutable_sampler_ =
nullptr;
541bool RenderPassVK::BindResource(
545 const std::shared_ptr<const ShaderMetadata>& metadata,
550bool RenderPassVK::BindResource(
size_t binding,
553 if (bound_buffer_offset_ >= kMaxBindings) {
557 const std::shared_ptr<const DeviceBuffer>& device_buffer = view.
buffer;
558 auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
563 if (!command_buffer_->GetEncoder()->Track(device_buffer)) {
569 vk::DescriptorBufferInfo buffer_info;
570 buffer_info.buffer =
buffer;
571 buffer_info.offset =
offset;
573 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
575 vk::WriteDescriptorSet write_set;
576 write_set.dstBinding = binding;
577 write_set.descriptorCount = 1u;
579 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
581 write_workspace_[descriptor_write_offset_++] = write_set;
589 std::shared_ptr<const Texture>
texture,
590 const std::unique_ptr<const Sampler>& sampler) {
591 if (bound_buffer_offset_ >= kMaxBindings) {
594 if (!
texture->IsValid() || !sampler) {
598 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
600 if (!command_buffer_->GetEncoder()->Track(
texture)) {
604 if (!immutable_sampler_) {
608 vk::DescriptorImageInfo image_info;
609 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
612 image_workspace_[bound_image_offset_++] = image_info;
614 vk::WriteDescriptorSet write_set;
615 write_set.dstBinding = slot.
binding;
616 write_set.descriptorCount = 1u;
617 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
618 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
620 write_workspace_[descriptor_write_offset_++] = write_set;
624bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
625 command_buffer_->GetEncoder()->GetCommandBuffer().endRenderPass();
629 const std::shared_ptr<Texture>& result_texture =
630 resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_;
631 if (result_texture->GetTextureDescriptor().usage &
632 TextureUsage::kShaderRead) {
635 barrier.
src_access = vk::AccessFlagBits::eColorAttachmentWrite |
636 vk::AccessFlagBits::eTransferWrite;
637 barrier.
src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
638 vk::PipelineStageFlagBits::eTransfer;
639 barrier.
dst_access = vk::AccessFlagBits::eShaderRead;
640 barrier.
dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
642 barrier.
new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
644 if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) {
static TextureVK & Cast(Texture &base)
const vk::Device & GetDevice() const
To do anything rendering related with Impeller, you need a context.
Describes the fixed function and programmable aspects of rendering and compute operations performed b...
const RenderTarget render_target_
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
vk::Sampler GetSampler() const
vk::ImageView GetImageView() const
void SetCachedFramebuffer(const SharedHandleVK< vk::Framebuffer > &framebuffer)
SharedHandleVK< vk::RenderPass > GetCachedRenderPass() const
std::shared_ptr< SamplerVK > GetImmutableSamplerVariant(const SamplerVK &sampler) const
SharedHandleVK< vk::Framebuffer > GetCachedFramebuffer() const
bool SetLayout(const BarrierVK &barrier) const
void SetCachedRenderPass(const SharedHandleVK< vk::RenderPass > &render_pass)
static const uint8_t buffer[]
std::shared_ptr< SharedObjectVKT< T > > SharedHandleVK
constexpr vk::IndexType ToVKIndexType(IndexType index_type)
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
static constexpr size_t kMagicSubpassInputBinding
static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil, Scalar depth)
static std::vector< vk::ClearValue > GetVKClearValues(const RenderTarget &target)
void InsertBarrierForInputAttachmentRead(const vk::CommandBuffer &buffer, const vk::Image &image)
Inserts the appropriate barriers to ensure that subsequent commands can read from the specified image...
static vk::ClearColorValue VKClearValueFromColor(Color color)
auto MakeSharedVK(vk::UniqueHandle< T, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE > handle)
Defines an operations and memory access barrier on a resource.
vk::CommandBuffer cmd_buffer
vk::AccessFlags src_access
vk::PipelineStageFlags dst_stage
vk::ImageLayout new_layout
vk::PipelineStageFlags src_stage
vk::AccessFlags dst_access
std::shared_ptr< const DeviceBuffer > buffer
Metadata required to bind a combined texture and sampler.
size_t binding
The Vulkan binding value.
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
static constexpr TRect MakeSize(const TSize< U > &size)
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.