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

Commit fe96317

Browse files
author
Jonah Williams
authored
[Impeller] Vulkan framebuffer fetch via VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS (#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 flutter/flutter#120223
1 parent 87bff52 commit fe96317

31 files changed

+343
-79
lines changed

impeller/compiler/code_gen_template.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,14 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %}
173173
// ===========================================================================
174174
// Metadata for Vulkan =======================================================
175175
// ===========================================================================
176-
static constexpr std::array<DescriptorSetLayout,{{length(buffers)+length(sampled_images)}}> kDescriptorSetLayouts{
176+
static constexpr std::array<DescriptorSetLayout,{{length(buffers)+length(sampled_images)+length(subpass_inputs)}}> kDescriptorSetLayouts{
177+
{% for subpass_input in subpass_inputs %}
178+
DescriptorSetLayout{
179+
{{subpass_input.binding}}, // binding = {{subpass_input.binding}}
180+
{{subpass_input.descriptor_type}}, // descriptor_type = {{subpass_input.descriptor_type}}
181+
{{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}}
182+
},
183+
{% endfor %}
177184
{% for buffer in buffers %}
178185
DescriptorSetLayout{
179186
{{buffer.binding}}, // binding = {{buffer.binding}}

impeller/compiler/reflector.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@ std::optional<nlohmann::json> Reflector::GenerateTemplateArguments() const {
188188

189189
const auto shader_resources = compiler_->get_shader_resources();
190190

191+
// Subpass Inputs.
192+
{
193+
auto& subpass_inputs = root["subpass_inputs"] = nlohmann::json::array_t{};
194+
if (auto subpass_inputs_json =
195+
ReflectResources(shader_resources.subpass_inputs);
196+
subpass_inputs_json.has_value()) {
197+
for (auto subpass_input : subpass_inputs_json.value()) {
198+
subpass_input["descriptor_type"] = "DescriptorType::kInputAttachment";
199+
subpass_inputs.emplace_back(std::move(subpass_input));
200+
}
201+
} else {
202+
return std::nullopt;
203+
}
204+
}
205+
191206
// Uniform and storage buffers.
192207
{
193208
auto& buffers = root["buffers"] = nlohmann::json::array_t{};

impeller/core/shader_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ enum class DescriptorType {
163163
kSampledImage,
164164
kImage,
165165
kSampler,
166+
kInputAttachment,
166167
};
167168

168169
struct DescriptorSetLayout {

impeller/entity/contents/content_context.cc

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -221,49 +221,64 @@ ContentContext::ContentContext(
221221
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
222222
framebuffer_blend_color_pipelines_.CreateDefault(
223223
*context_, options_trianglestrip,
224-
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
224+
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal},
225+
UseSubpassInput::kYes);
225226
framebuffer_blend_colorburn_pipelines_.CreateDefault(
226227
*context_, options_trianglestrip,
227-
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
228+
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal},
229+
UseSubpassInput::kYes);
228230
framebuffer_blend_colordodge_pipelines_.CreateDefault(
229231
*context_, options_trianglestrip,
230-
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
232+
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal},
233+
UseSubpassInput::kYes);
231234
framebuffer_blend_darken_pipelines_.CreateDefault(
232235
*context_, options_trianglestrip,
233-
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
236+
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal},
237+
UseSubpassInput::kYes);
234238
framebuffer_blend_difference_pipelines_.CreateDefault(
235239
*context_, options_trianglestrip,
236-
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
240+
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal},
241+
UseSubpassInput::kYes);
237242
framebuffer_blend_exclusion_pipelines_.CreateDefault(
238243
*context_, options_trianglestrip,
239-
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
244+
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal},
245+
UseSubpassInput::kYes);
240246
framebuffer_blend_hardlight_pipelines_.CreateDefault(
241247
*context_, options_trianglestrip,
242-
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
248+
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal},
249+
UseSubpassInput::kYes);
243250
framebuffer_blend_hue_pipelines_.CreateDefault(
244251
*context_, options_trianglestrip,
245-
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
252+
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal},
253+
UseSubpassInput::kYes);
246254
framebuffer_blend_lighten_pipelines_.CreateDefault(
247255
*context_, options_trianglestrip,
248-
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
256+
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal},
257+
UseSubpassInput::kYes);
249258
framebuffer_blend_luminosity_pipelines_.CreateDefault(
250259
*context_, options_trianglestrip,
251-
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
260+
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal},
261+
UseSubpassInput::kYes);
252262
framebuffer_blend_multiply_pipelines_.CreateDefault(
253263
*context_, options_trianglestrip,
254-
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
264+
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal},
265+
UseSubpassInput::kYes);
255266
framebuffer_blend_overlay_pipelines_.CreateDefault(
256267
*context_, options_trianglestrip,
257-
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
268+
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal},
269+
UseSubpassInput::kYes);
258270
framebuffer_blend_saturation_pipelines_.CreateDefault(
259271
*context_, options_trianglestrip,
260-
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
272+
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal},
273+
UseSubpassInput::kYes);
261274
framebuffer_blend_screen_pipelines_.CreateDefault(
262275
*context_, options_trianglestrip,
263-
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
276+
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal},
277+
UseSubpassInput::kYes);
264278
framebuffer_blend_softlight_pipelines_.CreateDefault(
265279
*context_, options_trianglestrip,
266-
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
280+
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal},
281+
UseSubpassInput::kYes);
267282
}
268283

