Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
image_create_info.initialLayout = vk::ImageLayout::eUndefined;
image_create_info.usage = vk::ImageUsageFlagBits::eSampled |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me think we should perhaps have a recommended usage as on optional on the texture descriptor. For later though.

vk::ImageUsageFlagBits::eColorAttachment |
vk::ImageUsageFlagBits::eTransferSrc |
vk::ImageUsageFlagBits::eTransferDst;

VmaAllocationCreateInfo alloc_create_info = {};
Expand Down
135 changes: 129 additions & 6 deletions impeller/renderer/backend/vulkan/blit_command_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,13 @@ std::string BlitCopyTextureToTextureCommandVK::GetLabel() const {
return false;
}

uint32_t mip_count = source_tex_vk.GetTextureDescriptor().mip_count;

// transition the source image to transfer source optimal
TransitionImageLayoutCommandVK transition_source_cmd =
TransitionImageLayoutCommandVK(source_image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferSrcOptimal);
vk::ImageLayout::eTransferSrcOptimal,
mip_count);
bool success = transition_source_cmd.Submit(fenced_command_buffer);
if (!success) {
VALIDATION_LOG << "Failed to transition source image layout";
Expand All @@ -72,7 +75,8 @@ std::string BlitCopyTextureToTextureCommandVK::GetLabel() const {
// transition the destination image to transfer destination optimal
TransitionImageLayoutCommandVK transition_dest_cmd =
TransitionImageLayoutCommandVK(dest_image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal);
vk::ImageLayout::eTransferDstOptimal,
mip_count);
success = transition_dest_cmd.Submit(fenced_command_buffer);
if (!success) {
VALIDATION_LOG << "Failed to transition destination image layout";
Expand Down Expand Up @@ -127,10 +131,13 @@ std::string BlitCopyTextureToBufferCommandVK::GetLabel() const {
image_copy.setImageExtent(
vk::Extent3D(source_region.size.width, source_region.size.height, 1));

uint32_t mip_count = source_tex_vk.GetTextureDescriptor().mip_count;

// transition the source image to transfer source optimal
TransitionImageLayoutCommandVK transition_source_cmd =
TransitionImageLayoutCommandVK(source_image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferSrcOptimal);
vk::ImageLayout::eTransferSrcOptimal,
mip_count);
bool success = transition_source_cmd.Submit(fenced_command_buffer);
if (!success) {
return false;
Expand Down Expand Up @@ -171,9 +178,125 @@ std::string BlitGenerateMipmapCommandVK::GetLabel() const {

[[nodiscard]] bool BlitGenerateMipmapCommandVK::Encode(
FencedCommandBufferVK* fenced_command_buffer) const {
// TODO(https://github.com/flutter/flutter/issues/120134): Support generating
// mipmaps on Vulkan.
IMPELLER_UNIMPLEMENTED;
const auto& source_tex_vk = TextureVK::Cast(*texture);
const auto source_image = source_tex_vk.GetImage();

const auto size = source_tex_vk.GetTextureDescriptor().size;
uint32_t mip_count = source_tex_vk.GetTextureDescriptor().mip_count;

uint32_t mip_width = size.width;
uint32_t mip_height = size.height;

// create the subresource range
vk::ImageSubresourceRange subresource_range{};
subresource_range.setAspectMask(vk::ImageAspectFlagBits::eColor);
subresource_range.setBaseArrayLayer(0);
subresource_range.setLayerCount(1);
subresource_range.setLevelCount(1);

// create a barrier to transition the image to transfer source optimal
vk::ImageMemoryBarrier barrier{};
barrier.setImage(source_image);
barrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
barrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
barrier.setSubresourceRange(subresource_range);

auto gen_mip_cmd = fenced_command_buffer->Get();

vk::CommandBufferBeginInfo begin_info;
begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
auto begin_res = gen_mip_cmd.begin(begin_info);

if (begin_res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to begin command buffer: "
<< vk::to_string(begin_res);
return false;
}

// transition all layers to transfer dst optimal
for (uint32_t i = 0; i < mip_count; i++) {
barrier.subresourceRange.baseMipLevel = i;
barrier.oldLayout = vk::ImageLayout::eUndefined;
barrier.newLayout = vk::ImageLayout::eTransferDstOptimal;
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;

gen_mip_cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer, {},
nullptr, nullptr, barrier);
}

for (uint32_t i = 1; i < mip_count; i++) {
barrier.subresourceRange.baseMipLevel = i - 1;
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;

gen_mip_cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer, {},
nullptr, nullptr, barrier);

vk::ImageBlit blit{};

// src
blit.srcOffsets[0] = vk::Offset3D(0, 0, 0);
blit.srcOffsets[1] = vk::Offset3D(mip_width, mip_height, 1);
blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;

// dst
blit.dstOffsets[0] = vk::Offset3D(0, 0, 0);
blit.dstOffsets[1] = vk::Offset3D(mip_width > 1 ? mip_width / 2 : 1,
mip_height > 1 ? mip_height / 2 : 1, 1);
blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;

gen_mip_cmd.blitImage(source_image, vk::ImageLayout::eTransferSrcOptimal,
source_image, vk::ImageLayout::eTransferDstOptimal,
blit, vk::Filter::eLinear);

// transition the previous mip level to shader read only optimal
barrier.oldLayout = vk::ImageLayout::eUndefined;
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;

gen_mip_cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eFragmentShader, {},
nullptr, nullptr, barrier);

if (mip_width > 1) {
mip_width /= 2;
}

if (mip_height > 1) {
mip_height /= 2;
}
}

// transition the last mip level to shader read only optimal
barrier.subresourceRange.baseMipLevel = mip_count - 1;
barrier.oldLayout = vk::ImageLayout::eUndefined;
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;

gen_mip_cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eFragmentShader, {},
nullptr, nullptr, barrier);

// submit the command buffer
auto res = gen_mip_cmd.end();
if (res != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res);
return false;
}

