Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Implement framebuffer-fetch via subpasses in Vulkan without extensions. #49787

Closed
wants to merge 4 commits into from
Closed
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
4 changes: 0 additions & 4 deletions impeller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ config("impeller_public_config") {
defines += [ "IMPELLER_ENABLE_VULKAN=1" ]
}

if (impeller_enable_vulkan_playgrounds) {
defines += [ "IMPELLER_ENABLE_VULKAN_PLAYGROUNDS=1" ]
}

if (impeller_trace_all_gl_calls) {
defines += [ "IMPELLER_TRACE_ALL_GL_CALLS" ]
}
Expand Down
45 changes: 15 additions & 30 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,64 +223,49 @@ ContentContext::ContentContext(
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
framebuffer_blend_color_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
framebuffer_blend_colorburn_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
framebuffer_blend_colordodge_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
framebuffer_blend_darken_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
framebuffer_blend_difference_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
framebuffer_blend_exclusion_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
framebuffer_blend_hardlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
framebuffer_blend_hue_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
framebuffer_blend_lighten_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
framebuffer_blend_luminosity_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
framebuffer_blend_multiply_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
framebuffer_blend_overlay_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
framebuffer_blend_saturation_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
framebuffer_blend_screen_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
framebuffer_blend_softlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal},
UseSubpassInput::kYes);
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
}

blend_color_pipelines_.CreateDefault(
Expand Down
4 changes: 1 addition & 3 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -799,15 +799,13 @@ class ContentContext {

void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::initializer_list<Scalar>& constants = {},
UseSubpassInput subpass_input = UseSubpassInput::kNo) {
const std::initializer_list<Scalar>& constants = {}) {
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));
}
Expand Down
33 changes: 0 additions & 33 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2577,39 +2577,6 @@ 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());
}

// This doesn't really tell you if the hashes will have frequent
// collisions, but since this type is only used to hash a bounded
// set of options, we can just compare benchmarks.
Expand Down
14 changes: 11 additions & 3 deletions impeller/fixtures/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import("//flutter/testing/testing.gni")
impeller_shaders("shader_fixtures") {
name = "fixtures"

# 2.3 adds support for framebuffer fetch in Metal.
metal_version = "2.3"

# Not analyzing because they are not performance critical, and mipmap uses
# textureLod, which uses an extension that malioc does not support.
analyze = false
Expand All @@ -16,8 +19,9 @@ impeller_shaders("shader_fixtures") {
"array.vert",
"box_fade.frag",
"box_fade.vert",
"colors.vert",
"colors.frag",
"colors.vert",
"half.frag",
"impeller.frag",
"impeller.vert",
"inactive_uniforms.frag",
Expand All @@ -27,12 +31,16 @@ impeller_shaders("shader_fixtures") {
"mipmaps.frag",
"mipmaps.vert",
"sample.comp",
"sepia.frag",
"sepia.vert",
"simple.vert",
"stage1.comp",
"stage2.comp",
"simple.vert",
"swizzle.frag",
"test_texture.frag",
"test_texture.vert",
"half.frag",
"texture.frag",
"texture.vert",
]

if (impeller_enable_opengles) {
Expand Down
17 changes: 17 additions & 0 deletions impeller/fixtures/sepia.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

out vec4 frag_color;

layout(input_attachment_index = 0) uniform subpassInputMS subpass_input;

void main() {
// https://github.com/chinmaygarde/merle/blob/3eecb311ac8862c41f0c53a5d9b360be923142bb/src/texture.cc#L195
const mat4 sepia_matrix = mat4(0.3588, 0.2990, 0.2392, 0.0000, //
0.7044, 0.5870, 0.4696, 0.0000, //
0.1368, 0.1140, 0.0912, 0.0000, //
0.0000, 0.0000, 0.0000, 1.0000 //
);
frag_color = sepia_matrix * subpassLoad(subpass_input, 0);
}
14 changes: 14 additions & 0 deletions impeller/fixtures/sepia.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

uniform UniformBuffer {
mat4 mvp;
}
uniform_buffer;

in vec3 vertex_position;

void main() {
gl_Position = uniform_buffer.mvp * vec4(vertex_position, 1.0);
}
11 changes: 11 additions & 0 deletions impeller/fixtures/swizzle.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

out vec4 frag_color;

layout(input_attachment_index = 0) uniform subpassInputMS subpass_input;

void main() {
frag_color = subpassLoad(subpass_input, 0).gbra;
}
13 changes: 13 additions & 0 deletions impeller/fixtures/texture.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

in vec2 interporlated_texture_coordinates;

out vec4 frag_color;

uniform sampler2D texture_contents;

void main() {
frag_color = texture(texture_contents, interporlated_texture_coordinates);
}
18 changes: 18 additions & 0 deletions impeller/fixtures/texture.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

uniform UniformBuffer {
mat4 mvp;
}
uniform_buffer;

in vec3 vertex_position;
in vec2 texture_coordinates;

out vec2 interpolated_texture_coordinates;

void main() {
gl_Position = uniform_buffer.mvp * vec4(vertex_position, 1.0);
interpolated_texture_coordinates = texture_coordinates;
}
34 changes: 31 additions & 3 deletions impeller/playground/backend/vulkan/playground_impl_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,38 @@ void PlaygroundImplVK::InitGlobalVulkanInstance() {
application_info.setPEngineName("PlaygroundImplVK");
application_info.setPApplicationName("PlaygroundImplVK");

auto instance_result =
vk::createInstanceUnique(vk::InstanceCreateInfo({}, &application_info));
CapabilitiesVK caps(false);
auto enabled_layers = caps.GetEnabledLayers();
auto enabled_extensions = caps.GetEnabledInstanceExtensions();

FML_CHECK(enabled_layers.has_value() && enabled_extensions.has_value());

std::vector<const char*> enabled_layers_c;
std::vector<const char*> enabled_extensions_c;

for (const auto& layer : enabled_layers.value()) {
enabled_layers_c.push_back(layer.c_str());
}

for (const auto& ext : enabled_extensions.value()) {
enabled_extensions_c.push_back(ext.c_str());
}

vk::InstanceCreateInfo instance_info;
instance_info.setPEnabledLayerNames(enabled_layers_c);
instance_info.setPEnabledExtensionNames(enabled_extensions_c);
instance_info.setPApplicationInfo(&application_info);

if (std::find(enabled_extensions->begin(), enabled_extensions->end(),
"VK_KHR_portability_enumeration") !=
enabled_extensions->end()) {
instance_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
}

auto instance_result = vk::createInstanceUnique(instance_info);
FML_CHECK(instance_result.result == vk::Result::eSuccess)
<< "Unable to initialize global Vulkan instance";
<< "Unable to initialize global Vulkan instance: "
<< vk::to_string(instance_result.result);
global_instance_ = std::move(instance_result.value);
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/playground/playground.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bool Playground::SupportsBackend(PlaygroundBackend backend) {
return false;
#endif // IMPELLER_ENABLE_OPENGLES
case PlaygroundBackend::kVulkan:
#if IMPELLER_ENABLE_VULKAN && IMPELLER_ENABLE_VULKAN_PLAYGROUNDS
#if IMPELLER_ENABLE_VULKAN
return true;
#else // IMPELLER_ENABLE_VULKAN
return false;
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/vulkan/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ impeller_component("vulkan") {
"pipeline_vk.h",
"queue_vk.cc",
"queue_vk.h",
"render_pass_builder_vk.cc",
"render_pass_builder_vk.h",
"render_pass_vk.cc",
"render_pass_vk.h",
"resource_manager_vk.cc",
Expand Down
20 changes: 7 additions & 13 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
allocator_.reset(allocator);
supports_memoryless_textures_ =
capabilities.SupportsDeviceTransientTextures();
supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch();
is_valid_ = true;
}

Expand All @@ -167,8 +166,7 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
PixelFormat format,
TextureUsageMask usage,
StorageMode mode,
bool supports_memoryless_textures,
bool supports_framebuffer_fetch) {
bool supports_memoryless_textures) {
vk::ImageUsageFlags vk_usage;

switch (mode) {
Expand All @@ -188,9 +186,7 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
} else {
vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
}
if (supports_framebuffer_fetch) {
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
}
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
}

if (usage & static_cast<TextureUsageMask>(TextureUsage::kShaderRead)) {
Expand Down Expand Up @@ -267,8 +263,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
const TextureDescriptor& desc,
VmaAllocator allocator,
vk::Device device,
bool supports_memoryless_textures,
bool supports_framebuffer_fetch)
bool supports_memoryless_textures)
: TextureSourceVK(desc), resource_(std::move(resource_manager)) {
FML_DCHECK(desc.format != PixelFormat::kUnknown);
vk::ImageCreateInfo image_info;
Expand All @@ -285,9 +280,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, supports_framebuffer_fetch);
image_info.usage =
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode,
supports_memoryless_textures);
image_info.sharingMode = vk::SharingMode::eExclusive;

VmaAllocationCreateInfo alloc_nfo = {};
Expand Down Expand Up @@ -415,8 +410,7 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
desc, //
allocator_.get(), //
device_holder->GetDevice(), //
supports_memoryless_textures_, //
supports_framebuffer_fetch_ //
supports_memoryless_textures_ //
);
if (!source->IsValid()) {
return nullptr;
Expand Down
1 change: 0 additions & 1 deletion impeller/renderer/backend/vulkan/allocator_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ 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;
Expand Down
Loading