tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_