Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / canvas / WebGLChild.cpp
blob54437c7528d530177da342632afc3f947b9c8a83
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/. */
6 #include "WebGLChild.h"
8 #include "ClientWebGLContext.h"
9 #include "mozilla/StaticPrefs_webgl.h"
10 #include "WebGLMethodDispatcher.h"
12 namespace mozilla::dom {
14 WebGLChild::WebGLChild(ClientWebGLContext& context)
15 : mContext(&context),
16 mDefaultCmdsShmemSize(StaticPrefs::webgl_out_of_process_shmem_size()) {}
18 WebGLChild::~WebGLChild() { (void)Send__delete__(this); }
20 void WebGLChild::ActorDestroy(ActorDestroyReason why) {
21 mPendingCmdsShmem = {};
24 // -
26 Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(
27 const size_t size, const size_t fyiAlignmentOverhead) {
28 if (!mPendingCmdsShmem.Size()) {
29 size_t capacity = mDefaultCmdsShmemSize;
30 if (capacity < size) {
31 capacity = size;
34 mPendingCmdsShmem = mozilla::ipc::BigBuffer::TryAlloc(capacity);
35 if (!mPendingCmdsShmem.Size()) {
36 NS_WARNING("Failed to alloc shmem for AllocPendingCmdBytes.");
37 return {};
39 mPendingCmdsPos = 0;
40 mPendingCmdsAlignmentOverhead = 0;
42 if (kIsDebug) {
43 const auto ptr = mPendingCmdsShmem.Data();
44 const auto initialOffset = AlignmentOffset(kUniversalAlignment, ptr);
45 MOZ_ALWAYS_TRUE(!initialOffset);
49 const auto range = Range<uint8_t>{mPendingCmdsShmem.AsSpan()};
51 auto itr = range.begin() + mPendingCmdsPos;
52 const auto offset = AlignmentOffset(kUniversalAlignment, itr.get());
53 mPendingCmdsPos += offset;
54 mPendingCmdsAlignmentOverhead += offset;
55 const auto required = mPendingCmdsPos + size;
56 if (required > range.length()) {
57 FlushPendingCmds();
58 return AllocPendingCmdBytes(size, fyiAlignmentOverhead);
60 itr = range.begin() + mPendingCmdsPos;
61 const auto remaining = Range<uint8_t>{itr, range.end()};
62 mPendingCmdsPos += size;
63 mPendingCmdsAlignmentOverhead += fyiAlignmentOverhead;
64 return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
67 void WebGLChild::FlushPendingCmds() {
68 if (!mPendingCmdsShmem.Size()) return;
70 const auto byteSize = mPendingCmdsPos;
71 SendDispatchCommands(std::move(mPendingCmdsShmem), byteSize);
72 mPendingCmdsShmem = {};
74 mFlushedCmdInfo.flushes += 1;
75 mFlushedCmdInfo.flushedCmdBytes += byteSize;
76 mFlushedCmdInfo.overhead += mPendingCmdsAlignmentOverhead;
77 if (mFlushedCmdInfo.flushesSinceLastCongestionCheck.isSome()) {
78 mFlushedCmdInfo.flushesSinceLastCongestionCheck.ref() += 1;
79 const auto startCongestionCheck = 20;
80 const auto maybeIPCMessageCongestion = 70;
81 const auto eventTarget = GetCurrentSerialEventTarget();
82 MOZ_ASSERT(eventTarget);
83 RefPtr<WebGLChild> self = this;
84 size_t generation = self->mFlushedCmdInfo.congestionCheckGeneration;
86 // When ClientWebGLContext uses async remote texture, sync GetFrontBuffer
87 // message is not sent in ClientWebGLContext::GetFrontBuffer(). It causes a
88 // case that a lot of async DispatchCommands messages are sent to
89 // WebGLParent without calling ClientWebGLContext::GetFrontBuffer(). The
90 // sending DispatchCommands messages could be faster than receiving message
91 // at WebGLParent by WebGLParent::RecvDispatchCommands(). If it happens,
92 // pending IPC messages could grow too much until out of resource. To detect
93 // the messages congestion, async Ping message is used. If the Ping response
94 // is not received until maybeIPCMessageCongestion, IPC message might be
95 // congested at WebGLParent. Then sending sync SyncPing flushes all pending
96 // messages.
97 // Due to the async nature of the async ping, it is possible for the flush
98 // check to exceed maybeIPCMessageCongestion, but that it it still bounded.
99 if (mFlushedCmdInfo.flushesSinceLastCongestionCheck.ref() ==
100 startCongestionCheck) {
101 SendPing()->Then(eventTarget, __func__, [self, generation]() {
102 if (generation == self->mFlushedCmdInfo.congestionCheckGeneration) {
103 // Confirmed IPC messages congestion does not happen.
104 // Reset flushesSinceLastCongestionCheck for next congestion check.
105 self->mFlushedCmdInfo.flushesSinceLastCongestionCheck = Some(0);
106 self->mFlushedCmdInfo.congestionCheckGeneration++;
109 } else if (mFlushedCmdInfo.flushesSinceLastCongestionCheck.ref() >
110 maybeIPCMessageCongestion) {
111 // IPC messages congestion might happen, send sync SyncPing for flushing
112 // pending messages.
113 SendSyncPing();
114 // Reset flushesSinceLastCongestionCheck for next congestion check.
115 mFlushedCmdInfo.flushesSinceLastCongestionCheck = Some(0);
116 mFlushedCmdInfo.congestionCheckGeneration++;
120 if (gl::GLContext::ShouldSpew()) {
121 const auto overheadRatio = float(mPendingCmdsAlignmentOverhead) /
122 (byteSize - mPendingCmdsAlignmentOverhead);
123 const auto totalOverheadRatio =
124 float(mFlushedCmdInfo.overhead) /
125 (mFlushedCmdInfo.flushedCmdBytes - mFlushedCmdInfo.overhead);
126 printf_stderr(
127 "[WebGLChild] Flushed %zu (%zu=%.2f%% overhead) bytes."
128 " (%zu (%.2f%% overhead) over %zu flushes)\n",
129 byteSize, mPendingCmdsAlignmentOverhead, 100 * overheadRatio,
130 mFlushedCmdInfo.flushedCmdBytes, 100 * totalOverheadRatio,
131 mFlushedCmdInfo.flushes);
135 // -
137 mozilla::ipc::IPCResult WebGLChild::RecvJsWarning(
138 const std::string& text) const {
139 if (!mContext) return IPC_OK();
140 mContext->JsWarning(text);
141 return IPC_OK();
144 mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss(
145 const webgl::ContextLossReason reason) const {
146 if (!mContext) return IPC_OK();
147 mContext->OnContextLoss(reason);
148 return IPC_OK();
151 } // namespace mozilla::dom