[Impeller] Vulkan framebuffer fetch via VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS (flutter/engine#48458)

Support framebuffer fetch on devices that have the extension VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS which gives us a fairly easy way to add subpass self dependencies.

Part of https://github.com/flutter/flutter/issues/120223
This commit is contained in:
Jonah Williams
2023-12-05 16:55:59 -08:00
committed by GitHub
parent 4431b52677
commit 82a8b5ddcf
31 changed files with 343 additions and 79 deletions

View File

@@ -173,7 +173,14 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %}
// ===========================================================================
// Metadata for Vulkan =======================================================
// ===========================================================================
static constexpr std::array<DescriptorSetLayout,{{length(buffers)+length(sampled_images)}}> kDescriptorSetLayouts{
static constexpr std::array<DescriptorSetLayout,{{length(buffers)+length(sampled_images)+length(subpass_inputs)}}> kDescriptorSetLayouts{
{% for subpass_input in subpass_inputs %}
DescriptorSetLayout{
{{subpass_input.binding}}, // binding = {{subpass_input.binding}}
{{subpass_input.descriptor_type}}, // descriptor_type = {{subpass_input.descriptor_type}}
{{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}}
},
{% endfor %}
{% for buffer in buffers %}
DescriptorSetLayout{
{{buffer.binding}}, // binding = {{buffer.binding}}

View File

@@ -188,6 +188,21 @@ std::optional<nlohmann::json> Reflector::GenerateTemplateArguments() const {
const auto shader_resources = compiler_->get_shader_resources();
// Subpass Inputs.
{
auto& subpass_inputs = root["subpass_inputs"] = nlohmann::json::array_t{};
if (auto subpass_inputs_json =
ReflectResources(shader_resources.subpass_inputs);
subpass_inputs_json.has_value()) {
for (auto subpass_input : subpass_inputs_json.value()) {
subpass_input["descriptor_type"] = "DescriptorType::kInputAttachment";
subpass_inputs.emplace_back(std::move(subpass_input));
}
} else {
return std::nullopt;
}
}
// Uniform and storage buffers.
{
auto& buffers = root["buffers"] = nlohmann::json::array_t{};

View File

@@ -163,6 +163,7 @@ enum class DescriptorType {
kSampledImage,
kImage,
kSampler,
kInputAttachment,
};
struct DescriptorSetLayout {

View File

@@ -221,49 +221,64 @@ ContentContext::ContentContext(
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
framebuffer_blend_color_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_colorburn_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_colordodge_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_darken_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_difference_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_exclusion_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_hardlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_hue_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_lighten_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_luminosity_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_multiply_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_overlay_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_saturation_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_screen_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal},
UseSubpassInput::kYes);
framebuffer_blend_softlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal},
UseSubpassInput::kYes);
}
blend_color_pipelines_.CreateDefault(

View File

@@ -18,6 +18,7 @@
#include "impeller/entity/entity.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/render_target.h"
#include "impeller/typographer/typographer_context.h"
@@ -713,13 +714,15 @@ class ContentContext {
void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::initializer_list<Scalar>& constants = {}) {
const std::initializer_list<Scalar>& constants = {},
UseSubpassInput subpass_input = UseSubpassInput::kNo) {
auto desc =
PipelineT::Builder::MakeDefaultPipelineDescriptor(context, constants);
if (!desc.has_value()) {
VALIDATION_LOG << "Failed to create default pipeline.";
return;
}
desc->SetUseSubpassInput(subpass_input);
options.ApplyToPipelineDescriptor(*desc);
SetDefault(options, std::make_unique<PipelineT>(context, desc));
}

View File

@@ -10,10 +10,12 @@
#include "fml/logging.h"
#include "gtest/gtest.h"
#include "impeller/core/formats.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/conical_gradient_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/color_filter_contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
@@ -41,6 +43,7 @@
#include "impeller/playground/playground.h"
#include "impeller/playground/widgets.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
@@ -2527,6 +2530,63 @@ TEST_P(EntityTest, DecalSpecializationAppliedToMorphologyFilter) {
expected_constants);
}
TEST_P(EntityTest, FramebufferFetchPipelinesDeclareUsage) {
auto content_context =
ContentContext(GetContext(), TypographerContextSkia::Make());
if (!content_context.GetDeviceCapabilities().SupportsFramebufferFetch()) {
GTEST_SKIP() << "Framebuffer fetch not supported.";
}
ContentContextOptions options;
options.color_attachment_pixel_format = PixelFormat::kR8G8B8A8UNormInt;
auto color_burn =
content_context.GetFramebufferBlendColorBurnPipeline(options);
EXPECT_TRUE(color_burn->GetDescriptor().UsesSubpassInput());
}
TEST_P(EntityTest, PipelineDescriptorEqAndHash) {
auto desc_1 = std::make_shared<PipelineDescriptor>();
auto desc_2 = std::make_shared<PipelineDescriptor>();
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
desc_1->SetUseSubpassInput(UseSubpassInput::kYes);
EXPECT_FALSE(desc_1->IsEqual(*desc_2));
EXPECT_NE(desc_1->GetHash(), desc_2->GetHash());
desc_2->SetUseSubpassInput(UseSubpassInput::kYes);
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
}
#ifdef FML_OS_LINUX
TEST_P(EntityTest, FramebufferFetchVulkanBindingOffsetIsTheSame) {
// Using framebuffer fetch on Vulkan requires that we maintain a subpass input
// binding that we don't have a good route for configuring with the current
// metadata approach. This test verifies that the binding value doesn't change
// from the expected constant.
// See also:
// * impeller/renderer/backend/vulkan/binding_helpers_vk.cc
// * impeller/entity/shaders/blending/framebuffer_blend.frag
// This test only works on Linux because macOS hosts incorrectly populate the
// Vulkan descriptor sets based on the MSL compiler settings.
bool expected_layout = false;
for (const DescriptorSetLayout& layout : FramebufferBlendColorBurnPipeline::
FragmentShader::kDescriptorSetLayouts) {
if (layout.binding == 64 &&
layout.descriptor_type == DescriptorType::kInputAttachment) {
expected_layout = true;
}
}
EXPECT_TRUE(expected_layout);
}
#endif
} // namespace testing
} // namespace impeller

