Backed out 4 changesets (bug 1858627) for causing clipboard/paste failures. CLOSED...
[gecko.git] / dom / canvas / WebGLCommandQueue.h
blobb10c11f67ffd9e781c8477bab8c914f702ade495
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_
9 #include <type_traits>
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"
16 namespace mozilla {
18 namespace webgl {
20 class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
21 RangedPtr<const uint8_t> mSrcItr;
22 const RangedPtr<const uint8_t> mSrcEnd;
24 public:
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())) {
35 mSrcItr = mSrcEnd;
36 return;
38 mSrcItr += padToAlign;
41 template <typename T>
42 Maybe<Range<const T>> ReadRange(const size_t elemCount) {
43 constexpr auto alignment = alignof(T);
44 AlignTo(alignment);
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());
55 mSrcItr += byteSize;
56 return Some(Range<const T>{begin, elemCount});
60 // -
62 namespace details {
64 class SizeOnlyProducerView final
65 : public webgl::ProducerView<SizeOnlyProducerView> {
66 struct Info {
67 size_t requiredByteCount = 0;
68 size_t alignmentOverhead = 0;
70 Info mInfo;
72 public:
73 SizeOnlyProducerView() : ProducerView(this) {}
75 template <typename T>
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;
86 return true;
89 const auto& Info() const { return mInfo; }
92 // -
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;
99 public:
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;
125 return true;
129 // -
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
143 // -
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...);
158 // -
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,
165 Args&... args) {
166 if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) {
167 return Some(argId);
169 return Deserialize(view, argId + 1, args...);
172 } // namespace webgl
174 // -
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.
185 // Example:
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.
193 // Example:
194 // template <>
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.
201 // Example:
202 // int result = Run<MyClass::MyMethod>(param1, std::move(param2));
204 template <template <size_t> typename Derived>
205 class EmptyMethodDispatcher {
206 public:
207 template <typename ObjectT>
208 static constexpr fn_t<bool, ObjectT&, webgl::RangeConsumerView&>*
209 DispatchCommandFuncById(const size_t id) {
210 return nullptr;
214 // -
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,
230 MethodType _Method>
231 class MethodDispatcher {
232 static constexpr auto Id = _Id;
233 static constexpr auto Method = _Method;
234 using DerivedType = Derived<Id>;
236 public:
237 template <class ObjectT>
238 static constexpr fn_t<bool, ObjectT&, webgl::RangeConsumerView&>*
239 DispatchCommandFuncById(const size_t targetId) {
240 if (targetId != Id)
241 return Derived<Id + 1>::template DispatchCommandFuncById<ObjectT>(
242 targetId);
244 return [](ObjectT& obj, webgl::RangeConsumerView& view) -> bool {
245 const auto viewWas = view;
246 (void)viewWas; // For debugging.
248 auto argsTuple = ArgsTuple(Method);
249 return std::apply(
250 [&](auto&... args) {
251 const auto badArgId = webgl::Deserialize(view, 1, args...);
252 if (badArgId) {
253 const auto& name = DerivedType::Name();
254 gfxCriticalError() << "webgl::Deserialize failed for " << name
255 << " arg " << *badArgId;
256 return false;
258 (obj.*Method)(args...);
259 return true;
261 argsTuple);
266 } // namespace mozilla
268 #endif // WEBGLCOMMANDQUEUE_H_