269284
blend_color_pipelines_.CreateDefault(

impeller/entity/contents/content_context.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "impeller/entity/entity.h"
1919
#include "impeller/renderer/capabilities.h"
2020
#include "impeller/renderer/pipeline.h"
21+
#include "impeller/renderer/pipeline_descriptor.h"
2122
#include "impeller/renderer/render_target.h"
2223
#include "impeller/typographer/typographer_context.h"
2324

@@ -713,13 +714,15 @@ class ContentContext {
713714

714715
void CreateDefault(const Context& context,
715716
const ContentContextOptions& options,
716-
const std::initializer_list<Scalar>& constants = {}) {
717+
const std::initializer_list<Scalar>& constants = {},
718+
UseSubpassInput subpass_input = UseSubpassInput::kNo) {
717719
auto desc =
718720
PipelineT::Builder::MakeDefaultPipelineDescriptor(context, constants);
719721
if (!desc.has_value()) {
720722
VALIDATION_LOG << "Failed to create default pipeline.";
721723
return;
722724
}
725+
desc->SetUseSubpassInput(subpass_input);
723726
options.ApplyToPipelineDescriptor(*desc);
724727
SetDefault(options, std::make_unique<PipelineT>(context, desc));
725728
}

impeller/entity/entity_unittests.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010

1111
#include "fml/logging.h"
1212
#include "gtest/gtest.h"
13+
#include "impeller/core/formats.h"
1314
#include "impeller/core/texture_descriptor.h"
1415
#include "impeller/entity/contents/atlas_contents.h"
1516
#include "impeller/entity/contents/clip_contents.h"
1617
#include "impeller/entity/contents/conical_gradient_contents.h"
18+
#include "impeller/entity/contents/content_context.h"
1719
#include "impeller/entity/contents/contents.h"
1820
#include "impeller/entity/contents/filters/color_filter_contents.h"
1921
#include "impeller/entity/contents/filters/filter_contents.h"
@@ -41,6 +43,7 @@
4143
#include "impeller/playground/playground.h"
4244
#include "impeller/playground/widgets.h"
4345
#include "impeller/renderer/command.h"
46+
#include "impeller/renderer/pipeline_descriptor.h"
4447
#include "impeller/renderer/render_pass.h"
4548
#include "impeller/renderer/vertex_buffer_builder.h"
4649
#include "impeller/typographer/backends/skia/text_frame_skia.h"
@@ -2527,6 +2530,63 @@ TEST_P(EntityTest, DecalSpecializationAppliedToMorphologyFilter) {
25272530
expected_constants);
25282531
}
25292532

2533+
TEST_P(EntityTest, FramebufferFetchPipelinesDeclareUsage) {
2534+
auto content_context =
2535+
ContentContext(GetContext(), TypographerContextSkia::Make());
2536+
if (!content_context.GetDeviceCapabilities().SupportsFramebufferFetch()) {
2537+
GTEST_SKIP() << "Framebuffer fetch not supported.";
2538+
}
2539+
2540+
ContentContextOptions options;
2541+
options.color_attachment_pixel_format = PixelFormat::kR8G8B8A8UNormInt;
2542+
auto color_burn =
2543+
content_context.GetFramebufferBlendColorBurnPipeline(options);
2544+
2545+
EXPECT_TRUE(color_burn->GetDescriptor().UsesSubpassInput());
2546+
}
2547+
2548+
TEST_P(EntityTest, PipelineDescriptorEqAndHash) {
2549+
auto desc_1 = std::make_shared<PipelineDescriptor>();
2550+
auto desc_2 = std::make_shared<PipelineDescriptor>();
2551+
2552+
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
2553+
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
2554+
2555+
desc_1->SetUseSubpassInput(UseSubpassInput::kYes);
2556+
2557+
EXPECT_FALSE(desc_1->IsEqual(*desc_2));
2558+
EXPECT_NE(desc_1->GetHash(), desc_2->GetHash());
2559+
2560+
desc_2->SetUseSubpassInput(UseSubpassInput::kYes);
2561+
2562+
EXPECT_TRUE(desc_1->IsEqual(*desc_2));
2563+
EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash());
2564+
}
2565+
2566+
#ifdef FML_OS_LINUX
2567+
TEST_P(EntityTest, FramebufferFetchVulkanBindingOffsetIsTheSame) {
2568+
// Using framebuffer fetch on Vulkan requires that we maintain a subpass input
2569+
// binding that we don't have a good route for configuring with the current
2570+
// metadata approach. This test verifies that the binding value doesn't change
2571+
// from the expected constant.
2572+
// See also:
2573+
// * impeller/renderer/backend/vulkan/binding_helpers_vk.cc
2574+
// * impeller/entity/shaders/blending/framebuffer_blend.frag
2575+
// This test only works on Linux because macOS hosts incorrectly populate the
2576+
// Vulkan descriptor sets based on the MSL compiler settings.
2577+
2578+
bool expected_layout = false;
2579+
for (const DescriptorSetLayout& layout : FramebufferBlendColorBurnPipeline::
2580+
FragmentShader::kDescriptorSetLayouts) {
2581+
if (layout.binding == 64 &&
2582+
layout.descriptor_type == DescriptorType::kInputAttachment) {
2583+
expected_layout = true;
2584+
}
2585+
}
2586+
EXPECT_TRUE(expected_layout);
2587+
}
2588+
#endif
2589+
25302590
} // namespace testing
25312591
} // namespace impeller
25322592

