-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Give Impeller a dedicated raster priority level worker loop. #43166
Changes from all commits
2d111a4
57b90e3
9f2f08c
6009f82
066d1a7
21e986b
a70c98c
199655d
8c1d8fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -139,6 +139,9 @@ void Playground::SetupWindow() { | |
} | ||
|
||
void Playground::TeardownWindow() { | ||
if (context_) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is my hacky take on making sure the concurrent message loop is torn down on the raster thread and not a worker thread |
||
context_->Shutdown(); | ||
} | ||
context_.reset(); | ||
renderer_.reset(); | ||
impl_.reset(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,18 +71,34 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
id<MTLDevice> device, | ||
id<MTLCommandQueue> command_queue, | ||
NSArray<id<MTLLibrary>>* shader_libraries, | ||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner, | ||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) | ||
: device_(device), | ||
command_queue_(command_queue), | ||
worker_task_runner_(std::move(worker_task_runner)), | ||
is_gpu_disabled_sync_switch_(std::move(is_gpu_disabled_sync_switch)) { | ||
// Validate device. | ||
if (!device_) { | ||
VALIDATION_LOG << "Could not setup valid Metal device."; | ||
return; | ||
} | ||
|
||
// Worker task runner. | ||
{ | ||
raster_message_loop_ = fml::ConcurrentMessageLoop::Create( | ||
std::min(4u, std::thread::hardware_concurrency())); | ||
raster_message_loop_->PostTaskToAllWorkers([]() { | ||
// See https://github.com/flutter/flutter/issues/65752 | ||
// Intentionally opt out of QoS for raster task workloads. | ||
[[NSThread currentThread] setThreadPriority:1.0]; | ||
sched_param param; | ||
int policy; | ||
pthread_t thread = pthread_self(); | ||
if (!pthread_getschedparam(thread, &policy, ¶m)) { | ||
param.sched_priority = 50; | ||
pthread_setschedparam(thread, policy, ¶m); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are both NSThread and pthread priority calls necessary? I expected only the first on to be a thing on iOS. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reminds me that we should probably use libDispatch with the right QoS classes on iOS. The platform will create the right number and nature of workers then. We had prototyped this on iOS in this patch but backed it out. Perhaps we can resuscitate it. |
||
} | ||
}); | ||
} | ||
|
||
// Setup the shader library. | ||
{ | ||
if (shader_libraries == nil) { | ||
|
@@ -210,7 +226,6 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
|
||
std::shared_ptr<ContextMTL> ContextMTL::Create( | ||
const std::vector<std::string>& shader_library_paths, | ||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner, | ||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) { | ||
auto device = CreateMetalDevice(); | ||
auto command_queue = CreateMetalCommandQueue(device); | ||
|
@@ -220,7 +235,7 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
auto context = std::shared_ptr<ContextMTL>(new ContextMTL( | ||
device, command_queue, | ||
MTLShaderLibraryFromFilePaths(device, shader_library_paths), | ||
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch))); | ||
std::move(is_gpu_disabled_sync_switch))); | ||
if (!context->IsValid()) { | ||
FML_LOG(ERROR) << "Could not create Metal context."; | ||
return nullptr; | ||
|
@@ -230,19 +245,18 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
|
||
std::shared_ptr<ContextMTL> ContextMTL::Create( | ||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data, | ||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner, | ||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch, | ||
const std::string& library_label) { | ||
auto device = CreateMetalDevice(); | ||
auto command_queue = CreateMetalCommandQueue(device); | ||
if (!command_queue) { | ||
return nullptr; | ||
} | ||
auto context = std::shared_ptr<ContextMTL>(new ContextMTL( | ||
device, command_queue, | ||
MTLShaderLibraryFromFileData(device, shader_libraries_data, | ||
library_label), | ||
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch))); | ||
auto context = std::shared_ptr<ContextMTL>( | ||
new ContextMTL(device, command_queue, | ||
MTLShaderLibraryFromFileData(device, shader_libraries_data, | ||
library_label), | ||
std::move(is_gpu_disabled_sync_switch))); | ||
if (!context->IsValid()) { | ||
FML_LOG(ERROR) << "Could not create Metal context."; | ||
return nullptr; | ||
|
@@ -254,14 +268,13 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
id<MTLDevice> device, | ||
id<MTLCommandQueue> command_queue, | ||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data, | ||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner, | ||
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch, | ||
const std::string& library_label) { | ||
auto context = std::shared_ptr<ContextMTL>(new ContextMTL( | ||
device, command_queue, | ||
MTLShaderLibraryFromFileData(device, shader_libraries_data, | ||
library_label), | ||
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch))); | ||
auto context = std::shared_ptr<ContextMTL>( | ||
new ContextMTL(device, command_queue, | ||
MTLShaderLibraryFromFileData(device, shader_libraries_data, | ||
library_label), | ||
std::move(is_gpu_disabled_sync_switch))); | ||
if (!context->IsValid()) { | ||
FML_LOG(ERROR) << "Could not create Metal context."; | ||
return nullptr; | ||
|
@@ -301,9 +314,14 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) { | |
return CreateCommandBufferInQueue(command_queue_); | ||
} | ||
|
||
const std::shared_ptr<fml::ConcurrentTaskRunner>& | ||
// |Context| | ||
void ContextMTL::Shutdown() { | ||
raster_message_loop_.reset(); | ||
} | ||
|
||
const std::shared_ptr<fml::ConcurrentTaskRunner> | ||
ContextMTL::GetWorkerTaskRunner() const { | ||
return worker_task_runner_; | ||
return raster_message_loop_->GetTaskRunner(); | ||
} | ||
|
||
std::shared_ptr<const fml::SyncSwitch> ContextMTL::GetIsGpuDisabledSyncSwitch() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,12 @@ | |
|
||
#include "impeller/renderer/backend/vulkan/context_vk.h" | ||
|
||
#ifdef FML_OS_ANDROID | ||
#include <pthread.h> | ||
#include <sys/resource.h> | ||
#include <sys/time.h> | ||
#endif // FML_OS_ANDROID | ||
|
||
#include <map> | ||
#include <memory> | ||
#include <optional> | ||
|
@@ -120,12 +126,15 @@ void ContextVK::Setup(Settings settings) { | |
return; | ||
} | ||
|
||
if (!settings.worker_task_runner) { | ||
VALIDATION_LOG | ||
<< "Cannot set up a Vulkan context without a worker task runner."; | ||
return; | ||
} | ||
worker_task_runner_ = settings.worker_task_runner; | ||
raster_message_loop_ = fml::ConcurrentMessageLoop::Create( | ||
std::min(4u, std::thread::hardware_concurrency())); | ||
#ifdef FML_OS_ANDROID | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, we should isolate all the platform specific bits in at least in |
||
raster_message_loop_->PostTaskToAllWorkers([]() { | ||
if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) { | ||
FML_LOG(ERROR) << "Failed to set Workers task runner priority"; | ||
} | ||
}); | ||
#endif // FML_OS_ANDROID | ||
|
||
auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; | ||
dispatcher.init(settings.proc_address_callback); | ||
|
@@ -335,10 +344,10 @@ void ContextVK::Setup(Settings settings) { | |
/// Setup the pipeline library. | ||
/// | ||
auto pipeline_library = std::shared_ptr<PipelineLibraryVK>( | ||
new PipelineLibraryVK(device_holder, // | ||
caps, // | ||
std::move(settings.cache_directory), // | ||
worker_task_runner_ // | ||
new PipelineLibraryVK(device_holder, // | ||
caps, // | ||
std::move(settings.cache_directory), // | ||
raster_message_loop_->GetTaskRunner() // | ||
)); | ||
|
||
if (!pipeline_library->IsValid()) { | ||
|
@@ -458,7 +467,11 @@ const vk::Device& ContextVK::GetDevice() const { | |
|
||
const std::shared_ptr<fml::ConcurrentTaskRunner> | ||
ContextVK::GetConcurrentWorkerTaskRunner() const { | ||
return worker_task_runner_; | ||
return raster_message_loop_->GetTaskRunner(); | ||
} | ||
|
||
void ContextVK::Shutdown() { | ||
raster_message_loop_->Terminate(); | ||
} | ||
|
||
std::unique_ptr<Surface> ContextVK::AcquireNextSurface() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes the failure case a bit more obvious. if you try to join a worker thread into itself then it will fail with an errorcode that may or may not be obvious without a debugger attached.