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

Commit f4fbabf

Browse files
authored
[Impeller] Implement framebuffer-fetch via subpasses in Vulkan without extensions. (#50154)
* Subpasses are not exposed in the HAL and the need for subpasses in Vulkan can be determined based on the presence and use of input-attachments in the shaders. This information is already reflected by the compiler. Because of this, all references to subpasses have been removed from APIs above the HAL. * `RenderPassBuilderVK` is a lightweight object used to generate render passes to use either with the pipelines (compat, base, or per-subpass) or during rendering along with the framebuffer. Using the builder also sets up the right subpass dependencies. As long as the builder contains compatible attachments and subpass counts, different subpasses stamped by the builder (via the `Build` method) are guaranteed to be compatible per the rules in the spec. * Pass attachments are now in the `eGeneral` layout. There was no observable difference in performance when manually inserting the right transitions. Except, a lot of transitions needed to be inserted. If we need it, we can add it back in short order. I wouldn't be averse to adding it if reviewers insist. * Additional pipeline state objects need not be created as the sub-pass self-dependencies are sufficient to setup the render-pass. * Speaking of the `rasterization_order_attachment_access` extension, its use has been removed in this patch. I am prototyping adding it back to measure the overhead introduced by manual subpass management. If the overhead is measurable, we can use the extension on devices that have it as an added optimization. * The complexity of command encoding remains linear (to the number of commands) per pass. * This patch only works on a single color attachment being used as an input attachment. While this is sufficient for current use cases, the Metal implementation is significantly more capable since the multiple attachments and attachment types (depth) are already supported. Rounding out support for this is in progress.
1 parent c4247c5 commit f4fbabf

36 files changed

+1195
-914
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5478,6 +5478,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.cc + ../..
54785478
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.h + ../../../flutter/LICENSE
54795479
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.cc + ../../../flutter/LICENSE
54805480
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.h + ../../../flutter/LICENSE
5481+
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc + ../../../flutter/LICENSE
5482+
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.h + ../../../flutter/LICENSE
54815483
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc + ../../../flutter/LICENSE
54825484
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.h + ../../../flutter/LICENSE
54835485
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk.cc + ../../../flutter/LICENSE
@@ -8335,6 +8337,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.cc
83358337
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_vk.h
83368338
FILE: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.cc
83378339
FILE: ../../../flutter/impeller/renderer/backend/vulkan/queue_vk.h
8340+
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.cc
8341+
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_builder_vk.h
83388342
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc
83398343
FILE: ../../../flutter/impeller/renderer/backend/vulkan/render_pass_vk.h
83408344
FILE: ../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk.cc

impeller/entity/contents/content_context.cc

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -240,64 +240,49 @@ ContentContext::ContentContext(
240240
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
241241
framebuffer_blend_color_pipelines_.CreateDefault(
242242
*context_, options_trianglestrip,
243-
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal},
244-
UseSubpassInput::kYes);
243+
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
245244
framebuffer_blend_colorburn_pipelines_.CreateDefault(
246245
*context_, options_trianglestrip,
247-
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal},
248-
UseSubpassInput::kYes);
246+
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
249247
framebuffer_blend_colordodge_pipelines_.CreateDefault(
250248
*context_, options_trianglestrip,
251-
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal},
252-
UseSubpassInput::kYes);
249+
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
253250
framebuffer_blend_darken_pipelines_.CreateDefault(
254251
*context_, options_trianglestrip,
255-
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal},
256-
UseSubpassInput::kYes);
252+
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
257253
framebuffer_blend_difference_pipelines_.CreateDefault(
258254
*context_, options_trianglestrip,
259-
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal},
260-
UseSubpassInput::kYes);
255+
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
261256
framebuffer_blend_exclusion_pipelines_.CreateDefault(
262257
*context_, options_trianglestrip,
263-
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal},
264-
UseSubpassInput::kYes);
258+
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
265259
framebuffer_blend_hardlight_pipelines_.CreateDefault(
266260
*context_, options_trianglestrip,
267-
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal},
268-
UseSubpassInput::kYes);
261+
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
269262
framebuffer_blend_hue_pipelines_.CreateDefault(
270263
*context_, options_trianglestrip,
271-
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal},
272-
UseSubpassInput::kYes);
264+
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
273265
framebuffer_blend_lighten_pipelines_.CreateDefault(
274266
*context_, options_trianglestrip,
275-
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal},
276-
UseSubpassInput::kYes);
267+
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
277268
framebuffer_blend_luminosity_pipelines_.CreateDefault(
278269
*context_, options_trianglestrip,
279-
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal},
280-
UseSubpassInput::kYes);
270+
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
281271
framebuffer_blend_multiply_pipelines_.CreateDefault(
282272
*context_, options_trianglestrip,
283-
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal},
284-
UseSubpassInput::kYes);
273+
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
285274
framebuffer_blend_overlay_pipelines_.CreateDefault(
286275
*context_, options_trianglestrip,
287-
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal},
288-
UseSubpassInput::kYes);
276+
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
289277
framebuffer_blend_saturation_pipelines_.CreateDefault(
290278
*context_, options_trianglestrip,
291-
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal},
292-
UseSubpassInput::kYes);
279+
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
293280
framebuffer_blend_screen_pipelines_.CreateDefault(
294281
*context_, options_trianglestrip,
295-
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal},
296-
UseSubpassInput::kYes);
282+
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
297283
framebuffer_blend_softlight_pipelines_.CreateDefault(
298284
*context_, options_trianglestrip,
299-
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal},
300-
UseSubpassInput::kYes);
285+
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
301286
}
302287

