Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
12 changes: 7 additions & 5 deletions impeller/aiks/picture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,20 @@ std::shared_ptr<Texture> Picture::RenderToTexture(
size, // size
"Picture Snapshot MSAA", // label
RenderTarget::
kDefaultColorAttachmentConfigMSAA // color_attachment_config
kDefaultColorAttachmentConfigMSAA, // color_attachment_config
true // persistent
#ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan.
,
std::nullopt // stencil_attachment_config
#endif // FML_OS_ANDROID
);
} else {
target = RenderTarget::CreateOffscreen(
*impeller_context, // context
size, // size
"Picture Snapshot", // label
RenderTarget::kDefaultColorAttachmentConfig // color_attachment_config
*impeller_context, // context
size, // size
"Picture Snapshot", // label
RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config
true // persistent
#ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan.
,
std::nullopt // stencil_attachment_config
Expand Down
2 changes: 2 additions & 0 deletions impeller/core/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class Allocator {

virtual ISize GetMaxTextureSizeSupported() const = 0;

virtual void IncrementFrameIndex() {}

protected:
Allocator();

Expand Down
1 change: 1 addition & 0 deletions impeller/core/texture_descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct TextureDescriptor {
static_cast<TextureUsageMask>(TextureUsage::kShaderRead);
SampleCount sample_count = SampleCount::kCount1;
CompressionType compression_type = CompressionType::kLossless;
bool persistent = false;

constexpr size_t GetByteSizeOfBaseMipLevel() const {
if (!IsValid()) {
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/scene_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ bool SceneContents::Render(const ContentContext& renderer,
.load_action = LoadAction::kClear,
.store_action = StoreAction::kMultisampleResolve,
}, // color_attachment_config
false,
RenderTarget::AttachmentConfig{
.storage_mode = StorageMode::kDeviceTransient,
.load_action = LoadAction::kDontCare,
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
.resolve_storage_mode = StorageMode::kDevicePrivate,
.load_action = LoadAction::kDontCare,
.store_action = StoreAction::kMultisampleResolve,
.clear_color = clear_color}, // color_attachment_config
.clear_color = clear_color}, // color_attachment_config
false,
GetDefaultStencilConfig(readable) // stencil_attachment_config
);
} else {
Expand All @@ -227,7 +228,8 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
.load_action = LoadAction::kDontCare,
.store_action = StoreAction::kDontCare,
.clear_color = clear_color,
}, // color_attachment_config
}, // color_attachment_config
false,
GetDefaultStencilConfig(readable) // stencil_attachment_config
);
}
Expand Down
170 changes: 149 additions & 21 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
VALIDATION_LOG << "Could not create memory allocator";
return;
}

for (auto i = 0u; i < 3u; i++) {
if (!CreateBufferPool(allocator, &staging_buffer_pools_[i])) {
return;
}
if (!CreateRenderTargetPool(allocator, &render_target_buffer_pools_[i])) {
return;
}
}

allocator_ = allocator;
supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures();
is_valid_ = true;
Expand All @@ -101,6 +111,15 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
AllocatorVK::~AllocatorVK() {
TRACE_EVENT0("impeller", "DestroyAllocatorVK");
if (allocator_) {
for (auto i = 0u; i < 3u; i++) {
if (staging_buffer_pools_[i]) {
::vmaDestroyPool(allocator_, staging_buffer_pools_[i]);
}
if (render_target_buffer_pools_[i]) {
::vmaDestroyPool(allocator_, render_target_buffer_pools_[i]);
}
}

::vmaDestroyAllocator(allocator_);
}
}
Expand Down Expand Up @@ -211,25 +230,16 @@ static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags(
}

