diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 450968be91055..a051333848cc4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -450,6 +450,8 @@ FILE: ../../../flutter/impeller/base/base_unittests.cc FILE: ../../../flutter/impeller/base/comparable.cc FILE: ../../../flutter/impeller/base/comparable.h FILE: ../../../flutter/impeller/base/config.h +FILE: ../../../flutter/impeller/base/platform/darwin/work_queue_darwin.cc +FILE: ../../../flutter/impeller/base/platform/darwin/work_queue_darwin.h FILE: ../../../flutter/impeller/base/promise.cc FILE: ../../../flutter/impeller/base/promise.h FILE: ../../../flutter/impeller/base/strings.cc @@ -462,6 +464,10 @@ FILE: ../../../flutter/impeller/base/validation.cc FILE: ../../../flutter/impeller/base/validation.h FILE: ../../../flutter/impeller/base/version.cc FILE: ../../../flutter/impeller/base/version.h +FILE: ../../../flutter/impeller/base/work_queue.cc +FILE: ../../../flutter/impeller/base/work_queue.h +FILE: ../../../flutter/impeller/base/work_queue_common.cc +FILE: ../../../flutter/impeller/base/work_queue_common.h FILE: ../../../flutter/impeller/blobcat/blob.cc FILE: ../../../flutter/impeller/blobcat/blob.h FILE: ../../../flutter/impeller/blobcat/blob_library.cc diff --git a/impeller/base/BUILD.gn b/impeller/base/BUILD.gn index 577d34d78f2b7..4edd4e1a154f9 100644 --- a/impeller/base/BUILD.gn +++ b/impeller/base/BUILD.gn @@ -24,8 +24,19 @@ impeller_component("base") { "validation.h", "version.cc", "version.h", + "work_queue.cc", + "work_queue.h", + "work_queue_common.cc", + "work_queue_common.h", ] + if (is_ios || is_mac) { + sources += [ + "platform/darwin/work_queue_darwin.cc", + "platform/darwin/work_queue_darwin.h", + ] + } + deps = [ "//flutter/fml" ] } diff --git a/impeller/base/platform/darwin/work_queue_darwin.cc b/impeller/base/platform/darwin/work_queue_darwin.cc new file mode 100644 index 0000000000000..6ac76520530ed --- /dev/null +++ b/impeller/base/platform/darwin/work_queue_darwin.cc @@ -0,0 +1,38 @@ +// 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/base/platform/darwin/work_queue_darwin.h" + +namespace impeller { + +std::shared_ptr WorkQueueDarwin::Create() { + auto queue = std::shared_ptr(new WorkQueueDarwin()); + if (!queue->IsValid()) { + return nullptr; + } + return queue; +} + +WorkQueueDarwin::WorkQueueDarwin() + : queue_(::dispatch_queue_create( + "io.flutter.impeller.wq", + ::dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL, + QOS_CLASS_USER_INITIATED, + -1))) {} + +WorkQueueDarwin::~WorkQueueDarwin() = default; + +bool WorkQueueDarwin::IsValid() const { + return queue_ != NULL; +} + +// |WorkQueue| +void WorkQueueDarwin::PostTask(fml::closure task) { + dispatch_async(queue_, ^() { + task(); + }); +} + +} // namespace impeller diff --git a/impeller/base/platform/darwin/work_queue_darwin.h b/impeller/base/platform/darwin/work_queue_darwin.h new file mode 100644 index 0000000000000..c82aca9eb285f --- /dev/null +++ b/impeller/base/platform/darwin/work_queue_darwin.h @@ -0,0 +1,36 @@ +// 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/base/work_queue.h" + +namespace impeller { + +class WorkQueueDarwin final : public WorkQueue { + public: + static std::shared_ptr Create(); + + // |WorkQueue| + ~WorkQueueDarwin(); + + bool IsValid() const; + + private: + dispatch_queue_t queue_ = NULL; + + WorkQueueDarwin(); + + // |WorkQueue| + void PostTask(fml::closure task) override; + + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueueDarwin); +}; + +} // namespace impeller diff --git a/impeller/base/work_queue.cc b/impeller/base/work_queue.cc new file mode 100644 index 0000000000000..f4a375496207a --- /dev/null +++ b/impeller/base/work_queue.cc @@ -0,0 +1,13 @@ +// 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 "flutter/impeller/base/work_queue.h" + +namespace impeller { + +WorkQueue::WorkQueue() = default; + +WorkQueue::~WorkQueue() = default; + +} // namespace impeller diff --git a/impeller/base/work_queue.h b/impeller/base/work_queue.h new file mode 100644 index 0000000000000..afd31c7acd53c --- /dev/null +++ b/impeller/base/work_queue.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 "flutter/fml/closure.h" +#include "flutter/fml/macros.h" + +namespace impeller { + +class WorkQueue : public std::enable_shared_from_this { + public: + virtual ~WorkQueue(); + + virtual void PostTask(fml::closure task) = 0; + + protected: + WorkQueue(); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueue); +}; + +} // namespace impeller diff --git a/impeller/base/work_queue_common.cc b/impeller/base/work_queue_common.cc new file mode 100644 index 0000000000000..9a1f0620148ec --- /dev/null +++ b/impeller/base/work_queue_common.cc @@ -0,0 +1,25 @@ +// 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/base/work_queue_common.h" + +namespace impeller { + +std::shared_ptr WorkQueueCommon::Create() { + return std::shared_ptr(new WorkQueueCommon()); +} + +WorkQueueCommon::WorkQueueCommon() + : loop_(fml::ConcurrentMessageLoop::Create(2u)) {} + +WorkQueueCommon::~WorkQueueCommon() { + loop_->Terminate(); +} + +// |WorkQueue| +void WorkQueueCommon::PostTask(fml::closure task) { + loop_->GetTaskRunner()->PostTask(std::move(task)); +} + +} // namespace impeller diff --git a/impeller/base/work_queue_common.h b/impeller/base/work_queue_common.h new file mode 100644 index 0000000000000..952f6ecbadacd --- /dev/null +++ b/impeller/base/work_queue_common.h @@ -0,0 +1,33 @@ +// 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/concurrent_message_loop.h" +#include "flutter/fml/macros.h" +#include "impeller/base/work_queue.h" + +namespace impeller { + +class WorkQueueCommon : public WorkQueue { + public: + static std::shared_ptr Create(); + + // |WorkQueue| + ~WorkQueueCommon(); + + private: + std::shared_ptr loop_; + + WorkQueueCommon(); + + // |WorkQueue| + void PostTask(fml::closure task) override; + + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueueCommon); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index a7522b412d7bf..7ff2339498613 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -6,6 +6,7 @@ #include "impeller/base/config.h" #include "impeller/base/validation.h" +#include "impeller/base/work_queue_common.h" namespace impeller { @@ -52,12 +53,21 @@ ContextGLES::ContextGLES( } } - // Create the sampler library + // Create the sampler library. { sampler_library_ = std::shared_ptr(new SamplerLibraryGLES()); } + // Create the work queue. + { + work_queue_ = WorkQueueCommon::Create(); + if (!work_queue_) { + VALIDATION_LOG << "Could not create work queue."; + return; + } + } + is_valid_ = true; } @@ -86,27 +96,37 @@ bool ContextGLES::IsValid() const { return is_valid_; } +// |Context| std::shared_ptr ContextGLES::GetResourceAllocator() const { return resource_allocator_; } +// |Context| std::shared_ptr ContextGLES::GetShaderLibrary() const { return shader_library_; } +// |Context| std::shared_ptr ContextGLES::GetSamplerLibrary() const { return sampler_library_; } +// |Context| std::shared_ptr ContextGLES::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| std::shared_ptr ContextGLES::CreateCommandBuffer() const { return std::shared_ptr( new CommandBufferGLES(weak_from_this(), reactor_)); } +// |Context| +std::shared_ptr ContextGLES::GetWorkQueue() const { + return work_queue_; +} + // |Context| bool ContextGLES::HasThreadingRestrictions() const { return true; diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index f96efd2098760..7c7246dc796b6 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -38,6 +38,7 @@ class ContextGLES final : public Context, std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; + std::shared_ptr work_queue_; std::shared_ptr resource_allocator_; bool is_valid_ = false; @@ -62,6 +63,9 @@ class ContextGLES final : public Context, // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() const override; + // |Context| bool HasThreadingRestrictions() const override; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index a08a9b252071c..45368a26ac737 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -42,6 +42,7 @@ class ContextMTL final : public Context, std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; std::shared_ptr resource_allocator_; + std::shared_ptr work_queue_; bool is_valid_ = false; ContextMTL(id device, NSArray>* shader_libraries); @@ -64,6 +65,9 @@ class ContextMTL final : public Context, // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() 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 c19f3888e6d18..b3a8d7ea5c805 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -9,6 +9,7 @@ #include "flutter/fml/file.h" #include "flutter/fml/logging.h" #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/sampler_descriptor.h" @@ -40,31 +41,43 @@ shader_library_ = std::move(library); } - // Setup command queues. - command_queue_ = device_.newCommandQueue; - - if (!command_queue_) { - return; + // Setup command queue. + { + command_queue_ = device_.newCommandQueue; + if (!command_queue_) { + VALIDATION_LOG << "Could not setup the command queue."; + return; + } + command_queue_.label = @"Impeller Command Queue"; } - command_queue_.label = @"Impeller Command Queue"; - // Setup the pipeline library. - { // + { pipeline_library_ = std::shared_ptr(new PipelineLibraryMTL(device_)); } // Setup the sampler library. - { // + { sampler_library_ = std::shared_ptr(new SamplerLibraryMTL(device_)); } + // Setup the resource allocator. { resource_allocator_ = std::shared_ptr( new AllocatorMTL(device_, "Impeller Permanents Allocator")); if (!resource_allocator_) { + VALIDATION_LOG << "Could not setup the resource allocator."; + return; + } + } + + // Setup the work queue. + { + work_queue_ = WorkQueueDarwin::Create(); + if (!work_queue_) { + VALIDATION_LOG << "Could not setup the work queue."; return; } } @@ -167,26 +180,36 @@ ContextMTL::~ContextMTL() = default; +// |Context| bool ContextMTL::IsValid() const { return is_valid_; } +// |Context| std::shared_ptr ContextMTL::GetShaderLibrary() const { return shader_library_; } +// |Context| std::shared_ptr ContextMTL::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| std::shared_ptr ContextMTL::GetSamplerLibrary() const { return sampler_library_; } +// |Context| std::shared_ptr ContextMTL::CreateCommandBuffer() const { return CreateCommandBufferInQueue(command_queue_); } +// |Context| +std::shared_ptr ContextMTL::GetWorkQueue() const { + return work_queue_; +} + std::shared_ptr ContextMTL::CreateCommandBufferInQueue( id queue) const { if (!IsValid()) { diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 52329dd833071..27a15e293222e 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -12,6 +12,7 @@ #include "flutter/fml/build_config.h" #include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" +#include "impeller/base/work_queue_common.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" @@ -407,6 +408,13 @@ ContextVK::ContextVK( return; } + auto work_queue = WorkQueueCommon::Create(); + + if (!work_queue) { + VALIDATION_LOG << "Could not create workqueue."; + return; + } + instance_ = std::move(instance.value); debug_messenger_ = std::move(debug_messenger); device_ = std::move(device.value); @@ -414,6 +422,7 @@ ContextVK::ContextVK( shader_library_ = std::move(shader_library); sampler_library_ = std::move(sampler_library); pipeline_library_ = std::move(pipeline_library); + work_queue_ = std::move(work_queue); graphics_queue_ = device_->getQueue(graphics_queue->family, graphics_queue->index); compute_queue_ = @@ -447,6 +456,11 @@ std::shared_ptr ContextVK::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| +std::shared_ptr ContextVK::GetWorkQueue() const { + return work_queue_; +} + std::shared_ptr ContextVK::CreateCommandBuffer() const { FML_UNREACHABLE(); } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index a83bd2d0a14b7..eadc810d44d36 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -78,6 +78,7 @@ class ContextVK final : public Context, public BackendCast { std::unique_ptr swapchain_; std::unique_ptr graphics_command_pool_; std::unique_ptr surface_producer_; + std::shared_ptr work_queue_; bool is_valid_ = false; ContextVK( @@ -102,6 +103,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index dad614f5051eb..7f13fce9ac684 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -16,6 +16,7 @@ class SamplerLibrary; class CommandBuffer; class PipelineLibrary; class Allocator; +class WorkQueue; class Context : public std::enable_shared_from_this { public: @@ -36,6 +37,8 @@ class Context : public std::enable_shared_from_this { virtual std::shared_ptr CreateCommandBuffer() const = 0; + virtual std::shared_ptr GetWorkQueue() const = 0; + virtual bool HasThreadingRestrictions() const; protected: