tor-browser

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

WebGLChild.cpp (6301B)


      1 /* -*- Mode: C++; tab-width: 20; 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 #include "WebGLChild.h"
      7 
      8 #include "ClientWebGLContext.h"
      9 #include "WebGLMethodDispatcher.h"
     10 #include "mozilla/StaticPrefs_webgl.h"
     11 
     12 namespace mozilla::dom {
     13 
     14 WebGLChild::WebGLChild(ClientWebGLContext& context)
     15    : mContext(&context),
     16      mDefaultCmdsShmemSize(StaticPrefs::webgl_out_of_process_shmem_size()) {}
     17 
     18 WebGLChild::~WebGLChild() { Destroy(); }
     19 
     20 void WebGLChild::Destroy() {
     21  if (!CanSend()) {
     22    return;
     23  }
     24  if (mContext) {
     25    mContext->OnDestroyChild(this);
     26  }
     27  (void)Send__delete__(this);
     28 }
     29 
     30 void WebGLChild::ActorDestroy(ActorDestroyReason why) {
     31  mPendingCmdsShmem = {};
     32 }
     33 
     34 // -
     35 
     36 Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(
     37    const size_t size, const size_t fyiAlignmentOverhead) {
     38  if (!mPendingCmdsShmem.Size()) {
     39    size_t capacity = mDefaultCmdsShmemSize;
     40    if (capacity < size) {
     41      capacity = size;
     42    }
     43 
     44    mPendingCmdsShmem = mozilla::ipc::BigBuffer::TryAlloc(capacity);
     45    if (!mPendingCmdsShmem.Size()) {
     46      NS_WARNING("Failed to alloc shmem for AllocPendingCmdBytes.");
     47      return {};
     48    }
     49    mPendingCmdsPos = 0;
     50    mPendingCmdsAlignmentOverhead = 0;
     51 
     52    if (kIsDebug) {
     53      const auto ptr = mPendingCmdsShmem.Data();
     54      const auto initialOffset = AlignmentOffset(kUniversalAlignment, ptr);
     55      MOZ_ALWAYS_TRUE(!initialOffset);
     56    }
     57  }
     58 
     59  const auto range = Range<uint8_t>{mPendingCmdsShmem.AsSpan()};
     60 
     61  auto itr = range.begin() + mPendingCmdsPos;
     62  const auto offset = AlignmentOffset(kUniversalAlignment, itr.get());
     63  mPendingCmdsPos += offset;
     64  mPendingCmdsAlignmentOverhead += offset;
     65  const auto required = mPendingCmdsPos + size;
     66  if (required > range.length()) {
     67    FlushPendingCmds();
     68    return AllocPendingCmdBytes(size, fyiAlignmentOverhead);
     69  }
     70  itr = range.begin() + mPendingCmdsPos;
     71  const auto remaining = Range<uint8_t>{itr, range.end()};
     72  mPendingCmdsPos += size;
     73  mPendingCmdsAlignmentOverhead += fyiAlignmentOverhead;
     74  return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
     75 }
     76 
     77 void WebGLChild::FlushPendingCmds() {
     78  if (!mPendingCmdsShmem.Size()) return;
     79 
     80  const auto byteSize = mPendingCmdsPos;
     81  SendDispatchCommands(std::move(mPendingCmdsShmem), byteSize);
     82  mPendingCmdsShmem = {};
     83 
     84  mFlushedCmdInfo.flushes += 1;
     85  mFlushedCmdInfo.flushedCmdBytes += byteSize;
     86  mFlushedCmdInfo.overhead += mPendingCmdsAlignmentOverhead;
     87 
     88  // Handle flushesSinceLastCongestionCheck
     89  mFlushedCmdInfo.flushesSinceLastCongestionCheck += 1;
     90  constexpr auto START_CONGESTION_CHECK_THRESHOLD = 20;
     91  constexpr auto ASSUME_IPC_CONGESTION_THRESHOLD = 70;
     92  RefPtr<WebGLChild> self = this;
     93  size_t generation = self->mFlushedCmdInfo.congestionCheckGeneration;
     94 
     95  // When ClientWebGLContext uses async remote texture, sync GetFrontBuffer
     96  // message is not sent in ClientWebGLContext::GetFrontBuffer(). It causes a
     97  // case that a lot of async DispatchCommands messages are sent to
     98  // WebGLParent without calling ClientWebGLContext::GetFrontBuffer(). The
     99  // sending DispatchCommands messages could be faster than receiving message
    100  // at WebGLParent by WebGLParent::RecvDispatchCommands(). If it happens,
    101  // pending IPC messages could grow too much until out of resource. To detect
    102  // the messages congestion, async Ping message is used. If the Ping response
    103  // is not received until maybeIPCMessageCongestion, IPC message might be
    104  // congested at WebGLParent. Then sending sync SyncPing flushes all pending
    105  // messages.
    106  // Due to the async nature of the async ping, it is possible for the flush
    107  // check to exceed maybeIPCMessageCongestion, but that it it still bounded.
    108  if (mFlushedCmdInfo.flushesSinceLastCongestionCheck ==
    109      START_CONGESTION_CHECK_THRESHOLD) {
    110    const auto eventTarget = RefPtr{GetCurrentSerialEventTarget()};
    111    MOZ_ASSERT(eventTarget);
    112    if (!eventTarget) {
    113      NS_WARNING("GetCurrentSerialEventTarget()->nullptr in FlushPendingCmds.");
    114    } else {
    115      SendPing()->Then(eventTarget, __func__, [self, generation]() {
    116        if (generation == self->mFlushedCmdInfo.congestionCheckGeneration) {
    117          // Confirmed IPC messages congestion does not happen.
    118          // Reset flushesSinceLastCongestionCheck for next congestion check.
    119          self->mFlushedCmdInfo.flushesSinceLastCongestionCheck = 0;
    120          self->mFlushedCmdInfo.congestionCheckGeneration++;
    121        }
    122      });
    123    }
    124  } else if (mFlushedCmdInfo.flushesSinceLastCongestionCheck >
    125             ASSUME_IPC_CONGESTION_THRESHOLD) {
    126    // IPC messages congestion might happen, send sync SyncPing for flushing
    127    // pending messages.
    128    SendSyncPing();
    129    // Reset flushesSinceLastCongestionCheck for next congestion check.
    130    mFlushedCmdInfo.flushesSinceLastCongestionCheck = 0;
    131    mFlushedCmdInfo.congestionCheckGeneration++;
    132  }
    133 
    134  if (gl::GLContext::ShouldSpew()) {
    135    const auto overheadRatio = float(mPendingCmdsAlignmentOverhead) /
    136                               (byteSize - mPendingCmdsAlignmentOverhead);
    137    const auto totalOverheadRatio =
    138        float(mFlushedCmdInfo.overhead) /
    139        (mFlushedCmdInfo.flushedCmdBytes - mFlushedCmdInfo.overhead);
    140    printf_stderr(
    141        "[WebGLChild] Flushed %zu (%zu=%.2f%% overhead) bytes."
    142        " (%zu (%.2f%% overhead) over %zu flushes)\n",
    143        byteSize, mPendingCmdsAlignmentOverhead, 100 * overheadRatio,
    144        mFlushedCmdInfo.flushedCmdBytes, 100 * totalOverheadRatio,
    145        mFlushedCmdInfo.flushes);
    146  }
    147 }
    148 
    149 // -
    150 
    151 mozilla::ipc::IPCResult WebGLChild::RecvJsWarning(
    152    const std::string& text) const {
    153  if (!mContext) return IPC_OK();
    154  mContext->JsWarning(text);
    155  return IPC_OK();
    156 }
    157 
    158 mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss(
    159    const webgl::ContextLossReason reason) const {
    160  if (!mContext) return IPC_OK();
    161  mContext->OnContextLoss(reason);
    162  return IPC_OK();
    163 }
    164 
    165 mozilla::ipc::IPCResult WebGLChild::RecvOnSyncComplete(
    166    const webgl::ObjectId id) const {
    167  if (!mContext) return IPC_OK();
    168  mContext->OnSyncComplete(id);
    169  return IPC_OK();
    170 }
    171 
    172 }  // namespace mozilla::dom