View File

@@ -10,9 +10,23 @@
#include <impeller/types.glsl>
#include "blend_select.glsl"
layout(constant_id = 0) const float blend_type = 0.0;
layout(constant_id = 1) const float supports_decal = 1.0;
// Warning: if any of the constant values or layouts are changed in this
// file, then the hard-coded constant value in
// impeller/renderer/backend/vulkan/binding_helpers_vk.cc
layout(constant_id = 0) const float blend_type = 0;
layout(constant_id = 1) const float supports_decal = 1;
#ifdef IMPELLER_TARGET_VULKAN
layout(set = 0,
binding = 0,
input_attachment_index = 0) uniform subpassInputMS uSub;
vec4 ReadDestination() {
return (subpassLoad(uSub, 0) + subpassLoad(uSub, 1) + subpassLoad(uSub, 2) +
subpassLoad(uSub, 3)) /
vec4(4.0);
}
#else
layout(set = 0,
binding = 0,
input_attachment_index = 0) uniform subpassInput uSub;
@@ -20,6 +34,7 @@ layout(set = 0,
vec4 ReadDestination() {
return subpassLoad(uSub);
}
#endif // IMPELLER_TARGET_VULKAN
uniform sampler2D texture_sampler_src;

View File

@@ -5,6 +5,9 @@
#include <impeller/conversions.glsl>
#include <impeller/types.glsl>
// Warning: if any of the constant values or layouts are changed in this
// file, then the hard-coded constant value in
// impeller/renderer/backend/vulkan/binding_helpers_vk.cc
uniform FrameInfo {
mat4 mvp;
float src_y_coord_scale;

View File

@@ -13,6 +13,7 @@
#include "flutter/fml/logging.h"
#include "flutter/fml/mapping.h"
#include "impeller/entity/vk/entity_shaders_vk.h"
#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h"
#include "impeller/entity/vk/modern_shaders_vk.h"
#include "impeller/fixtures/vk/fixtures_shaders_vk.h"
#include "impeller/playground/imgui/vk/imgui_shaders_vk.h"
@@ -33,6 +34,9 @@ ShaderLibraryMappingsForPlayground() {
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
impeller_modern_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_vk_data,
impeller_framebuffer_blend_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_fixtures_shaders_vk_data,
impeller_fixtures_shaders_vk_length),

View File

@@ -12,6 +12,7 @@
#include "impeller/renderer/backend/vulkan/device_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "vulkan/vulkan_enums.hpp"
namespace impeller {
@@ -148,6 +149,7 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
allocator_.reset(allocator);
supports_memoryless_textures_ =
capabilities.SupportsDeviceTransientTextures();
supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch();
is_valid_ = true;
}
@@ -167,7 +169,8 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
PixelFormat format,
TextureUsageMask usage,
StorageMode mode,
bool supports_memoryless_textures) {
bool supports_memoryless_textures,
bool supports_framebuffer_fetch) {
vk::ImageUsageFlags vk_usage;
switch (mode) {
@@ -187,6 +190,9 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
} else {
vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
}
if (supports_framebuffer_fetch) {
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
}
}
if (usage & static_cast<TextureUsageMask>(TextureUsage::kShaderRead)) {
@@ -263,7 +269,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
const TextureDescriptor& desc,
VmaAllocator allocator,
vk::Device device,
bool supports_memoryless_textures)
bool supports_memoryless_textures,
bool supports_framebuffer_fetch)
: TextureSourceVK(desc), resource_(std::move(resource_manager)) {
FML_DCHECK(desc.format != PixelFormat::kUnknown);
TRACE_EVENT0("impeller", "CreateDeviceTexture");
@@ -281,9 +288,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
image_info.arrayLayers = ToArrayLayerCount(desc.type);
image_info.tiling = vk::ImageTiling::eOptimal;
image_info.initialLayout = vk::ImageLayout::eUndefined;
image_info.usage =
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode,
supports_memoryless_textures);
image_info.usage = ToVKImageUsageFlags(
desc.format, desc.usage, desc.storage_mode,
supports_memoryless_textures, supports_framebuffer_fetch);
image_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_nfo = {};
@@ -412,7 +419,8 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
desc, //
allocator_.get(), //
device_holder->GetDevice(), //
supports_memoryless_textures_ //
supports_memoryless_textures_, //
supports_framebuffer_fetch_ //
);
if (!source->IsValid()) {
return nullptr;

View File

@@ -33,6 +33,7 @@ class AllocatorVK final : public Allocator {
ISize max_texture_size_;
bool is_valid_ = false;
bool supports_memoryless_textures_ = false;
bool supports_framebuffer_fetch_ = false;
// TODO(jonahwilliams): figure out why CI can't create these buffer pools.
bool created_buffer_pool_ = true;
uint32_t frame_count_ = 0;

View File

@@ -11,12 +11,17 @@
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/compute_command.h"
#include "vulkan/vulkan_core.h"
namespace impeller {
// Warning: if any of the constant values or layouts are changed in the
// framebuffer fetch shader, then this input binding may need to be
// manually changed.
static constexpr size_t kMagicSubpassInputBinding = 64;
static bool BindImages(const Bindings& bindings,
Allocator& allocator,
const std::shared_ptr<CommandEncoderVK>& encoder,
@@ -117,7 +122,8 @@ static bool BindBuffers(const Bindings& bindings,
fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
const ContextVK& context,
const std::shared_ptr<CommandEncoderVK>& encoder,
const std::vector<Command>& commands) {
const std::vector<Command>& commands,
const TextureVK& input_attachment) {
if (commands.empty()) {
return std::vector<vk::DescriptorSet>{};
}
@@ -127,6 +133,7 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
// to allocate a correctly sized descriptor pool.
size_t buffer_count = 0;
size_t samplers_count = 0;
size_t subpass_count = 0;
std::vector<vk::DescriptorSetLayout> layouts;
layouts.reserve(commands.size());
@@ -134,12 +141,14 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
buffer_count += command.vertex_bindings.buffers.size();
buffer_count += command.fragment_bindings.buffers.size();
samplers_count += command.fragment_bindings.sampled_images.size();
subpass_count +=
command.pipeline->GetDescriptor().UsesSubpassInput() ? 1 : 0;
layouts.emplace_back(
PipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout());
}
auto descriptor_result =
encoder->AllocateDescriptorSets(buffer_count, samplers_count, layouts);
auto descriptor_result = encoder->AllocateDescriptorSets(
buffer_count, samplers_count, subpass_count, layouts);
if (!descriptor_result.ok()) {
return descriptor_result.status();
}
@@ -153,9 +162,9 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
std::vector<vk::DescriptorImageInfo> images;
std::vector<vk::DescriptorBufferInfo> buffers;
std::vector<vk::WriteDescriptorSet> writes;
images.reserve(samplers_count);
images.reserve(samplers_count + subpass_count);
buffers.reserve(buffer_count);
writes.reserve(samplers_count + buffer_count);
writes.reserve(samplers_count + buffer_count + subpass_count);
auto& allocator = *context.GetResourceAllocator();
auto desc_index = 0u;
@@ -173,6 +182,23 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
return fml::Status(fml::StatusCode::kUnknown,
"Failed to bind texture or buffer.");
}
if (command.pipeline->GetDescriptor().UsesSubpassInput()) {
vk::DescriptorImageInfo image_info;
image_info.imageLayout = vk::ImageLayout::eGeneral;
image_info.sampler = VK_NULL_HANDLE;
image_info.imageView = input_attachment.GetImageView();
images.push_back(image_info);
vk::WriteDescriptorSet write_set;
write_set.dstSet = descriptor_sets[desc_index];
write_set.dstBinding = kMagicSubpassInputBinding;
write_set.descriptorCount = 1u;
write_set.descriptorType = vk::DescriptorType::eInputAttachment;
write_set.pImageInfo = &images.back();
writes.push_back(write_set);
}
desc_index += 1;
}
@@ -203,7 +229,7 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
ComputePipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout());
}
auto descriptor_result =
encoder->AllocateDescriptorSets(buffer_count, samplers_count, layouts);
encoder->AllocateDescriptorSets(buffer_count, samplers_count, 0, layouts);
if (!descriptor_result.ok()) {
return descriptor_result.status();
}

