diff options
Diffstat (limited to 'dom/canvas/WebGLCommandQueue.h')
-rw-r--r-- | dom/canvas/WebGLCommandQueue.h | 824 |
1 files changed, 824 insertions, 0 deletions
diff --git a/dom/canvas/WebGLCommandQueue.h b/dom/canvas/WebGLCommandQueue.h new file mode 100644 index 0000000000..8c168bfec2 --- /dev/null +++ b/dom/canvas/WebGLCommandQueue.h @@ -0,0 +1,824 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WEBGLCOMMANDQUEUE_H_ +#define WEBGLCOMMANDQUEUE_H_ + +#include <type_traits> +#include "mozilla/FunctionTypeTraits.h" +#include "mozilla/dom/ProducerConsumerQueue.h" +#include "mozilla/ipc/IPDLParamTraits.h" +#include "QueueParamTraits.h" +#include "WebGLTypes.h" + +// Get around a bug in Clang related to __thiscall method pointers +#if defined(_M_IX86) +# define SINK_FCN_CC __thiscall +#else +# define SINK_FCN_CC +#endif + +namespace mozilla { + +using webgl::QueueStatus; + +namespace webgl { + +class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> { + RangedPtr<const uint8_t> mSrcItr; + const RangedPtr<const uint8_t> mSrcEnd; + + public: + auto Remaining() const { return *MaybeAs<size_t>(mSrcEnd - mSrcItr); } + + explicit RangeConsumerView(const Range<const uint8_t> range) + : ConsumerView(this, nullptr, 0), + mSrcItr(range.begin()), + mSrcEnd(range.end()) { + (void)Remaining(); // assert size non-negative + } + + void AlignTo(const size_t alignment) { + const auto offset = AlignmentOffset(alignment, mSrcItr.get()); + if (offset > Remaining()) { + mSrcItr = mSrcEnd; + return; + } + mSrcItr += offset; + } + + template <typename T> + Maybe<Range<const T>> ReadRange(const size_t elemCount) { + AlignTo(alignof(T)); + + constexpr auto elemSize = sizeof(T); + const auto byteSizeChecked = CheckedInt<size_t>(elemCount) * elemSize; + MOZ_RELEASE_ASSERT(byteSizeChecked.isValid()); + const auto& byteSize = byteSizeChecked.value(); + + const auto remaining = Remaining(); + if (byteSize > remaining) return {}; + + const auto begin = reinterpret_cast<const T*>(mSrcItr.get()); + mSrcItr += byteSize; + return Some(Range<const T>{begin, elemCount}); + } +}; + +// - + +namespace details { + +class SizeOnlyProducerView final + : public webgl::ProducerView<SizeOnlyProducerView> { + size_t mRequiredSize = 0; + + public: + SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {} + + template <typename T> + void WriteFromRange(const Range<const T>& src) { + constexpr auto alignment = alignof(T); + const size_t byteSize = ByteSize(src); + // printf_stderr("SizeOnlyProducerView: @%zu +%zu\n", alignment, byteSize); + + const auto offset = AlignmentOffset(alignment, mRequiredSize); + mRequiredSize += offset; + + mRequiredSize += byteSize; + } + + const auto& RequiredSize() const { return mRequiredSize; } +}; + +// - + +class RangeProducerView final : public webgl::ProducerView<RangeProducerView> { + const RangedPtr<uint8_t> mDestBegin; + const RangedPtr<uint8_t> mDestEnd; + RangedPtr<uint8_t> mDestItr; + + public: + auto Remaining() const { return *MaybeAs<size_t>(mDestEnd - mDestItr); } + + explicit RangeProducerView(const Range<uint8_t> range) + : ProducerView(this, 0, nullptr), + mDestBegin(range.begin()), + mDestEnd(range.end()), + mDestItr(mDestBegin) { + (void)Remaining(); // assert size non-negative + } + + template <typename T> + void WriteFromRange(const Range<const T>& src) { + constexpr auto alignment = alignof(T); + const size_t byteSize = ByteSize(src); + // printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize); + + const auto offset = AlignmentOffset(alignment, mDestItr.get()); + mDestItr += offset; + + MOZ_ASSERT(byteSize <= Remaining()); + if (byteSize) { + memcpy(mDestItr.get(), src.begin().get(), byteSize); + } + mDestItr += byteSize; + } +}; + +// - + +template <typename ProducerViewT> +inline void Serialize(ProducerViewT&) {} + +template <typename ProducerViewT, typename Arg, typename... Args> +inline void Serialize(ProducerViewT& view, const Arg& arg, + const Args&... args) { + MOZ_ALWAYS_TRUE(view.WriteParam(arg) == QueueStatus::kSuccess); + Serialize(view, args...); +} + +} // namespace details + +// - + +template <typename... Args> +size_t SerializedSize(const Args&... args) { + webgl::details::SizeOnlyProducerView sizeView; + webgl::details::Serialize(sizeView, args...); + return sizeView.RequiredSize(); +} + +template <typename... Args> +void Serialize(Range<uint8_t> dest, const Args&... args) { + webgl::details::RangeProducerView view(dest); + webgl::details::Serialize(view, args...); +} + +// - + +inline bool Deserialize(RangeConsumerView& view) { return true; } + +template <typename Arg, typename... Args> +inline bool Deserialize(RangeConsumerView& view, Arg& arg, Args&... args) { + if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) return false; + return Deserialize(view, args...); +} + +} // namespace webgl + +// - + +using mozilla::ipc::IPDLParamTraits; + +enum CommandResult { kSuccess, kTimeExpired, kQueueEmpty, kError }; + +enum CommandSyncType { ASYNC, SYNC }; + +/** + * A CommandSource is obtained from a CommandQueue. Use it by inserting a + * command (represented by type Command) using InsertCommand, which also + * needs all parameters to the command. They are then serialized and sent + * to the CommandSink, which must understand the Command+Args combination + * to execute it. + */ +template <typename Command, typename _Source> +class CommandSource { + using Source = _Source; + + public: + explicit CommandSource(UniquePtr<Source>&& aSource) + : mSource(std::move(aSource)) { + MOZ_ASSERT(mSource); + } + + template <typename... Args> + QueueStatus InsertCommand(Command aCommand, Args&&... aArgs) { + return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand, + aArgs...); + } + + QueueStatus InsertCommand(Command aCommand) { + return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand); + } + + template <typename... Args> + QueueStatus RunCommand(Command aCommand, Args&&... aArgs) { + return InsertCommand(aCommand, std::forward<Args>(aArgs)...); + } + + // For IPDL: + CommandSource() = default; + + protected: + friend struct IPDLParamTraits<mozilla::CommandSource<Command, Source>>; + + UniquePtr<Source> mSource; +}; + +/** + * A CommandSink is obtained from a CommandQueue. It executes commands that + * originated in its CommandSource. Use this class by calling one of the + * Process methods, which will autonomously deserialize, dispatch and + * post-process the execution. This class handles deserialization -- dispatch + * and processing are to be provided by a subclass in its implementation of the + * pure-virtual DispatchCommand method. DispatchCommand implementations can + * easily run functions and methods using arguments taken from the command + * queue by calling the Dispatch methods in this class. + */ +template <typename Command, typename _Sink> +class CommandSink { + using Sink = _Sink; + + public: + explicit CommandSink(UniquePtr<Sink>&& aSink) : mSink(std::move(aSink)) { + MOZ_ASSERT(mSink); + } + + /** + * Attempts to process the next command in the queue, if one is available. + */ + CommandResult ProcessOne(const Maybe<TimeDuration>& aTimeout) { + Command command; + QueueStatus status = (aTimeout.isNothing() || aTimeout.value()) + ? this->mSink->TryWaitRemove(aTimeout, command) + : this->mSink->TryRemove(command); + + if (status == QueueStatus::kSuccess) { + if (DispatchCommand(command)) { + return CommandResult::kSuccess; + } + return CommandResult::kError; + } + + if (status == QueueStatus::kNotReady) { + return CommandResult::kQueueEmpty; + } + + if (status == QueueStatus::kOOMError) { + ReportOOM(); + } + return CommandResult::kError; + } + + CommandResult ProcessOneNow() { return ProcessOne(Some(TimeDuration(0))); } + + /** + * Drains the queue until the queue is empty or an error occurs, whichever + * comes first. + * Returns the result of the last attempt to process a command, which will + * be either QueueEmpty or Error. + */ + CommandResult ProcessAll() { + CommandResult result; + do { + result = ProcessOneNow(); + } while (result == CommandResult::kSuccess); + return result; + } + + /** + * Drains the queue until aDuration expires, the queue is empty, or an error + * occurs, whichever comes first. + * Returns the result of the last attempt to process a command. + */ + CommandResult ProcessUpToDuration(TimeDuration aDuration) { + TimeStamp start = TimeStamp::Now(); + TimeStamp now = start; + CommandResult result; + + do { + result = ProcessOne(Some(aDuration - (now - start))); + now = TimeStamp::Now(); + } while ((result == CommandResult::kSuccess) && + ((now - start) < aDuration)); + return result; + } + + // For IPDL: + CommandSink() = default; + + // non-void return value, non-const method variant + template <typename T, typename ReturnType, typename... Args> + bool DispatchAsyncMethod(T& aObj, ReturnType (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!ReadArgs(args)) { + return false; + } + CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{}); + return true; + } + + // non-void return value, const method variant + template <typename T, typename ReturnType, typename... Args> + bool DispatchAsyncMethod(const T& aObj, + ReturnType (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!ReadArgs(args)) { + return false; + } + CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{}); + return true; + } + + // void return value, non-const method variant + template <typename T, typename... Args> + bool DispatchAsyncMethod(T* aObj, void (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!ReadArgs(args)) { + return false; + } + + CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{}); + return true; + } + + // void return value, const method variant + template <typename T, typename... Args> + bool DispatchAsyncMethod(const T* aObj, void (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!ReadArgs(args)) { + return false; + } + + CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{}); + return true; + } + + protected: + friend struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>>; + + /** + * Implementations will usually be something like a big switch statement + * that calls one of the Dispatch methods in this class. + */ + virtual bool DispatchCommand(Command command) = 0; + + /** + * Implementations can override this to detect out-of-memory during + * deserialization. + */ + virtual void ReportOOM() {} + + template <typename... Args, size_t... Indices> + QueueStatus CallTryRemove(std::tuple<Args...>& aArgs, + std::index_sequence<Indices...>) { + QueueStatus status = mSink->TryRemove(std::get<Indices>(aArgs)...); + // The CommandQueue inserts the command and the args together as an atomic + // operation. We already read the command so the args must also be + // available. + MOZ_ASSERT(status != QueueStatus::kNotReady); + return status; + } + + QueueStatus CallTryRemove(std::tuple<>& aArgs, + std::make_integer_sequence<size_t, 0>) { + return QueueStatus::kSuccess; + } + + template <typename T, typename MethodType, typename... Args, + size_t... Indices, + typename ReturnType = + typename mozilla::FunctionTypeTraits<MethodType>::ReturnType> + ReturnType CallMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs, + std::index_sequence<Indices...>) { + return (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...); + } + + template <typename T, typename MethodType, typename... Args, + size_t... Indices> + void CallVoidMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs, + std::index_sequence<Indices...>) { + (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...); + } + + template <typename... Args> + bool ReadArgs(std::tuple<Args...>& aArgs) { + QueueStatus status = + CallTryRemove(aArgs, std::index_sequence_for<Args...>{}); + return IsSuccess(status); + } + + UniquePtr<Sink> mSink; +}; + +enum SyncResponse : uint8_t { RESPONSE_NAK, RESPONSE_ACK }; + +/** + * This is the Source for a SyncCommandSink. It takes an extra queue, + * the ResponseQueue, and uses it to receive synchronous responses from + * the sink. The ResponseQueue is a regular queue, not a CommandQueue. + */ +template <typename Command, typename _Source, typename _ResponseQueue> +class SyncCommandSource : public CommandSource<Command, _Source> { + public: + using BaseType = CommandSource<Command, _Source>; + using Source = _Source; + using ResponseQueue = _ResponseQueue; + using ResponseSink = typename ResponseQueue::Consumer; + + SyncCommandSource(UniquePtr<Source>&& aSource, + UniquePtr<ResponseSink>&& aResponseSink) + : CommandSource<Command, Source>(std::move(aSource)), + mResponseSink(std::move(aResponseSink)) {} + + template <typename... Args> + QueueStatus RunAsyncCommand(Command aCommand, Args&&... aArgs) { + return this->RunCommand(aCommand, std::forward<Args>(aArgs)...); + } + + template <typename... Args> + QueueStatus RunVoidSyncCommand(Command aCommand, Args&&... aArgs) { + QueueStatus status = + RunAsyncCommand(aCommand, std::forward<Args>(aArgs)...); + return IsSuccess(status) ? this->ReadSyncResponse() : status; + } + + template <typename ResultType, typename... Args> + QueueStatus RunSyncCommand(Command aCommand, ResultType& aReturn, + Args&&... aArgs) { + QueueStatus status = + RunVoidSyncCommand(aCommand, std::forward<Args>(aArgs)...); + return IsSuccess(status) ? this->ReadResult(aReturn) : status; + } + + // for IPDL: + SyncCommandSource() = default; + friend struct mozilla::ipc::IPDLParamTraits< + SyncCommandSource<Command, Source, ResponseQueue>>; + + protected: + QueueStatus ReadSyncResponse() { + SyncResponse response; + QueueStatus status = + mResponseSink->TryWaitRemove(Nothing() /* wait forever */, response); + MOZ_ASSERT(status != QueueStatus::kNotReady); + + if (IsSuccess(status) && response != RESPONSE_ACK) { + return QueueStatus::kFatalError; + } + return status; + } + + template <typename T> + QueueStatus ReadResult(T& aResult) { + QueueStatus status = mResponseSink->TryRemove(aResult); + // The Sink posts the response code and result as an atomic transaction. We + // already read the response code so the result must be available. + MOZ_ASSERT(status != QueueStatus::kNotReady); + return status; + } + + UniquePtr<ResponseSink> mResponseSink; +}; + +/** + * This is the Sink for a SyncCommandSource. It takes an extra queue, the + * ResponseQueue, and uses it to issue synchronous responses to the client. + * Subclasses can use the DispatchSync methods in this class in their + * DispatchCommand implementations. + * The ResponseQueue is not a CommandQueue. + */ +template <typename Command, typename _Sink, typename _ResponseQueue> +class SyncCommandSink : public CommandSink<Command, _Sink> { + using BaseType = CommandSink<Command, _Sink>; + using ResponseQueue = _ResponseQueue; + using Sink = _Sink; + using ResponseSource = typename ResponseQueue::Producer; + + public: + SyncCommandSink(UniquePtr<Sink>&& aSink, + UniquePtr<ResponseSource>&& aResponseSource) + : CommandSink<Command, Sink>(std::move(aSink)), + mResponseSource(std::move(aResponseSource)) { + MOZ_ASSERT(mResponseSource); + } + + // for IPDL: + SyncCommandSink() = default; + friend struct mozilla::ipc::IPDLParamTraits< + SyncCommandSink<Command, Sink, ResponseQueue>>; + + // Places RESPONSE_ACK and the typed return value, or RESPONSE_NAK, in + // the response queue, + // __cdecl/__thiscall non-const method variant. + template <typename T, typename ReturnType, typename... Args> + bool DispatchSyncMethod(T& aObj, + ReturnType SINK_FCN_CC (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + ReturnType response = BaseType::CallMethod( + aObj, aMethod, args, std::index_sequence_for<Args...>{}); + + return WriteACK(response); + } + + // __cdecl/__thiscall const method variant. + template <typename T, typename ReturnType, typename... Args> + bool DispatchSyncMethod(const T& aObj, + ReturnType SINK_FCN_CC (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + ReturnType response = BaseType::CallMethod( + aObj, aMethod, args, std::index_sequence_for<Args...>{}); + + return WriteACK(response); + } + +#if defined(_M_IX86) + // __stdcall non-const method variant. + template <typename T, typename ReturnType, typename... Args> + bool DispatchSyncMethod(T& aObj, + ReturnType __stdcall (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + ReturnType response = BaseType::CallMethod( + aObj, aMethod, args, std::index_sequence_for<Args...>{}); + + return WriteACK(response); + } + + // __stdcall const method variant. + template <typename T, typename ReturnType, typename... Args> + bool DispatchSyncMethod(const T& aObj, + ReturnType __stdcall (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + ReturnType response = BaseType::CallMethod( + aObj, aMethod, args, std::index_sequence_for<Args...>{}); + + return WriteACK(response); + } +#endif + + // __cdecl/__thiscall non-const void method variant + template <typename T, typename... Args> + bool DispatchSyncMethod(T& aObj, void SINK_FCN_CC (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + BaseType::CallVoidMethod(aObj, aMethod, args, + std::index_sequence_for<Args...>{}); + return WriteACK(); + } + + // __cdecl/__thiscall const void method variant + template <typename T, typename... Args> + bool DispatchSyncMethod(const T& aObj, + void SINK_FCN_CC (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + BaseType::CallVoidMethod(aObj, aMethod, args, + std::index_sequence_for<Args...>{}); + return WriteACK(); + } + +#if defined(_M_IX86) + // __stdcall non-const void method variant + template <typename T, typename... Args> + bool DispatchSyncMethod(T& aObj, void __stdcall (T::*aMethod)(Args...)) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + BaseType::CallVoidMethod(aObj, aMethod, args, + std::index_sequence_for<Args...>{}); + return WriteACK(); + } + + // __stdcall const void method variant + template <typename T, typename... Args> + bool DispatchSyncMethod(const T& aObj, + void __stdcall (T::*aMethod)(Args...) const) { + std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args; + if (!BaseType::ReadArgs(args)) { + WriteNAK(); + return false; + } + + BaseType::CallVoidMethod(aObj, aMethod, args, + std::index_sequence_for<Args...>{}); + return WriteACK(); + } +#endif + + protected: + template <typename... Args> + bool WriteArgs(const Args&... aArgs) { + return IsSuccess(mResponseSource->TryInsert(aArgs...)); + } + + template <typename... Args> + bool WriteACK(const Args&... aArgs) { + SyncResponse ack = RESPONSE_ACK; + return WriteArgs(ack, aArgs...); + } + + bool WriteNAK() { + SyncResponse nak = RESPONSE_NAK; + return WriteArgs(nak); + } + + UniquePtr<ResponseSource> mResponseSource; +}; + +// The MethodDispatcher setup uses a CommandSink to read parameters, call the +// given method using the given synchronization protocol, and provide +// compile-time lookup of the ID by class method. +// To use this system, first define a dispatcher subclass of +// EmptyMethodDispatcher. This class must be parameterized by command ID. +// +// Example: +// template <size_t id=0> class MyDispatcher +// : public EmptyMethodDispatcher<MyDispatcher> {}; +// +// Then, for each command handled, specialize this to subclass MethodDispatcher. +// The subclass must define the Method. It may optionally define isSync for +// synchronous methods. +// +// Example: +// template <> +// class MyDispatcher<0> +// : public MethodDispatcher<MyDispatcher, 0, +// decltype(&MyClass::MyMethod), MyClass::MyMethod, +// CommandSyncType::ASYNC> {}; +// +// The method may then be called from the source and run on the sink. +// +// Example: +// int result = Run<MyClass::MyMethod>(param1, std::move(param2)); + +template <template <size_t> typename Derived> +class EmptyMethodDispatcher { + public: + template <typename ObjectT> + static MOZ_ALWAYS_INLINE bool DispatchCommand(ObjectT&, const size_t, + webgl::RangeConsumerView&) { + MOZ_CRASH("Illegal ID in DispatchCommand"); + } + static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t) { + MOZ_CRASH("Illegal ID in SyncType"); + } +}; + +// - + +template <typename ReturnT, typename ObjectT, typename... Args> +std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple( + ReturnT (ObjectT::*)(Args... args)) { + return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{}; +} + +template <typename ReturnT, typename ObjectT, typename... Args> +std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple( + ReturnT (ObjectT::*)(Args... args) const) { + return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{}; +} + +// Derived type must be parameterized by the ID. +template <template <size_t> typename Derived, size_t ID, typename MethodType, + MethodType method, CommandSyncType syncType> +class MethodDispatcher { + static constexpr size_t kId = ID; + using DerivedType = Derived<ID>; + using NextDispatcher = Derived<ID + 1>; + + public: + template <typename ObjectT> + static MOZ_ALWAYS_INLINE bool DispatchCommand( + ObjectT& obj, const size_t id, webgl::RangeConsumerView& view) { + if (id == kId) { + auto argsTuple = ArgsTuple(method); + + return std::apply( + [&](auto&... args) { + if (!webgl::Deserialize(view, args...)) return false; + (obj.*method)(args...); + return true; + }, + argsTuple); + } + return Derived<kId + 1>::DispatchCommand(obj, id, view); + } + + static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) { + return (aId == kId) ? syncType : NextDispatcher::SyncType(kId); + } + + static constexpr CommandSyncType SyncType() { return syncType; } + static constexpr size_t Id() { return kId; } + static constexpr MethodType Method() { return method; } +}; + +namespace ipc { +template <typename T> +struct IPDLParamTraits; + +template <typename Command, typename Source> +struct IPDLParamTraits<mozilla::CommandSource<Command, Source>> { + public: + typedef mozilla::CommandSource<Command, Source> paramType; + + static void Write(IPC::Message* aMsg, IProtocol* aActor, + const paramType& aParam) { + WriteIPDLParam(aMsg, aActor, aParam.mSource); + } + + static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, + IProtocol* aActor, paramType* aResult) { + return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSource); + } +}; + +template <typename Command, typename Sink> +struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>> { + public: + typedef mozilla::CommandSink<Command, Sink> paramType; + + static void Write(IPC::Message* aMsg, IProtocol* aActor, + const paramType& aParam) { + WriteIPDLParam(aMsg, aActor, aParam.mSink); + } + + static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, + IProtocol* aActor, paramType* aResult) { + return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSink); + } +}; + +template <typename Command, typename Source, typename ResponseQueue> +struct IPDLParamTraits< + mozilla::SyncCommandSource<Command, Source, ResponseQueue>> + : public IPDLParamTraits<mozilla::CommandSource<Command, Source>> { + public: + typedef mozilla::SyncCommandSource<Command, Source, ResponseQueue> paramType; + typedef typename paramType::BaseType paramBaseType; + + static void Write(IPC::Message* aMsg, IProtocol* aActor, + const paramType& aParam) { + WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam)); + WriteIPDLParam(aMsg, aActor, aParam.mResponseSink); + } + + static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, + IProtocol* aActor, paramType* aParam) { + bool result = + ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam)); + return result && ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSink); + } +}; + +template <typename Command, typename Sink, typename ResponseQueue> +struct IPDLParamTraits<mozilla::SyncCommandSink<Command, Sink, ResponseQueue>> + : public IPDLParamTraits<mozilla::CommandSink<Command, Sink>> { + public: + typedef mozilla::SyncCommandSink<Command, Sink, ResponseQueue> paramType; + typedef typename paramType::BaseType paramBaseType; + + static void Write(IPC::Message* aMsg, IProtocol* aActor, + const paramType& aParam) { + WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam)); + WriteIPDLParam(aMsg, aActor, aParam.mResponseSource); + } + + static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, + IProtocol* aActor, paramType* aParam) { + bool result = + ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam)); + return result && + ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSource); + } +}; + +} // namespace ipc + +} // namespace mozilla + +#endif // WEBGLCOMMANDQUEUE_H_ |