impeller/entity/shaders/blending/framebuffer_blend.frag

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,31 @@
1010
#include <impeller/types.glsl>
1111
#include "blend_select.glsl"
1212

13-
layout(constant_id = 0) const float blend_type = 0.0;
14-
layout(constant_id = 1) const float supports_decal = 1.0;
13+
// Warning: if any of the constant values or layouts are changed in this
14+
// file, then the hard-coded constant value in
15+
// impeller/renderer/backend/vulkan/binding_helpers_vk.cc
16+
layout(constant_id = 0) const float blend_type = 0;
17+
layout(constant_id = 1) const float supports_decal = 1;
1518

19+
#ifdef IMPELLER_TARGET_VULKAN
20+
layout(set = 0,
21+
binding = 0,
22+
input_attachment_index = 0) uniform subpassInputMS uSub;
23+
24+
vec4 ReadDestination() {
25+
return (subpassLoad(uSub, 0) + subpassLoad(uSub, 1) + subpassLoad(uSub, 2) +
26+
subpassLoad(uSub, 3)) /
27+
vec4(4.0);
28+
}
29+
#else
1630
layout(set = 0,
1731
binding = 0,
1832
input_attachment_index = 0) uniform subpassInput uSub;
1933

2034
vec4 ReadDestination() {
2135
return subpassLoad(uSub);
2236
}
37+
#endif // IMPELLER_TARGET_VULKAN
2338

2439
uniform sampler2D texture_sampler_src;
2540

impeller/entity/shaders/blending/framebuffer_blend.vert

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include <impeller/conversions.glsl>
66
#include <impeller/types.glsl>
77