View File

@@ -8,6 +8,7 @@
#include "fml/status_or.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "impeller/renderer/command.h"
#include "impeller/renderer/compute_command.h"
@@ -16,7 +17,8 @@ namespace impeller {
fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
const ContextVK& context,
const std::shared_ptr<CommandEncoderVK>& encoder,
const std::vector<Command>& commands);
const std::vector<Command>& commands,
const TextureVK& input_attachment);
fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
const ContextVK& context,

View File

@@ -9,6 +9,7 @@
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "vulkan/vulkan_core.h"
namespace impeller {
@@ -156,6 +157,10 @@ static const char* GetDeviceExtensionName(OptionalDeviceExtensionVK ext) {
switch (ext) {
case OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback:
return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
case OptionalDeviceExtensionVK::kARMRasterizationOrderAttachmentAccess:
return VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME;
case OptionalDeviceExtensionVK::kEXTRasterizationOrderAttachmentAccess:
return VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME;
case OptionalDeviceExtensionVK::kLast:
return "Unknown";
}
@@ -401,6 +406,18 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
});
}
{
supports_framebuffer_fetch_ =
(optional_device_extensions_.find(
OptionalDeviceExtensionVK::
kARMRasterizationOrderAttachmentAccess) !=
optional_device_extensions_.end() ||
optional_device_extensions_.find(
OptionalDeviceExtensionVK::
kEXTRasterizationOrderAttachmentAccess) !=
optional_device_extensions_.end());
}
return true;
}
@@ -431,7 +448,7 @@ bool CapabilitiesVK::SupportsTextureToTextureBlits() const {
// |Capabilities|
bool CapabilitiesVK::SupportsFramebufferFetch() const {
return false;
return supports_framebuffer_fetch_;
}
// |Capabilities|

View File

@@ -10,7 +10,6 @@
#include <string>
#include <vector>
#include "flutter/fml/macros.h"
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "impeller/renderer/capabilities.h"
@@ -22,6 +21,8 @@ class ContextVK;
enum class OptionalDeviceExtensionVK : uint32_t {
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_creation_feedback.html
kEXTPipelineCreationFeedback,
kARMRasterizationOrderAttachmentAccess,
kEXTRasterizationOrderAttachmentAccess,
kLast,
};
@@ -110,6 +111,7 @@ class CapabilitiesVK final : public Capabilities,
vk::PhysicalDeviceProperties device_properties_;
bool supports_compute_subgroups_ = false;
bool supports_device_transient_textures_ = false;
bool supports_framebuffer_fetch_ = false;
bool is_valid_ = false;
bool HasExtension(const std::string& ext) const;

View File

@@ -298,13 +298,14 @@ fml::StatusOr<std::vector<vk::DescriptorSet>>
CommandEncoderVK::AllocateDescriptorSets(
uint32_t buffer_count,
uint32_t sampler_count,
uint32_t subpass_count,
const std::vector<vk::DescriptorSetLayout>& layouts) {
if (!IsValid()) {
return fml::Status(fml::StatusCode::kUnknown, "command encoder invalid");
}
return tracked_objects_->GetDescriptorPool().AllocateDescriptorSets(
buffer_count, sampler_count, layouts);
buffer_count, sampler_count, subpass_count, layouts);
}
void CommandEncoderVK::PushDebugGroup(const char* label) const {

View File

@@ -84,6 +84,7 @@ class CommandEncoderVK {
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);
private:

View File

@@ -9,6 +9,7 @@
#include "impeller/base/allocation.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
#include "vulkan/vulkan_enums.hpp"
#include "vulkan/vulkan_handles.hpp"
namespace impeller {
@@ -82,12 +83,14 @@ fml::StatusOr<std::vector<vk::DescriptorSet>>
DescriptorPoolVK::AllocateDescriptorSets(
uint32_t buffer_count,
uint32_t sampler_count,
uint32_t subpass_count,
const std::vector<vk::DescriptorSetLayout>& layouts) {
std::shared_ptr<const ContextVK> strong_context = context_.lock();
if (!strong_context) {
return fml::Status(fml::StatusCode::kUnknown, "No device");
}
auto minimum_capacity = std::max(sampler_count, buffer_count);
auto minimum_capacity =
std::max(std::max(sampler_count, buffer_count), subpass_count);
auto [new_pool, capacity] =
strong_context->GetDescriptorPoolRecycler()->Get(minimum_capacity);
if (!new_pool) {
@@ -185,6 +188,8 @@ DescriptorPoolAndSize DescriptorPoolRecyclerVK::Create(
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer,
minimum_capacity},
vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer,
minimum_capacity},
vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment,
minimum_capacity}};
vk::DescriptorPoolCreateInfo pool_info;
pool_info.setMaxSets(minimum_capacity + minimum_capacity);

View File

@@ -32,6 +32,7 @@ class DescriptorPoolVK {
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);
private:

View File

@@ -66,7 +66,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimMakesDescriptorPoolAvailable) {
{
// Fetch a pool (which will be created).
auto pool = DescriptorPoolVK(context);
pool.AllocateDescriptorSets(1024, 1024, {});
pool.AllocateDescriptorSets(1024, 1024, 1024, {});
}
// There is a chance that the first death rattle item below is destroyed in
@@ -106,7 +106,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) {
std::vector<std::unique_ptr<DescriptorPoolVK>> pools;
for (auto i = 0u; i < 33; i++) {
auto pool = std::make_unique<DescriptorPoolVK>(context);
pool->AllocateDescriptorSets(1024, 1024, {});
pool->AllocateDescriptorSets(1024, 1024, 1024, {});
pools.push_back(std::move(pool));
}
}
@@ -135,7 +135,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) {
std::vector<std::unique_ptr<DescriptorPoolVK>> pools;
for (auto i = 0u; i < 33; i++) {
auto pool = std::make_unique<DescriptorPoolVK>(context);
pool->AllocateDescriptorSets(1024, 1024, {});
pool->AllocateDescriptorSets(1024, 1024, 1024, {});
pools.push_back(std::move(pool));
}
}

