From a35156b7327f9fb29f459a87c71fc299d5d43389 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 28 Sep 2021 13:01:41 +0000 Subject: [PATCH] dawn_node: Add binding/AsyncRunner Used to poll a wgpu::Device with calls to Tick() while there are asynchronous tasks in flight. Bug: dawn:1123 Change-Id: Ieee75b983df836a6df09ae4ff81f7382f4be4995 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64905 Commit-Queue: Ben Clayton Reviewed-by: Austin Eng --- src/dawn_node/binding/AsyncRunner.cpp | 55 +++++++++++++++++++ src/dawn_node/binding/AsyncRunner.h | 76 +++++++++++++++++++++++++++ src/dawn_node/binding/CMakeLists.txt | 2 + 3 files changed, 133 insertions(+) create mode 100644 src/dawn_node/binding/AsyncRunner.cpp create mode 100644 src/dawn_node/binding/AsyncRunner.h diff --git a/src/dawn_node/binding/AsyncRunner.cpp b/src/dawn_node/binding/AsyncRunner.cpp new file mode 100644 index 0000000000..7162b2e754 --- /dev/null +++ b/src/dawn_node/binding/AsyncRunner.cpp @@ -0,0 +1,55 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/dawn_node/binding/AsyncRunner.h" + +#include +#include + +namespace wgpu { namespace binding { + + AsyncRunner::AsyncRunner(Napi::Env env, wgpu::Device device) : env_(env), device_(device) { + } + + void AsyncRunner::Begin() { + assert(count_ != std::numeric_limits::max()); + if (count_++ == 0) { + QueueTick(); + } + } + + void AsyncRunner::End() { + assert(count_ > 0); + count_--; + } + + void AsyncRunner::QueueTick() { + // TODO(crbug.com/dawn/1127): We probably want to reduce the frequency at which this gets + // called. + env_.Global() + .Get("setImmediate") + .As() + .Call({ + // TODO(crbug.com/dawn/1127): Create once, reuse. + Napi::Function::New(env_, + [this](const Napi::CallbackInfo&) { + if (count_ > 0) { + device_.Tick(); + QueueTick(); + } + }), + }); + } + +}} // namespace wgpu::binding diff --git a/src/dawn_node/binding/AsyncRunner.h b/src/dawn_node/binding/AsyncRunner.h new file mode 100644 index 0000000000..83644c09af --- /dev/null +++ b/src/dawn_node/binding/AsyncRunner.h @@ -0,0 +1,76 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWN_NODE_BINDING_ASYNC_RUNNER_H_ +#define DAWN_NODE_BINDING_ASYNC_RUNNER_H_ + +#include +#include + +#include "dawn/webgpu_cpp.h" +#include "napi.h" + +namespace wgpu { namespace binding { + + // AsyncRunner is used to poll a wgpu::Device with calls to Tick() while there are asynchronous + // tasks in flight. + class AsyncRunner { + public: + AsyncRunner(Napi::Env env, wgpu::Device device); + + // Begin() should be called when a new asynchronous task is started. + // If the number of executing asynchronous tasks transitions from 0 to 1, then a function + // will be scheduled on the main JavaScript thread to call wgpu::Device::Tick() whenever the + // thread is idle. This will be repeatedly called until the number of executing asynchronous + // tasks reaches 0 again. + void Begin(); + + // End() should be called once the asynchronous task has finished. + // Every call to Begin() should eventually result in a call to End(). + void End(); + + private: + void QueueTick(); + Napi::Env env_; + wgpu::Device const device_; + uint64_t count_ = 0; + }; + + // AsyncTask is a RAII helper for calling AsyncRunner::Begin() on construction, and + // AsyncRunner::End() on destruction. + class AsyncTask { + public: + inline AsyncTask(AsyncTask&&) = default; + + // Constructor. + // Calls AsyncRunner::Begin() + inline AsyncTask(std::shared_ptr runner) : runner_(std::move(runner)) { + runner_->Begin(); + }; + + // Destructor. + // Calls AsyncRunner::End() + inline ~AsyncTask() { + runner_->End(); + } + + private: + AsyncTask(const AsyncTask&) = delete; + AsyncTask& operator=(const AsyncTask&) = delete; + std::shared_ptr runner_; + }; + +}} // namespace wgpu::binding + +#endif // DAWN_NODE_BINDING_ASYNC_RUNNER_H_ diff --git a/src/dawn_node/binding/CMakeLists.txt b/src/dawn_node/binding/CMakeLists.txt index c12f86e9cc..faad89440c 100644 --- a/src/dawn_node/binding/CMakeLists.txt +++ b/src/dawn_node/binding/CMakeLists.txt @@ -13,6 +13,8 @@ # limitations under the License. add_library(dawn_node_binding STATIC + "AsyncRunner.cpp" + "AsyncRunner.h" "Errors.cpp" "Errors.h" )