return true;
}

Expand Down
10 changes: 7 additions & 3 deletions impeller/renderer/backend/vulkan/commands_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ namespace impeller {
TransitionImageLayoutCommandVK::TransitionImageLayoutCommandVK(
vk::Image image,
vk::ImageLayout old_layout,
vk::ImageLayout new_layout)
: image_(image), old_layout_(old_layout), new_layout_(new_layout) {}
vk::ImageLayout new_layout,
uint32_t mip_levels)
: image_(image),
old_layout_(old_layout),
new_layout_(new_layout),
mip_levels_(mip_levels) {}

TransitionImageLayoutCommandVK::~TransitionImageLayoutCommandVK() = default;

Expand All @@ -35,7 +39,7 @@ bool TransitionImageLayoutCommandVK::Submit(
vk::ImageSubresourceRange()
.setAspectMask(vk::ImageAspectFlagBits::eColor)
.setBaseMipLevel(0)
.setLevelCount(1)
.setLevelCount(mip_levels_)
.setBaseArrayLayer(0)
.setLayerCount(1));

Expand Down
4 changes: 3 additions & 1 deletion impeller/renderer/backend/vulkan/commands_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class TransitionImageLayoutCommandVK {
public:
TransitionImageLayoutCommandVK(vk::Image image,
vk::ImageLayout old_layout,
vk::ImageLayout new_layout);
vk::ImageLayout new_layout,
uint32_t mip_levels);

~TransitionImageLayoutCommandVK();

Expand All @@ -24,6 +25,7 @@ class TransitionImageLayoutCommandVK {
vk::Image image_;
vk::ImageLayout old_layout_;
vk::ImageLayout new_layout_;
uint32_t mip_levels_;

FML_DISALLOW_COPY_AND_ASSIGN(TransitionImageLayoutCommandVK);
};
Expand Down
28 changes: 17 additions & 11 deletions impeller/renderer/backend/vulkan/render_pass_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "impeller/renderer/backend/vulkan/render_pass_vk.h"

#include <array>
#include <cstdint>
#include <vector>

#include "fml/logging.h"
Expand Down Expand Up @@ -71,7 +72,9 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
const auto& stencil0 = render_target.GetStencilAttachment();

auto& texture = TextureVK::Cast(*color0.texture);
const auto& size = texture.GetTextureDescriptor().size;
vk::Framebuffer framebuffer = CreateFrameBuffer(texture);
uint32_t mip_count = texture.GetTextureDescriptor().mip_count;

command_buffer_->GetDeletionQueue()->Push(
[device = device_, fbo = framebuffer]() {
Expand All @@ -80,15 +83,15 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {

// layout transition.
if (!TransitionImageLayout(texture.GetImage(), vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal)) {
vk::ImageLayout::eColorAttachmentOptimal,
mip_count)) {
return false;
}

vk::ClearValue clear_value;
clear_value.color =
vk::ClearColorValue(std::array<float, 4>{0.0f, 0.0f, 0.0, 0.0f});

const auto& size = texture.GetTextureDescriptor().size;
vk::Rect2D render_area =
vk::Rect2D()
.setOffset(vk::Offset2D(0, 0))
Expand Down Expand Up @@ -124,7 +127,8 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
}

if (!TransitionImageLayout(texture.GetImage(), vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal)) {
vk::ImageLayout::eColorAttachmentOptimal,
mip_count)) {
return false;
}

Expand Down Expand Up @@ -315,18 +319,19 @@ bool RenderPassVK::UpdateDescriptorSets(const char* label,
const SamplerVK& sampler_vk = SamplerVK::Cast(sampler);

const SampledImageSlot& slot = bindings.sampled_images.at(index);
uint32_t mip_levels = texture_vk.GetTextureDescriptor().mip_count;

if (!TransitionImageLayout(texture_vk.GetImage(),
vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal)) {
if (!TransitionImageLayout(
texture_vk.GetImage(), vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal, mip_levels)) {
return false;
}

CopyBufferToImage(texture_vk);

if (!TransitionImageLayout(texture_vk.GetImage(),
vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal)) {
if (!TransitionImageLayout(
texture_vk.GetImage(), vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal, mip_levels)) {
return false;
}

Expand Down Expand Up @@ -394,9 +399,10 @@ vk::Framebuffer RenderPassVK::CreateFrameBuffer(

bool RenderPassVK::TransitionImageLayout(vk::Image image,
vk::ImageLayout layout_old,
vk::ImageLayout layout_new) const {
vk::ImageLayout layout_new,
uint32_t mip_levels) const {
auto transition_cmd =
TransitionImageLayoutCommandVK(image, layout_old, layout_new);
TransitionImageLayoutCommandVK(image, layout_old, layout_new, mip_levels);
return transition_cmd.Submit(command_buffer_.get());
}

Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/backend/vulkan/render_pass_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ class RenderPassVK final : public RenderPass {

bool TransitionImageLayout(vk::Image image,
vk::ImageLayout layout_old,
vk::ImageLayout layout_new) const;
vk::ImageLayout layout_new,
uint32_t mip_levels) const;

bool CopyBufferToImage(const TextureVK& texture_vk) const;

Expand Down