/* -*- 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 #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 { RangedPtr mSrcItr; const RangedPtr mSrcEnd; public: auto Remaining() const { return *MaybeAs(mSrcEnd - mSrcItr); } explicit RangeConsumerView(const Range 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 Maybe> ReadRange(const size_t elemCount) { constexpr auto alignment = alignof(T); AlignTo(alignment); constexpr auto elemSize = sizeof(T); const auto byteSizeChecked = CheckedInt(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(mSrcItr.get()); mSrcItr += byteSize; return Some(Range{begin, elemCount}); } }; // - namespace details { class SizeOnlyProducerView final : public webgl::ProducerView { struct Info { size_t requiredByteCount = 0; size_t alignmentOverhead = 0; }; Info mInfo; public: SizeOnlyProducerView() : ProducerView(this) {} template bool WriteFromRange(const Range& 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 { const RangedPtr mDestBegin; const RangedPtr mDestEnd; RangedPtr mDestItr; public: auto Remaining() const { return *MaybeAs(mDestEnd - mDestItr); } explicit RangeProducerView(const Range range) : ProducerView(this), mDestBegin(range.begin()), mDestEnd(range.end()), mDestItr(mDestBegin) { (void)Remaining(); // assert size non-negative } template bool WriteFromRange(const Range& src) { // uint32_t/float data may masquerade as a Range. 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 inline void Serialize(ProducerViewT&) {} template inline void Serialize(ProducerViewT& view, const Arg& arg, const Args&... args) { MOZ_ALWAYS_TRUE(view.WriteParam(arg)); Serialize(view, args...); } } // namespace details // - template auto SerializationInfo(const Args&... args) { webgl::details::SizeOnlyProducerView sizeView; webgl::details::Serialize(sizeView, args...); return sizeView.Info(); } template void Serialize(Range dest, const Args&... args) { webgl::details::RangeProducerView view(dest); webgl::details::Serialize(view, args...); } // - inline Maybe Deserialize(RangeConsumerView&, size_t) { return {}; } template inline Maybe Deserialize(RangeConsumerView& view, const uint16_t argId, Arg& arg, Args&... args) { if (!webgl::QueueParamTraits::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 class MyDispatcher // : public EmptyMethodDispatcher {}; // // 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 {}; // // The method may then be called from the source and run on the sink. // // Example: // int result = Run(param1, std::move(param2)); template