7 #include <unordered_map>
9 #include "fml/concurrent_message_loop.h"
20 #include <sys/resource.h>
30 #include "flutter/fml/cpu_affinity.h"
31 #include "flutter/fml/trace_event.h"
47 VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
59 const vk::Instance& instance) {
60 for (
const auto& device : instance.enumeratePhysicalDevices().value) {
69 std::initializer_list<QueueIndexVK> queues) {
70 std::map<
size_t ,
size_t > family_index_map;
71 for (
const auto& queue : queues) {
72 family_index_map[queue.family] = 0;
74 for (
const auto& queue : queues) {
75 auto value = family_index_map[queue.family];
76 family_index_map[queue.family] = std::max(
value, queue.index);
79 static float kQueuePriority = 1.0f;
80 std::vector<vk::DeviceQueueCreateInfo> infos;
81 for (
const auto& item : family_index_map) {
82 vk::DeviceQueueCreateInfo info;
83 info.setQueueFamilyIndex(item.first);
84 info.setQueueCount(item.second + 1);
85 info.setQueuePriorities(kQueuePriority);
86 infos.push_back(info);
91 static std::optional<QueueIndexVK>
PickQueue(
const vk::PhysicalDevice& device,
92 vk::QueueFlagBits flags) {
95 const auto families = device.getQueueFamilyProperties();
96 for (
size_t i = 0u; i < families.size(); i++) {
97 if (!(families[i].queueFlags & flags)) {
106 auto context = std::shared_ptr<ContextVK>(
new ContextVK());
107 context->Setup(std::move(settings));
108 if (!context->IsValid()) {
118 return std::clamp(hardware_concurrency / 2ull, 1ull, 4ull);
122 thread_local uint64_t tls_context_count = 0;
123 uint64_t CalculateHash(
void* ptr) {
126 return ++tls_context_count;
130 ContextVK::ContextVK() : hash_(CalculateHash(this)) {}
133 if (device_holder_ && device_holder_->device) {
134 [[maybe_unused]]
auto result = device_holder_->device->waitIdle();
143 void ContextVK::Setup(Settings settings) {
144 TRACE_EVENT0(
"impeller",
"ContextVK::Setup");
146 if (!settings.proc_address_callback) {
152 raster_message_loop_->PostTaskToAllWorkers([]() {
155 fml::RequestAffinity(fml::CpuAffinity::kNotPerformance);
156 #ifdef FML_OS_ANDROID
157 if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
158 FML_LOG(ERROR) <<
"Failed to set Workers task runner priority";
163 auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
164 dispatcher.init(settings.proc_address_callback);
166 std::vector<std::string> embedder_instance_extensions;
167 std::vector<std::string> embedder_device_extensions;
168 if (settings.embedder_data.has_value()) {
169 embedder_instance_extensions = settings.embedder_data->instance_extensions;
170 embedder_device_extensions = settings.embedder_data->device_extensions;
172 auto caps = std::shared_ptr<CapabilitiesVK>(
new CapabilitiesVK(
173 settings.enable_validation,
174 settings.fatal_missing_validations,
175 settings.embedder_data.has_value(),
176 embedder_instance_extensions,
177 embedder_device_extensions
180 if (!caps->IsValid()) {
187 auto enabled_layers = caps->GetEnabledLayers();
188 auto enabled_extensions = caps->GetEnabledInstanceExtensions();
190 if (!enabled_layers.has_value() || !enabled_extensions.has_value()) {
195 vk::InstanceCreateFlags instance_flags = {};
197 if (std::find(enabled_extensions.value().begin(),
198 enabled_extensions.value().end(),
199 "VK_KHR_portability_enumeration") !=
200 enabled_extensions.value().end()) {
201 instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
204 std::vector<const char*> enabled_layers_c;
205 std::vector<const char*> enabled_extensions_c;
207 for (
const auto& layer : enabled_layers.value()) {
208 enabled_layers_c.push_back(layer.c_str());
211 for (
const auto& ext : enabled_extensions.value()) {
212 enabled_extensions_c.push_back(ext.c_str());
215 vk::ApplicationInfo application_info;
216 application_info.setApplicationVersion(VK_API_VERSION_1_0);
217 application_info.setApiVersion(VK_API_VERSION_1_1);
218 application_info.setEngineVersion(VK_API_VERSION_1_0);
219 application_info.setPEngineName(
"Impeller");
220 application_info.setPApplicationName(
"Impeller");
222 vk::StructureChain<vk::InstanceCreateInfo, vk::ValidationFeaturesEXT>
225 if (!caps->AreValidationsEnabled()) {
226 instance_chain.unlink<vk::ValidationFeaturesEXT>();
229 std::vector<vk::ValidationFeatureEnableEXT> enabled_validations = {
230 vk::ValidationFeatureEnableEXT::eSynchronizationValidation,
233 auto validation = instance_chain.get<vk::ValidationFeaturesEXT>();
234 validation.setEnabledValidationFeatures(enabled_validations);
236 auto instance_info = instance_chain.get<vk::InstanceCreateInfo>();
237 instance_info.setPEnabledLayerNames(enabled_layers_c);
238 instance_info.setPEnabledExtensionNames(enabled_extensions_c);
239 instance_info.setPApplicationInfo(&application_info);
240 instance_info.setFlags(instance_flags);
242 auto device_holder = std::make_shared<DeviceHolderImpl>();
243 if (!settings.embedder_data.has_value()) {
244 auto instance = vk::createInstanceUnique(instance_info);
245 if (instance.result != vk::Result::eSuccess) {
247 << vk::to_string(instance.result);
250 device_holder->instance = std::move(instance.value);
252 device_holder->instance.reset(settings.embedder_data->instance);
253 device_holder->owned =
false;
255 dispatcher.init(device_holder->instance.get());
264 std::make_unique<DebugReportVK>(*caps, device_holder->instance.get());
266 if (!debug_report->IsValid()) {
274 if (!settings.embedder_data.has_value()) {
275 auto physical_device =
277 if (!physical_device.has_value()) {
281 device_holder->physical_device = physical_device.value();
283 device_holder->physical_device = settings.embedder_data->physical_device;
289 auto graphics_queue =
290 PickQueue(device_holder->physical_device, vk::QueueFlagBits::eGraphics);
291 auto transfer_queue =
292 PickQueue(device_holder->physical_device, vk::QueueFlagBits::eTransfer);
294 PickQueue(device_holder->physical_device, vk::QueueFlagBits::eCompute);
296 if (!graphics_queue.has_value()) {
300 if (!transfer_queue.has_value()) {
301 transfer_queue = graphics_queue.value();
303 if (!compute_queue.has_value()) {
311 auto enabled_device_extensions =
312 caps->GetEnabledDeviceExtensions(device_holder->physical_device);
313 if (!enabled_device_extensions.has_value()) {
319 std::vector<const char*> enabled_device_extensions_c;
320 for (
const auto& ext : enabled_device_extensions.value()) {
321 enabled_device_extensions_c.push_back(ext.c_str());
325 {graphics_queue.value(), compute_queue.value(), transfer_queue.value()});
327 const auto enabled_features =
328 caps->GetEnabledDeviceFeatures(device_holder->physical_device);
329 if (!enabled_features.has_value()) {
335 vk::DeviceCreateInfo device_info;
337 device_info.setPNext(&enabled_features.value().get());
338 device_info.setQueueCreateInfos(queue_create_infos);
339 device_info.setPEnabledExtensionNames(enabled_device_extensions_c);
342 if (!settings.embedder_data.has_value()) {
344 device_holder->physical_device.createDeviceUnique(device_info);
345 if (device_result.result != vk::Result::eSuccess) {
349 device_holder->device = std::move(device_result.value);
351 device_holder->device.reset(settings.embedder_data->device);
354 if (!caps->SetPhysicalDevice(device_holder->physical_device,
355 *enabled_features)) {
363 auto allocator = std::shared_ptr<AllocatorVK>(
new AllocatorVK(
365 application_info.apiVersion,
366 device_holder->physical_device,
368 device_holder->instance.get(),
372 if (!allocator->IsValid()) {
380 auto pipeline_library = std::shared_ptr<PipelineLibraryVK>(
381 new PipelineLibraryVK(device_holder,
383 std::move(settings.cache_directory),
384 raster_message_loop_->GetTaskRunner()
387 if (!pipeline_library->IsValid()) {
392 auto sampler_library =
393 std::shared_ptr<SamplerLibraryVK>(
new SamplerLibraryVK(device_holder));
395 auto shader_library = std::shared_ptr<ShaderLibraryVK>(
396 new ShaderLibraryVK(device_holder,
397 settings.shader_libraries_data)
400 if (!shader_library->IsValid()) {
409 std::shared_ptr<FenceWaiterVK>(
new FenceWaiterVK(device_holder));
415 if (!resource_manager) {
420 auto command_pool_recycler =
421 std::make_shared<CommandPoolRecyclerVK>(weak_from_this());
422 if (!command_pool_recycler) {
427 auto descriptor_pool_recycler =
428 std::make_shared<DescriptorPoolRecyclerVK>(weak_from_this());
429 if (!descriptor_pool_recycler) {
438 if (!settings.embedder_data.has_value()) {
440 graphics_queue.value(),
441 compute_queue.value(),
442 transfer_queue.value()
447 settings.embedder_data->queue_family_index);
449 if (!queues.IsValid()) {
454 VkPhysicalDeviceProperties physical_device_properties;
455 dispatcher.vkGetPhysicalDeviceProperties(device_holder->physical_device,
456 &physical_device_properties);
464 std::make_unique<DriverInfoVK>(device_holder->physical_device);
466 caps->ApplyWorkarounds(workarounds_);
467 sampler_library->ApplyWorkarounds(workarounds_);
469 device_holder_ = std::move(device_holder);
470 idle_waiter_vk_ = std::make_shared<IdleWaiterVK>(device_holder_);
471 driver_info_ = std::move(driver_info);
472 debug_report_ = std::move(debug_report);
473 allocator_ = std::move(allocator);
474 shader_library_ = std::move(shader_library);
475 sampler_library_ = std::move(sampler_library);
476 pipeline_library_ = std::move(pipeline_library);
477 yuv_conversion_library_ = std::shared_ptr<YUVConversionLibraryVK>(
478 new YUVConversionLibraryVK(device_holder_));
479 queues_ = std::move(queues);
480 device_capabilities_ = std::move(caps);
481 fence_waiter_ = std::move(fence_waiter);
482 resource_manager_ = std::move(resource_manager);
483 command_pool_recycler_ = std::move(command_pool_recycler);
484 descriptor_pool_recycler_ = std::move(descriptor_pool_recycler);
485 device_name_ = std::string(physical_device_properties.deviceName);
486 command_queue_vk_ = std::make_shared<CommandQueueVK>(weak_from_this());
487 should_enable_surface_control_ = settings.enable_surface_control;
493 gpu_tracer_ = std::make_shared<GPUTracerVK>(weak_from_this(),
494 settings.enable_gpu_tracing);
495 gpu_tracer_->InitializeQueryPool(*
this);
522 return shader_library_;
526 return sampler_library_;
530 return pipeline_library_;
535 auto tls_pool = recycler->Get();
542 std::shared_ptr<DescriptorPoolVK> descriptor_pool;
544 Lock lock(desc_pool_mutex_);
545 DescriptorPoolMap::iterator current_pool =
546 cached_descriptor_pool_.find(std::this_thread::get_id());
547 if (current_pool == cached_descriptor_pool_.end()) {
549 (cached_descriptor_pool_[std::this_thread::get_id()] =
550 std::make_shared<DescriptorPoolVK>(weak_from_this()));
552 descriptor_pool = current_pool->second;
556 auto tracked_objects = std::make_shared<TrackedObjectsVK>(
557 weak_from_this(), std::move(tls_pool), std::move(descriptor_pool),
561 if (!tracked_objects || !tracked_objects->IsValid() || !queue) {
565 vk::CommandBufferBeginInfo begin_info;
566 begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
567 if (tracked_objects->GetCommandBuffer().begin(begin_info) !=
568 vk::Result::eSuccess) {
573 tracked_objects->GetGPUProbe().RecordCmdBufferStart(
574 tracked_objects->GetCommandBuffer());
579 std::move(tracked_objects)
584 return *device_holder_->instance;
588 return device_holder_->device.get();
591 const std::shared_ptr<fml::ConcurrentTaskRunner>
593 return raster_message_loop_->GetTaskRunner();
602 fence_waiter_.reset();
603 resource_manager_.reset();
605 raster_message_loop_->Terminate();
609 return std::make_shared<SurfaceContextVK>(shared_from_this());
613 return device_capabilities_;
621 return device_holder_->physical_device;
625 return fence_waiter_;
629 return resource_manager_;
634 return command_pool_recycler_;
643 return descriptor_pool_recycler_;
647 return command_queue_vk_;
651 std::shared_ptr<CommandBuffer> command_buffer) {
652 if (should_batch_cmd_buffers_) {
653 pending_command_buffers_.push_back(std::move(command_buffer));
661 if (pending_command_buffers_.empty()) {
665 if (should_batch_cmd_buffers_) {
666 bool result =
GetCommandQueue()->Submit(pending_command_buffers_).ok();
667 pending_command_buffers_.clear();
688 attachment.
texture->GetTextureDescriptor().format,
689 attachment.
texture->GetTextureDescriptor().sample_count,
698 depth->texture->GetTextureDescriptor().format,
699 depth->texture->GetTextureDescriptor().sample_count,
704 stencil.has_value()) {
706 stencil->texture->GetTextureDescriptor().format,
707 stencil->texture->GetTextureDescriptor().sample_count,
708 stencil->load_action,
709 stencil->store_action
718 Lock lock(desc_pool_mutex_);
719 cached_descriptor_pool_.erase(std::this_thread::get_id());
721 command_pool_recycler_->Dispose();
724 const std::shared_ptr<YUVConversionLibraryVK>&
726 return yuv_conversion_library_;
734 return should_enable_surface_control_;
static CapabilitiesVK & Cast(Capabilities &base)
The Vulkan layers and extensions wrangler.
void SetOffscreenFormat(PixelFormat pixel_format) const
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
static void DestroyThreadLocalPools(const ContextVK *context)
Clean up resources held by all per-thread command pools associated with the given context.
void SetOffscreenFormat(PixelFormat pixel_format)
std::shared_ptr< Allocator > GetResourceAllocator() const override
Returns the allocator used to create textures and buffers on the device.
std::shared_ptr< ResourceManagerVK > GetResourceManager() const
vk::PhysicalDevice GetPhysicalDevice() const
const std::shared_ptr< YUVConversionLibraryVK > & GetYUVConversionLibrary() const
bool SetDebugName(T handle, std::string_view label) const
bool EnqueueCommandBuffer(std::shared_ptr< CommandBuffer > command_buffer) override
Enqueue command_buffer for submission by the end of the frame.
const vk::Device & GetDevice() const
bool FlushCommandBuffers() override
Flush all pending command buffers.
bool IsValid() const override
Determines if a context is valid. If the caller ever receives an invalid context, they must discard i...
const std::unique_ptr< DriverInfoVK > & GetDriverInfo() const
void DisposeThreadLocalCachedResources() override
std::shared_ptr< CommandBuffer > CreateCommandBuffer() const override
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
virtual bool SubmitOnscreen(std::shared_ptr< CommandBuffer > cmd_buffer) override
Submit the command buffer that renders to the onscreen surface.
std::shared_ptr< SamplerLibrary > GetSamplerLibrary() const override
Returns the library of combined image samplers used in shaders.
static std::shared_ptr< ContextVK > Create(Settings settings)
std::shared_ptr< PipelineLibrary > GetPipelineLibrary() const override
Returns the library of pipelines used by render or compute commands.
const std::shared_ptr< QueueVK > & GetGraphicsQueue() const
const std::shared_ptr< const Capabilities > & GetCapabilities() const override
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
RuntimeStageBackend GetRuntimeStageBackend() const override
Retrieve the runtime stage for this context type.
std::shared_ptr< CommandPoolRecyclerVK > GetCommandPoolRecycler() const
std::shared_ptr< CommandQueue > GetCommandQueue() const override
Return the graphics queue for submitting command buffers.
void InitializeCommonlyUsedShadersIfNeeded() const override
std::shared_ptr< FenceWaiterVK > GetFenceWaiter() const
bool GetShouldEnableSurfaceControlSwapchain() const
Whether the Android Surface control based swapchain should be enabled.
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
BackendType GetBackendType() const override
Get the graphics backend of an Impeller context.
std::string DescribeGpuModel() const override
const WorkaroundsVK & GetWorkarounds() const
const std::shared_ptr< fml::ConcurrentTaskRunner > GetConcurrentWorkerTaskRunner() const
static size_t ChooseThreadCountForWorkers(size_t hardware_concurrency)
std::shared_ptr< ShaderLibrary > GetShaderLibrary() const override
Returns the library of shaders used to specify the programmable stages of a pipeline.
vk::Instance GetInstance() const
std::shared_ptr< DeviceHolderVK > GetDeviceHolder() const
void Shutdown() override
Force all pending asynchronous work to finish. This is achieved by deleting all owned concurrent mess...
std::shared_ptr< DescriptorPoolRecyclerVK > GetDescriptorPoolRecycler() const
std::shared_ptr< SurfaceContextVK > CreateSurfaceContext()
RenderPassBuilderVK & SetDepthStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
RenderPassBuilderVK & SetStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
RenderPassBuilderVK & SetColorAttachment(size_t index, PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action, vk::ImageLayout current_layout=vk::ImageLayout::eUndefined)
vk::UniqueRenderPass Build(const vk::Device &device) const
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
virtual RenderTarget CreateOffscreenMSAA(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config=RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_msaa_texture=nullptr, const std::shared_ptr< Texture > &existing_color_resolve_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr)
bool IterateAllColorAttachments(const std::function< bool(size_t index, const ColorAttachment &attachment)> &iterator) const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
static std::shared_ptr< ResourceManagerVK > Create()
Creates a shared resource manager (a dedicated thread).
ScopedObject< Object > Create(CtorArgs &&... args)
bool HasValidationLayers()
static std::optional< QueueIndexVK > PickQueue(const vk::PhysicalDevice &device, vk::QueueFlagBits flags)
static std::optional< vk::PhysicalDevice > PickPhysicalDevice(const CapabilitiesVK &caps, const vk::Instance &instance)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
static bool gHasValidationLayers
WorkaroundsVK GetWorkaroundsFromDriverInfo(DriverInfoVK &driver_info)
static std::vector< vk::DeviceQueueCreateInfo > GetQueueCreateInfos(std::initializer_list< QueueIndexVK > queues)
std::shared_ptr< Texture > texture
static QueuesVK FromEmbedderQueue(vk::Queue queue, uint32_t queue_family_index)
static QueuesVK FromQueueIndices(const vk::Device &device, QueueIndexVK graphics, QueueIndexVK compute, QueueIndexVK transfer)
std::shared_ptr< QueueVK > graphics_queue
A non-exhaustive set of driver specific workarounds.
bool batch_submit_command_buffer_timeout