WebGLCommandQueue.h (8022B)
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/. */ 5 6 #ifndef WEBGLCOMMANDQUEUE_H_ 7 #define WEBGLCOMMANDQUEUE_H_ 8 9 #include <type_traits> 10 11 #include "QueueParamTraits.h" 12 #include "WebGLTypes.h" 13 #include "mozilla/gfx/Logging.h" 14 15 namespace mozilla { 16 17 namespace webgl { 18 19 class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> { 20 RangedPtr<const uint8_t> mSrcItr; 21 const RangedPtr<const uint8_t> mSrcEnd; 22 23 public: 24 auto Remaining() const { return *MaybeAs<size_t>(mSrcEnd - mSrcItr); } 25 26 explicit RangeConsumerView(const Range<const uint8_t> range) 27 : ConsumerView(this), mSrcItr(range.begin()), mSrcEnd(range.end()) { 28 (void)Remaining(); // assert size non-negative 29 } 30 31 void AlignTo(const size_t alignment) { 32 const auto padToAlign = AlignmentOffset(alignment, mSrcItr.get()); 33 if (MOZ_UNLIKELY(padToAlign > Remaining())) { 34 mSrcItr = mSrcEnd; 35 return; 36 } 37 mSrcItr += padToAlign; 38 } 39 40 template <typename T> 41 Maybe<Range<const T>> ReadRange(const size_t elemCount) { 42 constexpr auto alignment = alignof(T); 43 AlignTo(alignment); 44 45 constexpr auto elemSize = sizeof(T); 46 const auto byteSizeChecked = CheckedInt<size_t>(elemCount) * elemSize; 47 MOZ_RELEASE_ASSERT(byteSizeChecked.isValid()); 48 const auto& byteSize = byteSizeChecked.value(); 49 50 const auto remaining = Remaining(); 51 if (MOZ_UNLIKELY(byteSize > remaining)) return {}; 52 53 const auto begin = reinterpret_cast<const T*>(mSrcItr.get()); 54 mSrcItr += byteSize; 55 return Some(Range<const T>{begin, elemCount}); 56 } 57 }; 58 59 // - 60 61 namespace details { 62 63 class SizeOnlyProducerView final 64 : public webgl::ProducerView<SizeOnlyProducerView> { 65 struct Info { 66 size_t requiredByteCount = 0; 67 size_t alignmentOverhead = 0; 68 }; 69 Info mInfo; 70 71 public: 72 SizeOnlyProducerView() : ProducerView(this) {} 73 74 template <typename T> 75 bool WriteFromRange(const Range<const T>& src) { 76 constexpr auto alignment = alignof(T); 77 const size_t byteSize = ByteSize(src); 78 // printf_stderr("SizeOnlyProducerView: @%zu +%zu\n", alignment, byteSize); 79 80 const auto padToAlign = AlignmentOffset(alignment, mInfo.requiredByteCount); 81 mInfo.alignmentOverhead += padToAlign; 82 83 mInfo.requiredByteCount += padToAlign; 84 mInfo.requiredByteCount += byteSize; 85 return true; 86 } 87 88 const auto& Info() const { return mInfo; } 89 }; 90 91 // - 92 93 class RangeProducerView final : public webgl::ProducerView<RangeProducerView> { 94 const RangedPtr<uint8_t> mDestBegin; 95 const RangedPtr<uint8_t> mDestEnd; 96 RangedPtr<uint8_t> mDestItr; 97 98 public: 99 auto Remaining() const { return *MaybeAs<size_t>(mDestEnd - mDestItr); } 100 101 explicit RangeProducerView(const Range<uint8_t> range) 102 : ProducerView(this), 103 mDestBegin(range.begin()), 104 mDestEnd(range.end()), 105 mDestItr(mDestBegin) { 106 (void)Remaining(); // assert size non-negative 107 } 108 109 template <typename T> 110 bool WriteFromRange(const Range<const T>& src) { 111 // uint32_t/float data may masquerade as a Range<uint8_t>. 112 constexpr auto alignment = alignof(T); 113 const size_t byteSize = ByteSize(src); 114 // printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize); 115 116 const auto padToAlign = AlignmentOffset(alignment, mDestItr.get()); 117 mDestItr += padToAlign; 118 119 MOZ_ASSERT(byteSize <= Remaining()); 120 if (MOZ_LIKELY(byteSize)) { 121 memcpy(mDestItr.get(), src.begin().get(), byteSize); 122 } 123 mDestItr += byteSize; 124 return true; 125 } 126 }; 127 128 // - 129 130 template <typename ProducerViewT> 131 inline void Serialize(ProducerViewT&) {} 132 133 template <typename ProducerViewT, typename Arg, typename... Args> 134 inline void Serialize(ProducerViewT& view, const Arg& arg, 135 const Args&... args) { 136 MOZ_ALWAYS_TRUE(view.WriteParam(arg)); 137 Serialize(view, args...); 138 } 139 140 } // namespace details 141 142 // - 143 144 template <typename... Args> 145 auto SerializationInfo(const Args&... args) { 146 webgl::details::SizeOnlyProducerView sizeView; 147 webgl::details::Serialize(sizeView, args...); 148 return sizeView.Info(); 149 } 150 151 template <typename... Args> 152 void Serialize(Range<uint8_t> dest, const Args&... args) { 153 webgl::details::RangeProducerView view(dest); 154 webgl::details::Serialize(view, args...); 155 } 156 157 // - 158 159 inline Maybe<uint16_t> Deserialize(RangeConsumerView&, size_t) { return {}; } 160 161 template <typename Arg, typename... Args> 162 inline Maybe<uint16_t> Deserialize(RangeConsumerView& view, 163 const uint16_t argId, Arg& arg, 164 Args&... args) { 165 if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) { 166 return Some(argId); 167 } 168 return Deserialize(view, argId + 1, args...); 169 } 170 171 } // namespace webgl 172 173 // - 174 175 template <class R, class... Args> 176 using fn_t = R(Args...); 177 178 // The MethodDispatcher setup uses a CommandSink to read parameters, call the 179 // given method using the given synchronization protocol, and provide 180 // compile-time lookup of the ID by class method. 181 // To use this system, first define a dispatcher subclass of 182 // EmptyMethodDispatcher. This class must be parameterized by command ID. 183 // 184 // Example: 185 // template <size_t id=0> class MyDispatcher 186 // : public EmptyMethodDispatcher<MyDispatcher> {}; 187 // 188 // Then, for each command handled, specialize this to subclass MethodDispatcher. 189 // The subclass must define the Method. It may optionally define isSync for 190 // synchronous methods. 191 // 192 // Example: 193 // template <> 194 // class MyDispatcher<0> 195 // : public MethodDispatcher<MyDispatcher, 0, 196 // decltype(&MyClass::MyMethod), MyClass::MyMethod> {}; 197 // 198 // The method may then be called from the source and run on the sink. 199 // 200 // Example: 201 // int result = Run<MyClass::MyMethod>(param1, std::move(param2)); 202 203 template <template <size_t> typename Derived> 204 class EmptyMethodDispatcher { 205 public: 206 template <typename ObjectT> 207 static constexpr fn_t<bool, ObjectT&, webgl::RangeConsumerView&>* 208 DispatchCommandFuncById(const size_t id) { 209 return nullptr; 210 } 211 }; 212 213 // - 214 215 template <typename ReturnT, typename ObjectT, typename... Args> 216 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple( 217 ReturnT (ObjectT::*)(Args... args)) { 218 return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{}; 219 } 220 221 template <typename ReturnT, typename ObjectT, typename... Args> 222 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple( 223 ReturnT (ObjectT::*)(Args... args) const) { 224 return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{}; 225 } 226 227 // Derived type must be parameterized by the ID. 228 template <template <size_t> typename Derived, size_t _Id, typename MethodType, 229 MethodType _Method> 230 class MethodDispatcher { 231 static constexpr auto Id = _Id; 232 static constexpr auto Method = _Method; 233 using DerivedType = Derived<Id>; 234 235 public: 236 template <class ObjectT> 237 static constexpr fn_t<bool, ObjectT&, webgl::RangeConsumerView&>* 238 DispatchCommandFuncById(const size_t targetId) { 239 if (targetId != Id) 240 return Derived<Id + 1>::template DispatchCommandFuncById<ObjectT>( 241 targetId); 242 243 return [](ObjectT& obj, webgl::RangeConsumerView& view) -> bool { 244 const auto viewWas = view; 245 (void)viewWas; // For debugging. 246 247 auto argsTuple = ArgsTuple(Method); 248 return std::apply( 249 [&](auto&... args) { 250 const auto badArgId = webgl::Deserialize(view, 1, args...); 251 if (badArgId) { 252 const auto& name = DerivedType::Name(); 253 gfxCriticalError() << "webgl::Deserialize failed for " << name 254 << " arg " << *badArgId; 255 return false; 256 } 257 (obj.*Method)(args...); 258 return true; 259 }, 260 argsTuple); 261 }; 262 } 263 }; 264 265 } // namespace mozilla 266 267 #endif // WEBGLCOMMANDQUEUE_H_