8+
// Warning: if any of the constant values or layouts are changed in this
9+
// file, then the hard-coded constant value in
10+
// impeller/renderer/backend/vulkan/binding_helpers_vk.cc
811
uniform FrameInfo {
912
mat4 mvp;
1013
float src_y_coord_scale;

impeller/playground/backend/vulkan/playground_impl_vk.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "flutter/fml/logging.h"
1414
#include "flutter/fml/mapping.h"
1515
#include "impeller/entity/vk/entity_shaders_vk.h"
16+
#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h"
1617
#include "impeller/entity/vk/modern_shaders_vk.h"
1718
#include "impeller/fixtures/vk/fixtures_shaders_vk.h"
1819
#include "impeller/playground/imgui/vk/imgui_shaders_vk.h"
@@ -33,6 +34,9 @@ ShaderLibraryMappingsForPlayground() {
3334
impeller_entity_shaders_vk_length),
3435
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
3536
impeller_modern_shaders_vk_length),
37+
std::make_shared<fml::NonOwnedMapping>(
38+
impeller_framebuffer_blend_shaders_vk_data,
39+
impeller_framebuffer_blend_shaders_vk_length),
3640
std::make_shared<fml::NonOwnedMapping>(
3741
impeller_fixtures_shaders_vk_data,
3842
impeller_fixtures_shaders_vk_length),

impeller/renderer/backend/vulkan/allocator_vk.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "impeller/renderer/backend/vulkan/device_buffer_vk.h"
1313
#include "impeller/renderer/backend/vulkan/formats_vk.h"
1414
#include "impeller/renderer/backend/vulkan/texture_vk.h"
15+
#include "vulkan/vulkan_enums.hpp"
1516

1617
namespace impeller {
1718

@@ -148,6 +149,7 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
148149
allocator_.reset(allocator);
149150
supports_memoryless_textures_ =
150151
capabilities.SupportsDeviceTransientTextures();
152+
supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch();
151153
is_valid_ = true;
152154
}
153155

@@ -167,7 +169,8 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
167169
PixelFormat format,
168170
TextureUsageMask usage,
169171
StorageMode mode,
170-
bool supports_memoryless_textures) {
172+
bool supports_memoryless_textures,
173+
bool supports_framebuffer_fetch) {
171174
vk::ImageUsageFlags vk_usage;
172175

173176
switch (mode) {
@@ -187,6 +190,9 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
187190
} else {
188191
vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
189192
}
193+
if (supports_framebuffer_fetch) {
194+
vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
195+
}
190196
}
191197

192198
if (usage & static_cast<TextureUsageMask>(TextureUsage::kShaderRead)) {
@@ -263,7 +269,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
263269
const TextureDescriptor& desc,
264270
VmaAllocator allocator,
265271
vk::Device device,
266-
bool supports_memoryless_textures)
272+
bool supports_memoryless_textures,
273+
bool supports_framebuffer_fetch)
267274
: TextureSourceVK(desc), resource_(std::move(resource_manager)) {
268275
FML_DCHECK(desc.format != PixelFormat::kUnknown);
269276
TRACE_EVENT0("impeller", "CreateDeviceTexture");
@@ -281,9 +288,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
281288
image_info.arrayLayers = ToArrayLayerCount(desc.type);
282289
image_info.tiling = vk::ImageTiling::eOptimal;
283290
image_info.initialLayout = vk::ImageLayout::eUndefined;
284-
image_info.usage =
285-
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode,
286-
supports_memoryless_textures);
291+
image_info.usage = ToVKImageUsageFlags(
292+
desc.format, desc.usage, desc.storage_mode,
293+
supports_memoryless_textures, supports_framebuffer_fetch);
287294
image_info.sharingMode = vk::SharingMode::eExclusive;
288295

289296
VmaAllocationCreateInfo alloc_nfo = {};
@@ -412,7 +419,8 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
412419
desc, //
413420
allocator_.get(), //
414421
device_holder->GetDevice(), //
415-
supports_memoryless_textures_ //
422+
supports_memoryless_textures_, //
423+
supports_framebuffer_fetch_ //
416424
);
417425
if (!source->IsValid()) {
418426
return nullptr;

0 commit comments

Comments
 (0)