1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGLCOMMANDQUEUE_H_
7 #define WEBGLCOMMANDQUEUE_H_
10 #include "mozilla/FunctionTypeTraits.h"
11 #include "mozilla/gfx/Logging.h"
12 #include "mozilla/ipc/IPDLParamTraits.h"
13 #include "QueueParamTraits.h"
14 #include "WebGLTypes.h"
20 class RangeConsumerView final
: public webgl::ConsumerView
<RangeConsumerView
> {
21 RangedPtr
<const uint8_t> mSrcItr
;
22 const RangedPtr
<const uint8_t> mSrcEnd
;
25 auto Remaining() const { return *MaybeAs
<size_t>(mSrcEnd
- mSrcItr
); }
27 explicit RangeConsumerView(const Range
<const uint8_t> range
)
28 : ConsumerView(this), mSrcItr(range
.begin()), mSrcEnd(range
.end()) {
29 (void)Remaining(); // assert size non-negative
32 void AlignTo(const size_t alignment
) {
33 const auto padToAlign
= AlignmentOffset(alignment
, mSrcItr
.get());
34 if (MOZ_UNLIKELY(padToAlign
> Remaining())) {
38 mSrcItr
+= padToAlign
;
42 Maybe
<Range
<const T
>> ReadRange(const size_t elemCount
) {
43 constexpr auto alignment
= alignof(T
);
46 constexpr auto elemSize
= sizeof(T
);
47 const auto byteSizeChecked
= CheckedInt
<size_t>(elemCount
) * elemSize
;
48 MOZ_RELEASE_ASSERT(byteSizeChecked
.isValid());
49 const auto& byteSize
= byteSizeChecked
.value();
51 const auto remaining
= Remaining();
52 if (MOZ_UNLIKELY(byteSize
> remaining
)) return {};
54 const auto begin
= reinterpret_cast<const T
*>(mSrcItr
.get());
56 return Some(Range
<const T
>{begin
, elemCount
});
64 class SizeOnlyProducerView final
65 : public webgl::ProducerView
<SizeOnlyProducerView
> {
67 size_t requiredByteCount
= 0;
68 size_t alignmentOverhead
= 0;
73 SizeOnlyProducerView() : ProducerView(this) {}
76 bool WriteFromRange(const Range
<const T
>& src
) {
77 constexpr auto alignment
= alignof(T
);
78 const size_t byteSize
= ByteSize(src
);
79 // printf_stderr("SizeOnlyProducerView: @%zu +%zu\n", alignment, byteSize);
81 const auto padToAlign
= AlignmentOffset(alignment
, mInfo
.requiredByteCount
);
82 mInfo
.alignmentOverhead
+= padToAlign
;
84 mInfo
.requiredByteCount
+= padToAlign
;
85 mInfo
.requiredByteCount
+= byteSize
;
89 const auto& Info() const { return mInfo
; }
94 class RangeProducerView final
: public webgl::ProducerView
<RangeProducerView
> {
95 const RangedPtr
<uint8_t> mDestBegin
;
96 const RangedPtr
<uint8_t> mDestEnd
;
97 RangedPtr
<uint8_t> mDestItr
;
100 auto Remaining() const { return *MaybeAs
<size_t>(mDestEnd
- mDestItr
); }
102 explicit RangeProducerView(const Range
<uint8_t> range
)
103 : ProducerView(this),
104 mDestBegin(range
.begin()),
105 mDestEnd(range
.end()),
106 mDestItr(mDestBegin
) {
107 (void)Remaining(); // assert size non-negative
110 template <typename T
>
111 bool WriteFromRange(const Range
<const T
>& src
) {
112 // uint32_t/float data may masquerade as a Range<uint8_t>.
113 constexpr auto alignment
= alignof(T
);
114 const size_t byteSize
= ByteSize(src
);
115 // printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize);
117 const auto padToAlign
= AlignmentOffset(alignment
, mDestItr
.get());
118 mDestItr
+= padToAlign
;
120 MOZ_ASSERT(byteSize
<= Remaining());
121 if (MOZ_LIKELY(byteSize
)) {
122 memcpy(mDestItr
.get(), src
.begin().get(), byteSize
);
124 mDestItr
+= byteSize
;
131 template <typename ProducerViewT
>
132 inline void Serialize(ProducerViewT
&) {}
134 template <typename ProducerViewT
, typename Arg
, typename
... Args
>
135 inline void Serialize(ProducerViewT
& view
, const Arg
& arg
,
136 const Args
&... args
) {
137 MOZ_ALWAYS_TRUE(view
.WriteParam(arg
));
138 Serialize(view
, args
...);
141 } // namespace details
145 template <typename
... Args
>
146 auto SerializationInfo(const Args
&... args
) {
147 webgl::details::SizeOnlyProducerView sizeView
;
148 webgl::details::Serialize(sizeView
, args
...);
149 return sizeView
.Info();
152 template <typename
... Args
>
153 void Serialize(Range
<uint8_t> dest
, const Args
&... args
) {
154 webgl::details::RangeProducerView
view(dest
);
155 webgl::details::Serialize(view
, args
...);
160 inline Maybe
<uint16_t> Deserialize(RangeConsumerView
&, size_t) { return {}; }
162 template <typename Arg
, typename
... Args
>
163 inline Maybe
<uint16_t> Deserialize(RangeConsumerView
& view
,
164 const uint16_t argId
, Arg
& arg
,
166 if (!webgl::QueueParamTraits
<Arg
>::Read(view
, &arg
)) {
169 return Deserialize(view
, argId
+ 1, args
...);
176 template <class R
, class... Args
>
177 using fn_t
= R(Args
...);
179 // The MethodDispatcher setup uses a CommandSink to read parameters, call the
180 // given method using the given synchronization protocol, and provide
181 // compile-time lookup of the ID by class method.
182 // To use this system, first define a dispatcher subclass of
183 // EmptyMethodDispatcher. This class must be parameterized by command ID.
186 // template <size_t id=0> class MyDispatcher
187 // : public EmptyMethodDispatcher<MyDispatcher> {};
189 // Then, for each command handled, specialize this to subclass MethodDispatcher.
190 // The subclass must define the Method. It may optionally define isSync for
191 // synchronous methods.
195 // class MyDispatcher<0>
196 // : public MethodDispatcher<MyDispatcher, 0,
197 // decltype(&MyClass::MyMethod), MyClass::MyMethod> {};
199 // The method may then be called from the source and run on the sink.
202 // int result = Run<MyClass::MyMethod>(param1, std::move(param2));
204 template <template <size_t> typename Derived
>
205 class EmptyMethodDispatcher
{
207 template <typename ObjectT
>
208 static constexpr fn_t
<bool, ObjectT
&, webgl::RangeConsumerView
&>*
209 DispatchCommandFuncById(const size_t id
) {
216 template <typename ReturnT
, typename ObjectT
, typename
... Args
>
217 std::tuple
<std::remove_cv_t
<std::remove_reference_t
<Args
>>...> ArgsTuple(
218 ReturnT (ObjectT::*)(Args
... args
)) {
219 return std::tuple
<std::remove_cv_t
<std::remove_reference_t
<Args
>>...>{};
222 template <typename ReturnT
, typename ObjectT
, typename
... Args
>
223 std::tuple
<std::remove_cv_t
<std::remove_reference_t
<Args
>>...> ArgsTuple(
224 ReturnT (ObjectT::*)(Args
... args
) const) {
225 return std::tuple
<std::remove_cv_t
<std::remove_reference_t
<Args
>>...>{};
228 // Derived type must be parameterized by the ID.
229 template <template <size_t> typename Derived
, size_t _Id
, typename MethodType
,
231 class MethodDispatcher
{
232 static constexpr auto Id
= _Id
;
233 static constexpr auto Method
= _Method
;
234 using DerivedType
= Derived
<Id
>;
237 template <class ObjectT
>
238 static constexpr fn_t
<bool, ObjectT
&, webgl::RangeConsumerView
&>*
239 DispatchCommandFuncById(const size_t targetId
) {
241 return Derived
<Id
+ 1>::template DispatchCommandFuncById
<ObjectT
>(
244 return [](ObjectT
& obj
, webgl::RangeConsumerView
& view
) -> bool {
245 const auto viewWas
= view
;
246 (void)viewWas
; // For debugging.
248 auto argsTuple
= ArgsTuple(Method
);
251 const auto badArgId
= webgl::Deserialize(view
, 1, args
...);
253 const auto& name
= DerivedType::Name();
254 gfxCriticalError() << "webgl::Deserialize failed for " << name
255 << " arg " << *badArgId
;
258 (obj
.*Method
)(args
...);
266 } // namespace mozilla
268 #endif // WEBGLCOMMANDQUEUE_H_