static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode,
bool is_texture,
size_t size) {
bool dedicated) {
VmaAllocationCreateFlags flags = 0;
switch (mode) {
case StorageMode::kHostVisible:
if (is_texture) {
if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) {
flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
} else {
flags |= {};
}
} else {
flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
if (dedicated) {
flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
}
return flags;
case StorageMode::kDevicePrivate:
if (is_texture &&
size >= kImageSizeThresholdForDedicatedMemoryAllocation) {
if (dedicated) {
flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
}
return flags;
Expand All @@ -239,11 +249,28 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode,
FML_UNREACHABLE();
}

static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags(
StorageMode mode) {
VmaAllocationCreateFlags flags = 0;
switch (mode) {
case StorageMode::kHostVisible:
flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
return flags;
case StorageMode::kDevicePrivate:
return flags;
case StorageMode::kDeviceTransient:
return flags;
}
FML_UNREACHABLE();
}

class AllocatedTextureSourceVK final : public TextureSourceVK {
public:
AllocatedTextureSourceVK(const TextureDescriptor& desc,
VmaAllocator allocator,
vk::Device device,
VmaPool pool,
bool supports_memoryless_textures)
: TextureSourceVK(desc) {
TRACE_EVENT0("impeller", "CreateDeviceTexture");
Expand All @@ -268,12 +295,24 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {

VmaAllocationCreateInfo alloc_nfo = {};

auto use_dedicated = desc.GetByteSizeOfBaseMipLevel() >
kImageSizeThresholdForDedicatedMemoryAllocation;

alloc_nfo.usage = ToVMAMemoryUsage();
alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags(
desc.storage_mode, supports_memoryless_textures);
if (desc.usage &
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget) &&
!desc.persistent) {
if (desc.storage_mode == StorageMode::kDevicePrivate ||
(desc.storage_mode == StorageMode::kDeviceTransient &&
!supports_memoryless_textures)) {
alloc_nfo.pool = pool;
use_dedicated = false;
}
}
alloc_nfo.flags =
ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true,
desc.GetByteSizeOfBaseMipLevel());
ToVmaAllocationCreateFlags(desc.storage_mode, use_dedicated);

auto create_info_native =
static_cast<vk::ImageCreateInfo::NativeType>(image_info);
Expand Down Expand Up @@ -377,10 +416,11 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
return nullptr;
}
auto source = std::make_shared<AllocatedTextureSourceVK>(
desc, //
allocator_, //
device_holder->GetDevice(), //
supports_memoryless_textures_ //
desc, //
allocator_, //
device_holder->GetDevice(), //
render_target_buffer_pools_[frame_index_ % 3u], //
supports_memoryless_textures_ //
);
if (!source->IsValid()) {
return nullptr;
Expand Down Expand Up @@ -408,8 +448,10 @@ std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
allocation_info.usage = ToVMAMemoryUsage();
allocation_info.preferredFlags =
ToVKBufferMemoryPropertyFlags(desc.storage_mode);
allocation_info.flags = ToVmaAllocationCreateFlags(
desc.storage_mode, /*is_texture=*/false, desc.size);
allocation_info.flags = ToVmaAllocationBufferCreateFlags(desc.storage_mode);
if (desc.storage_mode == StorageMode::kHostVisible) {
allocation_info.pool = staging_buffer_pools_[frame_index_ % 3u];
}

VkBuffer buffer = {};
VmaAllocation buffer_allocation = {};
Expand Down Expand Up @@ -437,4 +479,90 @@ std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
);
}

// static
bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) {
vk::BufferCreateInfo buffer_info;
buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eUniformBuffer |
vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst;
buffer_info.size = 1u; // doesn't matter
buffer_info.sharingMode = vk::SharingMode::eExclusive;
auto buffer_info_native =
static_cast<vk::BufferCreateInfo::NativeType>(buffer_info);

VmaAllocationCreateInfo allocation_info = {};
allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
allocation_info.preferredFlags =
ToVKBufferMemoryPropertyFlags(StorageMode::kHostVisible);
allocation_info.flags =
ToVmaAllocationBufferCreateFlags(StorageMode::kHostVisible);

uint32_t memTypeIndex;
auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not find memory type for buffer pool.";
return false;
}

