diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1c8291fb821a9..6b43cac4a16a6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2428,10 +2428,8 @@ FILE: ../../../flutter/shell/platform/windows/system_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/task_runner.cc FILE: ../../../flutter/shell/platform/windows/task_runner.h FILE: ../../../flutter/shell/platform/windows/task_runner_unittests.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32.h -FILE: ../../../flutter/shell/platform/windows/task_runner_win32_window.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32_window.h +FILE: ../../../flutter/shell/platform/windows/task_runner_window.cc +FILE: ../../../flutter/shell/platform/windows/task_runner_window.h FILE: ../../../flutter/shell/platform/windows/text_input_manager.cc FILE: ../../../flutter/shell/platform/windows/text_input_manager.h FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index e5b2018fd267f..e38aa14714555 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -13,10 +13,15 @@ #include "impeller/compiler/compiler_backend.h" #include "impeller/compiler/includer.h" #include "impeller/compiler/logger.h" +#include "impeller/compiler/types.h" namespace impeller { namespace compiler { +const uint32_t kFragBindingBase = 128; +const size_t kNumUniformKinds = + int(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1; + static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir, const SourceOptions& source_options) { auto sl_compiler = std::make_shared(ir); @@ -104,6 +109,15 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, return compiler; } +void Compiler::SetBindingBase(shaderc::CompileOptions& compiler_opts) const { + for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds; + uniform_kind++) { + compiler_opts.SetBindingBaseForStage( + ToShaderCShaderKind(SourceType::kFragmentShader), + static_cast(uniform_kind), kFragBindingBase); + } +} + Compiler::Compiler(const fml::Mapping& source_mapping, SourceOptions source_options, Reflector::Options reflector_options) @@ -212,6 +226,7 @@ Compiler::Compiler(const fml::Mapping& source_mapping, } spirv_options.SetAutoBindUniforms(true); + SetBindingBase(spirv_options); spirv_options.SetAutoMapLocations(true); std::vector included_file_names; diff --git a/impeller/compiler/compiler.h b/impeller/compiler/compiler.h index 9dd3d901c3dde..379f610fd2286 100644 --- a/impeller/compiler/compiler.h +++ b/impeller/compiler/compiler.h @@ -57,6 +57,8 @@ class Compiler { std::string GetDependencyNames(std::string separator) const; + void SetBindingBase(shaderc::CompileOptions& compiler_opts) const; + FML_DISALLOW_COPY_AND_ASSIGN(Compiler); }; diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 85b3abaa5f9c5..402d05fe7346f 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -6,6 +6,11 @@ #include +#include "flutter/fml/file.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/unique_fd.h" + namespace impeller { namespace compiler { namespace testing { @@ -58,6 +63,13 @@ static std::string SLFileName(const char* fixture_name, return stream.str(); } +std::unique_ptr CompilerTest::GetReflectionJson( + const char* fixture_name) const { + auto filename = ReflectionJSONName(fixture_name); + auto fd = fml::OpenFileReadOnly(intermediates_directory_, filename.c_str()); + return fml::FileMapping::CreateReadOnly(fd); +} + bool CompilerTest::CanCompileAndReflect(const char* fixture_name, SourceType source_type) const { auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index a7be1c688b198..0e4fd94fd3929 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -25,6 +25,9 @@ class CompilerTest : public ::testing::TestWithParam { const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; + std::unique_ptr GetReflectionJson( + const char* fixture_name) const; + private: fml::UniqueFD intermediates_directory_; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index d19d9f00c98c0..f46b745c81703 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -9,6 +9,8 @@ #include "impeller/compiler/source_options.h" #include "impeller/compiler/types.h" +#include "nlohmann/json.hpp" + namespace impeller { namespace compiler { namespace testing { @@ -50,6 +52,27 @@ TEST_P(CompilerTest, CanCompileComputeShader) { ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader)); } +TEST_P(CompilerTest, BindingBaseForFragShader) { + if (GetParam() == TargetPlatform::kFlutterSPIRV) { + // This is a failure of reflection which this target doesn't perform. + GTEST_SKIP(); + } + + ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader)); + ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader)); + + auto get_binding = [&](const char* fixture) -> uint32_t { + auto json_fd = GetReflectionJson(fixture); + nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping()); + return shader_json["buffers"][0]["binding"].get(); + }; + + auto vert_uniform_binding = get_binding("sample.vert"); + auto frag_uniform_binding = get_binding("sample.frag"); + + ASSERT_GT(frag_uniform_binding, vert_uniform_binding); +} + TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { if (GetParam() == TargetPlatform::kFlutterSPIRV) { // This is a failure of reflection which this target doesn't perform. diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index d955a90bfa9df..635125cc1ecc9 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -43,6 +43,7 @@ test_fixtures("file_fixtures") { "embarcadero.jpg", "kalimba.jpg", "sample.comp", + "sample.frag", "sample.tesc", "sample.tese", "sample.vert", diff --git a/impeller/fixtures/sample.frag b/impeller/fixtures/sample.frag new file mode 100644 index 0000000000000..5d9c83604dd68 --- /dev/null +++ b/impeller/fixtures/sample.frag @@ -0,0 +1,14 @@ +// 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. + +uniform FragInfo { + vec4 color; +} +frag_info; + +out vec4 frag_color; + +void main() { + frag_color = frag_info.color; +} diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 3aa94757e4cff..d8b39d099be59 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -92,10 +92,8 @@ source_set("flutter_windows_source") { "system_utils.h", "task_runner.cc", "task_runner.h", - "task_runner_win32.cc", - "task_runner_win32.h", - "task_runner_win32_window.cc", - "task_runner_win32_window.h", + "task_runner_window.cc", + "task_runner_window.h", "text_input_manager.cc", "text_input_manager.h", "text_input_plugin.cc", diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 20d7318aaceab..3ed63ae3a3556 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -156,7 +156,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = TaskRunner::Create( + task_runner_ = std::make_unique( embedder_api_.GetCurrentTime, [this](const auto* task) { if (!engine_) { std::cerr << "Cannot post an engine task when engine is not running." diff --git a/shell/platform/windows/task_runner.cc b/shell/platform/windows/task_runner.cc index 464afbc43827e..10a699403d919 100644 --- a/shell/platform/windows/task_runner.cc +++ b/shell/platform/windows/task_runner.cc @@ -12,7 +12,15 @@ namespace flutter { TaskRunner::TaskRunner(CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired) : get_current_time_(get_current_time), - on_task_expired_(std::move(on_task_expired)) {} + on_task_expired_(std::move(on_task_expired)) { + main_thread_id_ = GetCurrentThreadId(); + task_runner_window_ = TaskRunnerWindow::GetSharedInstance(); + task_runner_window_->AddDelegate(this); +} + +TaskRunner::~TaskRunner() { + task_runner_window_->RemoveDelegate(this); +} std::chrono::nanoseconds TaskRunner::ProcessTasks() { const TaskTimePoint now = GetCurrentTimeForTask(); @@ -101,4 +109,12 @@ void TaskRunner::EnqueueTask(Task task) { WakeUp(); } +bool TaskRunner::RunsTasksOnCurrentThread() const { + return GetCurrentThreadId() == main_thread_id_; +} + +void TaskRunner::WakeUp() { + task_runner_window_->WakeUp(); +} + } // namespace flutter diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h index 685ed77e93f08..b211dbedcd427 100644 --- a/shell/platform/windows/task_runner.h +++ b/shell/platform/windows/task_runner.h @@ -14,21 +14,30 @@ #include #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner_window.h" namespace flutter { typedef uint64_t (*CurrentTimeProc)(); -class TaskRunner { +// A custom task runner that integrates with user32 GetMessage semantics so +// that host app can own its own message loop and flutter still gets to process +// tasks on a timely basis. +class TaskRunner : public TaskRunnerWindow::Delegate { public: using TaskTimePoint = std::chrono::steady_clock::time_point; using TaskExpiredCallback = std::function; using TaskClosure = std::function; - virtual ~TaskRunner() = default; + // Creates a new task runner with the current thread, current time + // provider, and callback for tasks that are ready to be run. + TaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + + virtual ~TaskRunner(); // Returns `true` if the current thread is this runner's thread. - virtual bool RunsTasksOnCurrentThread() const = 0; + virtual bool RunsTasksOnCurrentThread() const; // Post a Flutter engine task to the event loop for delayed execution. void PostFlutterTask(FlutterTask flutter_task, @@ -47,33 +56,9 @@ class TaskRunner { } } - // Creates a new task runner with the current thread, current time - // provider, and callback for tasks that are ready to be run. - static std::unique_ptr Create( - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - - protected: - TaskRunner(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - - // Schedules timers to call `ProcessTasks()` at the runner's thread. - virtual void WakeUp() = 0; - - // Executes expired task, and returns the duration until the next task - // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. - // - // Each platform implementations must call this to schedule the tasks. + // |TaskRunnerWindow::Delegate| std::chrono::nanoseconds ProcessTasks(); - // Returns the current TaskTimePoint that can be used to determine whether a - // task is expired. - // - // Tests can override this to mock up the time. - virtual TaskTimePoint GetCurrentTimeForTask() const { - return TaskTimePoint::clock::now(); - } - private: typedef std::variant TaskVariant; @@ -95,6 +80,17 @@ class TaskRunner { // Enqueues the given task. void EnqueueTask(Task task); + // Schedules timers to call `ProcessTasks()` at the runner's thread. + virtual void WakeUp(); + + // Returns the current TaskTimePoint that can be used to determine whether a + // task is expired. + // + // Tests can override this to mock up the time. + virtual TaskTimePoint GetCurrentTimeForTask() const { + return TaskTimePoint::clock::now(); + } + // Returns a TaskTimePoint computed from the given target time from Flutter. TaskTimePoint TimePointFromFlutterTime( uint64_t flutter_target_time_nanos) const; @@ -103,6 +99,8 @@ class TaskRunner { TaskExpiredCallback on_task_expired_; std::mutex task_queue_mutex_; std::priority_queue, Task::Comparer> task_queue_; + DWORD main_thread_id_; + std::shared_ptr task_runner_window_; TaskRunner(const TaskRunner&) = delete; TaskRunner& operator=(const TaskRunner&) = delete; diff --git a/shell/platform/windows/task_runner_win32.cc b/shell/platform/windows/task_runner_win32.cc deleted file mode 100644 index 01c7179c792f5..0000000000000 --- a/shell/platform/windows/task_runner_win32.cc +++ /dev/null @@ -1,40 +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 "flutter/shell/platform/windows/task_runner_win32.h" - -namespace flutter { - -// static -std::unique_ptr TaskRunner::Create( - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(get_current_time, on_task_expired); -} - -TaskRunnerWin32::TaskRunnerWin32(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) - : TaskRunner(get_current_time, on_task_expired) { - main_thread_id_ = GetCurrentThreadId(); - task_runner_window_ = TaskRunnerWin32Window::GetSharedInstance(); - task_runner_window_->AddDelegate(this); -} - -TaskRunnerWin32::~TaskRunnerWin32() { - task_runner_window_->RemoveDelegate(this); -} - -bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { - return GetCurrentThreadId() == main_thread_id_; -} - -std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { - return TaskRunner::ProcessTasks(); -} - -void TaskRunnerWin32::WakeUp() { - task_runner_window_->WakeUp(); -} - -} // namespace flutter diff --git a/shell/platform/windows/task_runner_win32.h b/shell/platform/windows/task_runner_win32.h deleted file mode 100644 index 6e3ceb8476f63..0000000000000 --- a/shell/platform/windows/task_runner_win32.h +++ /dev/null @@ -1,46 +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. - -#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ - -#include - -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/task_runner.h" -#include "flutter/shell/platform/windows/task_runner_win32_window.h" - -namespace flutter { - -// A custom task runner that integrates with user32 GetMessage semantics so that -// host app can own its own message loop and flutter still gets to process -// tasks on a timely basis. -class TaskRunnerWin32 : public TaskRunner, - public TaskRunnerWin32Window::Delegate { - public: - TaskRunnerWin32(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - virtual ~TaskRunnerWin32(); - - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; - - // |TaskRunnerWin32Window::Delegate| - std::chrono::nanoseconds ProcessTasks() override; - - protected: - // |TaskRunner| - void WakeUp() override; - - private: - DWORD main_thread_id_; - std::shared_ptr task_runner_window_; - - TaskRunnerWin32(const TaskRunnerWin32&) = delete; - TaskRunnerWin32& operator=(const TaskRunnerWin32&) = delete; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ diff --git a/shell/platform/windows/task_runner_win32_window.cc b/shell/platform/windows/task_runner_window.cc similarity index 72% rename from shell/platform/windows/task_runner_win32_window.cc rename to shell/platform/windows/task_runner_window.cc index a08f88cd33621..ccdf4b570ac13 100644 --- a/shell/platform/windows/task_runner_win32_window.cc +++ b/shell/platform/windows/task_runner_window.cc @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/windows/task_runner_win32_window.h" +#include "flutter/shell/platform/windows/task_runner_window.h" #include #include namespace flutter { -TaskRunnerWin32Window::TaskRunnerWin32Window() { +TaskRunnerWindow::TaskRunnerWindow() { WNDCLASS window_class = RegisterWindowClass(); window_handle_ = CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0, @@ -31,7 +31,7 @@ TaskRunnerWin32Window::TaskRunnerWin32Window() { } } -TaskRunnerWin32Window::~TaskRunnerWin32Window() { +TaskRunnerWindow::~TaskRunnerWindow() { if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; @@ -39,37 +39,36 @@ TaskRunnerWin32Window::~TaskRunnerWin32Window() { UnregisterClass(window_class_name_.c_str(), nullptr); } -std::shared_ptr -TaskRunnerWin32Window::GetSharedInstance() { - static std::weak_ptr instance; +std::shared_ptr TaskRunnerWindow::GetSharedInstance() { + static std::weak_ptr instance; auto res = instance.lock(); if (!res) { // can't use make_shared with private contructor - res.reset(new TaskRunnerWin32Window()); + res.reset(new TaskRunnerWindow()); instance = res; } return res; } -void TaskRunnerWin32Window::WakeUp() { +void TaskRunnerWindow::WakeUp() { if (!PostMessage(window_handle_, WM_NULL, 0, 0)) { std::cerr << "Failed to post message to main thread." << std::endl; } } -void TaskRunnerWin32Window::AddDelegate(Delegate* delegate) { +void TaskRunnerWindow::AddDelegate(Delegate* delegate) { delegates_.push_back(delegate); SetTimer(std::chrono::nanoseconds::zero()); } -void TaskRunnerWin32Window::RemoveDelegate(Delegate* delegate) { +void TaskRunnerWindow::RemoveDelegate(Delegate* delegate) { auto i = std::find(delegates_.begin(), delegates_.end(), delegate); if (i != delegates_.end()) { delegates_.erase(i); } } -void TaskRunnerWin32Window::ProcessTasks() { +void TaskRunnerWindow::ProcessTasks() { auto next = std::chrono::nanoseconds::max(); auto delegates_copy(delegates_); for (auto delegate : delegates_copy) { @@ -82,7 +81,7 @@ void TaskRunnerWin32Window::ProcessTasks() { SetTimer(next); } -void TaskRunnerWin32Window::SetTimer(std::chrono::nanoseconds when) { +void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) { if (when == std::chrono::nanoseconds::max()) { KillTimer(window_handle_, 0); } else { @@ -91,7 +90,7 @@ void TaskRunnerWin32Window::SetTimer(std::chrono::nanoseconds when) { } } -WNDCLASS TaskRunnerWin32Window::RegisterWindowClass() { +WNDCLASS TaskRunnerWindow::RegisterWindowClass() { window_class_name_ = L"FlutterTaskRunnerWindow"; WNDCLASS window_class{}; @@ -110,9 +109,9 @@ WNDCLASS TaskRunnerWin32Window::RegisterWindowClass() { } LRESULT -TaskRunnerWin32Window::HandleMessage(UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { +TaskRunnerWindow::HandleMessage(UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { switch (message) { case WM_TIMER: case WM_NULL: @@ -122,11 +121,11 @@ TaskRunnerWin32Window::HandleMessage(UINT const message, return DefWindowProcW(window_handle_, message, wparam, lparam); } -LRESULT TaskRunnerWin32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (auto* that = reinterpret_cast( +LRESULT TaskRunnerWindow::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (auto* that = reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA))) { return that->HandleMessage(message, wparam, lparam); } else { diff --git a/shell/platform/windows/task_runner_win32_window.h b/shell/platform/windows/task_runner_window.h similarity index 78% rename from shell/platform/windows/task_runner_win32_window.h rename to shell/platform/windows/task_runner_window.h index a11d8ef0dd628..ae874f82af71f 100644 --- a/shell/platform/windows/task_runner_win32_window.h +++ b/shell/platform/windows/task_runner_window.h @@ -15,14 +15,18 @@ namespace flutter { // Hidden HWND responsible for processing flutter tasks on main thread -class TaskRunnerWin32Window { +class TaskRunnerWindow { public: class Delegate { public: + // Executes expired task, and returns the duration until the next task + // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. + // + // Each platform implementation must call this to schedule the tasks. virtual std::chrono::nanoseconds ProcessTasks() = 0; }; - static std::shared_ptr GetSharedInstance(); + static std::shared_ptr GetSharedInstance(); // Triggers processing delegate tasks on main thread void WakeUp(); @@ -30,10 +34,10 @@ class TaskRunnerWin32Window { void AddDelegate(Delegate* delegate); void RemoveDelegate(Delegate* delegate); - ~TaskRunnerWin32Window(); + ~TaskRunnerWindow(); private: - TaskRunnerWin32Window(); + TaskRunnerWindow(); void ProcessTasks();