Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Vulkan framebuffer fetch via VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS #48458

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions impeller/compiler/reflector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,13 @@ std::optional<nlohmann::json> Reflector::GenerateTemplateArguments() const {
}

const auto shader_resources = compiler_->get_shader_resources();
// Subpass inputs.
jonahwilliams marked this conversation as resolved.
Show resolved Hide resolved
{
auto& subpass_inputs = root["subpass_inputs"] = nlohmann::json::array_t{};
for (const auto& subpass_input : shader_resources.subpass_inputs) {
//
}
}

// Uniform and storage buffers.
{
Expand Down
44 changes: 29 additions & 15 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,49 +221,63 @@ ContentContext::ContentContext(
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
framebuffer_blend_color_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kColor), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kColor), supports_decal},
true);
framebuffer_blend_colorburn_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kColorBurn), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kColorBurn), supports_decal},
true);
framebuffer_blend_colordodge_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kColorDodge), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kColorDodge), supports_decal},
true);
framebuffer_blend_darken_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kDarken), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kDarken), supports_decal},
true);
framebuffer_blend_difference_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kDifference), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kDifference), supports_decal},
true);
framebuffer_blend_exclusion_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kExclusion), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kExclusion), supports_decal},
true);
framebuffer_blend_hardlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kHardLight), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kHardLight), supports_decal},
true);
framebuffer_blend_hue_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kHue), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kHue), supports_decal}, true);
framebuffer_blend_lighten_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kLighten), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kLighten), supports_decal},
true);
framebuffer_blend_luminosity_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kLuminosity), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kLuminosity), supports_decal},
true);
framebuffer_blend_multiply_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kMultiply), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kMultiply), supports_decal},
true);
framebuffer_blend_overlay_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kOverlay), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kOverlay), supports_decal},
true);
framebuffer_blend_saturation_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kSaturation), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kSaturation), supports_decal},
true);
framebuffer_blend_screen_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kScreen), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kScreen), supports_decal},
true);
framebuffer_blend_softlight_pipelines_.CreateDefault(
*context_, options_trianglestrip,
{static_cast<int32_t>(BlendSelectValues::kSoftLight), supports_decal});
{static_cast<int32_t>(BlendSelectValues::kSoftLight), supports_decal},
true);
}

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

void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::initializer_list<int32_t>& constants = {}) {
const std::initializer_list<int32_t>& constants = {},
bool has_subpass_input = false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using an enum instead of a bool so that this reads more nicely at the callsites, e.g. enum class UseSubpassInput { kYes, kNo, };

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the nice parts of clangd is that it does this for me 😸

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively use the google-style argument comments, but I prefer the enum. I don't have clangd when I'mr eading the callsites in your patch :D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is why objective-c has YES and NO constants 😄

auto desc =
PipelineT::Builder::MakeDefaultPipelineDescriptor(context, constants);
if (!desc.has_value()) {
VALIDATION_LOG << "Failed to create default pipeline.";
return;
}
desc->SetHasSubpassDependency(has_subpass_input);
options.ApplyToPipelineDescriptor(*desc);
SetDefault(options, std::make_unique<PipelineT>(context, desc));
}
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/framebuffer_blend_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ bool FramebufferBlendContents::Render(const ContentContext& renderer,

frag_info.src_input_alpha = src_snapshot->opacity;
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
cmd.bind_framebuffer = true;

return pass.AddCommand(std::move(cmd));
}
Expand Down
4 changes: 4 additions & 0 deletions impeller/playground/backend/vulkan/playground_impl_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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),
Expand Down
34 changes: 28 additions & 6 deletions impeller/renderer/backend/vulkan/binding_helpers_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#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 {

Expand Down Expand Up @@ -117,7 +118,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 vk::ImageView& image_view) {
if (commands.empty()) {
return std::vector<vk::DescriptorSet>{};
}
Expand All @@ -127,19 +129,21 @@ 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());

for (const auto& command : commands) {
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.bind_framebuffer ? 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();
}
Expand All @@ -153,9 +157,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;
Expand All @@ -173,6 +177,24 @@ fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
return fml::Status(fml::StatusCode::kUnknown,
"Failed to bind texture or buffer.");
}

