| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GPU_WEBGPU_CALLBACK_H_ |
| #define GPU_WEBGPU_CALLBACK_H_ |
| |
| #include <memory> |
| |
| #include "base/functional/callback.h" |
| |
| namespace gpu::webgpu { |
| |
| // WGPUCallback<Callback> is a heap-allocated version of |
| // base::OnceCallback or base::RepeatingCallback. |
| // It is allocated on the heap so that it can be reinterpret_cast to/from |
| // void* and passed to WGPU C callbacks. |
| // |
| // Example: |
| // WGPUOnceCallback<F>* callback = |
| // BindWGPUOnceCallback(func, arg1); |
| // |
| // // |someWGPUFunction| expects callback function with arguments: |
| // // Args... args, void* userdata. |
| // // When it is called, it will forward to func(arg1, args...). |
| // GetProcs().someWGPUFunction( |
| // callback->UnboundCallback(), callback->AsUserdata()); |
| template <typename Callback> |
| class WGPUCallbackBase; |
| |
| template <typename Callback> |
| class WGPUOnceCallback; |
| |
| template <typename Callback> |
| class WGPURepeatingCallback; |
| |
| template <template <typename> class BaseCallbackTemplate, |
| typename R, |
| typename... Args> |
| class WGPUCallbackBase<BaseCallbackTemplate<R(Args...)>> { |
| using BaseCallback = BaseCallbackTemplate<R(Args...)>; |
| |
| static constexpr bool is_once_callback = |
| std::is_same<BaseCallback, base::OnceCallback<R(Args...)>>::value; |
| static constexpr bool is_repeating_callback = |
| std::is_same<BaseCallback, base::RepeatingCallback<R(Args...)>>::value; |
| static_assert( |
| is_once_callback || is_repeating_callback, |
| "Callback must be base::OnceCallback or base::RepeatingCallback"); |
| |
| public: |
| explicit WGPUCallbackBase(BaseCallback callback) |
| : callback_(std::move(callback)) {} |
| |
| void* AsUserdata() { return static_cast<void*>(this); } |
| |
| protected: |
| using UnboundCallbackFunction = R (*)(Args..., void*); |
| |
| static WGPUCallbackBase* FromUserdata(void* userdata) { |
| return static_cast<WGPUCallbackBase*>(userdata); |
| } |
| |
| R Run(Args... args) && { |
| static_assert( |
| is_once_callback, |
| "Run on a moved receiver must only be called on a once callback."); |
| return std::move(callback_).Run(std::forward<Args>(args)...); |
| } |
| |
| R Run(Args... args) const& { |
| static_assert(is_repeating_callback, |
| "Run on a unmoved receiver must only be called on a " |
| "repeating callback."); |
| return callback_.Run(std::forward<Args>(args)...); |
| } |
| |
| private: |
| BaseCallback callback_; |
| }; |
| |
| template <typename R, typename... Args> |
| class WGPUOnceCallback<R(Args...)> |
| : public WGPUCallbackBase<base::OnceCallback<R(Args...)>> { |
| using BaseCallback = base::OnceCallback<R(Args...)>; |
| |
| public: |
| using WGPUCallbackBase<BaseCallback>::WGPUCallbackBase; |
| |
| typename WGPUCallbackBase<BaseCallback>::UnboundCallbackFunction |
| UnboundCallback() { |
| return CallUnboundOnceCallback; |
| } |
| |
| private: |
| static R CallUnboundOnceCallback(Args... args, void* handle) { |
| // After this non-repeating callback is run, it should delete itself. |
| auto callback = |
| std::unique_ptr<WGPUOnceCallback>(static_cast<WGPUOnceCallback*>( |
| WGPUCallbackBase<BaseCallback>::FromUserdata(handle))); |
| return std::move(*callback).Run(std::forward<Args>(args)...); |
| } |
| }; |
| |
| template <typename R, typename... Args> |
| class WGPURepeatingCallback<R(Args...)> |
| : public WGPUCallbackBase<base::RepeatingCallback<R(Args...)>> { |
| using BaseCallback = base::RepeatingCallback<R(Args...)>; |
| |
| public: |
| using WGPUCallbackBase<BaseCallback>::WGPUCallbackBase; |
| |
| typename WGPUCallbackBase<BaseCallback>::UnboundCallbackFunction |
| UnboundCallback() { |
| return CallUnboundRepeatingCallback; |
| } |
| |
| private: |
| static R CallUnboundRepeatingCallback(Args... args, void* handle) { |
| return static_cast<WGPURepeatingCallback*>( |
| WGPUCallbackBase<BaseCallback>::FromUserdata(handle)) |
| ->Run(std::forward<Args>(args)...); |
| } |
| }; |
| |
| template <typename FunctionType, typename... BoundParameters> |
| auto BindWGPUOnceCallback(FunctionType&& function, |
| BoundParameters&&... bound_parameters) { |
| static constexpr bool is_method = |
| base::internal::MakeFunctorTraits<FunctionType>::is_method; |
| static constexpr bool is_weak_method = |
| base::internal::IsWeakMethod<is_method, BoundParameters...>(); |
| static_assert(!is_weak_method, |
| "BindWGPUOnceCallback cannot be used with weak methods"); |
| |
| auto cb = base::BindOnce(std::forward<FunctionType>(function), |
| std::forward<BoundParameters>(bound_parameters)...); |
| return new WGPUOnceCallback<typename decltype(cb)::RunType>(std::move(cb)); |
| } |
| |
| template <typename FunctionType, typename... BoundParameters> |
| auto BindWGPURepeatingCallback(FunctionType&& function, |
| BoundParameters&&... bound_parameters) { |
| auto cb = |
| base::BindRepeating(std::forward<FunctionType>(function), |
| std::forward<BoundParameters>(bound_parameters)...); |
| return std::make_unique< |
| WGPURepeatingCallback<typename decltype(cb)::RunType>>(std::move(cb)); |
| } |
| |
| } // namespace gpu::webgpu |
| |
| #endif // GPU_WEBGPU_CALLBACK_H_ |