[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:
@@ -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}}
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -163,6 +163,7 @@ enum class DescriptorType {
|
||||
kSampledImage,
|
||||
kImage,
|
||||
kSampler,
|
||||
kInputAttachment,
|
||||
};
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user