if (command.bind_framebuffer) {
vk::DescriptorImageInfo image_info;
image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
image_info.sampler = VK_NULL_HANDLE;
image_info.imageView = image_view;
images.push_back(image_info);

vk::WriteDescriptorSet write_set;
write_set.dstSet = descriptor_sets[desc_index];
// MAGIC! see description in pipeline_library_vk.cc
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just look this up on the descriptor sets.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the subpass doesn't show up in host builds I can't use any of the constants.

write_set.dstBinding = 64u;
write_set.descriptorCount = 1u;
write_set.descriptorType = vk::DescriptorType::eInputAttachment;
write_set.pImageInfo = &images.back();

writes.push_back(write_set);
}
desc_index += 1;
}

Expand Down Expand Up @@ -203,7 +225,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();
}
Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/backend/vulkan/binding_helpers_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,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 vk::ImageView& image_view);

fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
const ContextVK& context,
Expand Down
14 changes: 13 additions & 1 deletion impeller/renderer/backend/vulkan/capabilities_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -401,6 +406,13 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
});
}

supports_framebuffer_fetch_ =
optional_device_extensions_.find(
OptionalDeviceExtensionVK::kARMRasterizationOrderAttachmentAccess) !=
optional_device_extensions_.end();
FML_LOG(ERROR) << "supports framebuffer fetch: "
jonahwilliams marked this conversation as resolved.
Show resolved Hide resolved
<< supports_framebuffer_fetch_;

return true;
}

Expand Down Expand Up @@ -431,7 +443,7 @@ bool CapabilitiesVK::SupportsTextureToTextureBlits() const {

// |Capabilities|
bool CapabilitiesVK::SupportsFramebufferFetch() const {
return false;
return supports_framebuffer_fetch_;
}

// |Capabilities|
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/vulkan/capabilities_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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,
jonahwilliams marked this conversation as resolved.
Show resolved Hide resolved
kLast,
};

Expand Down Expand Up @@ -110,6 +112,8 @@ 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;
;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray line

bool is_valid_ = false;

bool HasExtension(const std::string& ext) const;
Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/backend/vulkan/command_encoder_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,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 {
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/command_encoder_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,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:
Expand Down
15 changes: 11 additions & 4 deletions impeller/renderer/backend/vulkan/descriptor_pool_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"
#include "vulkan/vulkan_structs.hpp"

namespace impeller {

Expand All @@ -19,7 +20,8 @@ DescriptorPoolVK::~DescriptorPoolVK() = default;

static vk::UniqueDescriptorPool CreatePool(const vk::Device& device,
uint32_t image_count,
uint32_t buffer_count) {
uint32_t buffer_count,
uint32_t subpass_count) {
TRACE_EVENT0("impeller", "CreateDescriptorPool");
std::vector<vk::DescriptorPoolSize> pools = {};
if (image_count > 0) {
Expand All @@ -32,8 +34,12 @@ static vk::UniqueDescriptorPool CreatePool(const vk::Device& device,
pools.emplace_back(vk::DescriptorPoolSize{
vk::DescriptorType::eStorageBuffer, buffer_count});
}
if (subpass_count > 0) {
pools.emplace_back(vk::DescriptorPoolSize{
vk::DescriptorType::eInputAttachment, subpass_count});
}
vk::DescriptorPoolCreateInfo pool_info;
pool_info.setMaxSets(image_count + buffer_count);
pool_info.setMaxSets(image_count + buffer_count + subpass_count);
pool_info.setPoolSizes(pools);
auto [result, pool] = device.createDescriptorPoolUnique(pool_info);
if (result != vk::Result::eSuccess) {
Expand All @@ -46,14 +52,15 @@ 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 DeviceHolder> strong_device = device_holder_.lock();
if (!strong_device) {
return fml::Status(fml::StatusCode::kUnknown, "No device");
}

auto new_pool =
CreatePool(strong_device->GetDevice(), sampler_count, buffer_count);
auto new_pool = CreatePool(strong_device->GetDevice(), sampler_count,
buffer_count, subpass_count);
if (!new_pool) {
return fml::Status(fml::StatusCode::kUnknown,
"Failed to create descriptor pool");
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/descriptor_pool_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,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:
Expand Down