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 "WebGLParent.h"
8 #include "WebGLChild.h"
9 #include "mozilla/layers/SharedSurfacesParent.h"
10 #include "mozilla/layers/TextureClientSharedSurface.h"
11 #include "ImageContainer.h"
12 #include "HostWebGLContext.h"
13 #include "WebGLMethodDispatcher.h"
15 namespace mozilla::dom
{
17 mozilla::ipc::IPCResult
WebGLParent::RecvInitialize(
18 const webgl::InitContextDesc
& desc
, webgl::InitContextResult
* const out
) {
19 mHost
= HostWebGLContext::Create({nullptr, this}, desc
, out
);
22 MOZ_ASSERT(!out
->error
->empty());
28 WebGLParent::WebGLParent(layers::SharedSurfacesHolder
* aSharedSurfacesHolder
,
29 const dom::ContentParentId
& aContentId
)
30 : mSharedSurfacesHolder(aSharedSurfacesHolder
), mContentId(aContentId
) {}
32 WebGLParent::~WebGLParent() = default;
36 using IPCResult
= mozilla::ipc::IPCResult
;
38 IPCResult
WebGLParent::RecvDispatchCommands(BigBuffer
&& shmem
,
39 const uint64_t cmdsByteSize
) {
40 AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS
);
42 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
45 const auto& gl
= mHost
->mContext
->GL();
46 const gl::GLContext::TlsScope
tlsIsCurrent(gl
);
48 MOZ_ASSERT(cmdsByteSize
);
49 const auto shmemBytes
= Range
<uint8_t>{shmem
.AsSpan()};
50 const auto byteSize
= std::min
<uint64_t>(shmemBytes
.length(), cmdsByteSize
);
51 const auto cmdsBytes
=
52 Range
<const uint8_t>{shmemBytes
.begin(), shmemBytes
.begin() + byteSize
};
53 auto view
= webgl::RangeConsumerView
{cmdsBytes
};
56 const auto initialOffset
=
57 AlignmentOffset(kUniversalAlignment
, cmdsBytes
.begin().get());
58 MOZ_ALWAYS_TRUE(!initialOffset
);
61 std::optional
<std::string
> fatalError
;
64 view
.AlignTo(kUniversalAlignment
);
66 if (!view
.ReadParam(&id
)) break;
68 // We split this up so that we don't end up in a long callstack chain of
69 // WebGLMethodDispatcher<i>|i=0->N. First get the lambda for dispatch, then
70 // invoke the lambda with our args.
72 WebGLMethodDispatcher
<0>::DispatchCommandFuncById
<HostWebGLContext
>(id
);
74 const nsPrintfCString
cstr(
75 "MethodDispatcher<%zu> not found. Please file a bug!", id
);
76 fatalError
= ToString(cstr
);
77 gfxCriticalError() << *fatalError
;
81 const auto ok
= (*pfn
)(*mHost
, view
);
83 const nsPrintfCString
cstr(
84 "DispatchCommand(id: %zu) failed. Please file a bug!", id
);
85 fatalError
= ToString(cstr
);
86 gfxCriticalError() << *fatalError
;
92 mHost
->JsWarning(*fatalError
);
93 mHost
->OnContextLoss(webgl::ContextLossReason::None
);
99 IPCResult
WebGLParent::RecvTexImage(const uint32_t level
,
100 const uint32_t respecFormat
,
102 const webgl::PackingInfo
& pi
,
103 webgl::TexUnpackBlobDesc
&& desc
) {
105 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
108 mHost
->TexImage(level
, respecFormat
, offset
, pi
, desc
);
114 mozilla::ipc::IPCResult
WebGLParent::Recv__delete__() {
119 void WebGLParent::ActorDestroy(ActorDestroyReason aWhy
) { mHost
= nullptr; }
121 mozilla::ipc::IPCResult
WebGLParent::RecvWaitForTxn(
122 layers::RemoteTextureOwnerId aOwnerId
,
123 layers::RemoteTextureTxnType aTxnType
, layers::RemoteTextureTxnId aTxnId
) {
125 mHost
->WaitForTxn(aOwnerId
, aTxnType
, aTxnId
);
132 IPCResult
WebGLParent::RecvGetFrontBufferSnapshot(
133 webgl::FrontBufferSnapshotIpc
* const ret
) {
134 return GetFrontBufferSnapshot(ret
, this);
137 IPCResult
WebGLParent::GetFrontBufferSnapshot(
138 webgl::FrontBufferSnapshotIpc
* const ret
, IProtocol
* aProtocol
) {
139 AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS
);
142 return IPC_FAIL(aProtocol
, "HostWebGLContext is not initialized.");
145 const bool ok
= [&]() {
146 const auto maybeSize
= mHost
->FrontBufferSnapshotInto({});
148 const auto& surfSize
= *maybeSize
;
149 const auto byteSize
= 4 * surfSize
.x
* surfSize
.y
;
151 auto shmem
= webgl::RaiiShmem::Alloc(aProtocol
, byteSize
);
153 NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
156 const auto range
= shmem
.ByteRange();
157 *ret
= {surfSize
, Some(shmem
.Extract())};
159 if (!mHost
->FrontBufferSnapshotInto(Some(range
))) {
160 gfxCriticalNote
<< "WebGLParent::RecvGetFrontBufferSnapshot: "
161 "FrontBufferSnapshotInto(some) failed after "
162 "FrontBufferSnapshotInto(none)";
169 // Zero means failure, as we still need to send any shmem we alloc.
170 ret
->surfSize
= {0, 0};
175 IPCResult
WebGLParent::RecvGetBufferSubData(const GLenum target
,
176 const uint64_t srcByteOffset
,
177 const uint64_t byteSize
,
179 AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS
);
181 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
184 const auto allocSize
= 1 + byteSize
;
185 auto shmem
= webgl::RaiiShmem::Alloc(this, allocSize
);
187 NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
191 const auto shmemRange
= shmem
.ByteRange();
192 const auto dataRange
=
193 Range
<uint8_t>{shmemRange
.begin() + 1, shmemRange
.end()};
195 // We need to always send the shmem:
196 // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
197 const auto ok
= mHost
->GetBufferSubData(target
, srcByteOffset
, dataRange
);
198 *(shmemRange
.begin().get()) = ok
;
199 *ret
= shmem
.Extract();
203 IPCResult
WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc
& desc
,
204 ReadPixelsBuffer
&& buffer
,
205 webgl::ReadPixelsResultIpc
* const ret
) {
206 AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS
);
209 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
212 if (buffer
.type() == ReadPixelsBuffer::TShmem
) {
213 const auto& shmem
= buffer
.get_Shmem();
214 const auto range
= shmem
.Range
<uint8_t>();
215 const auto res
= mHost
->ReadPixelsInto(desc
, range
);
220 const uint64_t byteSize
= buffer
.get_uint64_t();
221 const auto allocSize
= std::max
<uint64_t>(1, byteSize
);
222 auto shmem
= webgl::RaiiShmem::Alloc(this, allocSize
);
224 NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
228 const auto range
= shmem
.ByteRange();
230 const auto res
= mHost
->ReadPixelsInto(desc
, range
);
231 *ret
= {res
, Some(shmem
.Extract())};
237 IPCResult
WebGLParent::RecvCheckFramebufferStatus(GLenum target
,
240 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
243 *ret
= mHost
->CheckFramebufferStatus(target
);
247 IPCResult
WebGLParent::RecvClientWaitSync(ObjectId id
, GLbitfield flags
,
248 GLuint64 timeout
, GLenum
* const ret
) {
250 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
253 *ret
= mHost
->ClientWaitSync(id
, flags
, timeout
);
257 IPCResult
WebGLParent::RecvCreateOpaqueFramebuffer(
258 const ObjectId id
, const OpaqueFramebufferOptions
& options
,
261 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
264 *ret
= mHost
->CreateOpaqueFramebuffer(id
, options
);
268 IPCResult
WebGLParent::RecvDrawingBufferSize(uvec2
* const ret
) {
270 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
273 *ret
= mHost
->DrawingBufferSize();
277 IPCResult
WebGLParent::RecvFinish() {
279 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
286 IPCResult
WebGLParent::RecvGetBufferParameter(GLenum target
, GLenum pname
,
287 Maybe
<double>* const ret
) {
289 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
292 *ret
= mHost
->GetBufferParameter(target
, pname
);
296 IPCResult
WebGLParent::RecvGetCompileResult(ObjectId id
,
297 webgl::CompileResult
* const ret
) {
299 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
302 *ret
= mHost
->GetCompileResult(id
);
306 IPCResult
WebGLParent::RecvGetError(GLenum
* const ret
) {
308 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
311 *ret
= mHost
->GetError();
315 IPCResult
WebGLParent::RecvGetFragDataLocation(ObjectId id
,
316 const std::string
& name
,
319 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
322 *ret
= mHost
->GetFragDataLocation(id
, name
);
326 IPCResult
WebGLParent::RecvGetFramebufferAttachmentParameter(
327 ObjectId id
, GLenum attachment
, GLenum pname
, Maybe
<double>* const ret
) {
329 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
332 *ret
= mHost
->GetFramebufferAttachmentParameter(id
, attachment
, pname
);
336 IPCResult
WebGLParent::RecvGetFrontBuffer(
337 ObjectId fb
, const bool vr
, Maybe
<layers::SurfaceDescriptor
>* const ret
) {
339 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
342 *ret
= mHost
->GetFrontBuffer(fb
, vr
);
346 IPCResult
WebGLParent::RecvGetIndexedParameter(GLenum target
, GLuint index
,
347 Maybe
<double>* const ret
) {
349 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
352 *ret
= mHost
->GetIndexedParameter(target
, index
);
356 IPCResult
WebGLParent::RecvGetInternalformatParameter(
357 const GLenum target
, const GLuint format
, const GLuint pname
,
358 Maybe
<std::vector
<int32_t>>* const ret
) {
360 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
363 *ret
= mHost
->GetInternalformatParameter(target
, format
, pname
);
367 IPCResult
WebGLParent::RecvGetLinkResult(ObjectId id
,
368 webgl::LinkResult
* const ret
) {
370 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
373 *ret
= mHost
->GetLinkResult(id
);
377 IPCResult
WebGLParent::RecvGetNumber(GLenum pname
, Maybe
<double>* const ret
) {
379 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
382 *ret
= mHost
->GetNumber(pname
);
386 IPCResult
WebGLParent::RecvGetQueryParameter(ObjectId id
, GLenum pname
,
387 Maybe
<double>* const ret
) {
389 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
392 *ret
= mHost
->GetQueryParameter(id
, pname
);
396 IPCResult
WebGLParent::RecvGetRenderbufferParameter(ObjectId id
, GLenum pname
,
397 Maybe
<double>* const ret
) {
399 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
402 *ret
= mHost
->GetRenderbufferParameter(id
, pname
);
406 IPCResult
WebGLParent::RecvGetSamplerParameter(ObjectId id
, GLenum pname
,
407 Maybe
<double>* const ret
) {
409 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
412 *ret
= mHost
->GetSamplerParameter(id
, pname
);
416 IPCResult
WebGLParent::RecvGetShaderPrecisionFormat(
417 GLenum shaderType
, GLenum precisionType
,
418 Maybe
<webgl::ShaderPrecisionFormat
>* const ret
) {
420 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
423 *ret
= mHost
->GetShaderPrecisionFormat(shaderType
, precisionType
);
427 IPCResult
WebGLParent::RecvGetString(GLenum pname
,
428 Maybe
<std::string
>* const ret
) {
430 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
433 *ret
= mHost
->GetString(pname
);
437 IPCResult
WebGLParent::RecvGetTexParameter(ObjectId id
, GLenum pname
,
438 Maybe
<double>* const ret
) {
440 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
443 *ret
= mHost
->GetTexParameter(id
, pname
);
447 IPCResult
WebGLParent::RecvGetUniform(ObjectId id
, uint32_t loc
,
448 webgl::GetUniformData
* const ret
) {
450 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
453 *ret
= mHost
->GetUniform(id
, loc
);
457 IPCResult
WebGLParent::RecvGetVertexAttrib(GLuint index
, GLenum pname
,
458 Maybe
<double>* const ret
) {
460 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
463 *ret
= mHost
->GetVertexAttrib(index
, pname
);
467 IPCResult
WebGLParent::RecvOnMemoryPressure() {
469 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
472 mHost
->OnMemoryPressure();
476 IPCResult
WebGLParent::RecvValidateProgram(ObjectId id
, bool* const ret
) {
478 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
481 *ret
= mHost
->ValidateProgram(id
);
485 } // namespace mozilla::dom