303288
blend_color_pipelines_.CreateDefault(

impeller/entity/contents/content_context.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -826,15 +826,13 @@ class ContentContext {
826826

827827
void CreateDefault(const Context& context,
828828
const ContentContextOptions& options,
829-
const std::initializer_list<Scalar>& constants = {},
830-
UseSubpassInput subpass_input = UseSubpassInput::kNo) {
829+
const std::initializer_list<Scalar>& constants = {}) {
831830
auto desc =
832831
PipelineT::Builder::MakeDefaultPipelineDescriptor(context, constants);
833832
if (!desc.has_value()) {
834833
VALIDATION_LOG << "Failed to create default pipeline.";
835834
return;
836835
}
837-
desc->SetUseSubpassInput(subpass_input);
838836
options.ApplyToPipelineDescriptor(*desc);
839837
SetDefault(options, std::make_unique<PipelineT>(context, desc));
840838
}

impeller/entity/entity_unittests.cc

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,39 +2689,6 @@ TEST_P(EntityTest, DecalSpecializationAppliedToMorphologyFilter) {
26892689
expected_constants);
26902690
}
26912691

2692-
TEST_P(EntityTest, FramebufferFetchPipelinesDeclareUsage) {
2693-
auto content_context =
2694-
ContentContext(GetContext(), TypographerContextSkia::Make());
2695-
if (!content_context.GetDeviceCapabilities().SupportsFramebufferFetch()) {
2696-
GTEST_SKIP() << "Framebuffer fetch not supported.";
2697-
}
2698-
2699-
ContentContextOptions options;
2700-
options.color_attachment_pixel_format = PixelFormat::kR8G8B8A8UNormInt;
2701-
auto color_burn =
2702-
content_context.GetFramebufferBlendColorBurnPipeline(options);
2703-
2704-
EXPECT_TRUE(color_burn->GetDescriptor().UsesSubpassInput());
2705-
}
2706-
2707-
TEST_P(EntityTest, PipelineDescriptorEqAndHash) {
2708-
auto desc_1 = std::make_shared<PipelineDescriptor>();
2709-
auto desc_2 = std::make_shared<PipelineDescriptor>();
2710-
2711-
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
2712-
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
2713-
2714-
desc_1->SetUseSubpassInput(UseSubpassInput::kYes);
2715-
2716-
EXPECT_FALSE(desc_1->IsEqual(*desc_2));
2717-
EXPECT_NE(desc_1->GetHash(), desc_2->GetHash());
2718-
2719-
desc_2->SetUseSubpassInput(UseSubpassInput::kYes);
2720-
2721-
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
2722-
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
2723-
}
2724-
27252692
// This doesn't really tell you if the hashes will have frequent
27262693
// collisions, but since this type is only used to hash a bounded
27272694
// set of options, we can just compare benchmarks.

impeller/fixtures/BUILD.gn

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import("//flutter/testing/testing.gni")
88
impeller_shaders("shader_fixtures") {
99
name = "fixtures"
1010

11+
# 2.3 adds support for framebuffer fetch in Metal.
12+
metal_version = "2.3"
13+
1114
# Not analyzing because they are not performance critical, and mipmap uses
1215
# textureLod, which uses an extension that malioc does not support.
1316
analyze = false
@@ -16,8 +19,9 @@ impeller_shaders("shader_fixtures") {
1619
"array.vert",
1720
"box_fade.frag",
1821
"box_fade.vert",
19-
"colors.vert",
2022
"colors.frag",
23+
"colors.vert",
24+
"half.frag",
2125
"impeller.frag",
2226
"impeller.vert",
2327
"inactive_uniforms.frag",
@@ -27,12 +31,16 @@ impeller_shaders("shader_fixtures") {
2731
"mipmaps.frag",
2832
"mipmaps.vert",
2933
"sample.comp",
34+
"sepia.frag",
35+
"sepia.vert",
36+
"simple.vert",
3037
"stage1.comp",
3138
"stage2.comp",
32-
"simple.vert",
39+
"swizzle.frag",
3340
"test_texture.frag",
3441
"test_texture.vert",
35-
"half.frag",
42+
"texture.frag",
43+
"texture.vert",
3644
]
3745

3846
if (impeller_enable_opengles) {

impeller/fixtures/sepia.frag

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
out vec4 frag_color;
6+
7+
layout(input_attachment_index = 0) uniform subpassInputMS subpass_input;
8+
9+
void main() {
10+
// https://github.com/chinmaygarde/merle/blob/3eecb311ac8862c41f0c53a5d9b360be923142bb/src/texture.cc#L195
11+
const mat4 sepia_matrix = mat4(0.3588, 0.2990, 0.2392, 0.0000, //
12+
0.7044, 0.5870, 0.4696, 0.0000, //
13+
0.1368, 0.1140, 0.0912, 0.0000, //
14+
0.0000, 0.0000, 0.0000, 1.0000 //
15+
);
16+
frag_color = sepia_matrix * subpassLoad(subpass_input, 0);
17+
}

impeller/fixtures/sepia.vert

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
uniform UniformBuffer {
6+
mat4 mvp;
7+
}
8+
uniform_buffer;
9+
10+
in vec3 vertex_position;
11+
12+
void main() {
13+
gl_Position = uniform_buffer.mvp * vec4(vertex_position, 1.0);
14+
}

impeller/fixtures/swizzle.frag

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
out vec4 frag_color;
6+
7+
layout(input_attachment_index = 0) uniform subpassInputMS subpass_input;
8+
9+
void main() {
10+
frag_color = subpassLoad(subpass_input, 0).gbra;
11+
}

impeller/fixtures/texture.frag

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
in vec2 interporlated_texture_coordinates;
6+
7+
out vec4 frag_color;
8+
9+
uniform sampler2D texture_contents;
10+
11+
void main() {
12+
frag_color = texture(texture_contents, interporlated_texture_coordinates);
13+
}

impeller/fixtures/texture.vert

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
uniform UniformBuffer {
6+
mat4 mvp;
7+
}
8+
uniform_buffer;
9+
10+
in vec3 vertex_position;
11+
in vec2 texture_coordinates;
12+
13+
out vec2 interpolated_texture_coordinates;
14+
15+
void main() {
16+
gl_Position = uniform_buffer.mvp * vec4(vertex_position, 1.0);
17+
interpolated_texture_coordinates = texture_coordinates;
18+
}

impeller/renderer/backend/vulkan/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ impeller_component("vulkan") {
7575
"pipeline_vk.h",
7676
"queue_vk.cc",
7777
"queue_vk.h",
78+
"render_pass_builder_vk.cc",
79+
"render_pass_builder_vk.h",
7880
"render_pass_vk.cc",
7981
"render_pass_vk.h",
8082
"resource_manager_vk.cc",

impeller/renderer/backend/vulkan/allocator_vk.cc

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
147147
allocator_.reset(allocator);
148148
supports_memoryless_textures_ =
149149
capabilities.SupportsDeviceTransientTextures();
150-
supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch();
151150
is_valid_ = true;
152151
}
153152

@@ -167,8 +166,7 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
167166
PixelFormat format,
168167
TextureUsageMask usage,
169168
StorageMode mode,
170-
bool supports_memoryless_textures,
171-
bool supports_framebuffer_fetch) {
169+
bool supports_memoryless_textures) {
172170
vk::ImageUsageFlags vk_usage;
173171

174172
switch (mode) {
@@ -188,9 +186,7 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
188186
} else {
189187
vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
190188
}
191-
if (supports_framebuffer_fetch) {
192-
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
193-
}
189+
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
194190
}
195191

196192
if (usage & static_cast<TextureUsageMask>(TextureUsage::kShaderRead)) {
@@ -267,8 +263,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
267263
const TextureDescriptor& desc,
268264
VmaAllocator allocator,
269265
vk::Device device,
270-
bool supports_memoryless_textures,
271-
bool supports_framebuffer_fetch)
266+
bool supports_memoryless_textures)
272267
: TextureSourceVK(desc), resource_(std::move(resource_manager)) {
273268
FML_DCHECK(desc.format != PixelFormat::kUnknown);
274269
vk::ImageCreateInfo image_info;
@@ -285,9 +280,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
285280
image_info.arrayLayers = ToArrayLayerCount(desc.type);
286281
image_info.tiling = vk::ImageTiling::eOptimal;
287282
image_info.initialLayout = vk::ImageLayout::eUndefined;
288-
image_info.usage = ToVKImageUsageFlags(
289-
desc.format, desc.usage, desc.storage_mode,
290-
supports_memoryless_textures, supports_framebuffer_fetch);
283+
image_info.usage =
284+
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode,
285+
supports_memoryless_textures);
291286
image_info.sharingMode = vk::SharingMode::eExclusive;
292287

293288
VmaAllocationCreateInfo alloc_nfo = {};
@@ -433,8 +428,7 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
433428
desc, //
434429
allocator_.get(), //
435430
device_holder->GetDevice(), //
436-
supports_memoryless_textures_, //
437-
supports_framebuffer_fetch_ //
431+
supports_memoryless_textures_ //
438432
);
439433
if (!source->IsValid()) {
440434
return nullptr;

impeller/renderer/backend/vulkan/allocator_vk.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class AllocatorVK final : public Allocator {
3434
ISize max_texture_size_;
3535
bool is_valid_ = false;
3636
bool supports_memoryless_textures_ = false;
37-
bool supports_framebuffer_fetch_ = false;
3837
// TODO(jonahwilliams): figure out why CI can't create these buffer pools.
3938
bool created_buffer_pool_ = true;
4039

impeller/renderer/backend/vulkan/barrier_vk.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ namespace impeller {
1818
/// and the Vulkan spec. The docs for the various member of this
1919
/// class are based on verbiage in the spec.
2020
///
21+
/// A useful mnemonic for building a mental model of how to add
22+
/// these barriers is to build a sentence like so; "All commands
23+
/// before this barrier may continue till they encounter a <src
24+
/// access> in the <src pipeline stage>. And, all commands after
25+
/// this barrier may proceed till <dst access> in the <dst pipeline
26+
/// stage>."
27+
///
2128
struct BarrierVK {
2229
vk::CommandBuffer cmd_buffer = {};
2330
vk::ImageLayout new_layout = vk::ImageLayout::eUndefined;

0 commit comments

Comments
 (0)