diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 0d4ce0443790b..f3cf26206c773 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1409,10 +1409,18 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc + ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc + ../../../flutter/LICENSE @@ -1454,6 +1462,8 @@ ORIGIN: ../../../flutter/impeller/renderer/buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/buffer_view.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/buffer_view.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/capabilities.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/capabilities.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/command.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/command.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/command_buffer.cc + ../../../flutter/LICENSE @@ -1468,13 +1478,10 @@ ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc + ../. ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/context.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/context.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/descriptor_set_layout.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/device_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/device_buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/device_buffer_descriptor.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/device_buffer_descriptor.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/device_capabilities.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/device_capabilities.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/formats.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/formats.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/gpu_tracer.cc + ../../../flutter/LICENSE @@ -3936,10 +3943,18 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -3981,6 +3996,8 @@ FILE: ../../../flutter/impeller/renderer/buffer.cc FILE: ../../../flutter/impeller/renderer/buffer.h FILE: ../../../flutter/impeller/renderer/buffer_view.cc FILE: ../../../flutter/impeller/renderer/buffer_view.h +FILE: ../../../flutter/impeller/renderer/capabilities.cc +FILE: ../../../flutter/impeller/renderer/capabilities.h FILE: ../../../flutter/impeller/renderer/command.cc FILE: ../../../flutter/impeller/renderer/command.h FILE: ../../../flutter/impeller/renderer/command_buffer.cc @@ -3995,13 +4012,10 @@ FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h FILE: ../../../flutter/impeller/renderer/context.cc FILE: ../../../flutter/impeller/renderer/context.h -FILE: ../../../flutter/impeller/renderer/descriptor_set_layout.h FILE: ../../../flutter/impeller/renderer/device_buffer.cc FILE: ../../../flutter/impeller/renderer/device_buffer.h FILE: ../../../flutter/impeller/renderer/device_buffer_descriptor.cc FILE: ../../../flutter/impeller/renderer/device_buffer_descriptor.h -FILE: ../../../flutter/impeller/renderer/device_capabilities.cc -FILE: ../../../flutter/impeller/renderer/device_capabilities.h FILE: ../../../flutter/impeller/renderer/formats.cc FILE: ../../../flutter/impeller/renderer/formats.h FILE: ../../../flutter/impeller/renderer/gpu_tracer.cc diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 634bf58f27642..04fdeb5b01e4e 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -108,7 +108,7 @@ bool GenerateMipmap(const std::shared_ptr& context, } pass->GenerateMipmap(std::move(texture), std::move(label)); pass->EncodeCommands(context->GetResourceAllocator()); - return true; + return buffer->SubmitCommands(); } TEST_P(AiksTest, CanRenderTiledTexture) { diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 97b48e357a321..10500e6c09d89 100644 --- a/impeller/aiks/picture.cc +++ b/impeller/aiks/picture.cc @@ -54,7 +54,7 @@ std::shared_ptr Picture::RenderToTexture( // features to Image someday. auto impeller_context = context.GetContext(); RenderTarget target; - if (impeller_context->GetDeviceCapabilities().SupportsOffscreenMSAA()) { + if (impeller_context->GetCapabilities()->SupportsOffscreenMSAA()) { target = RenderTarget::CreateOffscreenMSAA(*impeller_context, size); } else { target = RenderTarget::CreateOffscreen(*impeller_context, size); diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index d2708052d1838..2666a53f9ca96 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -22,8 +22,6 @@ constexpr std::string_view kReflectionHeaderTemplate = #include "impeller/renderer/compute_command.h" {# // nogncheck #} -#include "impeller/renderer/descriptor_set_layout.h" {# // nogncheck #} - #include "impeller/renderer/sampler.h" {# // nogncheck #} #include "impeller/renderer/shader_types.h" {# // nogncheck #} @@ -166,17 +164,15 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} {% for buffer in buffers %} DescriptorSetLayout{ {{buffer.binding}}, // binding = {{buffer.binding}} - DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer - 1, // descriptorCount = 1 - {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} + DescriptorType::kUniformBuffer, // descriptor_type = Uniform Buffer + {{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}} }, {% endfor %} {% for sampled_image in sampled_images %} DescriptorSetLayout{ {{sampled_image.binding}}, // binding = {{sampled_image.binding}} - DescriptorType::kSampledImage, // descriptorType = Sampled Image - 1, // descriptorCount = 1 - {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} + DescriptorType::kSampledImage, // descriptor_type = Sampled Image + {{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}} }, {% endfor %} }; diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 36287aaf935f7..54a9fb46250fc 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -154,7 +154,8 @@ static std::unique_ptr CreateDefaultPipeline( return nullptr; } // Apply default ContentContextOptions to the descriptor. - const auto default_color_fmt = context.GetColorAttachmentPixelFormat(); + const auto default_color_fmt = + context.GetCapabilities()->GetDefaultColorFormat(); ContentContextOptions{.color_attachment_pixel_format = default_color_fmt} .ApplyToPipelineDescriptor(*desc); return std::make_unique(context, desc); @@ -175,7 +176,7 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); - if (context_->GetDeviceCapabilities().SupportsSSBO()) { + if (context_->GetCapabilities()->SupportsSSBO()) { linear_gradient_ssbo_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); radial_gradient_ssbo_fill_pipelines_[{}] = @@ -183,7 +184,7 @@ ContentContext::ContentContext(std::shared_ptr context) sweep_gradient_ssbo_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); } - if (context_->GetDeviceCapabilities().SupportsFramebufferFetch()) { + if (context_->GetCapabilities()->SupportsFramebufferFetch()) { framebuffer_blend_color_pipelines_[{}] = CreateDefaultPipeline(*context_); framebuffer_blend_colorburn_pipelines_[{}] = @@ -315,8 +316,7 @@ std::shared_ptr ContentContext::MakeSubpass( auto context = GetContext(); RenderTarget subpass_target; - if (context->GetDeviceCapabilities().SupportsOffscreenMSAA() && - msaa_enabled) { + if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) { subpass_target = RenderTarget::CreateOffscreenMSAA( *context, texture_size, SPrintF("%s Offscreen", label.c_str()), RenderTarget::kDefaultColorAttachmentConfigMSAA, std::nullopt); @@ -374,8 +374,8 @@ std::shared_ptr ContentContext::GetContext() const { return context_; } -const IDeviceCapabilities& ContentContext::GetDeviceCapabilities() const { - return context_->GetDeviceCapabilities(); +const Capabilities& ContentContext::GetDeviceCapabilities() const { + return *context_->GetCapabilities(); } void ContentContext::SetWireframe(bool wireframe) { diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 236167f3a9e58..3449236aae490 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -47,7 +47,7 @@ #include "impeller/entity/vertices.frag.h" #include "impeller/entity/yuv_to_rgb_filter.frag.h" #include "impeller/entity/yuv_to_rgb_filter.vert.h" -#include "impeller/renderer/device_capabilities.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/pipeline.h" #include "impeller/scene/scene_context.h" @@ -601,7 +601,7 @@ class ContentContext { std::shared_ptr GetGlyphAtlasContext() const; - const IDeviceCapabilities& GetDeviceCapabilities() const; + const Capabilities& GetDeviceCapabilities() const; void SetWireframe(bool wireframe); diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index 841027d84fc54..9f7aaadbde09c 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -102,10 +102,9 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, /// Get or create runtime stage pipeline. /// - const auto& device_capabilities = context->GetDeviceCapabilities(); - const auto color_attachment_format = context->GetColorAttachmentPixelFormat(); - const auto stencil_attachment_format = - device_capabilities.GetDefaultStencilFormat(); + const auto& caps = context->GetCapabilities(); + const auto color_attachment_format = caps->GetDefaultColorFormat(); + const auto stencil_attachment_format = caps->GetDefaultStencilFormat(); using VS = RuntimeEffectVertexShader; PipelineDescriptor desc; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 487c56d063976..5e00c6b1c1ee0 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -152,7 +152,7 @@ static RenderTarget CreateRenderTarget(ContentContext& renderer, /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. - if (context->GetDeviceCapabilities().SupportsOffscreenMSAA()) { + if (context->GetCapabilities()->SupportsOffscreenMSAA()) { return RenderTarget::CreateOffscreenMSAA( *context, // context size, // size @@ -210,8 +210,8 @@ bool EntityPass::Render(ContentContext& renderer, command_buffer->SetLabel("EntityPass Root Command Buffer"); if (renderer.GetContext() - ->GetDeviceCapabilities() - .SupportsTextureToTextureBlits()) { + ->GetCapabilities() + ->SupportsTextureToTextureBlits()) { auto blit_pass = command_buffer->CreateBlitPass(); blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(), diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 2418d1dae7c9a..cf26700b41706 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -82,9 +82,8 @@ } data_->metal_layer = [CAMetalLayer layer]; data_->metal_layer.device = ContextMTL::Cast(*context).GetMTLDevice(); - // This pixel format is one of the documented supported formats. - const auto color_fmt = context->GetColorAttachmentPixelFormat(); - data_->metal_layer.pixelFormat = ToMTLPixelFormat(color_fmt); + data_->metal_layer.pixelFormat = + ToMTLPixelFormat(context->GetCapabilities()->GetDefaultColorFormat()); data_->metal_layer.framebufferOnly = NO; cocoa_window.contentView.layer = data_->metal_layer; cocoa_window.contentView.wantsLayer = YES; diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 85042638b8044..ecce6934d7ae4 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -402,8 +402,13 @@ std::shared_ptr Playground::CreateTextureForFixture( std::shared_ptr Playground::CreateTextureForFixture( const char* fixture_name, bool enable_mipmapping) const { - return CreateTextureForFixture(OpenAssetAsMapping(fixture_name), - enable_mipmapping); + auto texture = CreateTextureForFixture(OpenAssetAsMapping(fixture_name), + enable_mipmapping); + if (texture == nullptr) { + return nullptr; + } + texture->SetLabel(fixture_name); + return texture; } std::shared_ptr Playground::CreateTextureCubeForFixture( diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 792fc8ed85ff9..f968e626ee074 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -16,6 +16,8 @@ impeller_component("renderer") { "buffer.h", "buffer_view.cc", "buffer_view.h", + "capabilities.cc", + "capabilities.h", "command.cc", "command.h", "command_buffer.cc", @@ -30,13 +32,10 @@ impeller_component("renderer") { "compute_pipeline_descriptor.h", "context.cc", "context.h", - "descriptor_set_layout.h", "device_buffer.cc", "device_buffer.h", "device_buffer_descriptor.cc", "device_buffer_descriptor.h", - "device_capabilities.cc", - "device_capabilities.h", "formats.cc", "formats.h", "gpu_tracer.cc", diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index 85e1bd3ee8f78..b523a0d598250 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -7,7 +7,7 @@ #include "impeller/base/config.h" #include "impeller/base/validation.h" #include "impeller/base/work_queue_common.h" -#include "impeller/renderer/device_capabilities.h" +#include "impeller/renderer/capabilities.h" namespace impeller { @@ -72,7 +72,7 @@ ContextGLES::ContextGLES(std::unique_ptr gl, // Create the device capabilities. { device_capabilities_ = - DeviceCapabilitiesBuilder() + CapabilitiesBuilder() .SetHasThreadingRestrictions(true) .SetSupportsOffscreenMSAA(false) .SetSupportsSSBO(false) @@ -145,13 +145,9 @@ std::shared_ptr ContextGLES::GetWorkQueue() const { } // |Context| -const IDeviceCapabilities& ContextGLES::GetDeviceCapabilities() const { - return *device_capabilities_; -} - -// |Context| -PixelFormat ContextGLES::GetColorAttachmentPixelFormat() const { - return PixelFormat::kR8G8B8A8UNormInt; +const std::shared_ptr& ContextGLES::GetCapabilities() + const { + return device_capabilities_; } } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 39e1384d97512..030877262741d 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -12,8 +12,8 @@ #include "impeller/renderer/backend/gles/reactor_gles.h" #include "impeller/renderer/backend/gles/sampler_library_gles.h" #include "impeller/renderer/backend/gles/shader_library_gles.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/context.h" -#include "impeller/renderer/device_capabilities.h" namespace impeller { @@ -41,7 +41,7 @@ class ContextGLES final : public Context, std::shared_ptr sampler_library_; std::shared_ptr work_queue_; std::shared_ptr resource_allocator_; - std::unique_ptr device_capabilities_; + std::shared_ptr device_capabilities_; bool is_valid_ = false; ContextGLES( @@ -70,10 +70,7 @@ class ContextGLES final : public Context, std::shared_ptr GetWorkQueue() const override; // |Context| - const IDeviceCapabilities& GetDeviceCapabilities() const override; - - // |Context| - PixelFormat GetColorAttachmentPixelFormat() const override; + const std::shared_ptr& GetCapabilities() const override; FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES); }; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index bd75e585d86c0..80b9bdc8f04ab 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -16,8 +16,8 @@ #include "impeller/renderer/backend/metal/gpu_tracer_mtl.h" #include "impeller/renderer/backend/metal/pipeline_library_mtl.h" #include "impeller/renderer/backend/metal/shader_library_mtl.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/context.h" -#include "impeller/renderer/device_capabilities.h" #include "impeller/renderer/sampler.h" namespace impeller { @@ -37,22 +37,6 @@ class ContextMTL final : public Context, id GetMTLDevice() const; - private: - id device_ = nullptr; - id command_queue_ = nullptr; - std::shared_ptr shader_library_; - std::shared_ptr pipeline_library_; - std::shared_ptr sampler_library_; - std::shared_ptr resource_allocator_; - std::shared_ptr work_queue_; - std::shared_ptr gpu_tracer_; - std::unique_ptr device_capabilities_; - bool is_valid_ = false; - - ContextMTL(id device, NSArray>* shader_libraries); - - bool SupportsFramebufferFetch() const; - // |Context| bool IsValid() const override; @@ -78,7 +62,24 @@ class ContextMTL final : public Context, std::shared_ptr GetGPUTracer() const override; // |Context| - const IDeviceCapabilities& GetDeviceCapabilities() const override; + const std::shared_ptr& GetCapabilities() const override; + + // |Context| + bool UpdateOffscreenLayerPixelFormat(PixelFormat format) override; + + private: + id device_ = nullptr; + id command_queue_ = nullptr; + std::shared_ptr shader_library_; + std::shared_ptr pipeline_library_; + std::shared_ptr sampler_library_; + std::shared_ptr resource_allocator_; + std::shared_ptr work_queue_; + std::shared_ptr gpu_tracer_; + std::shared_ptr device_capabilities_; + bool is_valid_ = false; + + ContextMTL(id device, NSArray>* shader_libraries); std::shared_ptr CreateCommandBufferInQueue( id queue) const; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 70c76592aa5fa..ce114a9862b5f 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -11,11 +11,56 @@ #include "flutter/fml/paths.h" #include "impeller/base/platform/darwin/work_queue_darwin.h" #include "impeller/renderer/backend/metal/sampler_library_mtl.h" -#include "impeller/renderer/device_capabilities.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/sampler_descriptor.h" namespace impeller { +static bool DeviceSupportsFramebufferFetch(id device) { + // The iOS simulator lies about supporting framebuffer fetch. +#if FML_OS_IOS_SIMULATOR + return false; +#endif // FML_OS_IOS_SIMULATOR + + if (@available(macOS 10.15, iOS 13, tvOS 13, *)) { + return [device supportsFamily:MTLGPUFamilyApple2]; + } + // According to + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf , Apple2 + // corresponds to iOS GPU family 2, which supports A8 devices. +#if FML_OS_IOS + return [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]; +#else + return false; +#endif // FML_OS_IOS +} + +static bool DeviceSupportsComputeSubgroups(id device) { + bool supports_subgroups = false; + // Refer to the "SIMD-scoped reduction operations" feature in the table + // below: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf + if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) { + supports_subgroups = [device supportsFamily:MTLGPUFamilyApple7] || + [device supportsFamily:MTLGPUFamilyMac2]; + } + return supports_subgroups; +} + +static std::unique_ptr InferMetalCapabilities( + id device, + PixelFormat color_format = PixelFormat::kB8G8R8A8UNormInt) { + return CapabilitiesBuilder() + .SetHasThreadingRestrictions(false) + .SetSupportsOffscreenMSAA(true) + .SetSupportsSSBO(true) + .SetSupportsTextureToTextureBlits(true) + .SetSupportsFramebufferFetch(DeviceSupportsFramebufferFetch(device)) + .SetDefaultColorFormat(color_format) + .SetDefaultStencilFormat(PixelFormat::kS8UInt) + .SetSupportsCompute(true, DeviceSupportsComputeSubgroups(device)) + .Build(); +} + ContextMTL::ContextMTL(id device, NSArray>* shader_libraries) : device_(device) { @@ -89,50 +134,11 @@ { gpu_tracer_ = std::shared_ptr(new GPUTracerMTL(device_)); } #endif - { - bool supports_subgroups = false; - // Refer to the "SIMD-scoped reduction operations" feature in the table - // below: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf - if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) { - supports_subgroups = [device supportsFamily:MTLGPUFamilyApple7] || - [device supportsFamily:MTLGPUFamilyMac2]; - } - - device_capabilities_ = - DeviceCapabilitiesBuilder() - .SetHasThreadingRestrictions(false) - .SetSupportsOffscreenMSAA(true) - .SetSupportsSSBO(true) - .SetSupportsTextureToTextureBlits(true) - .SetSupportsFramebufferFetch(SupportsFramebufferFetch()) - .SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt) - .SetDefaultStencilFormat(PixelFormat::kS8UInt) - .SetSupportsCompute(true, supports_subgroups) - .Build(); - } + device_capabilities_ = InferMetalCapabilities(device_); is_valid_ = true; } -bool ContextMTL::SupportsFramebufferFetch() const { - // The iOS simulator lies about supporting framebuffer fetch. -#if FML_OS_IOS_SIMULATOR - return false; -#endif // FML_OS_IOS_SIMULATOR - - if (@available(macOS 10.15, iOS 13, tvOS 13, *)) { - return [device_ supportsFamily:MTLGPUFamilyApple2]; - } - // According to - // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf , Apple2 - // corresponds to iOS GPU family 2, which supports A8 devices. -#if FML_OS_IOS - return [device_ supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]; -#else - return false; -#endif // FML_OS_IOS -} - static NSArray>* MTLShaderLibraryFromFilePaths( id device, const std::vector& libraries_paths) { @@ -287,8 +293,14 @@ return device_; } -const IDeviceCapabilities& ContextMTL::GetDeviceCapabilities() const { - return *device_capabilities_; +const std::shared_ptr& ContextMTL::GetCapabilities() const { + return device_capabilities_; +} + +// |Context| +bool ContextMTL::UpdateOffscreenLayerPixelFormat(PixelFormat format) { + device_capabilities_ = InferMetalCapabilities(device_); + return true; } } // namespace impeller diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index 70eedfd7aee60..dccdac147f4e9 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -64,6 +64,7 @@ resolve_tex_desc.format = color_format; resolve_tex_desc.size = msaa_tex_desc.size; resolve_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + resolve_tex_desc.sample_count = SampleCount::kCount1; resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate; std::shared_ptr resolve_tex = @@ -86,7 +87,7 @@ stencil_tex_desc.type = TextureType::kTexture2DMultisample; stencil_tex_desc.sample_count = SampleCount::kCount4; stencil_tex_desc.format = - context->GetDeviceCapabilities().GetDefaultStencilFormat(); + context->GetCapabilities()->GetDefaultStencilFormat(); stencil_tex_desc.size = msaa_tex_desc.size; stencil_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 2c30458c842b8..a5de877f8afc9 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -18,10 +18,18 @@ impeller_component("vulkan") { "command_buffer_vk.h", "command_encoder_vk.cc", "command_encoder_vk.h", + "command_pool_vk.cc", + "command_pool_vk.h", "context_vk.cc", "context_vk.h", + "debug_report_vk.cc", + "debug_report_vk.h", + "descriptor_pool_vk.cc", + "descriptor_pool_vk.h", "device_buffer_vk.cc", "device_buffer_vk.h", + "fence_waiter_vk.cc", + "fence_waiter_vk.h", "formats_vk.cc", "formats_vk.h", "pipeline_library_vk.cc", diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index f1c1e210e6ec9..25631dacb5ec9 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -152,10 +152,12 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format, } } - // TODO (https://github.com/flutter/flutter/issues/121634): - // Add transfer usage flags to support blit passes - vk_usage |= vk::ImageUsageFlagBits::eTransferSrc | - vk::ImageUsageFlagBits::eTransferDst; + if (mode != StorageMode::kDeviceTransient) { + // TODO (https://github.com/flutter/flutter/issues/121634): + // Add transfer usage flags to support blit passes + vk_usage |= vk::ImageUsageFlagBits::eTransferSrc | + vk::ImageUsageFlagBits::eTransferDst; + } return vk_usage; } @@ -211,8 +213,10 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, - vk::Device device) { + vk::Device device) + : TextureSourceVK(desc) { vk::ImageCreateInfo image_info; + image_info.flags = ToVKImageCreateFlags(desc.type); image_info.imageType = vk::ImageType::e2D; image_info.format = ToVKImageFormat(desc.format); image_info.extent = VkExtent3D{ @@ -229,13 +233,11 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode); image_info.sharingMode = vk::SharingMode::eExclusive; - VmaAllocationCreateInfo alloc_create_info = {}; + VmaAllocationCreateInfo alloc_nfo = {}; - alloc_create_info.usage = ToVMAMemoryUsage(); - alloc_create_info.preferredFlags = - ToVKMemoryPropertyFlags(desc.storage_mode, true); - alloc_create_info.flags = - ToVmaAllocationCreateFlags(desc.storage_mode, true); + alloc_nfo.usage = ToVMAMemoryUsage(); + alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode, true); + alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, true); auto create_info_native = static_cast(image_info); @@ -244,13 +246,13 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { VmaAllocation allocation = {}; VmaAllocationInfo allocation_info = {}; { - auto result = vk::Result{vmaCreateImage(allocator, // - &create_info_native, // - &alloc_create_info, // - &vk_image, // - &allocation, // - &allocation_info // - )}; + auto result = vk::Result{::vmaCreateImage(allocator, // + &create_info_native, // + &alloc_nfo, // + &vk_image, // + &allocation, // + &allocation_info // + )}; if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to allocate Vulkan Image: " << vk::to_string(result); @@ -262,25 +264,24 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { allocator_ = allocator; allocation_ = allocation; - vk::ImageViewCreateInfo view_create_info = {}; - view_create_info.image = image_; - view_create_info.viewType = vk::ImageViewType::e2D; - view_create_info.format = image_info.format; - view_create_info.subresourceRange.aspectMask = - ToVKImageAspectFlags(desc.format); - view_create_info.subresourceRange.levelCount = image_info.mipLevels; - view_create_info.subresourceRange.layerCount = 1u; + vk::ImageViewCreateInfo view_info = {}; + view_info.image = image_; + view_info.viewType = ToVKImageViewType(desc.type); + view_info.format = image_info.format; + view_info.subresourceRange.aspectMask = ToVKImageAspectFlags(desc.format); + view_info.subresourceRange.levelCount = image_info.mipLevels; + view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type); // Vulkan does not have an image format that is equivalent to // `MTLPixelFormatA8Unorm`, so we use `R8Unorm` instead. Given that the // shaders expect that alpha channel to be set in the cases, we swizzle. // See: https://github.com/flutter/flutter/issues/115461 for more details. if (desc.format == PixelFormat::kA8UNormInt) { - view_create_info.components.a = vk::ComponentSwizzle::eR; - view_create_info.components.r = vk::ComponentSwizzle::eA; + view_info.components.a = vk::ComponentSwizzle::eR; + view_info.components.r = vk::ComponentSwizzle::eA; } - auto [result, image_view] = device.createImageViewUnique(view_create_info); + auto [result, image_view] = device.createImageViewUnique(view_info); if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to create an image view for allocation: " << vk::to_string(result); @@ -294,7 +295,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { ~AllocatedTextureSourceVK() { image_view_.reset(); if (image_) { - vmaDestroyImage( + ::vmaDestroyImage( allocator_, // static_cast(image_), // allocation_ // @@ -335,9 +336,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { bool IsValid() const { return is_valid_; } - vk::Image GetVKImage() const override { return image_; } + vk::Image GetImage() const override { return image_; } - vk::ImageView GetVKImageView() const override { return image_view_.get(); } + vk::ImageView GetImageView() const override { return image_view_.get(); } private: vk::Image image_ = {}; @@ -362,7 +363,7 @@ std::shared_ptr AllocatorVK::OnCreateTexture( if (!source->IsValid()) { return nullptr; } - return std::make_shared(desc, context_, std::move(source)); + return std::make_shared(context_, std::move(source)); } // |Allocator| diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index f4a9e8ee3b297..0b4f3541bce98 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -28,7 +28,7 @@ class AllocatorVK final : public Allocator { VmaAllocator allocator_ = {}; std::weak_ptr context_; vk::Device device_; - ISize max_texture_size_ = {4096, 4096}; + ISize max_texture_size_; bool is_valid_ = false; AllocatorVK(std::weak_ptr context, diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index 8c27935cf84c8..98c8ab0d4ec85 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -29,11 +29,27 @@ bool BlitCopyTextureToTextureCommandVK::Encode( const auto& src = TextureVK::Cast(*source); const auto& dst = TextureVK::Cast(*destination); - const auto src_layout = vk::ImageLayout::eTransferSrcOptimal; - const auto dst_layout = vk::ImageLayout::eTransferDstOptimal; - - if (!src.SetLayout(src_layout, cmd_buffer) || - !dst.SetLayout(dst_layout, cmd_buffer)) { + LayoutTransition src_tran; + src_tran.cmd_buffer = cmd_buffer; + src_tran.new_layout = vk::ImageLayout::eTransferSrcOptimal; + src_tran.src_access = vk::AccessFlagBits::eTransferWrite | + vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eColorAttachmentWrite; + src_tran.src_stage = vk::PipelineStageFlagBits::eTransfer | + vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eColorAttachmentOutput; + src_tran.dst_access = vk::AccessFlagBits::eTransferRead; + src_tran.dst_stage = vk::PipelineStageFlagBits::eTransfer; + + LayoutTransition dst_tran; + dst_tran.cmd_buffer = cmd_buffer; + dst_tran.new_layout = vk::ImageLayout::eTransferDstOptimal; + dst_tran.src_access = {}; + dst_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + dst_tran.dst_access = vk::AccessFlagBits::eShaderRead; + dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + if (!src.SetLayout(src_tran) || !dst.SetLayout(dst_tran)) { VALIDATION_LOG << "Could not complete layout transitions."; return false; } @@ -54,11 +70,11 @@ bool BlitCopyTextureToTextureCommandVK::Encode( // Issue the copy command now that the images are already in the right // layouts. - cmd_buffer.copyImage(src.GetImage(), // - src_layout, // - dst.GetImage(), // - dst_layout, // - image_copy // + cmd_buffer.copyImage(src.GetImage(), // + src_tran.new_layout, // + dst.GetImage(), // + dst_tran.new_layout, // + image_copy // ); return true; @@ -79,6 +95,20 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const { // cast source and destination to TextureVK const auto& src = TextureVK::Cast(*source); + + LayoutTransition transition; + transition.cmd_buffer = cmd_buffer; + transition.new_layout = vk::ImageLayout::eTransferSrcOptimal; + transition.src_access = vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eTransferWrite | + vk::AccessFlagBits::eColorAttachmentWrite; + transition.src_stage = vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer | + vk::PipelineStageFlagBits::eColorAttachmentOutput; + transition.dst_access = vk::AccessFlagBits::eShaderRead; + transition.dst_stage = vk::PipelineStageFlagBits::eVertexShader | + vk::PipelineStageFlagBits::eFragmentShader; + const auto& dst = DeviceBufferVK::Cast(*destination); vk::BufferImageCopy image_copy; @@ -92,15 +122,15 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const { image_copy.setImageExtent( vk::Extent3D(source_region.size.width, source_region.size.height, 1)); - if (!src.SetLayout(vk::ImageLayout::eTransferSrcOptimal, cmd_buffer)) { + if (!src.SetLayout(transition)) { VALIDATION_LOG << "Could not encode layout transition."; return false; } - cmd_buffer.copyImageToBuffer(src.GetImage(), // - vk::ImageLayout::eTransferSrcOptimal, // - dst.GetVKBufferHandle(), // - image_copy // + cmd_buffer.copyImageToBuffer(src.GetImage(), // + transition.new_layout, // + dst.GetBuffer(), // + image_copy // ); return true; @@ -204,10 +234,12 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { // offsets[0] is origin. blit.srcOffsets[1].x = size.width; blit.srcOffsets[1].y = size.height; + blit.srcOffsets[1].z = 1u; // offsets[0] is origin. - blit.dstOffsets[1].x = size.width >> mip_level; - blit.dstOffsets[1].y = size.height >> mip_level; + blit.dstOffsets[1].x = std::max(size.width >> mip_level, 1u); + blit.dstOffsets[1].y = std::max(size.height >> mip_level, 1u); + blit.dstOffsets[1].z = 1u; cmd.blitImage(image, // src image vk::ImageLayout::eTransferSrcOptimal, // src layout @@ -222,27 +254,27 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { // Transition all mip levels to shader read. The base mip level has a // different "old" layout than the rest now. InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - vk::AccessFlagBits::eTransferRead, // src access mask - vk::AccessFlagBits::eShaderRead, // dst access mask - vk::ImageLayout::eTransferSrcOptimal, // old layout - vk::ImageLayout::eShaderReadOnlyOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eAllGraphics, // dst stage - 0u // mip level + cmd, // command buffer + image, // image + vk::AccessFlagBits::eTransferWrite, // src access mask + vk::AccessFlagBits::eShaderRead, // dst access mask + vk::ImageLayout::eTransferSrcOptimal, // old layout + vk::ImageLayout::eShaderReadOnlyOptimal, // new layout + vk::PipelineStageFlagBits::eTransfer, // src stage + vk::PipelineStageFlagBits::eFragmentShader, // dst stage + 0u // mip level ); InsertImageMemoryBarrier( - cmd, // command buffer - image, // image - vk::AccessFlagBits::eTransferRead, // src access mask - vk::AccessFlagBits::eShaderRead, // dst access mask - vk::ImageLayout::eTransferDstOptimal, // old layout - vk::ImageLayout::eShaderReadOnlyOptimal, // new layout - vk::PipelineStageFlagBits::eTransfer, // src stage - vk::PipelineStageFlagBits::eAllGraphics, // dst stage - 1u, // mip level - mip_count - 1 // mip level count + cmd, // command buffer + image, // image + vk::AccessFlagBits::eTransferWrite, // src access mask + vk::AccessFlagBits::eShaderRead, // dst access mask + vk::ImageLayout::eTransferDstOptimal, // old layout + vk::ImageLayout::eShaderReadOnlyOptimal, // new layout + vk::PipelineStageFlagBits::eTransfer, // src stage + vk::PipelineStageFlagBits::eFragmentShader, // dst stage + 1u, // mip level + mip_count - 1 // mip level count ); // We modified the layouts of this image from underneath it. Tell it its new diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 645ae1cf70375..048dc3592c645 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -4,39 +4,337 @@ #include "impeller/renderer/backend/vulkan/capabilities_vk.h" +#include + +#include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/vk.h" namespace impeller { -CapabilitiesVK::CapabilitiesVK() { - for (const auto& ext : vk::enumerateInstanceExtensionProperties().value) { - extensions_.insert(ext.extensionName); +static constexpr const char* kInstanceLayer = "ImpellerInstance"; + +CapabilitiesVK::CapabilitiesVK(bool enable_validations) + : enable_validations_(enable_validations) { + auto extensions = vk::enumerateInstanceExtensionProperties(); + auto layers = vk::enumerateInstanceLayerProperties(); + + if (extensions.result != vk::Result::eSuccess || + layers.result != vk::Result::eSuccess) { + return; } - for (const auto& layer : vk::enumerateInstanceLayerProperties().value) { - layers_.insert(layer.layerName); + for (const auto& ext : extensions.value) { + exts_[kInstanceLayer].insert(ext.extensionName); + } + + for (const auto& layer : layers.value) { + const std::string layer_name = layer.layerName; + auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name); + if (layer_exts.result != vk::Result::eSuccess) { + return; + } + for (const auto& layer_ext : layer_exts.value) { + exts_[layer_name].insert(layer_ext.extensionName); + } } + + is_valid_ = true; } CapabilitiesVK::~CapabilitiesVK() = default; -bool CapabilitiesVK::HasExtension(const std::string& extension) const { - return extensions_.count(extension) == 1u; +bool CapabilitiesVK::IsValid() const { + return is_valid_; +} + +bool CapabilitiesVK::AreValidationsEnabled() const { + return enable_validations_; +} + +std::optional> CapabilitiesVK::GetRequiredLayers() + const { + std::vector required; + + if (enable_validations_) { + if (!HasLayer("VK_LAYER_KHRONOS_validation")) { + VALIDATION_LOG + << "Requested validations but the validation layer was not found."; + return std::nullopt; + } + required.push_back("VK_LAYER_KHRONOS_validation"); + } + + return required; +} + +std::optional> +CapabilitiesVK::GetRequiredInstanceExtensions() const { + std::vector required; + + if (!HasExtension("VK_KHR_surface")) { + // Swapchain support is required and this is a dependency of + // VK_KHR_swapchain. + VALIDATION_LOG << "Could not find the surface extension."; + return std::nullopt; + } + required.push_back("VK_KHR_surface"); + + auto has_wsi = false; + if (HasExtension("VK_MVK_macos_surface")) { + required.push_back("VK_MVK_macos_surface"); + has_wsi = true; + } + + if (HasExtension("VK_EXT_metal_surface")) { + required.push_back("VK_EXT_metal_surface"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_portability_enumeration")) { + required.push_back("VK_KHR_portability_enumeration"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_win32_surface")) { + required.push_back("VK_KHR_win32_surface"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_android_surface")) { + required.push_back("VK_KHR_android_surface"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_xcb_surface")) { + required.push_back("VK_KHR_xcb_surface"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_xlib_surface")) { + required.push_back("VK_KHR_xlib_surface"); + has_wsi = true; + } + + if (HasExtension("VK_KHR_wayland_surface")) { + required.push_back("VK_KHR_wayland_surface"); + has_wsi = true; + } + + if (!has_wsi) { + // Don't really care which WSI extension there is as long there is at least + // one. + VALIDATION_LOG << "Could not find a WSI extension."; + return std::nullopt; + } + + if (enable_validations_) { + if (!HasExtension("VK_EXT_debug_utils")) { + VALIDATION_LOG << "Requested validations but could not find the " + "VK_EXT_debug_utils extension."; + return std::nullopt; + } + required.push_back("VK_EXT_debug_utils"); + + if (!HasExtension("VK_EXT_validation_features")) { + VALIDATION_LOG << "Requested validations but could not find the " + "VK_EXT_validation_features extension."; + return std::nullopt; + } + required.push_back("VK_EXT_validation_features"); + } + + return required; +} + +std::optional> +CapabilitiesVK::GetRequiredDeviceExtensions( + const vk::PhysicalDevice& physical_device) const { + auto device_extensions = physical_device.enumerateDeviceExtensionProperties(); + if (device_extensions.result != vk::Result::eSuccess) { + return std::nullopt; + } + + std::set exts; + for (const auto& device_extension : device_extensions.value) { + exts.insert(device_extension.extensionName); + } + + std::vector required; + + if (exts.find("VK_KHR_swapchain") == exts.end()) { + VALIDATION_LOG << "Device does not support the swapchain extension."; + return std::nullopt; + } + required.push_back("VK_KHR_swapchain"); + + // Required for non-conformant implementations like MoltenVK. + if (exts.find("VK_KHR_portability_subset") != exts.end()) { + required.push_back("VK_KHR_portability_subset"); + } + return required; +} + +static bool HasSuitableColorFormat(const vk::PhysicalDevice& device, + vk::Format format) { + const auto props = device.getFormatProperties(format); + // This needs to be more comprehensive. + return !!(props.optimalTilingFeatures & + vk::FormatFeatureFlagBits::eColorAttachment); +} + +static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device, + vk::Format format) { + const auto props = device.getFormatProperties(format); + return !!(props.optimalTilingFeatures & + vk::FormatFeatureFlagBits::eDepthStencilAttachment); +} + +static bool PhysicalDeviceSupportsRequiredFormats( + const vk::PhysicalDevice& device) { + const auto has_color_format = + HasSuitableColorFormat(device, vk::Format::eB8G8R8A8Unorm); + const auto has_depth_stencil_format = + HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint) || + HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint); + return has_color_format && has_depth_stencil_format; +} + +static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) { + auto properties = physical_device.getProperties(); + if (!(properties.limits.framebufferColorSampleCounts & + (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) { + return false; + } + return true; +} + +static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) { + auto queue_flags = vk::QueueFlags{}; + for (const auto& queue : physical_device.getQueueFamilyProperties()) { + if (queue.queueCount == 0) { + continue; + } + queue_flags |= queue.queueFlags; + } + return static_cast(queue_flags & + (vk::QueueFlagBits::eGraphics | + vk::QueueFlagBits::eCompute | + vk::QueueFlagBits::eTransfer)); +} + +std::optional +CapabilitiesVK::GetRequiredDeviceFeatures( + const vk::PhysicalDevice& device) const { + if (!PhysicalDeviceSupportsRequiredFormats(device)) { + VALIDATION_LOG << "Device doesn't support the required formats."; + return std::nullopt; + } + + if (!HasRequiredProperties(device)) { + VALIDATION_LOG << "Device doesn't support the required properties."; + return std::nullopt; + } + + if (!HasRequiredQueues(device)) { + VALIDATION_LOG << "Device doesn't support the required queues."; + return std::nullopt; + } + + if (!GetRequiredDeviceExtensions(device).has_value()) { + VALIDATION_LOG << "Device doesn't support the required queues."; + return std::nullopt; + } + + const auto device_features = device.getFeatures(); + + vk::PhysicalDeviceFeatures required; + + // We require this for enabling wireframes in the playground. But its not + // necessarily a big deal if we don't have this feature. + required.fillModeNonSolid = device_features.fillModeNonSolid; + + return required; } bool CapabilitiesVK::HasLayer(const std::string& layer) const { - return layers_.count(layer) == 1u; + for (const auto& [found_layer, exts] : exts_) { + if (found_layer == layer) { + return true; + } + } + return false; } -bool CapabilitiesVK::HasLayerExtension(const std::string& layer, - const std::string& extension) { - for (const auto& ext : - vk::enumerateInstanceExtensionProperties(layer).value) { - if (std::string{ext.extensionName} == extension) { +bool CapabilitiesVK::HasExtension(const std::string& ext) const { + for (const auto& [layer, exts] : exts_) { + if (exts.find(ext) != exts.end()) { return true; } } return false; } +bool CapabilitiesVK::SetDevice(const vk::PhysicalDevice& device) { + if (HasSuitableColorFormat(device, vk::Format::eB8G8R8A8Unorm)) { + color_format_ = PixelFormat::kB8G8R8A8UNormInt; + } else { + return false; + } + + if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) { + depth_stencil_format_ = PixelFormat::kS8UInt; + } else if (HasSuitableDepthStencilFormat(device, + vk::Format::eD24UnormS8Uint)) { + depth_stencil_format_ = PixelFormat::kD32FloatS8UInt; + } else { + return false; + } + return true; +} + +// |Capabilities| +bool CapabilitiesVK::HasThreadingRestrictions() const { + return false; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsOffscreenMSAA() const { + return true; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsSSBO() const { + return false; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsTextureToTextureBlits() const { + return true; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsFramebufferFetch() const { + return false; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsCompute() const { + return false; +} + +// |Capabilities| +bool CapabilitiesVK::SupportsComputeSubgroups() const { + return false; +} + +// |Capabilities| +PixelFormat CapabilitiesVK::GetDefaultColorFormat() const { + return color_format_; +} + +// |Capabilities| +PixelFormat CapabilitiesVK::GetDefaultStencilFormat() const { + return depth_stencil_format_; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 2b62e05e498ca..21545e4384bc7 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -4,29 +4,81 @@ #pragma once +#include #include #include +#include #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/capabilities.h" namespace impeller { -class CapabilitiesVK { +class ContextVK; + +//------------------------------------------------------------------------------ +/// @brief The Vulkan layers and extensions wrangler. +/// +class CapabilitiesVK final : public Capabilities { public: - CapabilitiesVK(); + CapabilitiesVK(bool enable_validations = false); ~CapabilitiesVK(); - bool HasExtension(const std::string& extension) const; + bool IsValid() const; - bool HasLayer(const std::string& layer) const; + bool AreValidationsEnabled() const; + + std::optional> GetRequiredLayers() const; + + std::optional> GetRequiredInstanceExtensions() const; + + std::optional> GetRequiredDeviceExtensions( + const vk::PhysicalDevice& physical_device) const; + + std::optional GetRequiredDeviceFeatures( + const vk::PhysicalDevice& physical_device) const; + + [[nodiscard]] bool SetDevice(const vk::PhysicalDevice& physical_device); + + // |Capabilities| + bool HasThreadingRestrictions() const override; + + // |Capabilities| + bool SupportsOffscreenMSAA() const override; - bool HasLayerExtension(const std::string& layer, - const std::string& extension); + // |Capabilities| + bool SupportsSSBO() const override; + + // |Capabilities| + bool SupportsTextureToTextureBlits() const override; + + // |Capabilities| + bool SupportsFramebufferFetch() const override; + + // |Capabilities| + bool SupportsCompute() const override; + + // |Capabilities| + bool SupportsComputeSubgroups() const override; + + // |Capabilities| + PixelFormat GetDefaultColorFormat() const override; + + // |Capabilities| + PixelFormat GetDefaultStencilFormat() const override; private: - std::set extensions_; - std::set layers_; + const bool enable_validations_; + std::map> exts_; + PixelFormat color_format_ = PixelFormat::kUnknown; + PixelFormat depth_stencil_format_ = PixelFormat::kUnknown; + bool is_valid_ = false; + + bool HasExtension(const std::string& ext) const; + + bool HasLayer(const std::string& layer) const; FML_DISALLOW_COPY_AND_ASSIGN(CapabilitiesVK); }; diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.cc b/impeller/renderer/backend/vulkan/command_encoder_vk.cc index 6fbf12950f49b..a65d61249aedd 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc @@ -5,31 +5,91 @@ #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "flutter/fml/closure.h" +#include "flutter/fml/trace_event.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" namespace impeller { +class TrackedObjectsVK { + public: + explicit TrackedObjectsVK(const vk::Device& device, + const std::shared_ptr& pool) + : desc_pool_(device) { + if (!pool) { + return; + } + auto buffer = pool->CreateGraphicsCommandBuffer(); + if (!buffer) { + return; + } + pool_ = pool; + buffer_ = std::move(buffer); + is_valid_ = true; + } + + ~TrackedObjectsVK() { + if (!buffer_) { + return; + } + auto pool = pool_.lock(); + if (!pool) { + VALIDATION_LOG + << "Command pool died before a command buffer could be recycled."; + return; + } + pool->CollectGraphicsCommandBuffer(std::move(buffer_)); + } + + bool IsValid() const { return is_valid_; } + + void Track(std::shared_ptr object) { + tracked_objects_.insert(std::move(object)); + } + + void Track(std::shared_ptr buffer) { + tracked_buffers_.insert(std::move(buffer)); + } + + void Track(std::shared_ptr texture) { + tracked_textures_.insert(std::move(texture)); + } + + vk::CommandBuffer GetCommandBuffer() const { return *buffer_; } + + DescriptorPoolVK& GetDescriptorPool() { return desc_pool_; } + + private: + DescriptorPoolVK desc_pool_; + std::weak_ptr pool_; + vk::UniqueCommandBuffer buffer_; + std::set> tracked_objects_; + std::set> tracked_buffers_; + std::set> tracked_textures_; + bool is_valid_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(TrackedObjectsVK); +}; + CommandEncoderVK::CommandEncoderVK(vk::Device device, vk::Queue queue, - vk::CommandPool pool) { - vk::CommandBufferAllocateInfo alloc_info; - alloc_info.commandPool = pool; - alloc_info.commandBufferCount = 1u; - alloc_info.level = vk::CommandBufferLevel::ePrimary; - auto [result, buffers] = device.allocateCommandBuffersUnique(alloc_info); - if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create command buffer."; + const std::shared_ptr& pool, + std::shared_ptr fence_waiter) + : fence_waiter_(std::move(fence_waiter)), + tracked_objects_(std::make_shared(device, pool)) { + if (!fence_waiter_ || !tracked_objects_->IsValid()) { return; } vk::CommandBufferBeginInfo begin_info; begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - if (buffers[0]->begin(begin_info) != vk::Result::eSuccess) { + if (tracked_objects_->GetCommandBuffer().begin(begin_info) != + vk::Result::eSuccess) { VALIDATION_LOG << "Could not begin command buffer."; return; } device_ = device; queue_ = queue; - command_buffer_ = std::move(buffers[0]); is_valid_ = true; } @@ -47,39 +107,40 @@ bool CommandEncoderVK::Submit() { // Success or failure, you only get to submit once. fml::ScopedCleanupClosure reset([&]() { Reset(); }); - if (command_buffer_->end() != vk::Result::eSuccess) { + InsertDebugMarker("QueueSubmit"); + + auto command_buffer = GetCommandBuffer(); + + if (command_buffer.end() != vk::Result::eSuccess) { return false; } auto [fence_result, fence] = device_.createFenceUnique({}); if (fence_result != vk::Result::eSuccess) { return false; } + vk::SubmitInfo submit_info; - submit_info.setCommandBuffers(*command_buffer_); + std::vector buffers = {command_buffer}; + submit_info.setCommandBuffers(buffers); if (queue_.submit(submit_info, *fence) != vk::Result::eSuccess) { return false; } - if (device_.waitForFences( - *fence, // fences - true, // wait all - std::numeric_limits::max() // timeout (ns) - ) != vk::Result::eSuccess) { - return false; - } - return true; + return fence_waiter_->AddFence( + std::move(fence), [tracked_objects = std::move(tracked_objects_)] { + // Nothing to do, we just drop the tracked objects on the floor. + }); } -const vk::CommandBuffer& CommandEncoderVK::GetCommandBuffer() const { - return *command_buffer_; +vk::CommandBuffer CommandEncoderVK::GetCommandBuffer() const { + if (tracked_objects_) { + return tracked_objects_->GetCommandBuffer(); + } + return {}; } void CommandEncoderVK::Reset() { - command_buffer_.reset(); - - tracked_objects_.clear(); - tracked_buffers_.clear(); - tracked_textures_.clear(); + tracked_objects_.reset(); queue_ = nullptr; device_ = nullptr; @@ -87,34 +148,82 @@ void CommandEncoderVK::Reset() { } bool CommandEncoderVK::Track(std::shared_ptr object) { - tracked_objects_.push_back(std::move(object)); + if (!IsValid()) { + return false; + } + tracked_objects_->Track(std::move(object)); return true; } bool CommandEncoderVK::Track(std::shared_ptr buffer) { - tracked_buffers_.emplace_back(std::move(buffer)); + if (!IsValid()) { + return false; + } + tracked_objects_->Track(std::move(buffer)); return true; } -bool CommandEncoderVK::Track(std::shared_ptr texture) { - tracked_textures_.emplace_back(std::move(texture)); +bool CommandEncoderVK::Track(std::shared_ptr texture) { + if (!IsValid()) { + return false; + } + tracked_objects_->Track(std::move(texture)); return true; } +bool CommandEncoderVK::Track(const std::shared_ptr& texture) { + if (!texture) { + return false; + } + return Track(TextureVK::Cast(*texture).GetTextureSource()); +} + +std::optional CommandEncoderVK::AllocateDescriptorSet( + const vk::DescriptorSetLayout& layout) { + if (!IsValid()) { + return std::nullopt; + } + return tracked_objects_->GetDescriptorPool().AllocateDescriptorSet(layout); +} + void CommandEncoderVK::PushDebugGroup(const char* label) const { - if (!vk::HasValidationLayers() || !command_buffer_) { + if (!HasValidationLayers()) { return; } vk::DebugUtilsLabelEXT label_info; label_info.pLabelName = label; - command_buffer_->beginDebugUtilsLabelEXT(label_info); + if (auto command_buffer = GetCommandBuffer()) { + command_buffer.beginDebugUtilsLabelEXT(label_info); + } + if (queue_) { + queue_.beginDebugUtilsLabelEXT(label_info); + } } void CommandEncoderVK::PopDebugGroup() const { - if (!vk::HasValidationLayers() || !command_buffer_) { + if (!HasValidationLayers()) { return; } - command_buffer_->endDebugUtilsLabelEXT(); + if (auto command_buffer = GetCommandBuffer()) { + command_buffer.endDebugUtilsLabelEXT(); + } + if (queue_) { + queue_.endDebugUtilsLabelEXT(); + } +} + +void CommandEncoderVK::InsertDebugMarker(const char* label) const { + if (!HasValidationLayers()) { + return; + } + vk::DebugUtilsLabelEXT label_info; + label_info.pLabelName = label; + if (auto command_buffer = GetCommandBuffer()) { + command_buffer.insertDebugUtilsLabelEXT(label_info); + } + if (queue_) { + queue_.insertDebugUtilsLabelEXT(label_info); + } } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.h b/impeller/renderer/backend/vulkan/command_encoder_vk.h index 66ac47f39bf68..8db33b50c1a7d 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.h +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h @@ -4,9 +4,12 @@ #pragma once -#include +#include +#include #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/command_pool_vk.h" +#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" #include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" @@ -15,6 +18,9 @@ namespace impeller { class ContextVK; class DeviceBuffer; class Texture; +class TextureSourceVK; +class TrackedObjectsVK; +class FenceWaiterVK; class CommandEncoderVK { public: @@ -28,26 +34,35 @@ class CommandEncoderVK { bool Track(std::shared_ptr buffer); - bool Track(std::shared_ptr texture); + bool Track(const std::shared_ptr& texture); - const vk::CommandBuffer& GetCommandBuffer() const; + bool Track(std::shared_ptr texture); + + vk::CommandBuffer GetCommandBuffer() const; void PushDebugGroup(const char* label) const; void PopDebugGroup() const; + void InsertDebugMarker(const char* label) const; + + std::optional AllocateDescriptorSet( + const vk::DescriptorSetLayout& layout); + private: friend class ContextVK; vk::Device device_ = {}; vk::Queue queue_ = {}; - vk::UniqueCommandBuffer command_buffer_; - std::vector> tracked_objects_; - std::vector> tracked_buffers_; - std::vector> tracked_textures_; + + std::shared_ptr fence_waiter_; + std::shared_ptr tracked_objects_; bool is_valid_ = false; - CommandEncoderVK(vk::Device device, vk::Queue queue, vk::CommandPool pool); + CommandEncoderVK(vk::Device device, + vk::Queue queue, + const std::shared_ptr& pool, + std::shared_ptr fence_waiter); void Reset(); diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.cc b/impeller/renderer/backend/vulkan/command_pool_vk.cc new file mode 100644 index 0000000000000..5ed2ed404807c --- /dev/null +++ b/impeller/renderer/backend/vulkan/command_pool_vk.cc @@ -0,0 +1,135 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/vulkan/command_pool_vk.h" + +#include +#include +#include + +#include "flutter/fml/thread_local.h" +#include "impeller/base/thread.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" + +namespace impeller { + +using CommandPoolMap = + std::map>; + +FML_THREAD_LOCAL fml::ThreadLocalUniquePtr tls_command_pool; + +static Mutex g_all_pools_mutex; +static std::unordered_map>> + g_all_pools IPLR_GUARDED_BY(g_all_pools_mutex); + +std::shared_ptr CommandPoolVK::GetThreadLocal( + const ContextVK* context) { + if (!context) { + return nullptr; + } + if (tls_command_pool.get() == nullptr) { + tls_command_pool.reset(new CommandPoolMap()); + } + CommandPoolMap& pool_map = *tls_command_pool.get(); + auto found = pool_map.find(context); + if (found != pool_map.end() && found->second->IsValid()) { + return found->second; + } + auto pool = std::shared_ptr(new CommandPoolVK(context)); + if (!pool->IsValid()) { + return nullptr; + } + pool_map[context] = pool; + { + Lock pool_lock(g_all_pools_mutex); + g_all_pools[context].push_back(pool); + } + return pool; +} + +void CommandPoolVK::ClearAllPools(const ContextVK* context) { + Lock pool_lock(g_all_pools_mutex); + if (auto found = g_all_pools.find(context); found != g_all_pools.end()) { + for (auto& weak_pool : found->second) { + auto pool = weak_pool.lock(); + if (!pool) { + // The pool has already died because the thread died. + continue; + } + // The pool is reset but its reference in the TLS map remains till the + // thread dies. + pool->Reset(); + } + g_all_pools.erase(found); + } +} + +CommandPoolVK::CommandPoolVK(const ContextVK* context) + : owner_id_(std::this_thread::get_id()) { + vk::CommandPoolCreateInfo pool_info; + + pool_info.queueFamilyIndex = context->GetGraphicsQueueInfo().index; + pool_info.flags = vk::CommandPoolCreateFlagBits::eTransient; + auto pool = context->GetDevice().createCommandPoolUnique(pool_info); + if (pool.result != vk::Result::eSuccess) { + return; + } + + device_ = context->GetDevice(); + graphics_pool_ = std::move(pool.value); + is_valid_ = true; +} + +CommandPoolVK::~CommandPoolVK() = default; + +bool CommandPoolVK::IsValid() const { + return is_valid_; +} + +void CommandPoolVK::Reset() { + Lock lock(buffers_to_collect_mutex_); + GarbageCollectBuffersIfAble(); + graphics_pool_.reset(); + is_valid_ = false; +} + +vk::CommandPool CommandPoolVK::GetGraphicsCommandPool() const { + return graphics_pool_.get(); +} + +vk::UniqueCommandBuffer CommandPoolVK::CreateGraphicsCommandBuffer() { + if (std::this_thread::get_id() != owner_id_) { + return {}; + } + { + Lock lock(buffers_to_collect_mutex_); + GarbageCollectBuffersIfAble(); + } + vk::CommandBufferAllocateInfo alloc_info; + alloc_info.commandPool = graphics_pool_.get(); + alloc_info.commandBufferCount = 1u; + alloc_info.level = vk::CommandBufferLevel::ePrimary; + auto [result, buffers] = device_.allocateCommandBuffersUnique(alloc_info); + if (result != vk::Result::eSuccess) { + return {}; + } + return std::move(buffers[0]); +} + +void CommandPoolVK::CollectGraphicsCommandBuffer( + vk::UniqueCommandBuffer buffer) { + Lock lock(buffers_to_collect_mutex_); + buffers_to_collect_.insert(MakeSharedVK(std::move(buffer))); + GarbageCollectBuffersIfAble(); +} + +void CommandPoolVK::GarbageCollectBuffersIfAble() { + if (std::this_thread::get_id() != owner_id_) { + return; + } + buffers_to_collect_.clear(); +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.h b/impeller/renderer/backend/vulkan/command_pool_vk.h new file mode 100644 index 0000000000000..7399e22686075 --- /dev/null +++ b/impeller/renderer/backend/vulkan/command_pool_vk.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/base/thread.h" +#include "impeller/renderer/backend/vulkan/shared_object_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class ContextVK; + +class CommandPoolVK { + public: + static std::shared_ptr GetThreadLocal( + const ContextVK* context); + + static void ClearAllPools(const ContextVK* context); + + ~CommandPoolVK(); + + bool IsValid() const; + + void Reset(); + + vk::CommandPool GetGraphicsCommandPool() const; + + vk::UniqueCommandBuffer CreateGraphicsCommandBuffer(); + + void CollectGraphicsCommandBuffer(vk::UniqueCommandBuffer buffer); + + private: + const std::thread::id owner_id_; + vk::Device device_ = {}; + vk::UniqueCommandPool graphics_pool_; + Mutex buffers_to_collect_mutex_; + std::set> buffers_to_collect_ + IPLR_GUARDED_BY(buffers_to_collect_mutex_); + bool is_valid_ = false; + + explicit CommandPoolVK(const ContextVK* context); + + void GarbageCollectBuffersIfAble() IPLR_REQUIRES(buffers_to_collect_mutex_); + + FML_DISALLOW_COPY_AND_ASSIGN(CommandPoolVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index a7974915d1f81..c394f3627b353 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -20,156 +20,30 @@ #include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" +#include "impeller/renderer/backend/vulkan/command_pool_vk.h" +#include "impeller/renderer/backend/vulkan/debug_report_vk.h" +#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/surface_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" -#include "impeller/renderer/device_capabilities.h" +#include "impeller/renderer/capabilities.h" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE -namespace { - -// TODO(csg): Mimic vulkan_debug_report.cc for prettier reports. -VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessengerCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) { - // There isn't stable messageIdNumber for this validation failure. - if (strstr(pCallbackData->pMessageIdName, - "CoreValidation-Shader-OutputNotConsumed") != nullptr) { - return VK_FALSE; - } - - if (pCallbackData->messageIdNumber == static_cast(0x82ae5050)) { - // This is a real error but we can't fix it due to our headers being too - // old. More more details see: - // https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465 - // This validation error currently only trips on macOS due to the use of - // texture swizzles. - return VK_FALSE; - } - - const auto prefix = impeller::vk::to_string( - impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT(severity)); - // Just so that the log doesn't say FML_DCHECK(false). - constexpr bool kVulkanValidationFailure = false; - FML_DCHECK(kVulkanValidationFailure) - << prefix << "[" << pCallbackData->messageIdNumber << "][" - << pCallbackData->pMessageIdName << "] : " << pCallbackData->pMessage; - - // The return value of this callback controls whether the Vulkan call that - // caused the validation message will be aborted or not We return VK_TRUE as - // we DO want Vulkan calls that cause a validation message to abort - return VK_TRUE; -} - -} // namespace - namespace impeller { -namespace vk { +// TODO(csg): Fix this after caps are reworked. +static bool gHasValidationLayers = false; bool HasValidationLayers() { - auto capabilities = std::make_unique(); - return capabilities->HasLayer(kKhronosValidationLayerName); -} - -} // namespace vk - -static std::set kRequiredDeviceExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, -#if FML_OS_MACOSX - "VK_KHR_portability_subset", // For Molten VK. No define present in header. -#endif -}; - -std::vector kRequiredWSIInstanceExtensions = { -#if FML_OS_WIN - "VK_KHR_win32_surface", -#elif FML_OS_ANDROID - "VK_KHR_android_surface", -#elif FML_OS_LINUX - "VK_KHR_xcb_surface", - "VK_KHR_xlib_surface", - "VK_KHR_wayland_surface", -#elif FML_OS_MACOSX - "VK_EXT_metal_surface", -#endif -}; - -#if FML_OS_MACOSX -static const char* MVK_MACOS_SURFACE_EXT = "VK_MVK_macos_surface"; -#endif - -static bool HasRequiredQueues(const vk::PhysicalDevice& device) { - auto present_flags = vk::QueueFlags{}; - for (const auto& queue : device.getQueueFamilyProperties()) { - if (queue.queueCount == 0) { - continue; - } - present_flags |= queue.queueFlags; - } - return static_cast(present_flags & - (vk::QueueFlagBits::eGraphics | - vk::QueueFlagBits::eCompute | - vk::QueueFlagBits::eTransfer)); -} - -static std::vector HasRequiredExtensions( - const vk::PhysicalDevice& device) { - std::set exts; - std::vector missing; - for (const auto& ext : device.enumerateDeviceExtensionProperties().value) { - exts.insert(ext.extensionName); - } - for (const auto& req_ext : kRequiredDeviceExtensions) { - if (exts.count(req_ext) != 1u) { - missing.push_back(req_ext); - } - } - return missing; -} - -static vk::PhysicalDeviceFeatures GetRequiredPhysicalDeviceFeatures() { - vk::PhysicalDeviceFeatures features; -#ifndef NDEBUG - features.setRobustBufferAccess(true); -#endif // NDEBUG - return features; -}; - -static bool HasRequiredProperties(const vk::PhysicalDevice& device) { - auto properties = device.getProperties(); - if (!(properties.limits.framebufferColorSampleCounts & - (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) { - return false; - } - return true; -} - -static bool IsPhysicalDeviceCompatible(const vk::PhysicalDevice& device) { - if (!HasRequiredQueues(device)) { - FML_LOG(ERROR) << "Device doesn't have required queues."; - return false; - } - auto missing_exts = HasRequiredExtensions(device); - if (!missing_exts.empty()) { - FML_LOG(ERROR) << "Device doesn't have required extensions: " - << fml::Join(missing_exts, ", "); - return false; - } - if (!HasRequiredProperties(device)) { - FML_LOG(ERROR) << "Device doesn't have required properties."; - return false; - } - return true; + return gHasValidationLayers; } static std::optional PickPhysicalDevice( + const CapabilitiesVK& caps, const vk::Instance& instance) { for (const auto& device : instance.enumeratePhysicalDevices().value) { - if (IsPhysicalDeviceCompatible(device)) { + if (caps.GetRequiredDeviceFeatures(device).has_value()) { return device; } } @@ -219,27 +93,37 @@ std::shared_ptr ContextVK::Create( const std::shared_ptr& pipeline_cache_data, std::shared_ptr worker_task_runner, const std::string& label) { - auto context = std::shared_ptr(new ContextVK( - proc_address_callback, // - shader_libraries_data, // - pipeline_cache_data, // - std::move(worker_task_runner), // - label // - )); + auto context = std::shared_ptr(new ContextVK()); + context->Setup(proc_address_callback, // + shader_libraries_data, // + pipeline_cache_data, // + std::move(worker_task_runner), // + label // + ); if (!context->IsValid()) { return nullptr; } return context; } -ContextVK::ContextVK( +ContextVK::ContextVK() = default; + +ContextVK::~ContextVK() { + if (device_) { + [[maybe_unused]] auto result = device_->waitIdle(); + } + CommandPoolVK::ClearAllPools(this); +} + +void ContextVK::Setup( PFN_vkGetInstanceProcAddr proc_address_callback, const std::vector>& shader_libraries_data, const std::shared_ptr& pipeline_cache_data, std::shared_ptr worker_task_runner, - const std::string& label) - : worker_task_runner_(std::move(worker_task_runner)) { - TRACE_EVENT0("impeller", "ContextVK::Create"); + const std::string& label) { + TRACE_EVENT0("impeller", "ContextVK::Setup"); + + worker_task_runner_ = std::move(worker_task_runner); if (!worker_task_runner_) { VALIDATION_LOG << "Invalid worker task runner."; @@ -249,95 +133,41 @@ ContextVK::ContextVK( auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; dispatcher.init(proc_address_callback); - auto capabilities = std::make_unique(); + auto caps = std::shared_ptr(new CapabilitiesVK()); - vk::InstanceCreateFlags instance_flags = {}; - std::vector enabled_layers; - std::vector enabled_extensions; - -// This define may need to change into a runtime check if using SwiftShader on -// Mac. -#if FML_OS_MACOSX - //---------------------------------------------------------------------------- - /// Ensure we need any Vulkan implementations that are not fully compliant - /// with the requested Vulkan Spec. This is necessary for MoltenVK on Mac - /// (backed by Metal). - /// - if (!capabilities->HasExtension( - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) { - VALIDATION_LOG << "On Mac: Required extension " - << VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME - << " absent."; + if (!caps->IsValid()) { + VALIDATION_LOG << "Could not determine device capabilities."; return; } - // Molten VK on Mac is not fully compliant. We opt into being OK not getting - // back a fully compliant version of a Vulkan implementation. - enabled_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; - if (!capabilities->HasExtension( - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { - VALIDATION_LOG << "On Mac: Required extension " - << VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME - << " absent."; - return; - } - // This is dependency of VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME which - // is a requirement for opting into Molten VK on Mac. - enabled_extensions.push_back( - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + gHasValidationLayers = caps->AreValidationsEnabled(); - // Required for glfw macOS surfaces. - if (!capabilities->HasExtension(MVK_MACOS_SURFACE_EXT)) { - VALIDATION_LOG << "On Mac: Required extension " << MVK_MACOS_SURFACE_EXT - << " absent."; - return; - } - enabled_extensions.push_back(MVK_MACOS_SURFACE_EXT); -#endif // FML_OS_MACOSX + auto enabled_layers = caps->GetRequiredLayers(); + auto enabled_extensions = caps->GetRequiredInstanceExtensions(); - //---------------------------------------------------------------------------- - /// Even though this is a WSI responsibility, require the surface extension - /// for swapchains. - if (!capabilities->HasExtension(VK_KHR_SURFACE_EXTENSION_NAME)) { - VALIDATION_LOG << "Required extension " VK_KHR_SURFACE_EXTENSION_NAME - << " absent."; + if (!enabled_layers.has_value() || !enabled_extensions.has_value()) { + VALIDATION_LOG << "Device has insufficient capabilities."; return; } - enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - //---------------------------------------------------------------------------- - /// Enable WSI Instance Extensions. Having any one of these is sufficient. - /// - bool has_wsi_extensions = false; - for (const auto& wsi_ext : kRequiredWSIInstanceExtensions) { - if (capabilities->HasExtension(wsi_ext)) { - enabled_extensions.push_back(wsi_ext.c_str()); - has_wsi_extensions = true; - } + vk::InstanceCreateFlags instance_flags = {}; + + if (std::find(enabled_extensions.value().begin(), + enabled_extensions.value().end(), + "VK_KHR_portability_enumeration") != + enabled_extensions.value().end()) { + instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; } - if (!has_wsi_extensions) { - VALIDATION_LOG - << "Instance doesn't have any of the required WSI extensions: " - << fml::Join(kRequiredWSIInstanceExtensions, ", "); - return; + + std::vector enabled_layers_c; + std::vector enabled_extensions_c; + + for (const auto& layer : enabled_layers.value()) { + enabled_layers_c.push_back(layer.c_str()); } - //---------------------------------------------------------------------------- - /// Enable any and all validation as well as debug toggles. - /// - auto has_debug_utils = false; - if (vk::HasValidationLayers()) { - enabled_layers.push_back(vk::kKhronosValidationLayerName); - if (capabilities->HasLayerExtension(vk::kKhronosValidationLayerName, - VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { - enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - has_debug_utils = true; - } else { - FML_LOG(ERROR) << "Vulkan debug utils are absent."; - } - } else { - FML_LOG(ERROR) << "Vulkan validation layers are absent."; + for (const auto& ext : enabled_extensions.value()) { + enabled_extensions_c.push_back(ext.c_str()); } vk::ApplicationInfo application_info; @@ -347,52 +177,50 @@ ContextVK::ContextVK( application_info.setPEngineName("Impeller"); application_info.setPApplicationName("Impeller"); + std::vector enabled_validations = { + // vk::ValidationFeatureEnableEXT::eBestPractices, + // vk::ValidationFeatureEnableEXT::eSynchronizationValidation, + }; + + vk::ValidationFeaturesEXT validation; + validation.setEnabledValidationFeatures(enabled_validations); + vk::InstanceCreateInfo instance_info; - instance_info.setPEnabledLayerNames(enabled_layers); - instance_info.setPEnabledExtensionNames(enabled_extensions); + if (caps->AreValidationsEnabled()) { + instance_info.pNext = &validation; + } + instance_info.setPEnabledLayerNames(enabled_layers_c); + instance_info.setPEnabledExtensionNames(enabled_extensions_c); instance_info.setPApplicationInfo(&application_info); instance_info.setFlags(instance_flags); auto instance = vk::createInstanceUnique(instance_info); if (instance.result != vk::Result::eSuccess) { - FML_LOG(ERROR) << "Could not create instance: " + VALIDATION_LOG << "Could not create instance: " << vk::to_string(instance.result); return; } dispatcher.init(instance.value.get()); - vk::UniqueDebugUtilsMessengerEXT debug_messenger; - - if (has_debug_utils) { - vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_info; - debug_messenger_info.messageSeverity = - vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | - vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; - debug_messenger_info.messageType = - vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | - vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | - vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation; - debug_messenger_info.pUserData = nullptr; - debug_messenger_info.pfnUserCallback = DebugUtilsMessengerCallback; - - auto debug_messenger_result = - instance.value->createDebugUtilsMessengerEXTUnique( - debug_messenger_info); - - if (debug_messenger_result.result != vk::Result::eSuccess) { - FML_LOG(ERROR) << "Could not create debug messenger: " - << vk::to_string(debug_messenger_result.result); - return; - } + //---------------------------------------------------------------------------- + /// Setup the debug report. + /// + /// Do this as early as possible since we could use the debug report from + /// initialization issues. + /// + auto debug_report = + std::make_unique(*caps, instance.value.get()); - debug_messenger = std::move(debug_messenger_result.value); + if (!debug_report->IsValid()) { + VALIDATION_LOG << "Could not setup debug report."; + return; } //---------------------------------------------------------------------------- /// Pick the physical device. /// - auto physical_device = PickPhysicalDevice(instance.value.get()); + auto physical_device = PickPhysicalDevice(*caps, instance.value.get()); if (!physical_device.has_value()) { VALIDATION_LOG << "No valid Vulkan device found."; return; @@ -408,29 +236,44 @@ ContextVK::ContextVK( auto compute_queue = PickQueue(physical_device.value(), vk::QueueFlagBits::eCompute); - physical_device_ = physical_device.value(); - if (!graphics_queue.has_value() || !transfer_queue.has_value() || !compute_queue.has_value()) { VALIDATION_LOG << "Could not pick device queues."; return; } - std::vector required_extensions; - for (const auto& ext : kRequiredDeviceExtensions) { - required_extensions.push_back(ext.data()); + //---------------------------------------------------------------------------- + /// Create the logical device. + /// + auto enabled_device_extensions = + caps->GetRequiredDeviceExtensions(physical_device.value()); + if (!enabled_device_extensions.has_value()) { + // This shouldn't happen since we already did device selection. But doesn't + // hurt to check again. + return; + } + + std::vector enabled_device_extensions_c; + for (const auto& ext : enabled_device_extensions.value()) { + enabled_device_extensions_c.push_back(ext.c_str()); } const auto queue_create_infos = GetQueueCreateInfos( {graphics_queue.value(), compute_queue.value(), transfer_queue.value()}); - const auto required_features = GetRequiredPhysicalDeviceFeatures(); + const auto required_features = + caps->GetRequiredDeviceFeatures(physical_device.value()); + if (!required_features.has_value()) { + // This shouldn't happen since the device can't be picked if this was not + // true. But doesn't hurt to check. + return; + } vk::DeviceCreateInfo device_info; device_info.setQueueCreateInfos(queue_create_infos); - device_info.setPEnabledExtensionNames(required_extensions); - device_info.setPEnabledFeatures(&required_features); + device_info.setPEnabledExtensionNames(enabled_device_extensions_c); + device_info.setPEnabledFeatures(&required_features.value()); // Device layers are deprecated and ignored. auto device = physical_device->createDeviceUnique(device_info); @@ -439,6 +282,14 @@ ContextVK::ContextVK( return; } + if (!caps->SetDevice(physical_device.value())) { + VALIDATION_LOG << "Capabilities could not be updated."; + return; + } + + //---------------------------------------------------------------------------- + /// Create the allocator. + /// auto allocator = std::shared_ptr(new AllocatorVK( weak_from_this(), // application_info.apiVersion, // @@ -479,6 +330,9 @@ ContextVK::ContextVK( return; } + //---------------------------------------------------------------------------- + /// Setup the work queues. + /// auto work_queue = WorkQueueCommon::Create(); if (!work_queue) { @@ -487,47 +341,12 @@ ContextVK::ContextVK( } //---------------------------------------------------------------------------- - /// Setup the command pool. + /// Create the fence waiter. /// - vk::CommandPoolCreateInfo graphics_command_pool_info; - graphics_command_pool_info.queueFamilyIndex = graphics_queue->index; - graphics_command_pool_info.flags = vk::CommandPoolCreateFlagBits::eTransient; - auto graphics_command_pool = - device.value->createCommandPoolUnique(graphics_command_pool_info); - if (graphics_command_pool.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create graphics command pool."; - return; - } - - //---------------------------------------------------------------------------- - /// Setup the descriptor pool. This needs to be dynamic but we just allocate a - /// jumbo pool and hope for the best. - /// - constexpr size_t kPoolSize = 1024 * 3; - - std::vector pool_sizes = { - {vk::DescriptorType::eSampler, kPoolSize}, - {vk::DescriptorType::eCombinedImageSampler, kPoolSize}, - {vk::DescriptorType::eSampledImage, kPoolSize}, - {vk::DescriptorType::eStorageImage, kPoolSize}, - {vk::DescriptorType::eUniformTexelBuffer, kPoolSize}, - {vk::DescriptorType::eStorageTexelBuffer, kPoolSize}, - {vk::DescriptorType::eUniformBuffer, kPoolSize}, - {vk::DescriptorType::eStorageBuffer, kPoolSize}, - {vk::DescriptorType::eUniformBufferDynamic, kPoolSize}, - {vk::DescriptorType::eStorageBufferDynamic, kPoolSize}, - {vk::DescriptorType::eInputAttachment, kPoolSize}, - }; - vk::DescriptorPoolCreateInfo pool_info = { - vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, // flags - static_cast(pool_sizes.size() * kPoolSize), // max sets - static_cast(pool_sizes.size()), // pool sizes count - pool_sizes.data() // pool sizes - }; - - auto descriptor_pool = device.value->createDescriptorPoolUnique(pool_info); - if (descriptor_pool.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Unable to create a descriptor pool"; + auto fence_waiter = + std::shared_ptr(new FenceWaiterVK(device.value.get())); + if (!fence_waiter->IsValid()) { + VALIDATION_LOG << "Could not create fence waiter."; return; } @@ -535,7 +354,8 @@ ContextVK::ContextVK( /// All done! /// instance_ = std::move(instance.value); - debug_messenger_ = std::move(debug_messenger); + debug_report_ = std::move(debug_report); + physical_device_ = physical_device.value(); device_ = std::move(device.value); allocator_ = std::move(allocator); shader_library_ = std::move(shader_library); @@ -548,27 +368,21 @@ ContextVK::ContextVK( device_->getQueue(compute_queue->family, compute_queue->index); transfer_queue_ = device_->getQueue(transfer_queue->family, transfer_queue->index); - device_capabilities_ = - DeviceCapabilitiesBuilder() - .SetHasThreadingRestrictions(false) - .SetSupportsOffscreenMSAA(true) - .SetSupportsSSBO(false) - .SetSupportsTextureToTextureBlits(true) - .SetSupportsFramebufferFetch(false) - .SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt) - .SetDefaultStencilFormat(PixelFormat::kS8UInt) - // TODO(110622): detect this and enable. - .SetSupportsCompute(false, false) - .Build(); - graphics_command_pool_ = std::move(graphics_command_pool.value); - descriptor_pool_ = std::move(descriptor_pool.value); + graphics_queue_info_ = graphics_queue.value(); + compute_queue_info_ = compute_queue.value(); + transfer_queue_info_ = transfer_queue.value(); + device_capabilities_ = std::move(caps); + fence_waiter_ = std::move(fence_waiter); is_valid_ = true; -} -ContextVK::~ContextVK() { - if (device_) { - [[maybe_unused]] auto result = device_->waitIdle(); - } + //---------------------------------------------------------------------------- + /// Label all the relevant objects. This happens after setup so that the debug + /// messengers have had a chance to be setup. + /// + SetDebugName(device_.get(), device_.get(), "ImpellerDevice"); + SetDebugName(device_.get(), graphics_queue_, "ImpellerGraphicsQ"); + SetDebugName(device_.get(), compute_queue_, "ImpellerComputeQ"); + SetDebugName(device_.get(), transfer_queue_, "ImpellerTransferQ"); } bool ContextVK::IsValid() const { @@ -597,9 +411,13 @@ std::shared_ptr ContextVK::GetWorkQueue() const { } std::shared_ptr ContextVK::CreateCommandBuffer() const { + auto encoder = CreateGraphicsCommandEncoder(); + if (!encoder) { + return nullptr; + } return std::shared_ptr( - new CommandBufferVK(shared_from_this(), // - CreateGraphicsCommandEncoder()) // + new CommandBufferVK(shared_from_this(), // + std::move(encoder)) // ); } @@ -646,37 +464,37 @@ bool ContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) { return true; } -PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { - return swapchain_ ? ToPixelFormat(swapchain_->GetSurfaceFormat()) - : PixelFormat::kB8G8R8A8UNormInt; -} - -const IDeviceCapabilities& ContextVK::GetDeviceCapabilities() const { - return *device_capabilities_; +const std::shared_ptr& ContextVK::GetCapabilities() const { + return device_capabilities_; } vk::Queue ContextVK::GetGraphicsQueue() const { return graphics_queue_; } -vk::CommandPool ContextVK::GetGraphicsCommandPool() const { - return *graphics_command_pool_; -} - -vk::DescriptorPool ContextVK::GetDescriptorPool() const { - return *descriptor_pool_; +QueueVK ContextVK::GetGraphicsQueueInfo() const { + return graphics_queue_info_; } vk::PhysicalDevice ContextVK::GetPhysicalDevice() const { return physical_device_; } +std::shared_ptr ContextVK::GetFenceWaiter() const { + return fence_waiter_; +} + std::unique_ptr ContextVK::CreateGraphicsCommandEncoder() const { + auto tls_pool = CommandPoolVK::GetThreadLocal(this); + if (!tls_pool) { + return nullptr; + } auto encoder = std::unique_ptr(new CommandEncoderVK( - *device_, // - graphics_queue_, // - *graphics_command_pool_ // + *device_, // + graphics_queue_, // + tls_pool, // + fence_waiter_ // )); if (!encoder->IsValid()) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 3cd22bb490b2b..089417971b960 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -15,24 +15,18 @@ #include "impeller/renderer/backend/vulkan/shader_library_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/context.h" -#include "impeller/renderer/device_capabilities.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/surface.h" namespace impeller { -namespace vk { - -// TODO(csg): Move this to its own TU for validations. -constexpr const char* kKhronosValidationLayerName = - "VK_LAYER_KHRONOS_validation"; - bool HasValidationLayers(); -} // namespace vk - class CommandEncoderVK; +class DebugReportVK; +class FenceWaiterVK; class ContextVK final : public Context, public BackendCast { public: @@ -64,14 +58,11 @@ class ContextVK final : public Context, public BackendCast { // |Context| std::shared_ptr CreateCommandBuffer() const override; - // |Context| - PixelFormat GetColorAttachmentPixelFormat() const override; - // |Context| std::shared_ptr GetWorkQueue() const override; // |Context| - const IDeviceCapabilities& GetDeviceCapabilities() const override; + const std::shared_ptr& GetCapabilities() const override; template bool SetDebugName(T handle, std::string_view label) const { @@ -82,22 +73,19 @@ class ContextVK final : public Context, public BackendCast { static bool SetDebugName(vk::Device device, T handle, std::string_view label) { - if (!vk::HasValidationLayers()) { + if (!HasValidationLayers()) { // No-op if validation layers are not enabled. return true; } - uint64_t handle_ptr = - reinterpret_cast(static_cast(handle)); + auto c_handle = static_cast(handle); - std::string label_str = std::string(label); - auto ret = device.setDebugUtilsObjectNameEXT( - vk::DebugUtilsObjectNameInfoEXT() - .setObjectType(T::objectType) - .setObjectHandle(handle_ptr) - .setPObjectName(label_str.c_str())); + vk::DebugUtilsObjectNameInfoEXT info; + info.objectType = T::objectType; + info.pObjectName = label.data(); + info.objectHandle = reinterpret_cast(c_handle); - if (ret != vk::Result::eSuccess) { + if (device.setDebugUtilsObjectNameEXT(info) != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to set debug name: " << label; return false; } @@ -119,16 +107,16 @@ class ContextVK final : public Context, public BackendCast { vk::Queue GetGraphicsQueue() const; - vk::CommandPool GetGraphicsCommandPool() const; - - vk::DescriptorPool GetDescriptorPool() const; + QueueVK GetGraphicsQueueInfo() const; vk::PhysicalDevice GetPhysicalDevice() const; + std::shared_ptr GetFenceWaiter() const; + private: std::shared_ptr worker_task_runner_; vk::UniqueInstance instance_; - vk::UniqueDebugUtilsMessengerEXT debug_messenger_; + std::unique_ptr debug_report_; vk::PhysicalDevice physical_device_; vk::UniqueDevice device_; std::shared_ptr allocator_; @@ -138,14 +126,19 @@ class ContextVK final : public Context, public BackendCast { vk::Queue graphics_queue_ = {}; vk::Queue compute_queue_ = {}; vk::Queue transfer_queue_ = {}; + QueueVK graphics_queue_info_ = {}; + QueueVK compute_queue_info_ = {}; + QueueVK transfer_queue_info_ = {}; std::shared_ptr swapchain_; std::shared_ptr work_queue_; - std::unique_ptr device_capabilities_; - vk::UniqueCommandPool graphics_command_pool_; - vk::UniqueDescriptorPool descriptor_pool_; + std::shared_ptr device_capabilities_; + std::shared_ptr fence_waiter_; + bool is_valid_ = false; - ContextVK( + ContextVK(); + + void Setup( PFN_vkGetInstanceProcAddr proc_address_callback, const std::vector>& shader_libraries_data, const std::shared_ptr& pipeline_cache_data, diff --git a/impeller/renderer/backend/vulkan/debug_report_vk.cc b/impeller/renderer/backend/vulkan/debug_report_vk.cc new file mode 100644 index 0000000000000..c538245aba50d --- /dev/null +++ b/impeller/renderer/backend/vulkan/debug_report_vk.cc @@ -0,0 +1,189 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/vulkan/debug_report_vk.h" + +#include "impeller/renderer/backend/vulkan/capabilities_vk.h" + +namespace impeller { + +DebugReportVK::DebugReportVK(const CapabilitiesVK& caps, + const vk::Instance& instance) { + if (!caps.AreValidationsEnabled()) { + is_valid_ = true; + return; + } + + vk::DebugUtilsMessengerCreateInfoEXT messenger_info; + messenger_info.messageSeverity = + vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; + messenger_info.messageType = + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | + vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | + vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation; + messenger_info.pUserData = this; + messenger_info.pfnUserCallback = DebugUtilsMessengerCallback; + + auto messenger = instance.createDebugUtilsMessengerEXTUnique(messenger_info); + + if (messenger.result != vk::Result::eSuccess) { + FML_LOG(ERROR) << "Could not create debug messenger: " + << vk::to_string(messenger.result); + return; + } + + messenger_ = std::move(messenger.value); + is_valid_ = true; +} + +DebugReportVK::~DebugReportVK() = default; + +bool DebugReportVK::IsValid() const { + return is_valid_; +} + +static std::string JoinLabels(const VkDebugUtilsLabelEXT* labels, + size_t count) { + std::stringstream stream; + for (size_t i = 0u; i < count; i++) { + stream << labels[i].pLabelName; + if (i != count - 1u) { + stream << ", "; + } + } + return stream.str(); +} + +static std::string JoinVKDebugUtilsObjectNameInfoEXT( + const VkDebugUtilsObjectNameInfoEXT* names, + size_t count) { + std::stringstream stream; + for (size_t i = 0u; i < count; i++) { + stream << vk::to_string(vk::ObjectType(names[i].objectType)) << " [" + << names[i].objectHandle << "] ["; + if (names[i].pObjectName != nullptr) { + stream << names[i].pObjectName; + } else { + stream << "UNNAMED"; + } + stream << "]"; + if (i != count - 1u) { + stream << ", "; + } + } + return stream.str(); +} + +VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportVK::DebugUtilsMessengerCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, + void* debug_report) { + auto result = + reinterpret_cast(debug_report) + ->OnDebugCallback( + static_cast( + severity), // + static_cast(type), // + callback_data // + ); + switch (result) { + case Result::kContinue: + return VK_FALSE; + case Result::kAbort: + return VK_TRUE; + } + return VK_FALSE; +} + +DebugReportVK::Result DebugReportVK::OnDebugCallback( + vk::DebugUtilsMessageSeverityFlagBitsEXT severity, + vk::DebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data) { + // Issue in older versions of the SDK. + // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/3554 + if (strstr(data->pMessageIdName, "CoreValidation-Shader-OutputNotConsumed") != + nullptr) { + return Result::kContinue; + } + + // This is a real error but we can't fix it due to our headers being too + // old. More more details see: + // https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465 + // This validation error currently only trips on macOS due to the use of + // texture swizzles. + if (data->messageIdNumber == static_cast(0x82ae5050)) { + return Result::kContinue; + } + + std::vector> items; + + items.emplace_back("Severity", vk::to_string(severity)); + + items.emplace_back("Type", vk::to_string(type)); + + if (data->pMessageIdName) { + items.emplace_back("ID Name", data->pMessageIdName); + } + + items.emplace_back("ID Number", std::to_string(data->messageIdNumber)); + + if (auto queues = JoinLabels(data->pQueueLabels, data->queueLabelCount); + !queues.empty()) { + items.emplace_back("Queue Breadcrumbs", std::move(queues)); + } else { + items.emplace_back("Queue Breadcrumbs", "[NONE]"); + } + + if (auto cmd_bufs = JoinLabels(data->pCmdBufLabels, data->cmdBufLabelCount); + !cmd_bufs.empty()) { + items.emplace_back("CMD Buffer Breadcrumbs", std::move(cmd_bufs)); + } else { + items.emplace_back("CMD Buffer Breadcrumbs", "[NONE]"); + } + + if (auto related = + JoinVKDebugUtilsObjectNameInfoEXT(data->pObjects, data->objectCount); + !related.empty()) { + items.emplace_back("Related Objects", std::move(related)); + } + + if (data->pMessage) { + items.emplace_back("Trigger", data->pMessage); + } + + size_t padding = 0; + + for (const auto& item : items) { + padding = std::max(padding, item.first.size()); + } + + padding += 1; + + std::stringstream stream; + + stream << std::endl; + + stream << "--- Vulkan Debug Report ----------------------------------------"; + + stream << std::endl; + + for (const auto& item : items) { + stream << "| " << std::setw(static_cast(padding)) << item.first + << std::setw(0) << ": " << item.second << std::endl; + } + + stream << "-----------------------------------------------------------------"; + + if (type == vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance) { + FML_LOG(INFO) << stream.str(); + } else { + VALIDATION_LOG << stream.str(); + } + + return Result::kAbort; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/debug_report_vk.h b/impeller/renderer/backend/vulkan/debug_report_vk.h new file mode 100644 index 0000000000000..387d7f6d28c20 --- /dev/null +++ b/impeller/renderer/backend/vulkan/debug_report_vk.h @@ -0,0 +1,44 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class CapabilitiesVK; + +class DebugReportVK { + public: + DebugReportVK(const CapabilitiesVK& caps, const vk::Instance& instance); + + ~DebugReportVK(); + + bool IsValid() const; + + private: + vk::UniqueDebugUtilsMessengerEXT messenger_; + bool is_valid_ = false; + + enum class Result { + kContinue, + kAbort, + }; + + Result OnDebugCallback(vk::DebugUtilsMessageSeverityFlagBitsEXT severity, + vk::DebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data); + + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessengerCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, + void* user_data); + + FML_DISALLOW_COPY_AND_ASSIGN(DebugReportVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc new file mode 100644 index 0000000000000..5fb1ef74fdcd9 --- /dev/null +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc @@ -0,0 +1,74 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" + +#include "flutter/fml/trace_event.h" +#include "impeller/base/allocation.h" + +namespace impeller { + +DescriptorPoolVK::DescriptorPoolVK(vk::Device device) : device_(device) {} + +DescriptorPoolVK::~DescriptorPoolVK() = default; + +static vk::UniqueDescriptorPool CreatePool(const vk::Device& device, + uint32_t pool_count) { + TRACE_EVENT0("impeller", "CreateDescriptorPool"); + std::vector pools = { + {vk::DescriptorType::eCombinedImageSampler, pool_count}, + {vk::DescriptorType::eUniformBuffer, pool_count}, + }; + + vk::DescriptorPoolCreateInfo pool_info; + pool_info.setMaxSets(pools.size() * pool_count); + pool_info.setPoolSizes(pools); + + auto [result, pool] = device.createDescriptorPoolUnique(pool_info); + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Unable to create a descriptor pool"; + } + return std::move(pool); +} + +std::optional DescriptorPoolVK::AllocateDescriptorSet( + const vk::DescriptorSetLayout& layout) { + auto pool = GetDescriptorPool(); + if (!pool) { + return std::nullopt; + } + vk::DescriptorSetAllocateInfo set_info; + set_info.setDescriptorPool(pool.value()); + set_info.setSetLayouts(layout); + auto [result, sets] = device_.allocateDescriptorSets(set_info); + if (result == vk::Result::eErrorOutOfPoolMemory) { + return GrowPool() ? AllocateDescriptorSet(layout) : std::nullopt; + } + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not allocate descriptor sets: " + << vk::to_string(result); + return std::nullopt; + } + return sets[0]; +} + +std::optional DescriptorPoolVK::GetDescriptorPool() { + if (pools_.empty()) { + return GrowPool() ? GetDescriptorPool() : std::nullopt; + } + return *pools_.back(); +} + +bool DescriptorPoolVK::GrowPool() { + const auto new_pool_size = Allocation::NextPowerOfTwoSize(pool_size_ + 1u); + auto new_pool = CreatePool(device_, new_pool_size); + if (!new_pool) { + return false; + } + pool_size_ = new_pool_size; + pools_.push(std::move(new_pool)); + return true; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h new file mode 100644 index 0000000000000..4af9c0bc8b13a --- /dev/null +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +//------------------------------------------------------------------------------ +/// @brief A short-lived dynamically-sized descriptor pool. Descriptors +/// from this pool don't need to be freed individually. Instead, the +/// pool must be collected after all the descriptors allocated from +/// it are done being used. +/// +/// The pool or it's descriptors may not be accessed from multiple +/// threads. +/// +/// Encoders create pools as necessary as they have the same +/// threading and lifecycle restrictions. +/// +class DescriptorPoolVK { + public: + explicit DescriptorPoolVK(vk::Device device); + + ~DescriptorPoolVK(); + + std::optional AllocateDescriptorSet( + const vk::DescriptorSetLayout& layout); + + private: + const vk::Device device_; + uint32_t pool_size_ = 31u; + std::queue pools_; + + std::optional GetDescriptorPool(); + + bool GrowPool(); + + FML_DISALLOW_COPY_AND_ASSIGN(DescriptorPoolVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.cc b/impeller/renderer/backend/vulkan/device_buffer_vk.cc index e38c63fa688fc..e9859ff9390a5 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.cc @@ -67,7 +67,7 @@ bool DeviceBufferVK::SetLabel(const std::string& label, Range range) { return SetLabel(label); } -vk::Buffer DeviceBufferVK::GetVKBufferHandle() const { +vk::Buffer DeviceBufferVK::GetBuffer() const { return buffer_; } diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 132be608c3617..2f579c13a1e9c 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h @@ -26,7 +26,7 @@ class DeviceBufferVK final : public DeviceBuffer, // |DeviceBuffer| ~DeviceBufferVK() override; - vk::Buffer GetVKBufferHandle() const; + vk::Buffer GetBuffer() const; private: friend class AllocatorVK; diff --git a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc new file mode 100644 index 0000000000000..06c4c094cbf67 --- /dev/null +++ b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc @@ -0,0 +1,108 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" + +#include + +#include "flutter/fml/thread.h" + +namespace impeller { + +FenceWaiterVK::FenceWaiterVK(vk::Device device) : device_(device) { + waiter_thread_ = std::make_unique([&]() { Main(); }); + is_valid_ = true; +} + +FenceWaiterVK::~FenceWaiterVK() { + Terminate(); + if (waiter_thread_) { + waiter_thread_->join(); + } +} + +bool FenceWaiterVK::IsValid() const { + return is_valid_; +} + +bool FenceWaiterVK::AddFence(vk::UniqueFence fence, + const fml::closure& callback) { + if (!IsValid() || !fence || !callback) { + return false; + } + { + std::scoped_lock lock(wait_set_mutex_); + wait_set_[MakeSharedVK(std::move(fence))] = callback; + } + wait_set_cv_.notify_one(); + return true; +} + +void FenceWaiterVK::Main() { + fml::Thread::SetCurrentThreadName( + fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"}); + + using namespace std::literals::chrono_literals; + + while (true) { + std::unique_lock lock(wait_set_mutex_); + + wait_set_cv_.wait(lock, [&]() { return !wait_set_.empty() || terminate_; }); + + auto wait_set = TrimAndCreateWaitSetLocked(); + + lock.unlock(); + + if (!wait_set.has_value()) { + break; + } + if (wait_set->empty()) { + continue; + } + + auto result = device_.waitForFences( + wait_set->size(), // fences count + wait_set->data(), // fences + false, // wait for all + std::chrono::nanoseconds{100ms}.count() // timeout (ns) + ); + if (!(result == vk::Result::eSuccess || result == vk::Result::eTimeout)) { + break; + } + } +} + +std::optional> +FenceWaiterVK::TrimAndCreateWaitSetLocked() { + if (terminate_) { + return std::nullopt; + } + std::vector fences; + fences.reserve(wait_set_.size()); + for (auto it = wait_set_.begin(); it != wait_set_.end();) { + switch (device_.getFenceStatus(it->first->Get())) { + case vk::Result::eSuccess: // Signalled. + it->second(); + it = wait_set_.erase(it); + break; + case vk::Result::eNotReady: // Un-signalled. + fences.push_back(it->first->Get()); + it++; + break; + default: + return std::nullopt; + } + } + return fences; +} + +void FenceWaiterVK::Terminate() { + { + std::scoped_lock lock(wait_set_mutex_); + terminate_ = true; + } + wait_set_cv_.notify_one(); +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/fence_waiter_vk.h b/impeller/renderer/backend/vulkan/fence_waiter_vk.h new file mode 100644 index 0000000000000..0f5087f0d2514 --- /dev/null +++ b/impeller/renderer/backend/vulkan/fence_waiter_vk.h @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include +#include +#include + +#include "flutter/fml/closure.h" +#include "flutter/fml/macros.h" +#include "impeller/base/thread.h" +#include "impeller/renderer/backend/vulkan/shared_object_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class ContextVK; + +class FenceWaiterVK { + public: + ~FenceWaiterVK(); + + bool IsValid() const; + + void Terminate(); + + bool AddFence(vk::UniqueFence fence, const fml::closure& callback); + + private: + friend class ContextVK; + + const vk::Device device_; + std::unique_ptr waiter_thread_; + std::mutex wait_set_mutex_; + std::condition_variable wait_set_cv_; + std::unordered_map, fml::closure> wait_set_; + bool terminate_ = false; + bool is_valid_ = false; + + explicit FenceWaiterVK(vk::Device device); + + void Main(); + + std::optional> TrimAndCreateWaitSetLocked(); + + FML_DISALLOW_COPY_AND_ASSIGN(FenceWaiterVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index 83ea4acc463b0..64e8f5a6c447d 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -6,7 +6,6 @@ #include "flutter/fml/macros.h" #include "impeller/renderer/backend/vulkan/vk.h" -#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/shader_types.h" #include "vulkan/vulkan_enums.hpp" @@ -205,6 +204,8 @@ constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { case SampleCount::kCount4: return vk::SampleCountFlagBits::e4; } + + FML_UNREACHABLE(); } constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) { @@ -269,7 +270,7 @@ constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding( const DescriptorSetLayout& layout) { vk::DescriptorSetLayoutBinding binding; binding.binding = layout.binding; - binding.descriptorCount = layout.descriptor_count; + binding.descriptorCount = 1u; vk::DescriptorType desc_type = vk::DescriptorType(); switch (layout.descriptor_type) { case DescriptorType::kSampledImage: @@ -546,9 +547,60 @@ constexpr uint32_t ToArrayLayerCount(TextureType type) { FML_UNREACHABLE(); } +constexpr vk::ImageViewType ToVKImageViewType(TextureType type) { + switch (type) { + case TextureType::kTexture2D: + case TextureType::kTexture2DMultisample: + return vk::ImageViewType::e2D; + case TextureType::kTextureCube: + return vk::ImageViewType::eCube; + } + FML_UNREACHABLE(); +} + +constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type) { + switch (type) { + case TextureType::kTexture2D: + case TextureType::kTexture2DMultisample: + return {}; + case TextureType::kTextureCube: + return vk::ImageCreateFlagBits::eCubeCompatible; + } + FML_UNREACHABLE(); +} + vk::PipelineDepthStencilStateCreateInfo ToVKPipelineDepthStencilStateCreateInfo( std::optional depth, std::optional front, std::optional back); +constexpr vk::ImageAspectFlags ToImageAspectFlags(vk::ImageLayout layout) { + switch (layout) { + case vk::ImageLayout::eColorAttachmentOptimal: + case vk::ImageLayout::eShaderReadOnlyOptimal: + case vk::ImageLayout::eTransferSrcOptimal: + case vk::ImageLayout::eTransferDstOptimal: + case vk::ImageLayout::ePresentSrcKHR: + return vk::ImageAspectFlagBits::eColor; + case vk::ImageLayout::eDepthAttachmentOptimal: + return vk::ImageAspectFlagBits::eDepth; + case vk::ImageLayout::eStencilAttachmentOptimal: + return vk::ImageAspectFlagBits::eStencil; + default: + FML_DLOG(INFO) << "Unknown layout to determine aspect: " + << vk::to_string(layout); + return vk::ImageAspectFlagBits::eNone; + } + FML_UNREACHABLE(); +} + +struct LayoutTransition { + vk::CommandBuffer cmd_buffer = {}; + vk::ImageLayout new_layout = vk::ImageLayout::eUndefined; + vk::PipelineStageFlags src_stage = vk::PipelineStageFlagBits::eNone; + vk::AccessFlags src_access = vk::AccessFlagBits::eNone; + vk::PipelineStageFlags dst_stage = vk::PipelineStageFlagBits::eNone; + vk::AccessFlags dst_access = vk::AccessFlagBits::eNone; +}; + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 1cc9e2303612d..6016a5bd59836 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -53,54 +53,6 @@ bool PipelineLibraryVK::IsValid() const { return is_valid_; } -// |PipelineLibrary| -PipelineFuture PipelineLibraryVK::GetPipeline( - PipelineDescriptor descriptor) { - Lock lock(pipelines_mutex_); - if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) { - return found->second; - } - - if (!IsValid()) { - return { - descriptor, - RealizedFuture>>(nullptr)}; - } - - auto promise = std::make_shared< - std::promise>>>(); - auto pipeline_future = - PipelineFuture{descriptor, promise->get_future()}; - pipelines_[descriptor] = pipeline_future; - - auto weak_this = weak_from_this(); - - worker_task_runner_->PostTask([descriptor, weak_this, promise]() { - auto thiz = weak_this.lock(); - if (!thiz) { - promise->set_value(nullptr); - VALIDATION_LOG << "Pipeline library was collected before the pipeline " - "could be created."; - return; - } - auto pipeline_create_info = - PipelineLibraryVK::Cast(thiz.get())->CreatePipeline(descriptor); - promise->set_value(std::make_shared( - weak_this, descriptor, std::move(pipeline_create_info))); - }); - - return pipeline_future; -} - -// |PipelineLibrary| -PipelineFuture PipelineLibraryVK::GetPipeline( - ComputePipelineDescriptor descriptor) { - auto promise = std::make_shared< - std::promise>>>(); - promise->set_value(nullptr); - return {descriptor, promise->get_future()}; -} - //------------------------------------------------------------------------------ /// @brief Creates an attachment description that does just enough to /// ensure render pass compatibility with the pass associated later @@ -123,17 +75,6 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription( ); } -// |PipelineLibrary| -void PipelineLibraryVK::RemovePipelinesWithEntryPoint( - std::shared_ptr function) { - Lock lock(pipelines_mutex_); - - fml::erase_if(pipelines_, [&](auto item) { - return item->first.GetEntrypointForStage(function->GetStage()) - ->IsEqual(*function); - }); -} - //---------------------------------------------------------------------------- /// Render Pass /// We are NOT going to use the same render pass with the framebuffer (later) @@ -145,8 +86,8 @@ void PipelineLibraryVK::RemovePipelinesWithEntryPoint( /// StencilAttachmentDescriptor, and, DepthAttachmentDescriptor. /// Right now, these are placeholders. /// -vk::UniqueRenderPass PipelineLibraryVK::CreateRenderPass( - const PipelineDescriptor& desc) { +static vk::UniqueRenderPass CreateRenderPass(const vk::Device& device, + const PipelineDescriptor& desc) { std::vector attachments; std::vector color_refs; @@ -190,7 +131,7 @@ vk::UniqueRenderPass PipelineLibraryVK::CreateRenderPass( render_pass_desc.setPSubpasses(&subpass_desc); render_pass_desc.setSubpassCount(1u); - auto [result, pass] = device_.createRenderPassUnique(render_pass_desc); + auto [result, pass] = device.createRenderPassUnique(render_pass_desc); if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to create render pass for pipeline '" << desc.GetLabel() << "'. Error: " << vk::to_string(result); @@ -210,7 +151,7 @@ constexpr vk::FrontFace ToVKFrontFace(WindingOrder order) { FML_UNREACHABLE(); } -std::unique_ptr PipelineLibraryVK::CreatePipeline( +std::unique_ptr PipelineLibraryVK::CreatePipeline( const PipelineDescriptor& desc) { TRACE_EVENT0("flutter", __FUNCTION__); vk::GraphicsPipelineCreateInfo pipeline_info; @@ -298,7 +239,7 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( blend_state.setAttachments(attachment_blend_state); pipeline_info.setPColorBlendState(&blend_state); - auto render_pass = CreateRenderPass(desc); + auto render_pass = CreateRenderPass(device_, desc); if (render_pass) { pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE); pipeline_info.setSubpass(0); @@ -341,33 +282,31 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( //---------------------------------------------------------------------------- /// Pipeline Layout a.k.a the descriptor sets and uniforms. /// - std::vector bindings = {}; + std::vector desc_bindings; for (auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) { auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout); - bindings.push_back(vk_desc_layout); + desc_bindings.push_back(vk_desc_layout); } - vk::DescriptorSetLayoutCreateInfo descriptor_set_create; - descriptor_set_create.setBindings(bindings); + vk::DescriptorSetLayoutCreateInfo descs_layout_info; + descs_layout_info.setBindings(desc_bindings); - auto descriptor_set_create_res = - device_.createDescriptorSetLayoutUnique(descriptor_set_create); - if (descriptor_set_create_res.result != vk::Result::eSuccess) { + auto [descs_result, descs_layout] = + device_.createDescriptorSetLayoutUnique(descs_layout_info); + if (descs_result != vk::Result::eSuccess) { VALIDATION_LOG << "unable to create uniform descriptors"; return nullptr; } - vk::UniqueDescriptorSetLayout descriptor_set_layout = - std::move(descriptor_set_create_res.value); - ContextVK::SetDebugName(device_, descriptor_set_layout.get(), - "Descriptor Set Layout" + desc.GetLabel()); + ContextVK::SetDebugName(device_, descs_layout.get(), + "Descriptor Set Layout " + desc.GetLabel()); //---------------------------------------------------------------------------- /// Create the pipeline layout. /// vk::PipelineLayoutCreateInfo pipeline_layout_info; - pipeline_layout_info.setSetLayouts(descriptor_set_layout.get()); + pipeline_layout_info.setSetLayouts(descs_layout.get()); auto pipeline_layout = device_.createPipelineLayoutUnique(pipeline_layout_info); if (pipeline_layout.result != vk::Result::eSuccess) { @@ -402,13 +341,81 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( } ContextVK::SetDebugName(device_, *pipeline_layout.value, - "Pipeline Layout" + desc.GetLabel()); + "Pipeline Layout " + desc.GetLabel()); ContextVK::SetDebugName(device_, *pipeline.value, - "Pipeline" + desc.GetLabel()); + "Pipeline " + desc.GetLabel()); + + return std::make_unique(weak_from_this(), // + desc, // + std::move(pipeline.value), // + std::move(render_pass), // + std::move(pipeline_layout.value), // + std::move(descs_layout) // + ); +} - return std::make_unique( - std::move(pipeline.value), std::move(render_pass), - std::move(pipeline_layout.value), std::move(descriptor_set_layout)); +// |PipelineLibrary| +PipelineFuture PipelineLibraryVK::GetPipeline( + PipelineDescriptor descriptor) { + Lock lock(pipelines_mutex_); + if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) { + return found->second; + } + + if (!IsValid()) { + return { + descriptor, + RealizedFuture>>(nullptr)}; + } + + auto promise = std::make_shared< + std::promise>>>(); + auto pipeline_future = + PipelineFuture{descriptor, promise->get_future()}; + pipelines_[descriptor] = pipeline_future; + + auto weak_this = weak_from_this(); + + worker_task_runner_->PostTask([descriptor, weak_this, promise]() { + auto thiz = weak_this.lock(); + if (!thiz) { + promise->set_value(nullptr); + VALIDATION_LOG << "Pipeline library was collected before the pipeline " + "could be created."; + return; + } + + auto pipeline = PipelineLibraryVK::Cast(*thiz).CreatePipeline(descriptor); + if (!pipeline) { + promise->set_value(nullptr); + VALIDATION_LOG << "Could not create pipeline: " << descriptor.GetLabel(); + return; + } + + promise->set_value(std::move(pipeline)); + }); + + return pipeline_future; +} + +// |PipelineLibrary| +PipelineFuture PipelineLibraryVK::GetPipeline( + ComputePipelineDescriptor descriptor) { + auto promise = std::make_shared< + std::promise>>>(); + promise->set_value(nullptr); + return {descriptor, promise->get_future()}; +} + +// |PipelineLibrary| +void PipelineLibraryVK::RemovePipelinesWithEntryPoint( + std::shared_ptr function) { + Lock lock(pipelines_mutex_); + + fml::erase_if(pipelines_, [&](auto item) { + return item->first.GetEntrypointForStage(function->GetStage()) + ->IsEqual(*function); + }); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.h b/impeller/renderer/backend/vulkan/pipeline_library_vk.h index f4cd10b76ffd8..6892ac126d17b 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.h @@ -62,10 +62,7 @@ class PipelineLibraryVK final void RemovePipelinesWithEntryPoint( std::shared_ptr function) override; - std::unique_ptr CreatePipeline( - const PipelineDescriptor& desc); - - vk::UniqueRenderPass CreateRenderPass(const PipelineDescriptor& desc); + std::unique_ptr CreatePipeline(const PipelineDescriptor& desc); FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibraryVK); }; diff --git a/impeller/renderer/backend/vulkan/pipeline_vk.cc b/impeller/renderer/backend/vulkan/pipeline_vk.cc index 87f65c9c99da6..208d63ae99fd8 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_vk.cc @@ -6,53 +6,40 @@ namespace impeller { -PipelineCreateInfoVK::PipelineCreateInfoVK( - vk::UniquePipeline pipeline, - vk::UniqueRenderPass render_pass, - vk::UniquePipelineLayout layout, - vk::UniqueDescriptorSetLayout descriptor_set_layout) - : pipeline_(std::move(pipeline)), +PipelineVK::PipelineVK(std::weak_ptr library, + const PipelineDescriptor& desc, + vk::UniquePipeline pipeline, + vk::UniqueRenderPass render_pass, + vk::UniquePipelineLayout layout, + vk::UniqueDescriptorSetLayout descriptor_set_layout) + : Pipeline(std::move(library), desc), + pipeline_(std::move(pipeline)), render_pass_(std::move(render_pass)), - pipeline_layout_(std::move(layout)), + layout_(std::move(layout)), descriptor_set_layout_(std::move(descriptor_set_layout)) { - is_valid_ = - pipeline_ && render_pass_ && pipeline_layout_ && descriptor_set_layout_; + is_valid_ = pipeline_ && render_pass_ && layout_ && descriptor_set_layout_; } -bool PipelineCreateInfoVK::IsValid() const { +PipelineVK::~PipelineVK() = default; + +bool PipelineVK::IsValid() const { return is_valid_; } -const vk::Pipeline& PipelineCreateInfoVK::GetVKPipeline() const { +const vk::Pipeline& PipelineVK::GetPipeline() const { return *pipeline_; } -vk::RenderPass PipelineCreateInfoVK::GetRenderPass() const { +const vk::RenderPass& PipelineVK::GetRenderPass() const { return *render_pass_; } -vk::PipelineLayout PipelineCreateInfoVK::GetPipelineLayout() const { - return *pipeline_layout_; +const vk::PipelineLayout& PipelineVK::GetPipelineLayout() const { + return *layout_; } -vk::DescriptorSetLayout PipelineCreateInfoVK::GetDescriptorSetLayout() const { +const vk::DescriptorSetLayout& PipelineVK::GetDescriptorSetLayout() const { return *descriptor_set_layout_; } -PipelineVK::PipelineVK(std::weak_ptr library, - const PipelineDescriptor& desc, - std::unique_ptr create_info) - : Pipeline(std::move(library), desc), - pipeline_info_(std::move(create_info)) {} - -PipelineVK::~PipelineVK() = default; - -bool PipelineVK::IsValid() const { - return pipeline_info_->IsValid(); -} - -PipelineCreateInfoVK* PipelineVK::GetCreateInfo() const { - return pipeline_info_.get(); -} - } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/pipeline_vk.h b/impeller/renderer/backend/vulkan/pipeline_vk.h index a10e31e12f176..7135dcf03eb5f 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_vk.h @@ -13,51 +13,41 @@ namespace impeller { -class PipelineCreateInfoVK { - public: - PipelineCreateInfoVK(vk::UniquePipeline pipeline, - vk::UniqueRenderPass render_pass, - vk::UniquePipelineLayout pipeline_layout, - vk::UniqueDescriptorSetLayout descriptor_set_layout); - - bool IsValid() const; - - const vk::Pipeline& GetVKPipeline() const; - - vk::RenderPass GetRenderPass() const; - - vk::PipelineLayout GetPipelineLayout() const; - - vk::DescriptorSetLayout GetDescriptorSetLayout() const; - - private: - bool is_valid_ = false; - vk::UniquePipeline pipeline_; - vk::UniqueRenderPass render_pass_; - vk::UniquePipelineLayout pipeline_layout_; - vk::UniqueDescriptorSetLayout descriptor_set_layout_; -}; - class PipelineVK final : public Pipeline, public BackendCast> { public: PipelineVK(std::weak_ptr library, const PipelineDescriptor& desc, - std::unique_ptr create_info); + vk::UniquePipeline pipeline, + vk::UniqueRenderPass render_pass, + vk::UniquePipelineLayout layout, + vk::UniqueDescriptorSetLayout descriptor_set_layout); // |Pipeline| ~PipelineVK() override; - PipelineCreateInfoVK* GetCreateInfo() const; + const vk::Pipeline& GetPipeline() const; + + const vk::RenderPass& GetRenderPass() const; + + const vk::PipelineLayout& GetPipelineLayout() const; + + const vk::DescriptorSetLayout& GetDescriptorSetLayout() const; private: friend class PipelineLibraryVK; + const vk::UniquePipeline pipeline_; + const vk::UniqueRenderPass render_pass_; + const vk::UniquePipelineLayout layout_; + const vk::UniqueDescriptorSetLayout descriptor_set_layout_; + bool is_valid_ = false; + // |Pipeline| bool IsValid() const override; - std::unique_ptr pipeline_info_; + std::unique_ptr CreatePipeline(const PipelineDescriptor& desc); FML_DISALLOW_COPY_AND_ASSIGN(PipelineVK); }; diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index b929e647e2594..091ad5251b127 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -6,9 +6,11 @@ #include #include +#include #include -#include "fml/logging.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" @@ -40,8 +42,9 @@ static vk::AttachmentDescription CreateAttachmentDescription( ); } -static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device, - const RenderTarget& target) { +static SharedHandleVK CreateVKRenderPass( + const vk::Device& device, + const RenderTarget& target) { std::vector attachments; std::vector color_refs; @@ -108,7 +111,7 @@ static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device, return {}; } - return std::move(pass); + return MakeSharedVK(std::move(pass)); } RenderPassVK::RenderPassVK(const std::shared_ptr& context, @@ -135,7 +138,7 @@ void RenderPassVK::OnSetLabel(std::string label) { if (!context) { return; } - ContextVK::Cast(*context).SetDebugName(*render_pass_, label.c_str()); + ContextVK::Cast(*context).SetDebugName(render_pass_->Get(), label.c_str()); debug_label_ = std::move(label); } @@ -225,34 +228,60 @@ static vk::UniqueFramebuffer CreateFramebuffer(const vk::Device& device, return std::move(framebuffer); } -static bool ConfigureRenderTargetAttachmentLayouts( - const RenderTarget& target, - const vk::CommandBuffer& command_buffer) { +static bool ConfigureAttachments(const RenderTarget& target, + const vk::CommandBuffer& command_buffer, + CommandEncoderVK& encoder) { for (const auto& [_, color] : target.GetColorAttachments()) { - if (!TextureVK::Cast(*color.texture) - .SetLayout(vk::ImageLayout::eColorAttachmentOptimal, - command_buffer)) { + const auto& color_tex = color.texture; + const auto& color_resolve_tex = color.resolve_texture; + + LayoutTransition color_tran; + color_tran.cmd_buffer = command_buffer; + color_tran.src_access = vk::AccessFlagBits::eColorAttachmentWrite | + vk::AccessFlagBits::eShaderWrite | + vk::AccessFlagBits::eTransferWrite; + color_tran.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput | + vk::PipelineStageFlagBits::eFragmentShader | + vk::PipelineStageFlagBits::eTransfer; + color_tran.dst_access = vk::AccessFlagBits::eShaderRead; + color_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + color_tran.new_layout = vk::ImageLayout::eColorAttachmentOptimal; + + // Transition and track the color texture. + if (!TextureVK::Cast(*color_tex).SetLayout(color_tran) || + !encoder.Track(color_tex)) { return false; } - if (color.resolve_texture) { - if (!TextureVK::Cast(*color.resolve_texture) - .SetLayout(vk::ImageLayout::eColorAttachmentOptimal, - command_buffer)) { + + // Transition and track the resolve texture, if there is one. + if (color_resolve_tex) { + if (!TextureVK::Cast(*color_resolve_tex).SetLayout(color_tran) || + !encoder.Track(color_resolve_tex)) { return false; } } } + + LayoutTransition depth_stencil_tran; + depth_stencil_tran.cmd_buffer = command_buffer; + depth_stencil_tran.src_access = {}; + depth_stencil_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + depth_stencil_tran.dst_access = vk::AccessFlagBits::eShaderRead; + depth_stencil_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + depth_stencil_tran.new_layout = vk::ImageLayout::eDepthAttachmentOptimal; if (auto depth = target.GetDepthAttachment(); depth.has_value()) { - if (!TextureVK::Cast(*depth->texture) - .SetLayout(vk::ImageLayout::eDepthAttachmentOptimal, - command_buffer)) { + if (!TextureVK::Cast(*depth->texture).SetLayout(depth_stencil_tran) || + !encoder.Track(depth->texture)) { return false; } } + + depth_stencil_tran.new_layout = vk::ImageLayout::eStencilAttachmentOptimal; if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) { - if (!TextureVK::Cast(*stencil->texture) - .SetLayout(vk::ImageLayout::eStencilAttachmentOptimal, - command_buffer)) { + if (!TextureVK::Cast(*stencil->texture).SetLayout(depth_stencil_tran) || + !encoder.Track(stencil->texture)) { return false; } } @@ -261,9 +290,19 @@ static bool ConfigureRenderTargetAttachmentLayouts( static bool UpdateBindingLayouts(const Bindings& bindings, const vk::CommandBuffer& buffer) { + LayoutTransition transition; + transition.cmd_buffer = buffer; + transition.src_access = vk::AccessFlagBits::eColorAttachmentWrite | + vk::AccessFlagBits::eTransferWrite; + transition.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput | + vk::PipelineStageFlagBits::eTransfer; + transition.dst_access = vk::AccessFlagBits::eShaderRead; + transition.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + transition.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + for (const auto& [_, texture] : bindings.textures) { - if (!TextureVK::Cast(*texture.resource) - .SetLayout(vk::ImageLayout::eShaderReadOnlyOptimal, buffer)) { + if (!TextureVK::Cast(*texture.resource).SetLayout(transition)) { return false; } } @@ -286,160 +325,124 @@ static bool UpdateBindingLayouts(const std::vector& commands, return true; } -static bool UpdateDescriptorSets(vk::Device device, - const Bindings& bindings, - Allocator& allocator, - vk::DescriptorSet desc_set, - CommandEncoderVK& encoder) { - std::vector writes; - - //---------------------------------------------------------------------------- - /// Setup buffer descriptors. - /// - std::vector buffer_desc; - for (const auto& [buffer_index, view] : bindings.buffers) { - const auto& buffer_view = view.resource.buffer; - - auto device_buffer = buffer_view->GetDeviceBuffer(allocator); - if (!device_buffer) { - VALIDATION_LOG << "Failed to get device buffer for vertex binding"; - return false; - } - - auto buffer = DeviceBufferVK::Cast(*device_buffer).GetVKBufferHandle(); - if (!buffer) { - return false; - } - - // Reserved index used for per-vertex data. - if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) { - continue; - } +static bool AllocateAndBindDescriptorSets(const ContextVK& context, + const Command& command, + CommandEncoderVK& encoder, + const PipelineVK& pipeline) { + auto desc_set = + encoder.AllocateDescriptorSet(pipeline.GetDescriptorSetLayout()); + if (!desc_set) { + return false; + } - if (!encoder.Track(device_buffer)) { - return false; - } + auto& allocator = *context.GetResourceAllocator(); - uint32_t offset = view.resource.range.offset; + std::unordered_map buffers; + std::unordered_map images; + std::vector writes; - vk::DescriptorBufferInfo desc_buffer_info; - desc_buffer_info.setBuffer(buffer); - desc_buffer_info.setOffset(offset); - desc_buffer_info.setRange(view.resource.range.length); - buffer_desc.push_back(desc_buffer_info); + auto bind_images = [&encoder, // + &images, // + &writes, // + &desc_set // + ](const Bindings& bindings) -> bool { + for (const auto& [index, sampler_handle] : bindings.samplers) { + if (bindings.textures.find(index) == bindings.textures.end()) { + return false; + } - const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index); + auto texture = bindings.textures.at(index).resource; + const auto& texture_vk = TextureVK::Cast(*texture); + const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource); - vk::WriteDescriptorSet write_set; - write_set.setDstSet(desc_set); - write_set.setDstBinding(uniform.binding); - write_set.setDescriptorCount(1); - write_set.setDescriptorType(vk::DescriptorType::eUniformBuffer); - write_set.setPBufferInfo(&buffer_desc.back()); + if (!encoder.Track(texture) || + !encoder.Track(sampler.GetSharedSampler())) { + return false; + } - writes.push_back(write_set); - } + const SampledImageSlot& slot = bindings.sampled_images.at(index); - //---------------------------------------------------------------------------- - /// Setup image descriptors. - /// - std::vector image_descs; - for (const auto& [index, sampler_handle] : bindings.samplers) { - if (bindings.textures.find(index) == bindings.textures.end()) { - VALIDATION_LOG << "Missing texture for sampler: " << index; - return false; - } + vk::DescriptorImageInfo image_info; + image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + image_info.sampler = sampler.GetSampler(); + image_info.imageView = texture_vk.GetImageView(); - auto texture = bindings.textures.at(index).resource; - const auto& texture_vk = TextureVK::Cast(*texture); - const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource); + vk::WriteDescriptorSet write_set; + write_set.dstSet = desc_set.value(); + write_set.dstBinding = slot.binding; + write_set.descriptorCount = 1u; + write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler; + write_set.pImageInfo = &(images[slot.binding] = image_info); - if (!encoder.Track(texture) || !encoder.Track(sampler.GetSharedSampler())) { - return false; + writes.push_back(write_set); } - const SampledImageSlot& slot = bindings.sampled_images.at(index); + return true; + }; - vk::DescriptorImageInfo desc_image_info; - desc_image_info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal); - desc_image_info.setSampler(sampler.GetSamplerVK()); - desc_image_info.setImageView(texture_vk.GetImageView()); - image_descs.push_back(desc_image_info); + auto bind_buffers = [&allocator, // + &encoder, // + &buffers, // + &writes, // + &desc_set // + ](const Bindings& bindings) -> bool { + for (const auto& [buffer_index, view] : bindings.buffers) { + const auto& buffer_view = view.resource.buffer; + + auto device_buffer = buffer_view->GetDeviceBuffer(allocator); + if (!device_buffer) { + VALIDATION_LOG << "Failed to get device buffer for vertex binding"; + return false; + } - vk::WriteDescriptorSet write_set; - write_set.setDstSet(desc_set); - write_set.setDstBinding(slot.binding); - write_set.setDescriptorCount(1); - write_set.setDescriptorType(vk::DescriptorType::eCombinedImageSampler); - write_set.setPImageInfo(&image_descs.back()); + auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer(); + if (!buffer) { + return false; + } - writes.push_back(write_set); - } + // Reserved index used for per-vertex data. + if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) { + continue; + } - if (writes.empty()) { - return true; - } - device.updateDescriptorSets(writes, {}); - return true; -} + if (!encoder.Track(device_buffer)) { + return false; + } -static bool AllocateAndBindDescriptorSets( - const ContextVK& context, - const Command& command, - CommandEncoderVK& encoder, - PipelineCreateInfoVK* pipeline_create_info) { - auto& allocator = *context.GetResourceAllocator(); - vk::PipelineLayout pipeline_layout = - pipeline_create_info->GetPipelineLayout(); + uint32_t offset = view.resource.range.offset; - vk::DescriptorSetAllocateInfo alloc_info; - std::array dsls = { - pipeline_create_info->GetDescriptorSetLayout(), - }; + vk::DescriptorBufferInfo buffer_info; + buffer_info.buffer = buffer; + buffer_info.offset = offset; + buffer_info.range = view.resource.range.length; - alloc_info.setDescriptorPool(context.GetDescriptorPool()); - alloc_info.setSetLayouts(dsls); + const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index); - auto [sets_result, sets] = - context.GetDevice().allocateDescriptorSetsUnique(alloc_info); - if (sets_result != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to allocate descriptor sets: " - << vk::to_string(sets_result); - return false; - } + vk::WriteDescriptorSet write_set; + write_set.dstSet = desc_set.value(); + write_set.dstBinding = uniform.binding; + write_set.descriptorCount = 1u; + write_set.descriptorType = vk::DescriptorType::eUniformBuffer; + write_set.pBufferInfo = &(buffers[uniform.binding] = buffer_info); - const auto set = MakeSharedVK(std::move(sets[0])); + writes.push_back(write_set); + } + return true; + }; - if (!encoder.Track(set)) { + if (!bind_buffers(command.vertex_bindings) || + !bind_buffers(command.fragment_bindings) || + !bind_images(command.fragment_bindings)) { return false; } - bool update_vertex_descriptors = - UpdateDescriptorSets(context.GetDevice(), // - command.vertex_bindings, // - allocator, // - *set, // - encoder // - ); - if (!update_vertex_descriptors) { - return false; - } - bool update_frag_descriptors = - UpdateDescriptorSets(context.GetDevice(), // - command.fragment_bindings, // - allocator, // - *set, // - encoder // - ); - if (!update_frag_descriptors) { - return false; - } + context.GetDevice().updateDescriptorSets(writes, {}); encoder.GetCommandBuffer().bindDescriptorSets( vk::PipelineBindPoint::eGraphics, // bind point - pipeline_layout, // layout + pipeline.GetPipelineLayout(), // layout 0, // first set - {vk::DescriptorSet{*set}}, // sets + {vk::DescriptorSet{*desc_set}}, // sets nullptr // offsets ); return true; @@ -486,19 +489,18 @@ static bool EncodeCommand(const Context& context, const auto& cmd_buffer = encoder.GetCommandBuffer(); - auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); - PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo(); + const auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); if (!AllocateAndBindDescriptorSets(ContextVK::Cast(context), // command, // encoder, // - pipeline_create_info // + pipeline_vk // )) { return false; } cmd_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, - pipeline_create_info->GetVKPipeline()); + pipeline_vk.GetPipeline()); // Set the viewport and scissors. SetViewportAndScissor(command, cmd_buffer, target_size); @@ -532,15 +534,13 @@ static bool EncodeCommand(const Context& context, } // Bind the vertex buffer. - auto vertex_buffer_handle = - DeviceBufferVK::Cast(*vertex_buffer).GetVKBufferHandle(); + auto vertex_buffer_handle = DeviceBufferVK::Cast(*vertex_buffer).GetBuffer(); vk::Buffer vertex_buffers[] = {vertex_buffer_handle}; vk::DeviceSize vertex_buffer_offsets[] = {vertex_buffer_view.range.offset}; cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets); // Bind the index buffer. - auto index_buffer_handle = - DeviceBufferVK::Cast(*index_buffer).GetVKBufferHandle(); + auto index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetBuffer(); cmd_buffer.bindIndexBuffer(index_buffer_handle, index_buffer_view.range.offset, ToVKIndexType(command.index_type)); @@ -556,14 +556,11 @@ static bool EncodeCommand(const Context& context, } bool RenderPassVK::OnEncodeCommands(const Context& context) const { + TRACE_EVENT0("impeller", "RenderPassVK::OnEncodeCommands"); if (!IsValid()) { return false; } - if (commands_.empty()) { - return true; - } - const auto& vk_context = ContextVK::Cast(context); const auto& render_target = GetRenderTarget(); @@ -593,16 +590,23 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { return false; } - if (!ConfigureRenderTargetAttachmentLayouts(render_target, cmd_buffer)) { + if (!ConfigureAttachments(render_target, cmd_buffer, *encoder)) { VALIDATION_LOG << "Could not complete attachment layout transitions."; return false; } + if (commands_.empty()) { + // All the necessary layout transitions of the attchments have been + // completed by this point. If there are no commands, there is nothing + // further to do. + return true; + } + const auto& target_size = render_target.GetRenderTargetSize(); auto framebuffer = MakeSharedVK( CreateFramebuffer(vk_context.GetDevice(), render_target_, *render_pass_)); - if (!encoder->Track(framebuffer)) { + if (!encoder->Track(framebuffer) || !encoder->Track(render_pass_)) { return false; } @@ -617,6 +621,7 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { pass_info.setClearValues(clear_values); { + TRACE_EVENT0("impeller", "EncodeRenderPassCommands"); cmd_buffer.beginRenderPass(pass_info, vk::SubpassContents::eInline); fml::ScopedCleanupClosure end_render_pass( diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index eae656062c299..ebb42d15dbafe 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -6,6 +6,7 @@ #include "flutter/fml/macros.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command.h" @@ -22,7 +23,7 @@ class RenderPassVK final : public RenderPass { private: friend class CommandBufferVK; - vk::UniqueRenderPass render_pass_; + SharedHandleVK render_pass_; std::weak_ptr encoder_; std::string debug_label_; bool is_valid_ = false; diff --git a/impeller/renderer/backend/vulkan/sampler_library_vk.cc b/impeller/renderer/backend/vulkan/sampler_library_vk.cc index 149c1ae957d4c..b62549eb88ad5 100644 --- a/impeller/renderer/backend/vulkan/sampler_library_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_library_vk.cc @@ -4,6 +4,7 @@ #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/sampler_vk.h" @@ -51,6 +52,11 @@ std::shared_ptr SamplerLibraryVK::GetSampler( if (!sampler->IsValid()) { return nullptr; } + + if (!desc.label.empty()) { + ContextVK::SetDebugName(device_, sampler->GetSampler(), desc.label.c_str()); + } + samplers_[desc] = sampler; return sampler; } diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc index 7d2f9bb5c94d4..5b706ce92edca 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -14,7 +14,7 @@ SamplerVK::SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler) SamplerVK::~SamplerVK() = default; -vk::Sampler SamplerVK::GetSamplerVK() const { +vk::Sampler SamplerVK::GetSampler() const { return *sampler_; } diff --git a/impeller/renderer/backend/vulkan/sampler_vk.h b/impeller/renderer/backend/vulkan/sampler_vk.h index d0268ced3819a..bf78d63a1b271 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.h +++ b/impeller/renderer/backend/vulkan/sampler_vk.h @@ -22,7 +22,7 @@ class SamplerVK final : public Sampler, public BackendCast { // |Sampler| ~SamplerVK() override; - vk::Sampler GetSamplerVK() const; + vk::Sampler GetSampler() const; const std::shared_ptr>& GetSharedSampler() const; diff --git a/impeller/renderer/backend/vulkan/shared_object_vk.h b/impeller/renderer/backend/vulkan/shared_object_vk.h index d3c42a50a04ef..fa87547fc9c67 100644 --- a/impeller/renderer/backend/vulkan/shared_object_vk.h +++ b/impeller/renderer/backend/vulkan/shared_object_vk.h @@ -25,10 +25,14 @@ class SharedObjectVKT : public SharedObjectVK { explicit SharedObjectVKT(UniqueResource res) : resource_(std::move(res)) {} - operator Resource() const { return *resource_; } + operator Resource() const { return Get(); } + + const Resource& Get() const { return *resource_; } private: UniqueResource resource_; + + FML_DISALLOW_COPY_AND_ASSIGN(SharedObjectVKT); }; template @@ -40,4 +44,7 @@ auto MakeSharedVK( return std::make_shared>(std::move(handle)); } +template +using SharedHandleVK = std::shared_ptr>; + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index a1f09a42b3c76..02992a35ebc0f 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -43,9 +43,8 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate; std::shared_ptr resolve_tex = - std::make_shared(resolve_tex_desc, // - context, // - swapchain_image // + std::make_shared(context, // + swapchain_image // ); if (!resolve_tex) { @@ -65,8 +64,7 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( stencil0_tex.storage_mode = StorageMode::kDeviceTransient; stencil0_tex.type = TextureType::kTexture2D; stencil0_tex.sample_count = SampleCount::kCount4; - stencil0_tex.format = - context->GetDeviceCapabilities().GetDefaultStencilFormat(); + stencil0_tex.format = context->GetCapabilities()->GetDefaultStencilFormat(); stencil0_tex.size = msaa_tex_desc.size; stencil0_tex.usage = static_cast(TextureUsage::kRenderTarget); diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc index 843f0b44a8bbd..c87797df753ab 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc @@ -6,25 +6,22 @@ namespace impeller { -SwapchainImageVK::SwapchainImageVK(vk::Device device, - vk::Image image, - PixelFormat image_format, - ISize image_size) - : image_(image), image_format_(image_format), image_size_(image_size) { +SwapchainImageVK::SwapchainImageVK(TextureDescriptor desc, + vk::Device device, + vk::Image image) + : TextureSourceVK(desc), image_(image) { vk::ImageViewCreateInfo view_info; view_info.image = image_; view_info.viewType = vk::ImageViewType::e2D; - view_info.format = ToVKImageFormat(image_format_); + view_info.format = ToVKImageFormat(desc.format); view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; view_info.subresourceRange.baseMipLevel = 0u; - view_info.subresourceRange.levelCount = 1u; view_info.subresourceRange.baseArrayLayer = 0u; - view_info.subresourceRange.layerCount = 1u; + view_info.subresourceRange.levelCount = desc.mip_count; + view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type); auto [view_result, view] = device.createImageViewUnique(view_info); if (view_result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create image view: " - << vk::to_string(view_result); return; } @@ -39,20 +36,20 @@ bool SwapchainImageVK::IsValid() const { } PixelFormat SwapchainImageVK::GetPixelFormat() const { - return image_format_; + return desc_.format; } ISize SwapchainImageVK::GetSize() const { - return image_size_; + return desc_.size; } // |TextureSourceVK| -vk::Image SwapchainImageVK::GetVKImage() const { +vk::Image SwapchainImageVK::GetImage() const { return image_; } // |TextureSourceVK| -vk::ImageView SwapchainImageVK::GetVKImageView() const { +vk::ImageView SwapchainImageVK::GetImageView() const { return image_view_.get(); } diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.h b/impeller/renderer/backend/vulkan/swapchain_image_vk.h index 9869b689aaa3d..db905e834948c 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.h @@ -14,10 +14,7 @@ namespace impeller { class SwapchainImageVK final : public TextureSourceVK { public: - SwapchainImageVK(vk::Device device, - vk::Image image, - PixelFormat image_format, - ISize image_size); + SwapchainImageVK(TextureDescriptor desc, vk::Device device, vk::Image image); // |TextureSourceVK| ~SwapchainImageVK() override; @@ -29,15 +26,13 @@ class SwapchainImageVK final : public TextureSourceVK { ISize GetSize() const; // |TextureSourceVK| - vk::Image GetVKImage() const override; + vk::Image GetImage() const override; // |TextureSourceVK| - vk::ImageView GetVKImageView() const override; + vk::ImageView GetImageView() const override; private: vk::Image image_ = VK_NULL_HANDLE; - PixelFormat image_format_ = PixelFormat::kUnknown; - ISize image_size_; vk::UniqueImageView image_view_ = {}; bool is_valid_ = false; diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc index ff40400c657a7..b4e4f2f899d53 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc @@ -150,7 +150,7 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr& context, } const auto format = ChooseSurfaceFormat( - formats, vk_context.GetDeviceCapabilities().GetDefaultColorFormat()); + formats, vk_context.GetCapabilities()->GetDefaultColorFormat()); if (!format.has_value()) { VALIDATION_LOG << "Swapchain has no supported formats."; return; @@ -213,19 +213,33 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr& context, return; } + TextureDescriptor texture_desc; + texture_desc.usage = + static_cast(TextureUsage::kRenderTarget); + texture_desc.storage_mode = StorageMode::kDevicePrivate; + texture_desc.format = ToPixelFormat(swapchain_info.imageFormat); + texture_desc.size = ISize::MakeWH(swapchain_info.imageExtent.width, + swapchain_info.imageExtent.height); + std::vector> swapchain_images; for (const auto& image : images) { - auto swapchain_image = std::make_shared( - vk_context.GetDevice(), // - image, // - ToPixelFormat(swapchain_info.imageFormat), // - ISize::MakeWH(swapchain_info.imageExtent.width, - swapchain_info.imageExtent.height) // - ); + auto swapchain_image = + std::make_shared(texture_desc, // texture descriptor + vk_context.GetDevice(), // device + image // image + ); if (!swapchain_image->IsValid()) { VALIDATION_LOG << "Could not create swapchain image."; return; } + + ContextVK::SetDebugName( + vk_context.GetDevice(), swapchain_image->GetImage(), + "SwapchainImage" + std::to_string(swapchain_images.size())); + ContextVK::SetDebugName( + vk_context.GetDevice(), swapchain_image->GetImageView(), + "SwapchainImageView" + std::to_string(swapchain_images.size())); + swapchain_images.emplace_back(swapchain_image); } @@ -366,24 +380,19 @@ bool SwapchainImplVK::Present(const std::shared_ptr& image, auto vk_cmd_buffer = CommandBufferVK::Cast(*cmd_buffer).GetEncoder()->GetCommandBuffer(); - vk::ImageMemoryBarrier image_barrier; - image_barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite; - image_barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead; - image_barrier.image = image->GetVKImage(); - image_barrier.oldLayout = vk::ImageLayout::eColorAttachmentOptimal; - image_barrier.newLayout = vk::ImageLayout::ePresentSrcKHR; - image_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - image_barrier.subresourceRange.baseMipLevel = 0u; - image_barrier.subresourceRange.levelCount = 1u; - image_barrier.subresourceRange.baseArrayLayer = 0u; - image_barrier.subresourceRange.layerCount = 1u; - vk_cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, // - vk::PipelineStageFlagBits::eAllGraphics, // - {}, // - nullptr, // - nullptr, // - image_barrier // - ); + + LayoutTransition transition; + transition.new_layout = vk::ImageLayout::ePresentSrcKHR; + transition.cmd_buffer = vk_cmd_buffer; + transition.src_access = vk::AccessFlagBits::eColorAttachmentWrite; + transition.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput; + transition.dst_access = {}; + transition.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe; + + if (!image->SetLayout(transition)) { + return false; + } + if (!cmd_buffer->SubmitCommands()) { return false; } diff --git a/impeller/renderer/backend/vulkan/texture_source_vk.cc b/impeller/renderer/backend/vulkan/texture_source_vk.cc index c411c62489cbf..25f231565e58e 100644 --- a/impeller/renderer/backend/vulkan/texture_source_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_source_vk.cc @@ -6,6 +6,59 @@ namespace impeller { +TextureSourceVK::TextureSourceVK(TextureDescriptor desc) : desc_(desc) {} + +TextureSourceVK::~TextureSourceVK() = default; + +const TextureDescriptor& TextureSourceVK::GetTextureDescriptor() const { + return desc_; +} + +vk::ImageLayout TextureSourceVK::GetLayout() const { + ReaderLock lock(layout_mutex_); + return layout_; +} + +vk::ImageLayout TextureSourceVK::SetLayoutWithoutEncoding( + vk::ImageLayout layout) const { + WriterLock lock(layout_mutex_); + const auto old_layout = layout_; + layout_ = layout; + return old_layout; +} + +bool TextureSourceVK::SetLayout(const LayoutTransition& transition) const { + const auto old_layout = SetLayoutWithoutEncoding(transition.new_layout); + if (transition.new_layout == old_layout) { + return true; + } + + vk::ImageMemoryBarrier image_barrier; + image_barrier.srcAccessMask = transition.src_access; + image_barrier.dstAccessMask = transition.dst_access; + image_barrier.oldLayout = old_layout; + image_barrier.newLayout = transition.new_layout; + image_barrier.image = GetImage(); + image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier.subresourceRange.aspectMask = + ToImageAspectFlags(transition.new_layout); + image_barrier.subresourceRange.baseMipLevel = 0u; + image_barrier.subresourceRange.levelCount = desc_.mip_count; + image_barrier.subresourceRange.baseArrayLayer = 0u; + image_barrier.subresourceRange.layerCount = ToArrayLayerCount(desc_.type); + + transition.cmd_buffer.pipelineBarrier(transition.src_stage, // src stage + transition.dst_stage, // dst stage + {}, // dependency flags + nullptr, // memory barriers + nullptr, // buffer barriers + image_barrier // image barriers + ); + + return true; +} + bool TextureSourceVK::SetContents(const TextureDescriptor& desc, const uint8_t* contents, size_t length, diff --git a/impeller/renderer/backend/vulkan/texture_source_vk.h b/impeller/renderer/backend/vulkan/texture_source_vk.h index 5fac2ce93980c..4b65739427c9b 100644 --- a/impeller/renderer/backend/vulkan/texture_source_vk.h +++ b/impeller/renderer/backend/vulkan/texture_source_vk.h @@ -5,6 +5,8 @@ #pragma once #include "flutter/fml/macros.h" +#include "impeller/base/thread.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/texture_descriptor.h" @@ -12,16 +14,34 @@ namespace impeller { class TextureSourceVK { public: - virtual ~TextureSourceVK() = default; + virtual ~TextureSourceVK(); + + const TextureDescriptor& GetTextureDescriptor() const; virtual bool SetContents(const TextureDescriptor& desc, const uint8_t* contents, size_t length, size_t slice); - virtual vk::Image GetVKImage() const = 0; + virtual vk::Image GetImage() const = 0; + + virtual vk::ImageView GetImageView() const = 0; + + bool SetLayout(const LayoutTransition& transition) const; + + vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const; + + vk::ImageLayout GetLayout() const; + + protected: + const TextureDescriptor desc_; + + explicit TextureSourceVK(TextureDescriptor desc); - virtual vk::ImageView GetVKImageView() const = 0; + private: + mutable RWMutex layout_mutex_; + mutable vk::ImageLayout layout_ IPLR_GUARDED_BY(layout_mutex_) = + vk::ImageLayout::eUndefined; }; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index 70c048e1f459f..cc8c57280cc19 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -4,12 +4,17 @@ #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/command_encoder_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" + namespace impeller { -TextureVK::TextureVK(TextureDescriptor desc, - std::weak_ptr context, +TextureVK::TextureVK(std::weak_ptr context, std::shared_ptr source) - : Texture(desc), context_(std::move(context)), source_(std::move(source)) {} + : Texture(source->GetTextureDescriptor()), + context_(std::move(context)), + source_(std::move(source)) {} TextureVK::~TextureVK() = default; @@ -20,6 +25,7 @@ void TextureVK::SetLabel(std::string_view label) { return; } ContextVK::Cast(*context).SetDebugName(GetImage(), label); + ContextVK::Cast(*context).SetDebugName(GetImageView(), label); } bool TextureVK::OnSetContents(const uint8_t* contents, @@ -33,11 +39,74 @@ bool TextureVK::OnSetContents(const uint8_t* contents, // Out of bounds access. if (length != desc.GetByteSizeOfBaseMipLevel()) { - VALIDATION_LOG << "illegal to set contents for invalid size"; + VALIDATION_LOG << "Illegal to set contents for invalid size."; + return false; + } + + auto context = context_.lock(); + if (!context) { + VALIDATION_LOG << "Context died before setting contents on texture."; + return false; + } + + auto staging_buffer = + context->GetResourceAllocator()->CreateBufferWithCopy(contents, length); + + if (!staging_buffer) { + VALIDATION_LOG << "Could not create staging buffer."; + return false; + } + + auto cmd_buffer = context->CreateCommandBuffer(); + + if (!cmd_buffer) { + return false; + } + + const auto encoder = CommandBufferVK::Cast(*cmd_buffer).GetEncoder(); + + if (!encoder->Track(staging_buffer) || !encoder->Track(source_)) { + return false; + } + + const auto& vk_cmd_buffer = encoder->GetCommandBuffer(); + + LayoutTransition transition; + transition.cmd_buffer = vk_cmd_buffer; + transition.new_layout = vk::ImageLayout::eTransferDstOptimal; + transition.src_access = {}; + transition.src_stage = vk::PipelineStageFlagBits::eTopOfPipe; + transition.dst_access = vk::AccessFlagBits::eTransferWrite; + transition.dst_stage = vk::PipelineStageFlagBits::eTransfer; + + if (!SetLayout(transition)) { return false; } - return source_->SetContents(desc, contents, length, slice); + vk::BufferImageCopy copy; + copy.bufferOffset = 0u; + copy.bufferRowLength = 0u; // 0u means tightly packed per spec. + copy.bufferImageHeight = 0u; // 0u means tightly packed per spec. + copy.imageOffset.x = 0u; + copy.imageOffset.y = 0u; + copy.imageOffset.z = 0u; + copy.imageExtent.width = desc.size.width; + copy.imageExtent.height = desc.size.height; + copy.imageExtent.depth = 1u; + copy.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; + copy.imageSubresource.mipLevel = 0u; + copy.imageSubresource.baseArrayLayer = slice; + copy.imageSubresource.layerCount = 1u; + + vk_cmd_buffer.copyBufferToImage( + DeviceBufferVK::Cast(*staging_buffer).GetBuffer(), // src buffer + GetImage(), // dst image + transition.new_layout, // dst image layout + 1u, // region count + © // regions + ); + + return cmd_buffer->SubmitCommands(); } bool TextureVK::OnSetContents(std::shared_ptr mapping, @@ -56,75 +125,29 @@ ISize TextureVK::GetSize() const { } vk::Image TextureVK::GetImage() const { - return source_->GetVKImage(); + return source_->GetImage(); } vk::ImageView TextureVK::GetImageView() const { - return source_->GetVKImageView(); + return source_->GetImageView(); } -static constexpr vk::ImageAspectFlags ToImageAspectFlags( - vk::ImageLayout layout) { - switch (layout) { - case vk::ImageLayout::eColorAttachmentOptimal: - case vk::ImageLayout::eShaderReadOnlyOptimal: - return vk::ImageAspectFlagBits::eColor; - case vk::ImageLayout::eDepthAttachmentOptimal: - return vk::ImageAspectFlagBits::eDepth; - case vk::ImageLayout::eStencilAttachmentOptimal: - return vk::ImageAspectFlagBits::eStencil; - default: - FML_DLOG(INFO) << "Unknown layout to determine aspect."; - return vk::ImageAspectFlagBits::eNone; - } - FML_UNREACHABLE(); +std::shared_ptr TextureVK::GetTextureSource() const { + return source_; } -vk::ImageLayout TextureVK::GetLayout() const { - ReaderLock lock(layout_mutex_); - return layout_; +bool TextureVK::SetLayout(const LayoutTransition& transition) const { + return source_ ? source_->SetLayout(transition) : false; } vk::ImageLayout TextureVK::SetLayoutWithoutEncoding( vk::ImageLayout layout) const { - WriterLock lock(layout_mutex_); - const auto old_layout = layout_; - layout_ = layout; - return old_layout; + return source_ ? source_->SetLayoutWithoutEncoding(layout) + : vk::ImageLayout::eUndefined; } -bool TextureVK::SetLayout(vk::ImageLayout new_layout, - const vk::CommandBuffer& buffer) const { - const auto old_layout = SetLayoutWithoutEncoding(new_layout); - if (new_layout == old_layout) { - return true; - } - - vk::ImageMemoryBarrier image_barrier; - image_barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | - vk::AccessFlagBits::eTransferWrite; - image_barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | - vk::AccessFlagBits::eShaderRead; - image_barrier.oldLayout = old_layout; - image_barrier.newLayout = new_layout; - image_barrier.image = GetImage(); - image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.subresourceRange.aspectMask = ToImageAspectFlags(new_layout); - image_barrier.subresourceRange.baseMipLevel = 0u; - image_barrier.subresourceRange.levelCount = GetTextureDescriptor().mip_count; - image_barrier.subresourceRange.baseArrayLayer = 0u; - image_barrier.subresourceRange.layerCount = 1u; - - buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, // src stage - vk::PipelineStageFlagBits::eAllGraphics, // dst stage - {}, // dependency flags - nullptr, // memory barriers - nullptr, // buffer barriers - image_barrier // image barriers - ); - - return true; +vk::ImageLayout TextureVK::GetLayout() const { + return source_ ? source_->GetLayout() : vk::ImageLayout::eUndefined; } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index 8ab9a00d27aa3..5128c2fd66ad5 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -8,9 +8,9 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" -#include "impeller/base/thread.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/texture_source_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/texture.h" @@ -19,8 +19,7 @@ namespace impeller { class TextureVK final : public Texture, public BackendCast { public: - TextureVK(TextureDescriptor desc, - std::weak_ptr context, + TextureVK(std::weak_ptr context, std::shared_ptr source); // |Texture| @@ -30,12 +29,14 @@ class TextureVK final : public Texture, public BackendCast { vk::ImageView GetImageView() const; - bool SetLayout(vk::ImageLayout layout, const vk::CommandBuffer& buffer) const; + bool SetLayout(const LayoutTransition& transition) const; vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const; vk::ImageLayout GetLayout() const; + std::shared_ptr GetTextureSource() const; + private: std::weak_ptr context_; std::shared_ptr source_; diff --git a/impeller/renderer/capabilities.cc b/impeller/renderer/capabilities.cc new file mode 100644 index 0000000000000..b7e6b944211c2 --- /dev/null +++ b/impeller/renderer/capabilities.cc @@ -0,0 +1,159 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/capabilities.h" + +namespace impeller { + +Capabilities::Capabilities() = default; + +Capabilities::~Capabilities() = default; + +class StandardCapabilities final : public Capabilities { + public: + // |Capabilities| + ~StandardCapabilities() override = default; + + // |Capabilities| + bool HasThreadingRestrictions() const override { + return has_threading_restrictions_; + } + + // |Capabilities| + bool SupportsOffscreenMSAA() const override { + return supports_offscreen_msaa_; + } + + // |Capabilities| + bool SupportsSSBO() const override { return supports_ssbo_; } + + // |Capabilities| + bool SupportsTextureToTextureBlits() const override { + return supports_texture_to_texture_blits_; + } + + // |Capabilities| + bool SupportsFramebufferFetch() const override { + return supports_framebuffer_fetch_; + } + + // |Capabilities| + bool SupportsCompute() const override { return supports_compute_; } + + // |Capabilities| + bool SupportsComputeSubgroups() const override { + return supports_compute_subgroups_; + } + + // |Capabilities| + PixelFormat GetDefaultColorFormat() const override { + return default_color_format_; + } + + // |Capabilities| + PixelFormat GetDefaultStencilFormat() const override { + return default_stencil_format_; + } + + private: + StandardCapabilities(bool has_threading_restrictions, + bool supports_offscreen_msaa, + bool supports_ssbo, + bool supports_texture_to_texture_blits, + bool supports_framebuffer_fetch, + bool supports_compute, + bool supports_compute_subgroups, + PixelFormat default_color_format, + PixelFormat default_stencil_format) + : has_threading_restrictions_(has_threading_restrictions), + supports_offscreen_msaa_(supports_offscreen_msaa), + supports_ssbo_(supports_ssbo), + supports_texture_to_texture_blits_(supports_texture_to_texture_blits), + supports_framebuffer_fetch_(supports_framebuffer_fetch), + supports_compute_(supports_compute), + supports_compute_subgroups_(supports_compute_subgroups), + default_color_format_(default_color_format), + default_stencil_format_(default_stencil_format) {} + + friend class CapabilitiesBuilder; + + bool has_threading_restrictions_ = false; + bool supports_offscreen_msaa_ = false; + bool supports_ssbo_ = false; + bool supports_texture_to_texture_blits_ = false; + bool supports_framebuffer_fetch_ = false; + bool supports_compute_ = false; + bool supports_compute_subgroups_ = false; + PixelFormat default_color_format_ = PixelFormat::kUnknown; + PixelFormat default_stencil_format_ = PixelFormat::kUnknown; + + FML_DISALLOW_COPY_AND_ASSIGN(StandardCapabilities); +}; + +CapabilitiesBuilder::CapabilitiesBuilder() = default; + +CapabilitiesBuilder::~CapabilitiesBuilder() = default; + +CapabilitiesBuilder& CapabilitiesBuilder::SetHasThreadingRestrictions( + bool value) { + has_threading_restrictions_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsOffscreenMSAA(bool value) { + supports_offscreen_msaa_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsSSBO(bool value) { + supports_ssbo_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsTextureToTextureBlits( + bool value) { + supports_texture_to_texture_blits_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsFramebufferFetch( + bool value) { + supports_framebuffer_fetch_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsCompute(bool compute, + bool subgroups) { + supports_compute_ = compute; + supports_compute_subgroups_ = subgroups; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultColorFormat( + PixelFormat value) { + default_color_format_ = value; + return *this; +} + +CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultStencilFormat( + PixelFormat value) { + default_stencil_format_ = value; + return *this; +} + +std::unique_ptr CapabilitiesBuilder::Build() { + return std::unique_ptr(new StandardCapabilities( // + has_threading_restrictions_, // + supports_offscreen_msaa_, // + supports_ssbo_, // + supports_texture_to_texture_blits_, // + supports_framebuffer_fetch_, // + supports_compute_, // + supports_compute_subgroups_, // + *default_color_format_, // + *default_stencil_format_ // + )); +} + +} // namespace impeller diff --git a/impeller/renderer/capabilities.h b/impeller/renderer/capabilities.h new file mode 100644 index 0000000000000..945e9fde3fbc2 --- /dev/null +++ b/impeller/renderer/capabilities.h @@ -0,0 +1,80 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#include "flutter/fml/macros.h" +#include "impeller/renderer/formats.h" + +namespace impeller { + +class Capabilities { + public: + virtual ~Capabilities(); + + virtual bool HasThreadingRestrictions() const = 0; + + virtual bool SupportsOffscreenMSAA() const = 0; + + virtual bool SupportsSSBO() const = 0; + + virtual bool SupportsTextureToTextureBlits() const = 0; + + virtual bool SupportsFramebufferFetch() const = 0; + + virtual bool SupportsCompute() const = 0; + + virtual bool SupportsComputeSubgroups() const = 0; + + virtual PixelFormat GetDefaultColorFormat() const = 0; + + virtual PixelFormat GetDefaultStencilFormat() const = 0; + + protected: + Capabilities(); + + FML_DISALLOW_COPY_AND_ASSIGN(Capabilities); +}; + +class CapabilitiesBuilder { + public: + CapabilitiesBuilder(); + + ~CapabilitiesBuilder(); + + CapabilitiesBuilder& SetHasThreadingRestrictions(bool value); + + CapabilitiesBuilder& SetSupportsOffscreenMSAA(bool value); + + CapabilitiesBuilder& SetSupportsSSBO(bool value); + + CapabilitiesBuilder& SetSupportsTextureToTextureBlits(bool value); + + CapabilitiesBuilder& SetSupportsFramebufferFetch(bool value); + + CapabilitiesBuilder& SetSupportsCompute(bool compute, bool subgroups); + + CapabilitiesBuilder& SetDefaultColorFormat(PixelFormat value); + + CapabilitiesBuilder& SetDefaultStencilFormat(PixelFormat value); + + std::unique_ptr Build(); + + private: + bool has_threading_restrictions_ = false; + bool supports_offscreen_msaa_ = false; + bool supports_ssbo_ = false; + bool supports_texture_to_texture_blits_ = false; + bool supports_framebuffer_fetch_ = false; + bool supports_compute_ = false; + bool supports_compute_subgroups_ = false; + std::optional default_color_format_ = std::nullopt; + std::optional default_stencil_format_ = std::nullopt; + + FML_DISALLOW_COPY_AND_ASSIGN(CapabilitiesBuilder); +}; + +} // namespace impeller diff --git a/impeller/renderer/compute_subgroup_unittests.cc b/impeller/renderer/compute_subgroup_unittests.cc index 1b93ae66ec243..f5305f278da57 100644 --- a/impeller/renderer/compute_subgroup_unittests.cc +++ b/impeller/renderer/compute_subgroup_unittests.cc @@ -39,7 +39,7 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) { auto context = GetContext(); ASSERT_TRUE(context); - ASSERT_TRUE(context->GetDeviceCapabilities().SupportsComputeSubgroups()); + ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups()); auto cmd_buffer = context->CreateCommandBuffer(); auto pass = cmd_buffer->CreateComputePass(); @@ -258,7 +258,7 @@ TEST_P(ComputeTest, QuadsToPolyline) { using QS = QuadPolylineComputeShader; auto context = GetContext(); ASSERT_TRUE(context); - ASSERT_TRUE(context->GetDeviceCapabilities().SupportsComputeSubgroups()); + ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups()); auto cmd_buffer = context->CreateCommandBuffer(); auto pass = cmd_buffer->CreateComputePass(); diff --git a/impeller/renderer/compute_unittests.cc b/impeller/renderer/compute_unittests.cc index ffed4bd7e8502..62ddeadb44b49 100644 --- a/impeller/renderer/compute_unittests.cc +++ b/impeller/renderer/compute_unittests.cc @@ -28,7 +28,7 @@ TEST_P(ComputeTest, CanCreateComputePass) { using CS = SampleComputeShader; auto context = GetContext(); ASSERT_TRUE(context); - ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute()); + ASSERT_TRUE(context->GetCapabilities()->SupportsCompute()); using SamplePipelineBuilder = ComputePipelineBuilder; auto pipeline_desc = @@ -111,7 +111,7 @@ TEST_P(ComputeTest, MultiStageInputAndOutput) { auto context = GetContext(); ASSERT_TRUE(context); - ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute()); + ASSERT_TRUE(context->GetCapabilities()->SupportsCompute()); auto pipeline_desc_1 = Stage1PipelineBuilder::MakeDefaultPipelineDescriptor(*context); diff --git a/impeller/renderer/context.cc b/impeller/renderer/context.cc index 9d8aad55e681a..1525dfc1bf0f9 100644 --- a/impeller/renderer/context.cc +++ b/impeller/renderer/context.cc @@ -14,8 +14,8 @@ std::shared_ptr Context::GetGPUTracer() const { return nullptr; } -PixelFormat Context::GetColorAttachmentPixelFormat() const { - return GetDeviceCapabilities().GetDefaultColorFormat(); +bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) { + return false; } } // namespace impeller diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index a6a485c3e6de3..f78d2e3d00f12 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -8,7 +8,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/renderer/device_capabilities.h" +#include "impeller/renderer/capabilities.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -27,9 +27,11 @@ class Context : public std::enable_shared_from_this { virtual bool IsValid() const = 0; - //---------------------------------------------------------------------------- - /// @return A resource allocator. - /// + virtual const std::shared_ptr& GetCapabilities() + const = 0; + + virtual bool UpdateOffscreenLayerPixelFormat(PixelFormat format); + virtual std::shared_ptr GetResourceAllocator() const = 0; virtual std::shared_ptr GetShaderLibrary() const = 0; @@ -42,15 +44,8 @@ class Context : public std::enable_shared_from_this { virtual std::shared_ptr GetWorkQueue() const = 0; - //---------------------------------------------------------------------------- - /// @return A GPU Tracer to trace gpu rendering. - /// virtual std::shared_ptr GetGPUTracer() const; - virtual PixelFormat GetColorAttachmentPixelFormat() const; - - virtual const IDeviceCapabilities& GetDeviceCapabilities() const = 0; - protected: Context(); diff --git a/impeller/renderer/descriptor_set_layout.h b/impeller/renderer/descriptor_set_layout.h deleted file mode 100644 index d853f0a663086..0000000000000 --- a/impeller/renderer/descriptor_set_layout.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include -#include - -#include "flutter/fml/macros.h" -#include "impeller/renderer/shader_types.h" - -namespace impeller { - -enum class DescriptorType { - kSampledImage, - kUniformBuffer, -}; - -struct DescriptorSetLayout { - uint32_t binding; - DescriptorType descriptor_type; - uint32_t descriptor_count; - ShaderStage shader_stage; -}; - -} // namespace impeller diff --git a/impeller/renderer/device_capabilities.cc b/impeller/renderer/device_capabilities.cc deleted file mode 100644 index bf88bbc4c5f6b..0000000000000 --- a/impeller/renderer/device_capabilities.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "impeller/renderer/device_capabilities.h" -#include "device_capabilities.h" - -namespace impeller { - -IDeviceCapabilities::IDeviceCapabilities(bool has_threading_restrictions, - bool supports_offscreen_msaa, - bool supports_ssbo, - bool supports_texture_to_texture_blits, - bool supports_framebuffer_fetch, - PixelFormat default_color_format, - PixelFormat default_stencil_format, - bool supports_compute, - bool supports_compute_subgroups) - : has_threading_restrictions_(has_threading_restrictions), - supports_offscreen_msaa_(supports_offscreen_msaa), - supports_ssbo_(supports_ssbo), - supports_texture_to_texture_blits_(supports_texture_to_texture_blits), - supports_framebuffer_fetch_(supports_framebuffer_fetch), - default_color_format_(default_color_format), - default_stencil_format_(default_stencil_format), - supports_compute_(supports_compute), - supports_compute_subgroups_(supports_compute_subgroups) {} - -IDeviceCapabilities::~IDeviceCapabilities() = default; - -bool IDeviceCapabilities::HasThreadingRestrictions() const { - return has_threading_restrictions_; -} - -bool IDeviceCapabilities::SupportsOffscreenMSAA() const { - return supports_offscreen_msaa_; -} - -bool IDeviceCapabilities::SupportsSSBO() const { - return supports_ssbo_; -} - -bool IDeviceCapabilities::SupportsTextureToTextureBlits() const { - return supports_texture_to_texture_blits_; -} - -bool IDeviceCapabilities::SupportsFramebufferFetch() const { - return supports_framebuffer_fetch_; -} - -PixelFormat IDeviceCapabilities::GetDefaultColorFormat() const { - return default_color_format_; -} - -PixelFormat IDeviceCapabilities::GetDefaultStencilFormat() const { - return default_stencil_format_; -} - -bool IDeviceCapabilities::SupportsCompute() const { - return supports_compute_; -} - -bool IDeviceCapabilities::SupportsComputeSubgroups() const { - return supports_compute_subgroups_; -} - -DeviceCapabilitiesBuilder::DeviceCapabilitiesBuilder() = default; - -DeviceCapabilitiesBuilder::~DeviceCapabilitiesBuilder() = default; - -DeviceCapabilitiesBuilder& -DeviceCapabilitiesBuilder::SetHasThreadingRestrictions(bool value) { - has_threading_restrictions_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsOffscreenMSAA( - bool value) { - supports_offscreen_msaa_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsSSBO( - bool value) { - supports_ssbo_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& -DeviceCapabilitiesBuilder::SetSupportsTextureToTextureBlits(bool value) { - supports_texture_to_texture_blits_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& -DeviceCapabilitiesBuilder::SetSupportsFramebufferFetch(bool value) { - supports_framebuffer_fetch_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetDefaultColorFormat( - PixelFormat value) { - default_color_format_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetDefaultStencilFormat( - PixelFormat value) { - default_stencil_format_ = value; - return *this; -} - -DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsCompute( - bool value, - bool subgroups) { - supports_compute_ = value; - supports_compute_subgroups_ = subgroups; - return *this; -} - -std::unique_ptr DeviceCapabilitiesBuilder::Build() { - FML_CHECK(default_color_format_.has_value()) - << "Default color format not set"; - FML_CHECK(default_stencil_format_.has_value()) - << "Default stencil format not set"; - - IDeviceCapabilities* capabilities = new IDeviceCapabilities( // - has_threading_restrictions_, // - supports_offscreen_msaa_, // - supports_ssbo_, // - supports_texture_to_texture_blits_, // - supports_framebuffer_fetch_, // - *default_color_format_, // - *default_stencil_format_, // - supports_compute_, // - supports_compute_subgroups_ // - ); - return std::unique_ptr(capabilities); -} - -} // namespace impeller diff --git a/impeller/renderer/device_capabilities.h b/impeller/renderer/device_capabilities.h deleted file mode 100644 index f74d95c27f494..0000000000000 --- a/impeller/renderer/device_capabilities.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include - -#include "flutter/fml/macros.h" -#include "impeller/renderer/formats.h" - -namespace impeller { - -class IDeviceCapabilities { - public: - ~IDeviceCapabilities(); - - bool HasThreadingRestrictions() const; - - bool SupportsOffscreenMSAA() const; - - bool SupportsSSBO() const; - - bool SupportsTextureToTextureBlits() const; - - bool SupportsFramebufferFetch() const; - - PixelFormat GetDefaultColorFormat() const; - - PixelFormat GetDefaultStencilFormat() const; - - bool SupportsCompute() const; - bool SupportsComputeSubgroups() const; - - private: - IDeviceCapabilities(bool has_threading_restrictions, - bool supports_offscreen_msaa, - bool supports_ssbo, - bool supports_texture_to_texture_blits, - bool supports_framebuffer_fetch, - PixelFormat default_color_format, - PixelFormat default_stencil_format, - bool supports_compute, - bool supports_compute_subgroups); - - friend class DeviceCapabilitiesBuilder; - - bool has_threading_restrictions_ = false; - bool supports_offscreen_msaa_ = false; - bool supports_ssbo_ = false; - bool supports_texture_to_texture_blits_ = false; - bool supports_framebuffer_fetch_ = false; - PixelFormat default_color_format_; - PixelFormat default_stencil_format_; - bool supports_compute_ = false; - bool supports_compute_subgroups_ = false; - - FML_DISALLOW_COPY_AND_ASSIGN(IDeviceCapabilities); -}; - -class DeviceCapabilitiesBuilder { - public: - DeviceCapabilitiesBuilder(); - - ~DeviceCapabilitiesBuilder(); - - DeviceCapabilitiesBuilder& SetHasThreadingRestrictions(bool value); - - DeviceCapabilitiesBuilder& SetSupportsOffscreenMSAA(bool value); - - DeviceCapabilitiesBuilder& SetSupportsSSBO(bool value); - - DeviceCapabilitiesBuilder& SetSupportsTextureToTextureBlits(bool value); - - DeviceCapabilitiesBuilder& SetSupportsFramebufferFetch(bool value); - - DeviceCapabilitiesBuilder& SetDefaultColorFormat(PixelFormat value); - - DeviceCapabilitiesBuilder& SetDefaultStencilFormat(PixelFormat value); - - DeviceCapabilitiesBuilder& SetSupportsCompute(bool value, bool subgroups); - - std::unique_ptr Build(); - - private: - bool has_threading_restrictions_ = false; - bool supports_offscreen_msaa_ = false; - bool supports_ssbo_ = false; - bool supports_texture_to_texture_blits_ = false; - bool supports_framebuffer_fetch_ = false; - bool supports_compute_ = false; - bool supports_compute_subgroups_ = false; - std::optional default_color_format_ = std::nullopt; - std::optional default_stencil_format_ = std::nullopt; - - FML_DISALLOW_COPY_AND_ASSIGN(DeviceCapabilitiesBuilder); -}; - -} // namespace impeller diff --git a/impeller/renderer/formats.h b/impeller/renderer/formats.h index 170a068da607f..79daace56ff96 100644 --- a/impeller/renderer/formats.h +++ b/impeller/renderer/formats.h @@ -188,6 +188,10 @@ enum class TextureUsage : TextureUsageMask { kRenderTarget = 1 << 2, }; +constexpr bool TextureUsageIsRenderTarget(TextureUsageMask mask) { + return static_cast(TextureUsage::kRenderTarget) & mask; +} + enum class TextureIntent { kUploadFromHost, kRenderToTexture, diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index efaab15e65865..c1c3fbb94781c 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -117,7 +117,7 @@ struct PipelineBuilder { // Configure the sole color attachments pixel format. This is by // convention. ColorAttachmentDescriptor color0; - color0.format = context.GetColorAttachmentPixelFormat(); + color0.format = context.GetCapabilities()->GetDefaultColorFormat(); color0.blending_enabled = true; desc.SetColorAttachmentDescriptor(0u, color0); } @@ -128,7 +128,7 @@ struct PipelineBuilder { stencil0.stencil_compare = CompareFunction::kEqual; desc.SetStencilAttachmentDescriptors(stencil0); desc.SetStencilPixelFormat( - context.GetDeviceCapabilities().GetDefaultStencilFormat()); + context.GetCapabilities()->GetDefaultStencilFormat()); } return true; diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index aba17fd6532ef..167a4d3d37b34 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -210,7 +210,7 @@ RenderTarget RenderTarget::CreateOffscreen( } RenderTarget target; - PixelFormat pixel_format = context.GetColorAttachmentPixelFormat(); + PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat(); TextureDescriptor color_tex0; color_tex0.storage_mode = color_attachment_config.storage_mode; color_tex0.format = pixel_format; @@ -233,8 +233,7 @@ RenderTarget RenderTarget::CreateOffscreen( if (stencil_attachment_config.has_value()) { TextureDescriptor stencil_tex0; stencil_tex0.storage_mode = stencil_attachment_config->storage_mode; - stencil_tex0.format = - context.GetDeviceCapabilities().GetDefaultStencilFormat(); + stencil_tex0.format = context.GetCapabilities()->GetDefaultStencilFormat(); stencil_tex0.size = size; stencil_tex0.usage = static_cast(TextureUsage::kRenderTarget); @@ -269,7 +268,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( } RenderTarget target; - PixelFormat pixel_format = context.GetColorAttachmentPixelFormat(); + PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat(); // Create MSAA color texture. @@ -327,8 +326,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( stencil_tex0.storage_mode = stencil_attachment_config->storage_mode; stencil_tex0.type = TextureType::kTexture2DMultisample; stencil_tex0.sample_count = SampleCount::kCount4; - stencil_tex0.format = - context.GetDeviceCapabilities().GetDefaultStencilFormat(); + stencil_tex0.format = context.GetCapabilities()->GetDefaultStencilFormat(); stencil_tex0.size = size; stencil_tex0.usage = static_cast(TextureUsage::kRenderTarget); diff --git a/impeller/renderer/sampler.h b/impeller/renderer/sampler.h index 2b14d2843c5a3..41a16f5b74865 100644 --- a/impeller/renderer/sampler.h +++ b/impeller/renderer/sampler.h @@ -20,7 +20,7 @@ class Sampler { protected: SamplerDescriptor desc_; - Sampler(SamplerDescriptor desc); + explicit Sampler(SamplerDescriptor desc); private: FML_DISALLOW_COPY_AND_ASSIGN(Sampler); diff --git a/impeller/renderer/shader_types.h b/impeller/renderer/shader_types.h index 400607c1f55f6..b29bffd6f1260 100644 --- a/impeller/renderer/shader_types.h +++ b/impeller/renderer/shader_types.h @@ -123,6 +123,17 @@ struct SampledImageSlot { constexpr bool HasSampler() const { return sampler_index < 32u; } }; +enum class DescriptorType { + kSampledImage, + kUniformBuffer, +}; + +struct DescriptorSetLayout { + uint32_t binding; + DescriptorType descriptor_type; + ShaderStage shader_stage; +}; + template struct Padding { private: diff --git a/impeller/renderer/testing/mocks.h b/impeller/renderer/testing/mocks.h index 1f387ee58e05a..7357cec41514c 100644 --- a/impeller/renderer/testing/mocks.h +++ b/impeller/renderer/testing/mocks.h @@ -97,9 +97,8 @@ class MockImpellerContext : public Context { MOCK_CONST_METHOD0(GetGPUTracer, std::shared_ptr()); - MOCK_CONST_METHOD0(GetColorAttachmentPixelFormat, PixelFormat()); - - MOCK_CONST_METHOD0(GetDeviceCapabilities, const IDeviceCapabilities&()); + MOCK_CONST_METHOD0(GetCapabilities, + const std::shared_ptr&()); }; class MockTexture : public Texture { diff --git a/impeller/renderer/vertex_descriptor.h b/impeller/renderer/vertex_descriptor.h index dffe6694f7caf..8d145bb0f503e 100644 --- a/impeller/renderer/vertex_descriptor.h +++ b/impeller/renderer/vertex_descriptor.h @@ -8,7 +8,6 @@ #include "flutter/fml/macros.h" #include "impeller/base/comparable.h" -#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/shader_types.h" namespace impeller { diff --git a/impeller/runtime_stage/runtime_stage_unittests.cc b/impeller/runtime_stage/runtime_stage_unittests.cc index 896ecab89e824..d5596afa6748f 100644 --- a/impeller/runtime_stage/runtime_stage_unittests.cc +++ b/impeller/runtime_stage/runtime_stage_unittests.cc @@ -242,13 +242,13 @@ TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) { ASSERT_TRUE(vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs)); desc.SetVertexDescriptor(std::move(vertex_descriptor)); ColorAttachmentDescriptor color0; - color0.format = GetContext()->GetColorAttachmentPixelFormat(); + color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat(); StencilAttachmentDescriptor stencil0; stencil0.stencil_compare = CompareFunction::kEqual; desc.SetColorAttachmentDescriptor(0u, color0); desc.SetStencilAttachmentDescriptors(stencil0); const auto stencil_fmt = - GetContext()->GetDeviceCapabilities().GetDefaultStencilFormat(); + GetContext()->GetCapabilities()->GetDefaultStencilFormat(); desc.SetStencilPixelFormat(stencil_fmt); auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get(); ASSERT_NE(pipeline, nullptr); diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 04c4cd84b26c6..45c02e5b28b1b 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -325,7 +325,7 @@ void ImageDecoderImpeller::Decode(fml::RefPtr descriptor, // Depending on whether the context has threading restrictions, stay on // the concurrent runner to perform texture upload or move to an IO // runner. - if (context->GetDeviceCapabilities().HasThreadingRestrictions()) { + if (context->GetCapabilities()->HasThreadingRestrictions()) { io_runner->PostTask(upload_texture_and_invoke_result); } else { upload_texture_and_invoke_result(); diff --git a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm index c1696ff309d70..a74343ba1fe26 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm +++ b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm @@ -8,8 +8,9 @@ #include "flutter/impeller/renderer/context.h" #include "flutter/shell/gpu/gpu_surface_metal_impeller.h" -namespace { -impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) { +namespace flutter { + +static impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) { switch (pixel_format) { case impeller::PixelFormat::kB10G10R10XR: return impeller::PixelFormat::kB10G10R10A10XR; @@ -17,66 +18,6 @@ return pixel_format; } } -} // namespace - -namespace impeller { -namespace { -// This appears to be the only safe way to override the -// GetColorAttachmentPixelFormat method. It is assumed in the Context that -// there will be one pixel format for the whole app which is not true. So, it -// is unsafe to mutate the Context and you cannot clone the Context at this -// level since the Context does not safely manage the MTLDevice. -class CustomColorAttachmentPixelFormatContext final : public Context { - public: - CustomColorAttachmentPixelFormatContext(const std::shared_ptr& context, - PixelFormat color_attachment_pixel_format) - : context_(context), color_attachment_pixel_format_(color_attachment_pixel_format) {} - - bool IsValid() const override { return context_->IsValid(); } - - std::shared_ptr GetResourceAllocator() const override { - return context_->GetResourceAllocator(); - } - - std::shared_ptr GetShaderLibrary() const override { - return context_->GetShaderLibrary(); - } - - std::shared_ptr GetSamplerLibrary() const override { - return context_->GetSamplerLibrary(); - } - - std::shared_ptr GetPipelineLibrary() const override { - return context_->GetPipelineLibrary(); - } - - std::shared_ptr CreateCommandBuffer() const override { - return context_->CreateCommandBuffer(); - } - - std::shared_ptr GetWorkQueue() const override { return context_->GetWorkQueue(); } - - std::shared_ptr GetGPUTracer() const override { return context_->GetGPUTracer(); } - - PixelFormat GetColorAttachmentPixelFormat() const override { - return color_attachment_pixel_format_; - } - - const IDeviceCapabilities& GetDeviceCapabilities() const override { - return context_->GetDeviceCapabilities(); - } - - private: - std::shared_ptr context_; - PixelFormat color_attachment_pixel_format_; -}; -} // namespace -} // namespace impeller - -namespace flutter { - -using impeller::CustomColorAttachmentPixelFormatContext; -using impeller::FromMTLPixelFormat; IOSSurfaceMetalImpeller::IOSSurfaceMetalImpeller(const fml::scoped_nsobject& layer, const std::shared_ptr& context) @@ -87,7 +28,8 @@ PixelFormat GetColorAttachmentPixelFormat() const override { if (!impeller_context_) { return; } - is_valid_ = true; + is_valid_ = impeller_context_->UpdateOffscreenLayerPixelFormat( + InferOffscreenLayerPixelFormat(impeller::FromMTLPixelFormat(layer_.get().pixelFormat))); } // |IOSSurface| @@ -105,11 +47,8 @@ PixelFormat GetColorAttachmentPixelFormat() const override { // |IOSSurface| std::unique_ptr IOSSurfaceMetalImpeller::CreateGPUSurface(GrDirectContext*) { - auto context = std::make_shared( - impeller_context_, - InferOffscreenLayerPixelFormat(FromMTLPixelFormat(layer_.get().pixelFormat))); - return std::make_unique(this, // - context // + return std::make_unique(this, // + impeller_context_ // ); }