View File

@@ -11,6 +11,7 @@
#include "impeller/core/formats.h"
#include "impeller/core/shader_types.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "vulkan/vulkan_enums.hpp"
namespace impeller {
@@ -281,6 +282,8 @@ constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type) {
case DescriptorType::kSampler:
return vk::DescriptorType::eSampler;
break;
case DescriptorType::kInputAttachment:
return vk::DescriptorType::eInputAttachment;
}
FML_UNREACHABLE();
@@ -427,7 +430,8 @@ constexpr vk::AttachmentDescription CreateAttachmentDescription(
SampleCount sample_count,
LoadAction load_action,
StoreAction store_action,
vk::ImageLayout current_layout) {
vk::ImageLayout current_layout,
bool supports_framebuffer_fetch) {
vk::AttachmentDescription vk_attachment;
vk_attachment.format = ToVKImageFormat(format);
@@ -466,7 +470,11 @@ constexpr vk::AttachmentDescription CreateAttachmentDescription(
switch (kind) {
case AttachmentKind::kColor:
vk_attachment.initialLayout = current_layout;
vk_attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal;
if (supports_framebuffer_fetch) {
vk_attachment.finalLayout = vk::ImageLayout::eGeneral;
} else {
vk_attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal;
}
break;
case AttachmentKind::kDepth:
case AttachmentKind::kStencil:

View File

@@ -19,6 +19,8 @@
#include "impeller/renderer/backend/vulkan/pipeline_vk.h"
#include "impeller/renderer/backend/vulkan/shader_function_vk.h"
#include "impeller/renderer/backend/vulkan/vertex_descriptor_vk.h"
#include "vulkan/vulkan_core.h"
#include "vulkan/vulkan_enums.hpp"
namespace impeller {
@@ -28,6 +30,7 @@ PipelineLibraryVK::PipelineLibraryVK(
fml::UniqueFD cache_directory,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
: device_holder_(device_holder),
supports_framebuffer_fetch_(caps->SupportsFramebufferFetch()),
pso_cache_(std::make_shared<PipelineCacheVK>(std::move(caps),
device_holder,
std::move(cache_directory))),
@@ -60,11 +63,12 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription(
SampleCount sample_count) {
// Load store ops are immaterial for pass compatibility. The right ops will be
// picked up when the pass associated with framebuffer.
return CreateAttachmentDescription(format, //
sample_count, //
LoadAction::kDontCare, //
StoreAction::kDontCare, //
vk::ImageLayout::eUndefined //
return CreateAttachmentDescription(format, //
sample_count, //
LoadAction::kDontCare, //
StoreAction::kDontCare, //
vk::ImageLayout::eUndefined, //
false //
);
}
@@ -78,10 +82,12 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription(
///
static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(
const vk::Device& device,
const PipelineDescriptor& desc) {
const PipelineDescriptor& desc,
bool supports_framebuffer_fetch) {
std::vector<vk::AttachmentDescription> attachments;
std::vector<vk::AttachmentReference> color_refs;
std::vector<vk::AttachmentReference> subpass_color_ref;
vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference;
color_refs.resize(desc.GetMaxColorAttacmentBindIndex() + 1,
@@ -96,6 +102,8 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(
attachments.emplace_back(
CreatePlaceholderAttachmentDescription(color.format, sample_count));
}
subpass_color_ref.push_back(vk::AttachmentReference{
static_cast<uint32_t>(0), vk::ImageLayout::eColorAttachmentOptimal});
if (auto depth = desc.GetDepthStencilAttachmentDescriptor();
depth.has_value()) {
@@ -115,6 +123,17 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(
vk::SubpassDescription subpass_desc;
subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
// If the device supports framebuffer fetch, compatibility pipelines are
// always created with the self reference and rasterization order flag. This
// ensures that all compiled pipelines are compatible with a render pass that
// contains a framebuffer fetch shader (advanced blends).
std::vector<vk::SubpassDependency> subpass_dependencies;
if (supports_framebuffer_fetch) {
subpass_desc.setFlags(vk::SubpassDescriptionFlagBits::
eRasterizationOrderAttachmentColorAccessARM);
subpass_desc.setInputAttachments(subpass_color_ref);
}
subpass_desc.setColorAttachments(color_refs);
subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);
@@ -122,6 +141,7 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(
render_pass_desc.setAttachments(attachments);
render_pass_desc.setPSubpasses(&subpass_desc);
render_pass_desc.setSubpassCount(1u);
render_pass_desc.setDependencies(subpass_dependencies);
auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
if (result != vk::Result::eSuccess) {
@@ -368,8 +388,8 @@ std::unique_ptr<PipelineVK> PipelineLibraryVK::CreatePipeline(
return nullptr;
}
auto render_pass =
CreateCompatRenderPassForPipeline(strong_device->GetDevice(), desc);
auto render_pass = CreateCompatRenderPassForPipeline(
strong_device->GetDevice(), desc, supports_framebuffer_fetch_);
if (render_pass) {
pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
pipeline_info.setSubpass(0);

View File

@@ -35,6 +35,7 @@ class PipelineLibraryVK final
friend ContextVK;
std::weak_ptr<DeviceHolder> device_holder_;
bool supports_framebuffer_fetch_ = false;
std::shared_ptr<PipelineCacheVK> pso_cache_;
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner_;
Mutex pipelines_mutex_;

View File

@@ -6,7 +6,6 @@
#include <memory>
#include "flutter/fml/macros.h"
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/backend/vulkan/device_holder.h"
#include "impeller/renderer/backend/vulkan/vk.h"

View File

@@ -21,6 +21,7 @@
#include "impeller/renderer/backend/vulkan/pipeline_vk.h"
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
#include "impeller/renderer/backend/vulkan/texture_vk.h"
#include "vulkan/vulkan_enums.hpp"
#include "vulkan/vulkan_handles.hpp"
#include "vulkan/vulkan_to_string.hpp"
@@ -28,7 +29,8 @@ namespace impeller {
static vk::AttachmentDescription CreateAttachmentDescription(
const Attachment& attachment,
const std::shared_ptr<Texture> Attachment::*texture_ptr) {
const std::shared_ptr<Texture> Attachment::*texture_ptr,
bool supports_framebuffer_fetch) {
const auto& texture = attachment.*texture_ptr;
if (!texture) {
return {};
@@ -50,6 +52,7 @@ static vk::AttachmentDescription CreateAttachmentDescription(
store_action = StoreAction::kStore;
}
// Always insert a barrier to transition to color attachment optimal.
if (current_layout != vk::ImageLayout::ePresentSrcKHR &&
current_layout != vk::ImageLayout::eUndefined) {
// Note: This should incur a barrier.
@@ -60,7 +63,8 @@ static vk::AttachmentDescription CreateAttachmentDescription(
desc.sample_count, //
load_action, //
store_action, //
current_layout //
current_layout,
supports_framebuffer_fetch //
);
}
@@ -96,7 +100,8 @@ static void SetTextureLayout(
SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
const ContextVK& context,
const std::shared_ptr<CommandBufferVK>& command_buffer) const {
const std::shared_ptr<CommandBufferVK>& command_buffer,
bool supports_framebuffer_fetch) const {
std::vector<vk::AttachmentDescription> attachments;
std::vector<vk::AttachmentReference> color_refs;
@@ -117,18 +122,22 @@ SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
kUnusedAttachmentReference);
for (const auto& [bind_point, color] : render_target_.GetColorAttachments()) {
color_refs[bind_point] =
vk::AttachmentReference{static_cast<uint32_t>(attachments.size()),
vk::ImageLayout::eColorAttachmentOptimal};
attachments.emplace_back(
CreateAttachmentDescription(color, &Attachment::texture));
color_refs[bind_point] = vk::AttachmentReference{
static_cast<uint32_t>(attachments.size()),
supports_framebuffer_fetch ? vk::ImageLayout::eGeneral
: vk::ImageLayout::eColorAttachmentOptimal};
attachments.emplace_back(CreateAttachmentDescription(
color, &Attachment::texture, supports_framebuffer_fetch));
SetTextureLayout(color, attachments.back(), command_buffer,
&Attachment::texture);
if (color.resolve_texture) {
resolve_refs[bind_point] = vk::AttachmentReference{
static_cast<uint32_t>(attachments.size()), vk::ImageLayout::eGeneral};
attachments.emplace_back(
CreateAttachmentDescription(color, &Attachment::resolve_texture));
static_cast<uint32_t>(attachments.size()),
supports_framebuffer_fetch
? vk::ImageLayout::eGeneral
: vk::ImageLayout::eColorAttachmentOptimal};
attachments.emplace_back(CreateAttachmentDescription(
color, &Attachment::resolve_texture, supports_framebuffer_fetch));
SetTextureLayout(color, attachments.back(), command_buffer,
&Attachment::resolve_texture);
}
@@ -138,8 +147,8 @@ SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
depth_stencil_ref = vk::AttachmentReference{
static_cast<uint32_t>(attachments.size()),
vk::ImageLayout::eDepthStencilAttachmentOptimal};
attachments.emplace_back(
CreateAttachmentDescription(depth.value(), &Attachment::texture));
attachments.emplace_back(CreateAttachmentDescription(
depth.value(), &Attachment::texture, supports_framebuffer_fetch));
SetTextureLayout(depth.value(), attachments.back(), command_buffer,
&Attachment::texture);
}
@@ -149,8 +158,8 @@ SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
depth_stencil_ref = vk::AttachmentReference{
static_cast<uint32_t>(attachments.size()),
vk::ImageLayout::eDepthStencilAttachmentOptimal};
attachments.emplace_back(
CreateAttachmentDescription(stencil.value(), &Attachment::texture));
attachments.emplace_back(CreateAttachmentDescription(
stencil.value(), &Attachment::texture, supports_framebuffer_fetch));
SetTextureLayout(stencil.value(), attachments.back(), command_buffer,
&Attachment::texture);
}
@@ -161,6 +170,16 @@ SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
subpass_desc.setResolveAttachments(resolve_refs);
subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);
std::vector<vk::SubpassDependency> subpass_dependencies;
std::vector<vk::AttachmentReference> subpass_color_ref;
subpass_color_ref.push_back(vk::AttachmentReference{
static_cast<uint32_t>(0), vk::ImageLayout::eColorAttachmentOptimal});
if (supports_framebuffer_fetch) {
subpass_desc.setFlags(vk::SubpassDescriptionFlagBits::
eRasterizationOrderAttachmentColorAccessARM);
subpass_desc.setInputAttachments(subpass_color_ref);
}
vk::RenderPassCreateInfo render_pass_desc;
render_pass_desc.setAttachments(attachments);
render_pass_desc.setPSubpasses(&subpass_desc);
@@ -245,7 +264,6 @@ SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
const auto target_size = render_target_.GetRenderTargetSize();
fb_info.width = target_size.width;
fb_info.height = target_size.height;
fb_info.layers = 1u;
std::vector<vk::ImageView> attachments;
@@ -490,7 +508,9 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
const auto& target_size = render_target_.GetRenderTargetSize();
auto render_pass = CreateVKRenderPass(vk_context, command_buffer);
auto render_pass = CreateVKRenderPass(
vk_context, command_buffer,
vk_context.GetCapabilities()->SupportsFramebufferFetch());
if (!render_pass) {
VALIDATION_LOG << "Could not create renderpass.";
return false;
@@ -516,8 +536,10 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
static_cast<uint32_t>(target_size.height);
pass_info.setClearValues(clear_values);
auto desc_sets_result =
AllocateAndBindDescriptorSets(vk_context, encoder, commands_);
const auto& color_image_vk = TextureVK::Cast(
*render_target_.GetColorAttachments().find(0u)->second.texture);
auto desc_sets_result = AllocateAndBindDescriptorSets(
vk_context, encoder, commands_, color_image_vk);
if (!desc_sets_result.ok()) {
return false;
}

View File

@@ -43,7 +43,8 @@ class RenderPassVK final : public RenderPass {
SharedHandleVK<vk::RenderPass> CreateVKRenderPass(
const ContextVK& context,
const std::shared_ptr<CommandBufferVK>& command_buffer) const;
const std::shared_ptr<CommandBufferVK>& command_buffer,
bool has_subpass_dependency) const;
SharedHandleVK<vk::Framebuffer> CreateVKFramebuffer(
const ContextVK& context,

View File

@@ -7,7 +7,6 @@
#include <future>
#include "compute_pipeline_descriptor.h"
#include "flutter/fml/macros.h"
#include "impeller/renderer/compute_pipeline_builder.h"
#include "impeller/renderer/compute_pipeline_descriptor.h"
#include "impeller/renderer/context.h"

View File

@@ -45,6 +45,7 @@ std::size_t PipelineDescriptor::GetHash() const {
fml::HashCombineSeed(seed, cull_mode_);
fml::HashCombineSeed(seed, primitive_type_);
fml::HashCombineSeed(seed, polygon_mode_);
fml::HashCombineSeed(seed, use_subpass_input_);
return seed;
}
@@ -65,7 +66,8 @@ bool PipelineDescriptor::IsEqual(const PipelineDescriptor& other) const {
cull_mode_ == other.cull_mode_ &&
primitive_type_ == other.primitive_type_ &&
polygon_mode_ == other.polygon_mode_ &&
specialization_constants_ == other.specialization_constants_;
specialization_constants_ == other.specialization_constants_ &&
use_subpass_input_ == other.use_subpass_input_;
}
PipelineDescriptor& PipelineDescriptor::SetLabel(std::string label) {

View File

@@ -20,6 +20,11 @@ class VertexDescriptor;
template <typename T>
class Pipeline;
enum class UseSubpassInput {
kYes,
kNo,
};
class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
public:
PipelineDescriptor();
@@ -128,6 +133,17 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
const std::vector<Scalar>& GetSpecializationConstants() const;
void SetUseSubpassInput(UseSubpassInput value) { use_subpass_input_ = value; }
bool UsesSubpassInput() const {
switch (use_subpass_input_) {
case UseSubpassInput::kYes:
return true;
case UseSubpassInput::kNo:
return false;
}
}
private:
std::string label_;
SampleCount sample_count_ = SampleCount::kCount1;
@@ -146,6 +162,7 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
back_stencil_attachment_descriptor_;
PrimitiveType primitive_type_ = PrimitiveType::kTriangle;
PolygonMode polygon_mode_ = PolygonMode::kFill;
UseSubpassInput use_subpass_input_ = UseSubpassInput::kNo;
std::vector<Scalar> specialization_constants_;
};

View File

@@ -6,6 +6,7 @@
#include "flutter/fml/paths.h"
#include "flutter/impeller/entity/vk/entity_shaders_vk.h"
#include "flutter/impeller/entity/vk/framebuffer_blend_shaders_vk.h"
#include "flutter/impeller/entity/vk/modern_shaders_vk.h"
#include "flutter/impeller/renderer/backend/vulkan/context_vk.h"
@@ -19,14 +20,17 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
const fml::RefPtr<vulkan::VulkanProcTable>& proc_table,
bool enable_vulkan_validation) {
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_vk_data,
impeller_framebuffer_blend_shaders_vk_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_vk_data,
impeller_scene_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_vk_data,
impeller_scene_shaders_vk_length),
#endif
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
impeller_modern_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
impeller_modern_shaders_vk_length),
};
PFN_vkGetInstanceProcAddr instance_proc_addr =

View File

@@ -37,6 +37,7 @@
#include "flutter/vulkan/procs/vulkan_proc_table.h" // nogncheck
#include "flutter/vulkan/swiftshader_path.h" // nogncheck
#include "impeller/entity/vk/entity_shaders_vk.h" // nogncheck
#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h" // nogncheck
#include "impeller/entity/vk/modern_shaders_vk.h" // nogncheck
#include "impeller/renderer/backend/vulkan/context_vk.h" // nogncheck
#include "impeller/renderer/backend/vulkan/surface_context_vk.h" // nogncheck
@@ -53,6 +54,9 @@ static std::vector<std::shared_ptr<fml::Mapping>> ShaderLibraryMappings() {
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
impeller_modern_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_vk_data,
impeller_framebuffer_blend_shaders_vk_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_vk_data,
impeller_scene_shaders_vk_length),