summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLCommandQueue.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLCommandQueue.h')
-rw-r--r--dom/canvas/WebGLCommandQueue.h267
1 files changed, 267 insertions, 0 deletions
diff --git a/dom/canvas/WebGLCommandQueue.h b/dom/canvas/WebGLCommandQueue.h
new file mode 100644
index 0000000000..bbbb1034c1
--- /dev/null
+++ b/dom/canvas/WebGLCommandQueue.h
@@ -0,0 +1,267 @@
+/* -*- 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/gfx/Logging.h"
+#include "mozilla/ipc/IPDLParamTraits.h"
+#include "QueueParamTraits.h"
+#include "WebGLTypes.h"
+
+namespace mozilla {
+
+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), mSrcItr(range.begin()), mSrcEnd(range.end()) {
+ (void)Remaining(); // assert size non-negative
+ }
+
+ void AlignTo(const size_t alignment) {
+ const auto padToAlign = AlignmentOffset(alignment, mSrcItr.get());
+ if (MOZ_UNLIKELY(padToAlign > Remaining())) {
+ mSrcItr = mSrcEnd;
+ return;
+ }
+ mSrcItr += padToAlign;
+ }
+
+ template <typename T>
+ Maybe<Range<const T>> ReadRange(const size_t elemCount) {
+ constexpr auto alignment = alignof(T);
+ AlignTo(alignment);
+
+ 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 (MOZ_UNLIKELY(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> {
+ struct Info {
+ size_t requiredByteCount = 0;
+ size_t alignmentOverhead = 0;
+ };
+ Info mInfo;
+
+ public:
+ SizeOnlyProducerView() : ProducerView(this) {}
+
+ template <typename T>
+ bool 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 padToAlign = AlignmentOffset(alignment, mInfo.requiredByteCount);
+ mInfo.alignmentOverhead += padToAlign;
+
+ mInfo.requiredByteCount += padToAlign;
+ mInfo.requiredByteCount += byteSize;
+ return true;
+ }
+
+ const auto& Info() const { return mInfo; }
+};
+
+// -
+
+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),
+ mDestBegin(range.begin()),
+ mDestEnd(range.end()),
+ mDestItr(mDestBegin) {
+ (void)Remaining(); // assert size non-negative
+ }
+
+ template <typename T>
+ bool WriteFromRange(const Range<const T>& src) {
+ // uint32_t/float data may masquerade as a Range<uint8_t>.
+ constexpr auto alignment = alignof(T);
+ const size_t byteSize = ByteSize(src);
+ // printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize);
+
+ const auto padToAlign = AlignmentOffset(alignment, mDestItr.get());
+ mDestItr += padToAlign;
+
+ MOZ_ASSERT(byteSize <= Remaining());
+ if (MOZ_LIKELY(byteSize)) {
+ memcpy(mDestItr.get(), src.begin().get(), byteSize);
+ }
+ mDestItr += byteSize;
+ return true;
+ }
+};
+
+// -
+
+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));
+ Serialize(view, args...);
+}
+
+} // namespace details
+
+// -
+
+template <typename... Args>
+auto SerializationInfo(const Args&... args) {
+ webgl::details::SizeOnlyProducerView sizeView;
+ webgl::details::Serialize(sizeView, args...);
+ return sizeView.Info();
+}
+
+template <typename... Args>
+void Serialize(Range<uint8_t> dest, const Args&... args) {
+ webgl::details::RangeProducerView view(dest);
+ webgl::details::Serialize(view, args...);
+}
+
+// -
+
+inline Maybe<uint16_t> Deserialize(RangeConsumerView&, size_t) { return {}; }
+
+template <typename Arg, typename... Args>
+inline Maybe<uint16_t> Deserialize(RangeConsumerView& view,
+ const uint16_t argId, Arg& arg,
+ Args&... args) {
+ if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) {
+ return Some(argId);
+ }
+ return Deserialize(view, argId + 1, args...);
+}
+
+} // namespace webgl
+
+// 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> {};
+//
+// 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 id,
+ webgl::RangeConsumerView&) {
+ const nsPrintfCString cstr(
+ "MethodDispatcher<%i> not found. Please file a bug!", int(id));
+ const auto str = ToString(cstr);
+ gfxCriticalError() << str;
+ return false;
+ }
+};
+
+// -
+
+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>
+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);
+
+ const auto viewWas = view;
+ (void)viewWas; // For debugging.
+ return std::apply(
+ [&](auto&... args) {
+ const auto badArgId = webgl::Deserialize(view, 1, args...);
+ if (badArgId) {
+ const auto& name = DerivedType::Name();
+ gfxCriticalError() << "webgl::Deserialize failed for " << name
+ << " arg " << *badArgId;
+ return false;
+ }
+ (obj.*method)(args...);
+ return true;
+ },
+ argsTuple);
+ }
+ return Derived<kId + 1>::DispatchCommand(obj, id, view);
+ }
+
+ static constexpr size_t Id() { return kId; }
+ static constexpr MethodType Method() { return method; }
+};
+
+} // namespace mozilla
+
+#endif // WEBGLCOMMANDQUEUE_H_