diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7c510864e4266..fdb72da12350e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1411,18 +1411,10 @@ 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 @@ -1464,8 +1456,6 @@ 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 @@ -1480,10 +1470,13 @@ 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 @@ -3947,18 +3940,10 @@ 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 @@ -4000,8 +3985,6 @@ 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 @@ -4016,10 +3999,13 @@ 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 04fdeb5b01e4e..634bf58f27642 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 buffer->SubmitCommands(); + return true; } TEST_P(AiksTest, CanRenderTiledTexture) { diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 10500e6c09d89..97b48e357a321 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->GetCapabilities()->SupportsOffscreenMSAA()) { + if (impeller_context->GetDeviceCapabilities().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 2666a53f9ca96..d2708052d1838 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -22,6 +22,8 @@ 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 #} @@ -164,15 +166,17 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} {% for buffer in buffers %} DescriptorSetLayout{ {{buffer.binding}}, // binding = {{buffer.binding}} - DescriptorType::kUniformBuffer, // descriptor_type = Uniform Buffer - {{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}} + DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer + 1, // descriptorCount = 1 + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} {% for sampled_image in sampled_images %} DescriptorSetLayout{ {{sampled_image.binding}}, // binding = {{sampled_image.binding}} - DescriptorType::kSampledImage, // descriptor_type = Sampled Image - {{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}} + DescriptorType::kSampledImage, // descriptorType = Sampled Image + 1, // descriptorCount = 1 + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} }; diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 54a9fb46250fc..36287aaf935f7 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -154,8 +154,7 @@ static std::unique_ptr CreateDefaultPipeline( return nullptr; } // Apply default ContentContextOptions to the descriptor. - const auto default_color_fmt = - context.GetCapabilities()->GetDefaultColorFormat(); + const auto default_color_fmt = context.GetColorAttachmentPixelFormat(); ContentContextOptions{.color_attachment_pixel_format = default_color_fmt} .ApplyToPipelineDescriptor(*desc); return std::make_unique(context, desc); @@ -176,7 +175,7 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); - if (context_->GetCapabilities()->SupportsSSBO()) { + if (context_->GetDeviceCapabilities().SupportsSSBO()) { linear_gradient_ssbo_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); radial_gradient_ssbo_fill_pipelines_[{}] = @@ -184,7 +183,7 @@ ContentContext::ContentContext(std::shared_ptr context) sweep_gradient_ssbo_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); } - if (context_->GetCapabilities()->SupportsFramebufferFetch()) { + if (context_->GetDeviceCapabilities().SupportsFramebufferFetch()) { framebuffer_blend_color_pipelines_[{}] = CreateDefaultPipeline(*context_); framebuffer_blend_colorburn_pipelines_[{}] = @@ -316,7 +315,8 @@ std::shared_ptr ContentContext::MakeSubpass( auto context = GetContext(); RenderTarget subpass_target; - if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) { + if (context->GetDeviceCapabilities().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 Capabilities& ContentContext::GetDeviceCapabilities() const { - return *context_->GetCapabilities(); +const IDeviceCapabilities& ContentContext::GetDeviceCapabilities() const { + return context_->GetDeviceCapabilities(); } void ContentContext::SetWireframe(bool wireframe) { diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 3449236aae490..236167f3a9e58 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/capabilities.h" +#include "impeller/renderer/device_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 Capabilities& GetDeviceCapabilities() const; + const IDeviceCapabilities& 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 9f7aaadbde09c..841027d84fc54 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -102,9 +102,10 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, /// Get or create runtime stage pipeline. /// - const auto& caps = context->GetCapabilities(); - const auto color_attachment_format = caps->GetDefaultColorFormat(); - const auto stencil_attachment_format = caps->GetDefaultStencilFormat(); + const auto& device_capabilities = context->GetDeviceCapabilities(); + const auto color_attachment_format = context->GetColorAttachmentPixelFormat(); + const auto stencil_attachment_format = + device_capabilities.GetDefaultStencilFormat(); using VS = RuntimeEffectVertexShader; PipelineDescriptor desc; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 5e00c6b1c1ee0..487c56d063976 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->GetCapabilities()->SupportsOffscreenMSAA()) { + if (context->GetDeviceCapabilities().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() - ->GetCapabilities() - ->SupportsTextureToTextureBlits()) { + ->GetDeviceCapabilities() + .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 cf26700b41706..2418d1dae7c9a 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -82,8 +82,9 @@ } data_->metal_layer = [CAMetalLayer layer]; data_->metal_layer.device = ContextMTL::Cast(*context).GetMTLDevice(); - data_->metal_layer.pixelFormat = - ToMTLPixelFormat(context->GetCapabilities()->GetDefaultColorFormat()); + // 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.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 ecce6934d7ae4..85042638b8044 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -402,13 +402,8 @@ std::shared_ptr Playground::CreateTextureForFixture( std::shared_ptr Playground::CreateTextureForFixture( const char* fixture_name, bool enable_mipmapping) const { - auto texture = CreateTextureForFixture(OpenAssetAsMapping(fixture_name), - enable_mipmapping); - if (texture == nullptr) { - return nullptr; - } - texture->SetLabel(fixture_name); - return texture; + return CreateTextureForFixture(OpenAssetAsMapping(fixture_name), + enable_mipmapping); } std::shared_ptr Playground::CreateTextureCubeForFixture( diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index f968e626ee074..792fc8ed85ff9 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -16,8 +16,6 @@ impeller_component("renderer") { "buffer.h", "buffer_view.cc", "buffer_view.h", - "capabilities.cc", - "capabilities.h", "command.cc", "command.h", "command_buffer.cc", @@ -32,10 +30,13 @@ 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 b523a0d598250..85e1bd3ee8f78 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/capabilities.h" +#include "impeller/renderer/device_capabilities.h" namespace impeller { @@ -72,7 +72,7 @@ ContextGLES::ContextGLES(std::unique_ptr gl, // Create the device capabilities. { device_capabilities_ = - CapabilitiesBuilder() + DeviceCapabilitiesBuilder() .SetHasThreadingRestrictions(true) .SetSupportsOffscreenMSAA(false) .SetSupportsSSBO(false) @@ -145,9 +145,13 @@ std::shared_ptr ContextGLES::GetWorkQueue() const { } // |Context| -const std::shared_ptr& ContextGLES::GetCapabilities() - const { - return device_capabilities_; +const IDeviceCapabilities& ContextGLES::GetDeviceCapabilities() const { + return *device_capabilities_; +} + +// |Context| +PixelFormat ContextGLES::GetColorAttachmentPixelFormat() const { + return PixelFormat::kR8G8B8A8UNormInt; } } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 030877262741d..39e1384d97512 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::shared_ptr device_capabilities_; + std::unique_ptr device_capabilities_; bool is_valid_ = false; ContextGLES( @@ -70,7 +70,10 @@ class ContextGLES final : public Context, std::shared_ptr GetWorkQueue() const override; // |Context| - const std::shared_ptr& GetCapabilities() const override; + const IDeviceCapabilities& GetDeviceCapabilities() const override; + + // |Context| + PixelFormat GetColorAttachmentPixelFormat() 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 80b9bdc8f04ab..bd75e585d86c0 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,6 +37,22 @@ 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; @@ -62,24 +78,7 @@ class ContextMTL final : public Context, std::shared_ptr GetGPUTracer() const override; // |Context| - 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); + const IDeviceCapabilities& GetDeviceCapabilities() const override; 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 ce114a9862b5f..70c76592aa5fa 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -11,56 +11,11 @@ #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/capabilities.h" +#include "impeller/renderer/device_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) { @@ -134,11 +89,50 @@ static bool DeviceSupportsComputeSubgroups(id device) { { gpu_tracer_ = std::shared_ptr(new GPUTracerMTL(device_)); } #endif - device_capabilities_ = InferMetalCapabilities(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]; + } + + device_capabilities_ = + DeviceCapabilitiesBuilder() + .SetHasThreadingRestrictions(false) + .SetSupportsOffscreenMSAA(true) + .SetSupportsSSBO(true) + .SetSupportsTextureToTextureBlits(true) + .SetSupportsFramebufferFetch(SupportsFramebufferFetch()) + .SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt) + .SetDefaultStencilFormat(PixelFormat::kS8UInt) + .SetSupportsCompute(true, supports_subgroups) + .Build(); + } 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) { @@ -293,14 +287,8 @@ static bool DeviceSupportsComputeSubgroups(id device) { return device_; } -const std::shared_ptr& ContextMTL::GetCapabilities() const { - return device_capabilities_; -} - -// |Context| -bool ContextMTL::UpdateOffscreenLayerPixelFormat(PixelFormat format) { - device_capabilities_ = InferMetalCapabilities(device_); - return true; +const IDeviceCapabilities& ContextMTL::GetDeviceCapabilities() const { + return *device_capabilities_; } } // namespace impeller diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index dccdac147f4e9..70eedfd7aee60 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -64,7 +64,6 @@ 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 = @@ -87,7 +86,7 @@ stencil_tex_desc.type = TextureType::kTexture2DMultisample; stencil_tex_desc.sample_count = SampleCount::kCount4; stencil_tex_desc.format = - context->GetCapabilities()->GetDefaultStencilFormat(); + context->GetDeviceCapabilities().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 a5de877f8afc9..2c30458c842b8 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -18,18 +18,10 @@ 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 25631dacb5ec9..f1c1e210e6ec9 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -152,12 +152,10 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format, } } - 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; - } + // 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; } @@ -213,10 +211,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, - vk::Device device) - : TextureSourceVK(desc) { + vk::Device device) { 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{ @@ -233,11 +229,13 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode); image_info.sharingMode = vk::SharingMode::eExclusive; - VmaAllocationCreateInfo alloc_nfo = {}; + VmaAllocationCreateInfo alloc_create_info = {}; - alloc_nfo.usage = ToVMAMemoryUsage(); - alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode, true); - alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, true); + alloc_create_info.usage = ToVMAMemoryUsage(); + alloc_create_info.preferredFlags = + ToVKMemoryPropertyFlags(desc.storage_mode, true); + alloc_create_info.flags = + ToVmaAllocationCreateFlags(desc.storage_mode, true); auto create_info_native = static_cast(image_info); @@ -246,13 +244,13 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { VmaAllocation allocation = {}; VmaAllocationInfo allocation_info = {}; { - auto result = vk::Result{::vmaCreateImage(allocator, // - &create_info_native, // - &alloc_nfo, // - &vk_image, // - &allocation, // - &allocation_info // - )}; + auto result = vk::Result{vmaCreateImage(allocator, // + &create_info_native, // + &alloc_create_info, // + &vk_image, // + &allocation, // + &allocation_info // + )}; if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to allocate Vulkan Image: " << vk::to_string(result); @@ -264,24 +262,25 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { allocator_ = allocator; allocation_ = allocation; - 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); + 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; // 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_info.components.a = vk::ComponentSwizzle::eR; - view_info.components.r = vk::ComponentSwizzle::eA; + view_create_info.components.a = vk::ComponentSwizzle::eR; + view_create_info.components.r = vk::ComponentSwizzle::eA; } - auto [result, image_view] = device.createImageViewUnique(view_info); + auto [result, image_view] = device.createImageViewUnique(view_create_info); if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to create an image view for allocation: " << vk::to_string(result); @@ -295,7 +294,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { ~AllocatedTextureSourceVK() { image_view_.reset(); if (image_) { - ::vmaDestroyImage( + vmaDestroyImage( allocator_, // static_cast(image_), // allocation_ // @@ -336,9 +335,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { bool IsValid() const { return is_valid_; } - vk::Image GetImage() const override { return image_; } + vk::Image GetVKImage() const override { return image_; } - vk::ImageView GetImageView() const override { return image_view_.get(); } + vk::ImageView GetVKImageView() const override { return image_view_.get(); } private: vk::Image image_ = {}; @@ -363,7 +362,7 @@ std::shared_ptr AllocatorVK::OnCreateTexture( if (!source->IsValid()) { return nullptr; } - return std::make_shared(context_, std::move(source)); + return std::make_shared(desc, context_, std::move(source)); } // |Allocator| diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index 0b4f3541bce98..f4a9e8ee3b297 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_; + ISize max_texture_size_ = {4096, 4096}; 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 98c8ab0d4ec85..8c27935cf84c8 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -29,27 +29,11 @@ bool BlitCopyTextureToTextureCommandVK::Encode( const auto& src = TextureVK::Cast(*source); const auto& dst = TextureVK::Cast(*destination); - 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)) { + 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)) { VALIDATION_LOG << "Could not complete layout transitions."; return false; } @@ -70,11 +54,11 @@ bool BlitCopyTextureToTextureCommandVK::Encode( // Issue the copy command now that the images are already in the right // layouts. - cmd_buffer.copyImage(src.GetImage(), // - src_tran.new_layout, // - dst.GetImage(), // - dst_tran.new_layout, // - image_copy // + cmd_buffer.copyImage(src.GetImage(), // + src_layout, // + dst.GetImage(), // + dst_layout, // + image_copy // ); return true; @@ -95,20 +79,6 @@ 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; @@ -122,15 +92,15 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const { image_copy.setImageExtent( vk::Extent3D(source_region.size.width, source_region.size.height, 1)); - if (!src.SetLayout(transition)) { + if (!src.SetLayout(vk::ImageLayout::eTransferSrcOptimal, cmd_buffer)) { VALIDATION_LOG << "Could not encode layout transition."; return false; } - cmd_buffer.copyImageToBuffer(src.GetImage(), // - transition.new_layout, // - dst.GetBuffer(), // - image_copy // + cmd_buffer.copyImageToBuffer(src.GetImage(), // + vk::ImageLayout::eTransferSrcOptimal, // + dst.GetVKBufferHandle(), // + image_copy // ); return true; @@ -234,12 +204,10 @@ 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 = std::max(size.width >> mip_level, 1u); - blit.dstOffsets[1].y = std::max(size.height >> mip_level, 1u); - blit.dstOffsets[1].z = 1u; + blit.dstOffsets[1].x = size.width >> mip_level; + blit.dstOffsets[1].y = size.height >> mip_level; cmd.blitImage(image, // src image vk::ImageLayout::eTransferSrcOptimal, // src layout @@ -254,27 +222,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::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 + 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 ); InsertImageMemoryBarrier( - 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 + 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 ); // 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 048dc3592c645..645ae1cf70375 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -4,337 +4,39 @@ #include "impeller/renderer/backend/vulkan/capabilities_vk.h" -#include - -#include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/vk.h" namespace impeller { -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; +CapabilitiesVK::CapabilitiesVK() { + for (const auto& ext : vk::enumerateInstanceExtensionProperties().value) { + extensions_.insert(ext.extensionName); } - 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); - } + for (const auto& layer : vk::enumerateInstanceLayerProperties().value) { + layers_.insert(layer.layerName); } - - is_valid_ = true; } CapabilitiesVK::~CapabilitiesVK() = default; -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::HasExtension(const std::string& extension) const { + return extensions_.count(extension) == 1u; } bool CapabilitiesVK::HasLayer(const std::string& layer) const { - for (const auto& [found_layer, exts] : exts_) { - if (found_layer == layer) { - return true; - } - } - return false; + return layers_.count(layer) == 1u; } -bool CapabilitiesVK::HasExtension(const std::string& ext) const { - for (const auto& [layer, exts] : exts_) { - if (exts.find(ext) != exts.end()) { +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) { 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 21545e4384bc7..2b62e05e498ca 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -4,81 +4,29 @@ #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 ContextVK; - -//------------------------------------------------------------------------------ -/// @brief The Vulkan layers and extensions wrangler. -/// -class CapabilitiesVK final : public Capabilities { +class CapabilitiesVK { public: - CapabilitiesVK(bool enable_validations = false); + CapabilitiesVK(); ~CapabilitiesVK(); - bool IsValid() 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 HasExtension(const std::string& extension) const; - // |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; + bool HasLayer(const std::string& layer) const; - // |Capabilities| - PixelFormat GetDefaultStencilFormat() const override; + bool HasLayerExtension(const std::string& layer, + const std::string& extension); private: - 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; + std::set extensions_; + std::set layers_; 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 a65d61249aedd..6fbf12950f49b 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc @@ -5,91 +5,31 @@ #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, - 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()) { + 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."; return; } vk::CommandBufferBeginInfo begin_info; begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - if (tracked_objects_->GetCommandBuffer().begin(begin_info) != - vk::Result::eSuccess) { + if (buffers[0]->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; } @@ -107,40 +47,39 @@ bool CommandEncoderVK::Submit() { // Success or failure, you only get to submit once. fml::ScopedCleanupClosure reset([&]() { Reset(); }); - InsertDebugMarker("QueueSubmit"); - - auto command_buffer = GetCommandBuffer(); - - if (command_buffer.end() != vk::Result::eSuccess) { + 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; - std::vector buffers = {command_buffer}; - submit_info.setCommandBuffers(buffers); + submit_info.setCommandBuffers(*command_buffer_); 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 fence_waiter_->AddFence( - std::move(fence), [tracked_objects = std::move(tracked_objects_)] { - // Nothing to do, we just drop the tracked objects on the floor. - }); + return true; } -vk::CommandBuffer CommandEncoderVK::GetCommandBuffer() const { - if (tracked_objects_) { - return tracked_objects_->GetCommandBuffer(); - } - return {}; +const vk::CommandBuffer& CommandEncoderVK::GetCommandBuffer() const { + return *command_buffer_; } void CommandEncoderVK::Reset() { - tracked_objects_.reset(); + command_buffer_.reset(); + + tracked_objects_.clear(); + tracked_buffers_.clear(); + tracked_textures_.clear(); queue_ = nullptr; device_ = nullptr; @@ -148,82 +87,34 @@ void CommandEncoderVK::Reset() { } bool CommandEncoderVK::Track(std::shared_ptr object) { - if (!IsValid()) { - return false; - } - tracked_objects_->Track(std::move(object)); + tracked_objects_.push_back(std::move(object)); return true; } bool CommandEncoderVK::Track(std::shared_ptr buffer) { - if (!IsValid()) { - return false; - } - tracked_objects_->Track(std::move(buffer)); + tracked_buffers_.emplace_back(std::move(buffer)); return true; } -bool CommandEncoderVK::Track(std::shared_ptr texture) { - if (!IsValid()) { - return false; - } - tracked_objects_->Track(std::move(texture)); +bool CommandEncoderVK::Track(std::shared_ptr texture) { + tracked_textures_.emplace_back(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 (!HasValidationLayers()) { + if (!vk::HasValidationLayers() || !command_buffer_) { return; } vk::DebugUtilsLabelEXT label_info; label_info.pLabelName = label; - if (auto command_buffer = GetCommandBuffer()) { - command_buffer.beginDebugUtilsLabelEXT(label_info); - } - if (queue_) { - queue_.beginDebugUtilsLabelEXT(label_info); - } + command_buffer_->beginDebugUtilsLabelEXT(label_info); } void CommandEncoderVK::PopDebugGroup() const { - if (!HasValidationLayers()) { + if (!vk::HasValidationLayers() || !command_buffer_) { return; } - 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); - } + command_buffer_->endDebugUtilsLabelEXT(); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.h b/impeller/renderer/backend/vulkan/command_encoder_vk.h index 8db33b50c1a7d..66ac47f39bf68 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.h +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h @@ -4,12 +4,9 @@ #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" @@ -18,9 +15,6 @@ namespace impeller { class ContextVK; class DeviceBuffer; class Texture; -class TextureSourceVK; -class TrackedObjectsVK; -class FenceWaiterVK; class CommandEncoderVK { public: @@ -34,35 +28,26 @@ class CommandEncoderVK { bool Track(std::shared_ptr buffer); - bool Track(const std::shared_ptr& texture); + bool Track(std::shared_ptr texture); - bool Track(std::shared_ptr texture); - - vk::CommandBuffer GetCommandBuffer() const; + const 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_ = {}; - - std::shared_ptr fence_waiter_; - std::shared_ptr tracked_objects_; + vk::UniqueCommandBuffer command_buffer_; + std::vector> tracked_objects_; + std::vector> tracked_buffers_; + std::vector> tracked_textures_; bool is_valid_ = false; - CommandEncoderVK(vk::Device device, - vk::Queue queue, - const std::shared_ptr& pool, - std::shared_ptr fence_waiter); + CommandEncoderVK(vk::Device device, vk::Queue queue, vk::CommandPool pool); void Reset(); diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.cc b/impeller/renderer/backend/vulkan/command_pool_vk.cc deleted file mode 100644 index 5ed2ed404807c..0000000000000 --- a/impeller/renderer/backend/vulkan/command_pool_vk.cc +++ /dev/null @@ -1,135 +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/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 deleted file mode 100644 index 7399e22686075..0000000000000 --- a/impeller/renderer/backend/vulkan/command_pool_vk.h +++ /dev/null @@ -1,55 +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 - -#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 c394f3627b353..a7974915d1f81 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -20,30 +20,156 @@ #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/capabilities.h" +#include "impeller/renderer/device_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 { -// TODO(csg): Fix this after caps are reworked. -static bool gHasValidationLayers = false; +namespace vk { bool HasValidationLayers() { - return gHasValidationLayers; + 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; } static std::optional PickPhysicalDevice( - const CapabilitiesVK& caps, const vk::Instance& instance) { for (const auto& device : instance.enumeratePhysicalDevices().value) { - if (caps.GetRequiredDeviceFeatures(device).has_value()) { + if (IsPhysicalDeviceCompatible(device)) { return device; } } @@ -93,37 +219,27 @@ 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()); - context->Setup(proc_address_callback, // - shader_libraries_data, // - pipeline_cache_data, // - std::move(worker_task_runner), // - label // - ); + auto context = std::shared_ptr(new ContextVK( + proc_address_callback, // + shader_libraries_data, // + pipeline_cache_data, // + std::move(worker_task_runner), // + label // + )); if (!context->IsValid()) { return nullptr; } return context; } -ContextVK::ContextVK() = default; - -ContextVK::~ContextVK() { - if (device_) { - [[maybe_unused]] auto result = device_->waitIdle(); - } - CommandPoolVK::ClearAllPools(this); -} - -void ContextVK::Setup( +ContextVK::ContextVK( 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) { - TRACE_EVENT0("impeller", "ContextVK::Setup"); - - worker_task_runner_ = std::move(worker_task_runner); + const std::string& label) + : worker_task_runner_(std::move(worker_task_runner)) { + TRACE_EVENT0("impeller", "ContextVK::Create"); if (!worker_task_runner_) { VALIDATION_LOG << "Invalid worker task runner."; @@ -133,41 +249,95 @@ void ContextVK::Setup( auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; dispatcher.init(proc_address_callback); - auto caps = std::shared_ptr(new CapabilitiesVK()); + auto capabilities = std::make_unique(); - if (!caps->IsValid()) { - VALIDATION_LOG << "Could not determine device capabilities."; + 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."; 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; - gHasValidationLayers = caps->AreValidationsEnabled(); - - auto enabled_layers = caps->GetRequiredLayers(); - auto enabled_extensions = caps->GetRequiredInstanceExtensions(); - - if (!enabled_layers.has_value() || !enabled_extensions.has_value()) { - VALIDATION_LOG << "Device has insufficient capabilities."; + 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); - 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; + // 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 - std::vector enabled_layers_c; - std::vector enabled_extensions_c; + //---------------------------------------------------------------------------- + /// 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."; + return; + } + enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - for (const auto& layer : enabled_layers.value()) { - enabled_layers_c.push_back(layer.c_str()); + //---------------------------------------------------------------------------- + /// 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; + } + } + if (!has_wsi_extensions) { + VALIDATION_LOG + << "Instance doesn't have any of the required WSI extensions: " + << fml::Join(kRequiredWSIInstanceExtensions, ", "); + return; } - for (const auto& ext : enabled_extensions.value()) { - enabled_extensions_c.push_back(ext.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."; } vk::ApplicationInfo application_info; @@ -177,50 +347,52 @@ void ContextVK::Setup( 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; - if (caps->AreValidationsEnabled()) { - instance_info.pNext = &validation; - } - instance_info.setPEnabledLayerNames(enabled_layers_c); - instance_info.setPEnabledExtensionNames(enabled_extensions_c); + instance_info.setPEnabledLayerNames(enabled_layers); + instance_info.setPEnabledExtensionNames(enabled_extensions); instance_info.setPApplicationInfo(&application_info); instance_info.setFlags(instance_flags); auto instance = vk::createInstanceUnique(instance_info); if (instance.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create instance: " + FML_LOG(ERROR) << "Could not create instance: " << vk::to_string(instance.result); return; } dispatcher.init(instance.value.get()); - //---------------------------------------------------------------------------- - /// 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()); + 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; + } - if (!debug_report->IsValid()) { - VALIDATION_LOG << "Could not setup debug report."; - return; + debug_messenger = std::move(debug_messenger_result.value); } //---------------------------------------------------------------------------- /// Pick the physical device. /// - auto physical_device = PickPhysicalDevice(*caps, instance.value.get()); + auto physical_device = PickPhysicalDevice(instance.value.get()); if (!physical_device.has_value()) { VALIDATION_LOG << "No valid Vulkan device found."; return; @@ -236,44 +408,29 @@ void ContextVK::Setup( 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; } - //---------------------------------------------------------------------------- - /// 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()); + std::vector required_extensions; + for (const auto& ext : kRequiredDeviceExtensions) { + required_extensions.push_back(ext.data()); } const auto queue_create_infos = GetQueueCreateInfos( {graphics_queue.value(), compute_queue.value(), transfer_queue.value()}); - 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; - } + const auto required_features = GetRequiredPhysicalDeviceFeatures(); vk::DeviceCreateInfo device_info; device_info.setQueueCreateInfos(queue_create_infos); - device_info.setPEnabledExtensionNames(enabled_device_extensions_c); - device_info.setPEnabledFeatures(&required_features.value()); + device_info.setPEnabledExtensionNames(required_extensions); + device_info.setPEnabledFeatures(&required_features); // Device layers are deprecated and ignored. auto device = physical_device->createDeviceUnique(device_info); @@ -282,14 +439,6 @@ void ContextVK::Setup( 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, // @@ -330,9 +479,6 @@ void ContextVK::Setup( return; } - //---------------------------------------------------------------------------- - /// Setup the work queues. - /// auto work_queue = WorkQueueCommon::Create(); if (!work_queue) { @@ -341,12 +487,47 @@ void ContextVK::Setup( } //---------------------------------------------------------------------------- - /// Create the fence waiter. + /// Setup the command pool. /// - auto fence_waiter = - std::shared_ptr(new FenceWaiterVK(device.value.get())); - if (!fence_waiter->IsValid()) { - VALIDATION_LOG << "Could not create 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"; return; } @@ -354,8 +535,7 @@ void ContextVK::Setup( /// All done! /// instance_ = std::move(instance.value); - debug_report_ = std::move(debug_report); - physical_device_ = physical_device.value(); + debug_messenger_ = std::move(debug_messenger); device_ = std::move(device.value); allocator_ = std::move(allocator); shader_library_ = std::move(shader_library); @@ -368,21 +548,27 @@ void ContextVK::Setup( device_->getQueue(compute_queue->family, compute_queue->index); transfer_queue_ = device_->getQueue(transfer_queue->family, transfer_queue->index); - 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); + 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); is_valid_ = true; +} - //---------------------------------------------------------------------------- - /// 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"); +ContextVK::~ContextVK() { + if (device_) { + [[maybe_unused]] auto result = device_->waitIdle(); + } } bool ContextVK::IsValid() const { @@ -411,13 +597,9 @@ 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(), // - std::move(encoder)) // + new CommandBufferVK(shared_from_this(), // + CreateGraphicsCommandEncoder()) // ); } @@ -464,37 +646,37 @@ bool ContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) { return true; } -const std::shared_ptr& ContextVK::GetCapabilities() const { - return device_capabilities_; +PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { + return swapchain_ ? ToPixelFormat(swapchain_->GetSurfaceFormat()) + : PixelFormat::kB8G8R8A8UNormInt; +} + +const IDeviceCapabilities& ContextVK::GetDeviceCapabilities() const { + return *device_capabilities_; } vk::Queue ContextVK::GetGraphicsQueue() const { return graphics_queue_; } -QueueVK ContextVK::GetGraphicsQueueInfo() const { - return graphics_queue_info_; +vk::CommandPool ContextVK::GetGraphicsCommandPool() const { + return *graphics_command_pool_; } -vk::PhysicalDevice ContextVK::GetPhysicalDevice() const { - return physical_device_; +vk::DescriptorPool ContextVK::GetDescriptorPool() const { + return *descriptor_pool_; } -std::shared_ptr ContextVK::GetFenceWaiter() const { - return fence_waiter_; +vk::PhysicalDevice ContextVK::GetPhysicalDevice() const { + return physical_device_; } 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_, // - tls_pool, // - fence_waiter_ // + *device_, // + graphics_queue_, // + *graphics_command_pool_ // )); if (!encoder->IsValid()) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 089417971b960..3cd22bb490b2b 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -15,18 +15,24 @@ #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: @@ -58,11 +64,14 @@ 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 std::shared_ptr& GetCapabilities() const override; + const IDeviceCapabilities& GetDeviceCapabilities() const override; template bool SetDebugName(T handle, std::string_view label) const { @@ -73,19 +82,22 @@ class ContextVK final : public Context, public BackendCast { static bool SetDebugName(vk::Device device, T handle, std::string_view label) { - if (!HasValidationLayers()) { + if (!vk::HasValidationLayers()) { // No-op if validation layers are not enabled. return true; } - auto c_handle = static_cast(handle); + uint64_t handle_ptr = + reinterpret_cast(static_cast(handle)); - vk::DebugUtilsObjectNameInfoEXT info; - info.objectType = T::objectType; - info.pObjectName = label.data(); - info.objectHandle = reinterpret_cast(c_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())); - if (device.setDebugUtilsObjectNameEXT(info) != vk::Result::eSuccess) { + if (ret != vk::Result::eSuccess) { VALIDATION_LOG << "Unable to set debug name: " << label; return false; } @@ -107,16 +119,16 @@ class ContextVK final : public Context, public BackendCast { vk::Queue GetGraphicsQueue() const; - QueueVK GetGraphicsQueueInfo() const; + vk::CommandPool GetGraphicsCommandPool() const; - vk::PhysicalDevice GetPhysicalDevice() const; + vk::DescriptorPool GetDescriptorPool() const; - std::shared_ptr GetFenceWaiter() const; + vk::PhysicalDevice GetPhysicalDevice() const; private: std::shared_ptr worker_task_runner_; vk::UniqueInstance instance_; - std::unique_ptr debug_report_; + vk::UniqueDebugUtilsMessengerEXT debug_messenger_; vk::PhysicalDevice physical_device_; vk::UniqueDevice device_; std::shared_ptr allocator_; @@ -126,19 +138,14 @@ 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::shared_ptr device_capabilities_; - std::shared_ptr fence_waiter_; - + std::unique_ptr device_capabilities_; + vk::UniqueCommandPool graphics_command_pool_; + vk::UniqueDescriptorPool descriptor_pool_; bool is_valid_ = false; - ContextVK(); - - void Setup( + ContextVK( 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 deleted file mode 100644 index c538245aba50d..0000000000000 --- a/impeller/renderer/backend/vulkan/debug_report_vk.cc +++ /dev/null @@ -1,189 +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/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 deleted file mode 100644 index 387d7f6d28c20..0000000000000 --- a/impeller/renderer/backend/vulkan/debug_report_vk.h +++ /dev/null @@ -1,44 +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 "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 deleted file mode 100644 index 5fb1ef74fdcd9..0000000000000 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc +++ /dev/null @@ -1,74 +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/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 deleted file mode 100644 index 4af9c0bc8b13a..0000000000000 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h +++ /dev/null @@ -1,48 +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/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 e9859ff9390a5..e38c63fa688fc 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::GetBuffer() const { +vk::Buffer DeviceBufferVK::GetVKBufferHandle() const { return buffer_; } diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 2f579c13a1e9c..132be608c3617 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 GetBuffer() const; + vk::Buffer GetVKBufferHandle() 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 deleted file mode 100644 index 06c4c094cbf67..0000000000000 --- a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc +++ /dev/null @@ -1,108 +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/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 deleted file mode 100644 index 0f5087f0d2514..0000000000000 --- a/impeller/renderer/backend/vulkan/fence_waiter_vk.h +++ /dev/null @@ -1,53 +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 -#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 64e8f5a6c447d..83ea4acc463b0 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -6,6 +6,7 @@ #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" @@ -204,8 +205,6 @@ constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { case SampleCount::kCount4: return vk::SampleCountFlagBits::e4; } - - FML_UNREACHABLE(); } constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) { @@ -270,7 +269,7 @@ constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding( const DescriptorSetLayout& layout) { vk::DescriptorSetLayoutBinding binding; binding.binding = layout.binding; - binding.descriptorCount = 1u; + binding.descriptorCount = layout.descriptor_count; vk::DescriptorType desc_type = vk::DescriptorType(); switch (layout.descriptor_type) { case DescriptorType::kSampledImage: @@ -547,60 +546,9 @@ 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 6016a5bd59836..1cc9e2303612d 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -53,6 +53,54 @@ 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 @@ -75,6 +123,17 @@ 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) @@ -86,8 +145,8 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription( /// StencilAttachmentDescriptor, and, DepthAttachmentDescriptor. /// Right now, these are placeholders. /// -static vk::UniqueRenderPass CreateRenderPass(const vk::Device& device, - const PipelineDescriptor& desc) { +vk::UniqueRenderPass PipelineLibraryVK::CreateRenderPass( + const PipelineDescriptor& desc) { std::vector attachments; std::vector color_refs; @@ -131,7 +190,7 @@ static vk::UniqueRenderPass CreateRenderPass(const vk::Device& device, 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); @@ -151,7 +210,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; @@ -239,7 +298,7 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( blend_state.setAttachments(attachment_blend_state); pipeline_info.setPColorBlendState(&blend_state); - auto render_pass = CreateRenderPass(device_, desc); + auto render_pass = CreateRenderPass(desc); if (render_pass) { pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE); pipeline_info.setSubpass(0); @@ -282,31 +341,33 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( //---------------------------------------------------------------------------- /// Pipeline Layout a.k.a the descriptor sets and uniforms. /// - std::vector desc_bindings; + std::vector bindings = {}; for (auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) { auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout); - desc_bindings.push_back(vk_desc_layout); + bindings.push_back(vk_desc_layout); } - vk::DescriptorSetLayoutCreateInfo descs_layout_info; - descs_layout_info.setBindings(desc_bindings); + vk::DescriptorSetLayoutCreateInfo descriptor_set_create; + descriptor_set_create.setBindings(bindings); - auto [descs_result, descs_layout] = - device_.createDescriptorSetLayoutUnique(descs_layout_info); - if (descs_result != vk::Result::eSuccess) { + auto descriptor_set_create_res = + device_.createDescriptorSetLayoutUnique(descriptor_set_create); + if (descriptor_set_create_res.result != vk::Result::eSuccess) { VALIDATION_LOG << "unable to create uniform descriptors"; return nullptr; } - ContextVK::SetDebugName(device_, descs_layout.get(), - "Descriptor Set Layout " + desc.GetLabel()); + vk::UniqueDescriptorSetLayout descriptor_set_layout = + std::move(descriptor_set_create_res.value); + ContextVK::SetDebugName(device_, descriptor_set_layout.get(), + "Descriptor Set Layout" + desc.GetLabel()); //---------------------------------------------------------------------------- /// Create the pipeline layout. /// vk::PipelineLayoutCreateInfo pipeline_layout_info; - pipeline_layout_info.setSetLayouts(descs_layout.get()); + pipeline_layout_info.setSetLayouts(descriptor_set_layout.get()); auto pipeline_layout = device_.createPipelineLayoutUnique(pipeline_layout_info); if (pipeline_layout.result != vk::Result::eSuccess) { @@ -341,81 +402,13 @@ 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()); - - 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) // - ); -} + "Pipeline" + desc.GetLabel()); -// |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); - }); + return std::make_unique( + std::move(pipeline.value), std::move(render_pass), + std::move(pipeline_layout.value), std::move(descriptor_set_layout)); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.h b/impeller/renderer/backend/vulkan/pipeline_library_vk.h index 6892ac126d17b..f4cd10b76ffd8 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.h @@ -62,7 +62,10 @@ class PipelineLibraryVK final void RemovePipelinesWithEntryPoint( std::shared_ptr function) override; - std::unique_ptr CreatePipeline(const PipelineDescriptor& desc); + std::unique_ptr CreatePipeline( + const PipelineDescriptor& desc); + + vk::UniqueRenderPass CreateRenderPass(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 208d63ae99fd8..87f65c9c99da6 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_vk.cc @@ -6,40 +6,53 @@ namespace impeller { -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)), +PipelineCreateInfoVK::PipelineCreateInfoVK( + vk::UniquePipeline pipeline, + vk::UniqueRenderPass render_pass, + vk::UniquePipelineLayout layout, + vk::UniqueDescriptorSetLayout descriptor_set_layout) + : pipeline_(std::move(pipeline)), render_pass_(std::move(render_pass)), - layout_(std::move(layout)), + pipeline_layout_(std::move(layout)), descriptor_set_layout_(std::move(descriptor_set_layout)) { - is_valid_ = pipeline_ && render_pass_ && layout_ && descriptor_set_layout_; + is_valid_ = + pipeline_ && render_pass_ && pipeline_layout_ && descriptor_set_layout_; } -PipelineVK::~PipelineVK() = default; - -bool PipelineVK::IsValid() const { +bool PipelineCreateInfoVK::IsValid() const { return is_valid_; } -const vk::Pipeline& PipelineVK::GetPipeline() const { +const vk::Pipeline& PipelineCreateInfoVK::GetVKPipeline() const { return *pipeline_; } -const vk::RenderPass& PipelineVK::GetRenderPass() const { +vk::RenderPass PipelineCreateInfoVK::GetRenderPass() const { return *render_pass_; } -const vk::PipelineLayout& PipelineVK::GetPipelineLayout() const { - return *layout_; +vk::PipelineLayout PipelineCreateInfoVK::GetPipelineLayout() const { + return *pipeline_layout_; } -const vk::DescriptorSetLayout& PipelineVK::GetDescriptorSetLayout() const { +vk::DescriptorSetLayout PipelineCreateInfoVK::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 7135dcf03eb5f..a10e31e12f176 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_vk.h @@ -13,41 +13,51 @@ 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, - vk::UniquePipeline pipeline, - vk::UniqueRenderPass render_pass, - vk::UniquePipelineLayout layout, - vk::UniqueDescriptorSetLayout descriptor_set_layout); + std::unique_ptr create_info); // |Pipeline| ~PipelineVK() override; - const vk::Pipeline& GetPipeline() const; - - const vk::RenderPass& GetRenderPass() const; - - const vk::PipelineLayout& GetPipelineLayout() const; - - const vk::DescriptorSetLayout& GetDescriptorSetLayout() const; + PipelineCreateInfoVK* GetCreateInfo() 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 CreatePipeline(const PipelineDescriptor& desc); + std::unique_ptr pipeline_info_; 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 091ad5251b127..b929e647e2594 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -6,11 +6,9 @@ #include #include -#include #include -#include "flutter/fml/logging.h" -#include "flutter/fml/trace_event.h" +#include "fml/logging.h" #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" @@ -42,9 +40,8 @@ static vk::AttachmentDescription CreateAttachmentDescription( ); } -static SharedHandleVK CreateVKRenderPass( - const vk::Device& device, - const RenderTarget& target) { +static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device, + const RenderTarget& target) { std::vector attachments; std::vector color_refs; @@ -111,7 +108,7 @@ static SharedHandleVK CreateVKRenderPass( return {}; } - return MakeSharedVK(std::move(pass)); + return std::move(pass); } RenderPassVK::RenderPassVK(const std::shared_ptr& context, @@ -138,7 +135,7 @@ void RenderPassVK::OnSetLabel(std::string label) { if (!context) { return; } - ContextVK::Cast(*context).SetDebugName(render_pass_->Get(), label.c_str()); + ContextVK::Cast(*context).SetDebugName(*render_pass_, label.c_str()); debug_label_ = std::move(label); } @@ -228,60 +225,34 @@ static vk::UniqueFramebuffer CreateFramebuffer(const vk::Device& device, return std::move(framebuffer); } -static bool ConfigureAttachments(const RenderTarget& target, - const vk::CommandBuffer& command_buffer, - CommandEncoderVK& encoder) { +static bool ConfigureRenderTargetAttachmentLayouts( + const RenderTarget& target, + const vk::CommandBuffer& command_buffer) { for (const auto& [_, color] : target.GetColorAttachments()) { - 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)) { + if (!TextureVK::Cast(*color.texture) + .SetLayout(vk::ImageLayout::eColorAttachmentOptimal, + command_buffer)) { return false; } - - // 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)) { + if (color.resolve_texture) { + if (!TextureVK::Cast(*color.resolve_texture) + .SetLayout(vk::ImageLayout::eColorAttachmentOptimal, + command_buffer)) { 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(depth_stencil_tran) || - !encoder.Track(depth->texture)) { + if (!TextureVK::Cast(*depth->texture) + .SetLayout(vk::ImageLayout::eDepthAttachmentOptimal, + command_buffer)) { return false; } } - - depth_stencil_tran.new_layout = vk::ImageLayout::eStencilAttachmentOptimal; if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) { - if (!TextureVK::Cast(*stencil->texture).SetLayout(depth_stencil_tran) || - !encoder.Track(stencil->texture)) { + if (!TextureVK::Cast(*stencil->texture) + .SetLayout(vk::ImageLayout::eStencilAttachmentOptimal, + command_buffer)) { return false; } } @@ -290,19 +261,9 @@ static bool ConfigureAttachments(const RenderTarget& target, 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(transition)) { + if (!TextureVK::Cast(*texture.resource) + .SetLayout(vk::ImageLayout::eShaderReadOnlyOptimal, buffer)) { return false; } } @@ -325,124 +286,160 @@ static bool UpdateBindingLayouts(const std::vector& commands, return true; } -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; - } - - auto& allocator = *context.GetResourceAllocator(); - - std::unordered_map buffers; - std::unordered_map images; +static bool UpdateDescriptorSets(vk::Device device, + const Bindings& bindings, + Allocator& allocator, + vk::DescriptorSet desc_set, + CommandEncoderVK& encoder) { std::vector writes; - 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; - } + //---------------------------------------------------------------------------- + /// Setup buffer descriptors. + /// + std::vector buffer_desc; + for (const auto& [buffer_index, view] : bindings.buffers) { + const auto& buffer_view = view.resource.buffer; - auto texture = bindings.textures.at(index).resource; - const auto& texture_vk = TextureVK::Cast(*texture); - const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource); + auto device_buffer = buffer_view->GetDeviceBuffer(allocator); + if (!device_buffer) { + VALIDATION_LOG << "Failed to get device buffer for vertex binding"; + return false; + } - if (!encoder.Track(texture) || - !encoder.Track(sampler.GetSharedSampler())) { - return false; - } + auto buffer = DeviceBufferVK::Cast(*device_buffer).GetVKBufferHandle(); + if (!buffer) { + return false; + } - const SampledImageSlot& slot = bindings.sampled_images.at(index); + // Reserved index used for per-vertex data. + if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) { + continue; + } - vk::DescriptorImageInfo image_info; - image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - image_info.sampler = sampler.GetSampler(); - image_info.imageView = texture_vk.GetImageView(); + if (!encoder.Track(device_buffer)) { + return false; + } - 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); + uint32_t offset = view.resource.range.offset; - writes.push_back(write_set); - } + 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); - return true; - }; + const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index); - 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(uniform.binding); + write_set.setDescriptorCount(1); + write_set.setDescriptorType(vk::DescriptorType::eUniformBuffer); + write_set.setPBufferInfo(&buffer_desc.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; - } + //---------------------------------------------------------------------------- + /// 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; + } - if (!encoder.Track(device_buffer)) { - return false; - } + auto texture = bindings.textures.at(index).resource; + const auto& texture_vk = TextureVK::Cast(*texture); + const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource); - uint32_t offset = view.resource.range.offset; + if (!encoder.Track(texture) || !encoder.Track(sampler.GetSharedSampler())) { + return false; + } - vk::DescriptorBufferInfo buffer_info; - buffer_info.buffer = buffer; - buffer_info.offset = offset; - buffer_info.range = view.resource.range.length; + const SampledImageSlot& slot = bindings.sampled_images.at(index); - const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index); + 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); - 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); + 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()); - writes.push_back(write_set); - } + writes.push_back(write_set); + } + + if (writes.empty()) { return true; + } + device.updateDescriptorSets(writes, {}); + return true; +} + +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(); + + vk::DescriptorSetAllocateInfo alloc_info; + std::array dsls = { + pipeline_create_info->GetDescriptorSetLayout(), }; - if (!bind_buffers(command.vertex_bindings) || - !bind_buffers(command.fragment_bindings) || - !bind_images(command.fragment_bindings)) { + alloc_info.setDescriptorPool(context.GetDescriptorPool()); + alloc_info.setSetLayouts(dsls); + + 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; + } + + const auto set = MakeSharedVK(std::move(sets[0])); + + if (!encoder.Track(set)) { return false; } - context.GetDevice().updateDescriptorSets(writes, {}); + 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; + } encoder.GetCommandBuffer().bindDescriptorSets( vk::PipelineBindPoint::eGraphics, // bind point - pipeline.GetPipelineLayout(), // layout + pipeline_layout, // layout 0, // first set - {vk::DescriptorSet{*desc_set}}, // sets + {vk::DescriptorSet{*set}}, // sets nullptr // offsets ); return true; @@ -489,18 +486,19 @@ static bool EncodeCommand(const Context& context, const auto& cmd_buffer = encoder.GetCommandBuffer(); - const auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); + auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); + PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo(); if (!AllocateAndBindDescriptorSets(ContextVK::Cast(context), // command, // encoder, // - pipeline_vk // + pipeline_create_info // )) { return false; } cmd_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, - pipeline_vk.GetPipeline()); + pipeline_create_info->GetVKPipeline()); // Set the viewport and scissors. SetViewportAndScissor(command, cmd_buffer, target_size); @@ -534,13 +532,15 @@ static bool EncodeCommand(const Context& context, } // Bind the vertex buffer. - auto vertex_buffer_handle = DeviceBufferVK::Cast(*vertex_buffer).GetBuffer(); + auto vertex_buffer_handle = + DeviceBufferVK::Cast(*vertex_buffer).GetVKBufferHandle(); 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).GetBuffer(); + auto index_buffer_handle = + DeviceBufferVK::Cast(*index_buffer).GetVKBufferHandle(); cmd_buffer.bindIndexBuffer(index_buffer_handle, index_buffer_view.range.offset, ToVKIndexType(command.index_type)); @@ -556,11 +556,14 @@ 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(); @@ -590,23 +593,16 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { return false; } - if (!ConfigureAttachments(render_target, cmd_buffer, *encoder)) { + if (!ConfigureRenderTargetAttachmentLayouts(render_target, cmd_buffer)) { 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) || !encoder->Track(render_pass_)) { + if (!encoder->Track(framebuffer)) { return false; } @@ -621,7 +617,6 @@ 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 ebb42d15dbafe..eae656062c299 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -6,7 +6,6 @@ #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" @@ -23,7 +22,7 @@ class RenderPassVK final : public RenderPass { private: friend class CommandBufferVK; - SharedHandleVK render_pass_; + vk::UniqueRenderPass 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 b62549eb88ad5..149c1ae957d4c 100644 --- a/impeller/renderer/backend/vulkan/sampler_library_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_library_vk.cc @@ -4,7 +4,6 @@ #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" @@ -52,11 +51,6 @@ 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 5b706ce92edca..7d2f9bb5c94d4 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::GetSampler() const { +vk::Sampler SamplerVK::GetSamplerVK() const { return *sampler_; } diff --git a/impeller/renderer/backend/vulkan/sampler_vk.h b/impeller/renderer/backend/vulkan/sampler_vk.h index bf78d63a1b271..d0268ced3819a 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 GetSampler() const; + vk::Sampler GetSamplerVK() 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 fa87547fc9c67..d3c42a50a04ef 100644 --- a/impeller/renderer/backend/vulkan/shared_object_vk.h +++ b/impeller/renderer/backend/vulkan/shared_object_vk.h @@ -25,14 +25,10 @@ class SharedObjectVKT : public SharedObjectVK { explicit SharedObjectVKT(UniqueResource res) : resource_(std::move(res)) {} - operator Resource() const { return Get(); } - - const Resource& Get() const { return *resource_; } + operator Resource() const { return *resource_; } private: UniqueResource resource_; - - FML_DISALLOW_COPY_AND_ASSIGN(SharedObjectVKT); }; template @@ -44,7 +40,4 @@ 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 02992a35ebc0f..a1f09a42b3c76 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -43,8 +43,9 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate; std::shared_ptr resolve_tex = - std::make_shared(context, // - swapchain_image // + std::make_shared(resolve_tex_desc, // + context, // + swapchain_image // ); if (!resolve_tex) { @@ -64,7 +65,8 @@ 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->GetCapabilities()->GetDefaultStencilFormat(); + stencil0_tex.format = + context->GetDeviceCapabilities().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 c87797df753ab..843f0b44a8bbd 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc @@ -6,22 +6,25 @@ namespace impeller { -SwapchainImageVK::SwapchainImageVK(TextureDescriptor desc, - vk::Device device, - vk::Image image) - : TextureSourceVK(desc), image_(image) { +SwapchainImageVK::SwapchainImageVK(vk::Device device, + vk::Image image, + PixelFormat image_format, + ISize image_size) + : image_(image), image_format_(image_format), image_size_(image_size) { vk::ImageViewCreateInfo view_info; view_info.image = image_; view_info.viewType = vk::ImageViewType::e2D; - view_info.format = ToVKImageFormat(desc.format); + view_info.format = ToVKImageFormat(image_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.levelCount = desc.mip_count; - view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type); + view_info.subresourceRange.layerCount = 1u; 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; } @@ -36,20 +39,20 @@ bool SwapchainImageVK::IsValid() const { } PixelFormat SwapchainImageVK::GetPixelFormat() const { - return desc_.format; + return image_format_; } ISize SwapchainImageVK::GetSize() const { - return desc_.size; + return image_size_; } // |TextureSourceVK| -vk::Image SwapchainImageVK::GetImage() const { +vk::Image SwapchainImageVK::GetVKImage() const { return image_; } // |TextureSourceVK| -vk::ImageView SwapchainImageVK::GetImageView() const { +vk::ImageView SwapchainImageVK::GetVKImageView() 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 db905e834948c..9869b689aaa3d 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.h @@ -14,7 +14,10 @@ namespace impeller { class SwapchainImageVK final : public TextureSourceVK { public: - SwapchainImageVK(TextureDescriptor desc, vk::Device device, vk::Image image); + SwapchainImageVK(vk::Device device, + vk::Image image, + PixelFormat image_format, + ISize image_size); // |TextureSourceVK| ~SwapchainImageVK() override; @@ -26,13 +29,15 @@ class SwapchainImageVK final : public TextureSourceVK { ISize GetSize() const; // |TextureSourceVK| - vk::Image GetImage() const override; + vk::Image GetVKImage() const override; // |TextureSourceVK| - vk::ImageView GetImageView() const override; + vk::ImageView GetVKImageView() 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 b4e4f2f899d53..ff40400c657a7 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.GetCapabilities()->GetDefaultColorFormat()); + formats, vk_context.GetDeviceCapabilities().GetDefaultColorFormat()); if (!format.has_value()) { VALIDATION_LOG << "Swapchain has no supported formats."; return; @@ -213,33 +213,19 @@ 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(texture_desc, // texture descriptor - vk_context.GetDevice(), // device - image // image - ); + auto swapchain_image = std::make_shared( + vk_context.GetDevice(), // + image, // + ToPixelFormat(swapchain_info.imageFormat), // + ISize::MakeWH(swapchain_info.imageExtent.width, + swapchain_info.imageExtent.height) // + ); 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); } @@ -380,19 +366,24 @@ bool SwapchainImplVK::Present(const std::shared_ptr& image, auto vk_cmd_buffer = CommandBufferVK::Cast(*cmd_buffer).GetEncoder()->GetCommandBuffer(); - - 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; - } - + 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 // + ); 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 25f231565e58e..c411c62489cbf 100644 --- a/impeller/renderer/backend/vulkan/texture_source_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_source_vk.cc @@ -6,59 +6,6 @@ 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 4b65739427c9b..5fac2ce93980c 100644 --- a/impeller/renderer/backend/vulkan/texture_source_vk.h +++ b/impeller/renderer/backend/vulkan/texture_source_vk.h @@ -5,8 +5,6 @@ #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" @@ -14,34 +12,16 @@ namespace impeller { class TextureSourceVK { public: - virtual ~TextureSourceVK(); - - const TextureDescriptor& GetTextureDescriptor() const; + virtual ~TextureSourceVK() = default; virtual bool SetContents(const TextureDescriptor& desc, const uint8_t* contents, size_t length, size_t slice); - 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::Image GetVKImage() const = 0; - private: - mutable RWMutex layout_mutex_; - mutable vk::ImageLayout layout_ IPLR_GUARDED_BY(layout_mutex_) = - vk::ImageLayout::eUndefined; + virtual vk::ImageView GetVKImageView() const = 0; }; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index cc8c57280cc19..70c048e1f459f 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -4,17 +4,12 @@ #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(std::weak_ptr context, +TextureVK::TextureVK(TextureDescriptor desc, + std::weak_ptr context, std::shared_ptr source) - : Texture(source->GetTextureDescriptor()), - context_(std::move(context)), - source_(std::move(source)) {} + : Texture(desc), context_(std::move(context)), source_(std::move(source)) {} TextureVK::~TextureVK() = default; @@ -25,7 +20,6 @@ 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, @@ -39,74 +33,11 @@ bool TextureVK::OnSetContents(const uint8_t* contents, // Out of bounds access. if (length != desc.GetByteSizeOfBaseMipLevel()) { - 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)) { + VALIDATION_LOG << "illegal to set contents for invalid size"; return false; } - 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(); + return source_->SetContents(desc, contents, length, slice); } bool TextureVK::OnSetContents(std::shared_ptr mapping, @@ -125,29 +56,75 @@ ISize TextureVK::GetSize() const { } vk::Image TextureVK::GetImage() const { - return source_->GetImage(); + return source_->GetVKImage(); } vk::ImageView TextureVK::GetImageView() const { - return source_->GetImageView(); + return source_->GetVKImageView(); } -std::shared_ptr TextureVK::GetTextureSource() const { - return source_; +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(); } -bool TextureVK::SetLayout(const LayoutTransition& transition) const { - return source_ ? source_->SetLayout(transition) : false; +vk::ImageLayout TextureVK::GetLayout() const { + ReaderLock lock(layout_mutex_); + return layout_; } vk::ImageLayout TextureVK::SetLayoutWithoutEncoding( vk::ImageLayout layout) const { - return source_ ? source_->SetLayoutWithoutEncoding(layout) - : vk::ImageLayout::eUndefined; + WriterLock lock(layout_mutex_); + const auto old_layout = layout_; + layout_ = layout; + return old_layout; } -vk::ImageLayout TextureVK::GetLayout() const { - return source_ ? source_->GetLayout() : 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; } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index 5128c2fd66ad5..8ab9a00d27aa3 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,7 +19,8 @@ namespace impeller { class TextureVK final : public Texture, public BackendCast { public: - TextureVK(std::weak_ptr context, + TextureVK(TextureDescriptor desc, + std::weak_ptr context, std::shared_ptr source); // |Texture| @@ -29,14 +30,12 @@ class TextureVK final : public Texture, public BackendCast { vk::ImageView GetImageView() const; - bool SetLayout(const LayoutTransition& transition) const; + bool SetLayout(vk::ImageLayout layout, const vk::CommandBuffer& buffer) 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 deleted file mode 100644 index b7e6b944211c2..0000000000000 --- a/impeller/renderer/capabilities.cc +++ /dev/null @@ -1,159 +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/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 deleted file mode 100644 index 945e9fde3fbc2..0000000000000 --- a/impeller/renderer/capabilities.h +++ /dev/null @@ -1,80 +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 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 f5305f278da57..1b93ae66ec243 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->GetCapabilities()->SupportsComputeSubgroups()); + ASSERT_TRUE(context->GetDeviceCapabilities().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->GetCapabilities()->SupportsComputeSubgroups()); + ASSERT_TRUE(context->GetDeviceCapabilities().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 62ddeadb44b49..ffed4bd7e8502 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->GetCapabilities()->SupportsCompute()); + ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute()); using SamplePipelineBuilder = ComputePipelineBuilder; auto pipeline_desc = @@ -111,7 +111,7 @@ TEST_P(ComputeTest, MultiStageInputAndOutput) { auto context = GetContext(); ASSERT_TRUE(context); - ASSERT_TRUE(context->GetCapabilities()->SupportsCompute()); + ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute()); auto pipeline_desc_1 = Stage1PipelineBuilder::MakeDefaultPipelineDescriptor(*context); diff --git a/impeller/renderer/context.cc b/impeller/renderer/context.cc index 1525dfc1bf0f9..9d8aad55e681a 100644 --- a/impeller/renderer/context.cc +++ b/impeller/renderer/context.cc @@ -14,8 +14,8 @@ std::shared_ptr Context::GetGPUTracer() const { return nullptr; } -bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) { - return false; +PixelFormat Context::GetColorAttachmentPixelFormat() const { + return GetDeviceCapabilities().GetDefaultColorFormat(); } } // namespace impeller diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index f78d2e3d00f12..a6a485c3e6de3 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -8,7 +8,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/renderer/capabilities.h" +#include "impeller/renderer/device_capabilities.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -27,11 +27,9 @@ class Context : public std::enable_shared_from_this { virtual bool IsValid() const = 0; - virtual const std::shared_ptr& GetCapabilities() - const = 0; - - virtual bool UpdateOffscreenLayerPixelFormat(PixelFormat format); - + //---------------------------------------------------------------------------- + /// @return A resource allocator. + /// virtual std::shared_ptr GetResourceAllocator() const = 0; virtual std::shared_ptr GetShaderLibrary() const = 0; @@ -44,8 +42,15 @@ 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 new file mode 100644 index 0000000000000..d853f0a663086 --- /dev/null +++ b/impeller/renderer/descriptor_set_layout.h @@ -0,0 +1,27 @@ +// 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 new file mode 100644 index 0000000000000..bf88bbc4c5f6b --- /dev/null +++ b/impeller/renderer/device_capabilities.cc @@ -0,0 +1,141 @@ +// 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 new file mode 100644 index 0000000000000..f74d95c27f494 --- /dev/null +++ b/impeller/renderer/device_capabilities.h @@ -0,0 +1,99 @@ +// 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 79daace56ff96..170a068da607f 100644 --- a/impeller/renderer/formats.h +++ b/impeller/renderer/formats.h @@ -188,10 +188,6 @@ 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 c1c3fbb94781c..efaab15e65865 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.GetCapabilities()->GetDefaultColorFormat(); + color0.format = context.GetColorAttachmentPixelFormat(); 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.GetCapabilities()->GetDefaultStencilFormat()); + context.GetDeviceCapabilities().GetDefaultStencilFormat()); } return true; diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 167a4d3d37b34..aba17fd6532ef 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.GetCapabilities()->GetDefaultColorFormat(); + PixelFormat pixel_format = context.GetColorAttachmentPixelFormat(); TextureDescriptor color_tex0; color_tex0.storage_mode = color_attachment_config.storage_mode; color_tex0.format = pixel_format; @@ -233,7 +233,8 @@ 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.GetCapabilities()->GetDefaultStencilFormat(); + stencil_tex0.format = + context.GetDeviceCapabilities().GetDefaultStencilFormat(); stencil_tex0.size = size; stencil_tex0.usage = static_cast(TextureUsage::kRenderTarget); @@ -268,7 +269,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( } RenderTarget target; - PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat(); + PixelFormat pixel_format = context.GetColorAttachmentPixelFormat(); // Create MSAA color texture. @@ -326,7 +327,8 @@ 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.GetCapabilities()->GetDefaultStencilFormat(); + stencil_tex0.format = + context.GetDeviceCapabilities().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 41a16f5b74865..2b14d2843c5a3 100644 --- a/impeller/renderer/sampler.h +++ b/impeller/renderer/sampler.h @@ -20,7 +20,7 @@ class Sampler { protected: SamplerDescriptor desc_; - explicit Sampler(SamplerDescriptor desc); + 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 b29bffd6f1260..400607c1f55f6 100644 --- a/impeller/renderer/shader_types.h +++ b/impeller/renderer/shader_types.h @@ -123,17 +123,6 @@ 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 7357cec41514c..1f387ee58e05a 100644 --- a/impeller/renderer/testing/mocks.h +++ b/impeller/renderer/testing/mocks.h @@ -97,8 +97,9 @@ class MockImpellerContext : public Context { MOCK_CONST_METHOD0(GetGPUTracer, std::shared_ptr()); - MOCK_CONST_METHOD0(GetCapabilities, - const std::shared_ptr&()); + MOCK_CONST_METHOD0(GetColorAttachmentPixelFormat, PixelFormat()); + + MOCK_CONST_METHOD0(GetDeviceCapabilities, const IDeviceCapabilities&()); }; class MockTexture : public Texture { diff --git a/impeller/renderer/vertex_descriptor.h b/impeller/renderer/vertex_descriptor.h index 8d145bb0f503e..dffe6694f7caf 100644 --- a/impeller/renderer/vertex_descriptor.h +++ b/impeller/renderer/vertex_descriptor.h @@ -8,6 +8,7 @@ #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 d5596afa6748f..896ecab89e824 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()->GetCapabilities()->GetDefaultColorFormat(); + color0.format = GetContext()->GetColorAttachmentPixelFormat(); StencilAttachmentDescriptor stencil0; stencil0.stencil_compare = CompareFunction::kEqual; desc.SetColorAttachmentDescriptor(0u, color0); desc.SetStencilAttachmentDescriptors(stencil0); const auto stencil_fmt = - GetContext()->GetCapabilities()->GetDefaultStencilFormat(); + GetContext()->GetDeviceCapabilities().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 45c02e5b28b1b..04c4cd84b26c6 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->GetCapabilities()->HasThreadingRestrictions()) { + if (context->GetDeviceCapabilities().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 a74343ba1fe26..c1696ff309d70 100644 --- a/shell/platform/darwin/ios/ios_surface_metal_impeller.mm +++ b/shell/platform/darwin/ios/ios_surface_metal_impeller.mm @@ -8,9 +8,8 @@ #include "flutter/impeller/renderer/context.h" #include "flutter/shell/gpu/gpu_surface_metal_impeller.h" -namespace flutter { - -static impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) { +namespace { +impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) { switch (pixel_format) { case impeller::PixelFormat::kB10G10R10XR: return impeller::PixelFormat::kB10G10R10A10XR; @@ -18,6 +17,66 @@ 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) @@ -28,8 +87,7 @@ if (!impeller_context_) { return; } - is_valid_ = impeller_context_->UpdateOffscreenLayerPixelFormat( - InferOffscreenLayerPixelFormat(impeller::FromMTLPixelFormat(layer_.get().pixelFormat))); + is_valid_ = true; } // |IOSSurface| @@ -47,8 +105,11 @@ // |IOSSurface| std::unique_ptr IOSSurfaceMetalImpeller::CreateGPUSurface(GrDirectContext*) { - return std::make_unique(this, // - impeller_context_ // + auto context = std::make_shared( + impeller_context_, + InferOffscreenLayerPixelFormat(FromMTLPixelFormat(layer_.get().pixelFormat))); + return std::make_unique(this, // + context // ); }