VmaPoolCreateInfo pool_create_info = {};
pool_create_info.memoryTypeIndex = memTypeIndex;
pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT |
VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT;

result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)};
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create buffer pool.";
return false;
}
return true;
}

bool AllocatorVK::CreateRenderTargetPool(VmaAllocator allocator,
VmaPool* pool) {
vk::ImageCreateInfo image_info;
image_info.flags = {};
image_info.imageType = vk::ImageType::e2D;
image_info.format = vk::Format::eR8G8B8A8Unorm;
image_info.extent = VkExtent3D{1u, 1u, 1u};
image_info.samples = vk::SampleCountFlagBits::e1;
image_info.mipLevels = 1u;
image_info.arrayLayers = 1u;
image_info.tiling = vk::ImageTiling::eOptimal;
image_info.initialLayout = vk::ImageLayout::eUndefined;
image_info.usage =
vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
image_info.sharingMode = vk::SharingMode::eExclusive;

auto create_info_native =
static_cast<vk::ImageCreateInfo::NativeType>(image_info);

VmaAllocationCreateInfo allocation_info = {};
allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
allocation_info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;

uint32_t memTypeIndex;
auto result = vk::Result{vmaFindMemoryTypeIndexForImageInfo(
allocator, &create_info_native, &allocation_info, &memTypeIndex)};
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not find memory type for buffer pool.";
return false;
}

VmaPoolCreateInfo pool_create_info = {};
pool_create_info.memoryTypeIndex = memTypeIndex;
pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT |
VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT;

result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)};
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create render target pool.";
return false;
}
return true;
}

} // namespace impeller
14 changes: 14 additions & 0 deletions impeller/renderer/backend/vulkan/allocator_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ class AllocatorVK final : public Allocator {

fml::RefPtr<vulkan::VulkanProcTable> vk_;
VmaAllocator allocator_ = {};

// Staging buffer pools.
VmaPool staging_buffer_pools_[3] = {};
// Render target buffer pools.
VmaPool render_target_buffer_pools_[3] = {};

std::weak_ptr<Context> context_;
std::weak_ptr<DeviceHolder> device_holder_;
ISize max_texture_size_;
bool is_valid_ = false;
bool supports_memoryless_textures_ = false;
uint32_t frame_index_ = 0u;

AllocatorVK(std::weak_ptr<Context> context,
uint32_t vulkan_api_version,
Expand All @@ -56,6 +63,13 @@ class AllocatorVK final : public Allocator {
// |Allocator|
ISize GetMaxTextureSizeSupported() const override;

// |Allocator|
void IncrementFrameIndex() override { frame_index_ += 1; }

static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool);

static bool CreateRenderTargetPool(VmaAllocator allocator, VmaPool* pool);

FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK);
};

Expand Down
3 changes: 3 additions & 0 deletions impeller/renderer/backend/vulkan/context_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class ContextVK final : public Context,

uint64_t GetHash() const { return hash_; }

uint32_t GetFrameIndex() const { return frame_index_; }

// |Context|
~ContextVK() override;

Expand Down Expand Up @@ -163,6 +165,7 @@ class ContextVK final : public Context,
std::string device_name_;
std::shared_ptr<fml::ConcurrentMessageLoop> raster_message_loop_;
const uint64_t hash_;
uint32_t frame_index_ = 0u;

bool is_valid_ = false;

Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/surface_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ std::unique_ptr<SurfaceVK> SurfaceVK::WrapSwapchainImage(
msaa_tex_desc.format = swapchain_image->GetPixelFormat();
msaa_tex_desc.size = swapchain_image->GetSize();
msaa_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
msaa_tex_desc.persistent = !supports_memoryless;

std::shared_ptr<Texture> msaa_tex;
if (supports_memoryless || !swapchain_image->HasMSAATexture()) {
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
}

const auto& context = ContextVK::Cast(*context_strong);
context.GetResourceAllocator()->IncrementFrameIndex();

const auto& sync = synchronizers_[current_frame_];

Expand Down
Loading