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/TextureClientSharedSurface.h"
10 #include "ImageContainer.h"
11 #include "HostWebGLContext.h"
12 #include "WebGLMethodDispatcher.h"
14 namespace mozilla::dom
{
16 mozilla::ipc::IPCResult
WebGLParent::RecvInitialize(
17 const webgl::InitContextDesc
& desc
, webgl::InitContextResult
* const out
) {
18 mHost
= HostWebGLContext::Create({nullptr, this}, desc
, out
);
21 MOZ_ASSERT(!out
->error
->empty());
27 WebGLParent::WebGLParent(const dom::ContentParentId
& aContentId
)
28 : mContentId(aContentId
) {}
30 WebGLParent::~WebGLParent() = default;
34 using IPCResult
= mozilla::ipc::IPCResult
;
36 IPCResult
WebGLParent::RecvDispatchCommands(BigBuffer
&& shmem
,
37 const uint64_t cmdsByteSize
) {
38 AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS
);
40 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
43 const auto& gl
= mHost
->mContext
->GL();
44 const gl::GLContext::TlsScope
tlsIsCurrent(gl
);
46 MOZ_ASSERT(cmdsByteSize
);
47 const auto shmemBytes
= Range
<uint8_t>{shmem
.AsSpan()};
48 const auto byteSize
= std::min
<uint64_t>(shmemBytes
.length(), cmdsByteSize
);
49 const auto cmdsBytes
=
50 Range
<const uint8_t>{shmemBytes
.begin(), shmemBytes
.begin() + byteSize
};
51 auto view
= webgl::RangeConsumerView
{cmdsBytes
};
54 const auto initialOffset
=
55 AlignmentOffset(kUniversalAlignment
, cmdsBytes
.begin().get());
56 MOZ_ALWAYS_TRUE(!initialOffset
);
59 std::optional
<std::string
> fatalError
;
62 view
.AlignTo(kUniversalAlignment
);
64 if (!view
.ReadParam(&id
)) break;
66 // We split this up so that we don't end up in a long callstack chain of
67 // WebGLMethodDispatcher<i>|i=0->N. First get the lambda for dispatch, then
68 // invoke the lambda with our args.
70 WebGLMethodDispatcher
<0>::DispatchCommandFuncById
<HostWebGLContext
>(id
);
72 const nsPrintfCString
cstr(
73 "MethodDispatcher<%zu> not found. Please file a bug!", id
);
74 fatalError
= ToString(cstr
);
75 gfxCriticalError() << *fatalError
;
79 const auto ok
= (*pfn
)(*mHost
, view
);
81 const nsPrintfCString
cstr(
82 "DispatchCommand(id: %zu) failed. Please file a bug!", id
);
83 fatalError
= ToString(cstr
);
84 gfxCriticalError() << *fatalError
;
90 mHost
->JsWarning(*fatalError
);
91 mHost
->OnContextLoss(webgl::ContextLossReason::None
);
97 IPCResult
WebGLParent::RecvTexImage(const uint32_t level
,
98 const uint32_t respecFormat
,
100 const webgl::PackingInfo
& pi
,
101 webgl::TexUnpackBlobDesc
&& desc
) {
103 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
106 mHost
->TexImage(level
, respecFormat
, offset
, pi
, desc
);
112 mozilla::ipc::IPCResult
WebGLParent::Recv__delete__() {
117 void WebGLParent::ActorDestroy(ActorDestroyReason aWhy
) { mHost
= nullptr; }
119 mozilla::ipc::IPCResult
WebGLParent::RecvWaitForTxn(
120 layers::RemoteTextureOwnerId aOwnerId
,
121 layers::RemoteTextureTxnType aTxnType
, layers::RemoteTextureTxnId aTxnId
) {
123 mHost
->WaitForTxn(aOwnerId
, aTxnType
, aTxnId
);
130 IPCResult
WebGLParent::RecvGetFrontBufferSnapshot(
131 webgl::FrontBufferSnapshotIpc
* const ret
) {
132 return GetFrontBufferSnapshot(ret
, this);
135 IPCResult
WebGLParent::GetFrontBufferSnapshot(
136 webgl::FrontBufferSnapshotIpc
* const ret
, IProtocol
* aProtocol
) {
137 AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS
);
140 return IPC_FAIL(aProtocol
, "HostWebGLContext is not initialized.");
143 const bool ok
= [&]() {
144 const auto maybeSize
= mHost
->FrontBufferSnapshotInto({});
146 const auto& surfSize
= *maybeSize
;
147 const auto byteSize
= 4 * surfSize
.x
* surfSize
.y
;
149 auto shmem
= webgl::RaiiShmem::Alloc(aProtocol
, byteSize
);
151 NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
154 const auto range
= shmem
.ByteRange();
155 *ret
= {surfSize
, Some(shmem
.Extract())};
157 if (!mHost
->FrontBufferSnapshotInto(Some(range
))) {
158 gfxCriticalNote
<< "WebGLParent::RecvGetFrontBufferSnapshot: "
159 "FrontBufferSnapshotInto(some) failed after "
160 "FrontBufferSnapshotInto(none)";
167 // Zero means failure, as we still need to send any shmem we alloc.
168 ret
->surfSize
= {0, 0};
173 IPCResult
WebGLParent::RecvGetBufferSubData(const GLenum target
,
174 const uint64_t srcByteOffset
,
175 const uint64_t byteSize
,
177 AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS
);
179 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
182 const auto allocSize
= 1 + byteSize
;
183 auto shmem
= webgl::RaiiShmem::Alloc(this, allocSize
);
185 NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
189 const auto shmemRange
= shmem
.ByteRange();
190 const auto dataRange
=
191 Range
<uint8_t>{shmemRange
.begin() + 1, shmemRange
.end()};
193 // We need to always send the shmem:
194 // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
195 const auto ok
= mHost
->GetBufferSubData(target
, srcByteOffset
, dataRange
);
196 *(shmemRange
.begin().get()) = ok
;
197 *ret
= shmem
.Extract();
201 IPCResult
WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc
& desc
,
202 ReadPixelsBuffer
&& buffer
,
203 webgl::ReadPixelsResultIpc
* const ret
) {
204 AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS
);
207 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
210 if (buffer
.type() == ReadPixelsBuffer::TShmem
) {
211 const auto& shmem
= buffer
.get_Shmem();
212 const auto range
= shmem
.Range
<uint8_t>();
213 const auto res
= mHost
->ReadPixelsInto(desc
, range
);
218 const uint64_t byteSize
= buffer
.get_uint64_t();
219 const auto allocSize
= std::max
<uint64_t>(1, byteSize
);
220 auto shmem
= webgl::RaiiShmem::Alloc(this, allocSize
);
222 NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
226 const auto range
= shmem
.ByteRange();
228 const auto res
= mHost
->ReadPixelsInto(desc
, range
);
229 *ret
= {res
, Some(shmem
.Extract())};
235 IPCResult
WebGLParent::RecvCheckFramebufferStatus(GLenum target
,
238 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
241 *ret
= mHost
->CheckFramebufferStatus(target
);
245 IPCResult
WebGLParent::RecvClientWaitSync(ObjectId id
, GLbitfield flags
,
246 GLuint64 timeout
, GLenum
* const ret
) {
248 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
251 *ret
= mHost
->ClientWaitSync(id
, flags
, timeout
);
255 IPCResult
WebGLParent::RecvCreateOpaqueFramebuffer(
256 const ObjectId id
, const OpaqueFramebufferOptions
& options
,
259 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
262 *ret
= mHost
->CreateOpaqueFramebuffer(id
, options
);
266 IPCResult
WebGLParent::RecvDrawingBufferSize(uvec2
* const ret
) {
268 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
271 *ret
= mHost
->DrawingBufferSize();
275 IPCResult
WebGLParent::RecvFinish() {
277 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
284 IPCResult
WebGLParent::RecvGetBufferParameter(GLenum target
, GLenum pname
,
285 Maybe
<double>* const ret
) {
287 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
290 *ret
= mHost
->GetBufferParameter(target
, pname
);
294 IPCResult
WebGLParent::RecvGetCompileResult(ObjectId id
,
295 webgl::CompileResult
* const ret
) {
297 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
300 *ret
= mHost
->GetCompileResult(id
);
304 IPCResult
WebGLParent::RecvGetError(GLenum
* const ret
) {
306 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
309 *ret
= mHost
->GetError();
313 IPCResult
WebGLParent::RecvGetFragDataLocation(ObjectId id
,
314 const std::string
& name
,
317 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
320 *ret
= mHost
->GetFragDataLocation(id
, name
);
324 IPCResult
WebGLParent::RecvGetFramebufferAttachmentParameter(
325 ObjectId id
, GLenum attachment
, GLenum pname
, Maybe
<double>* const ret
) {
327 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
330 *ret
= mHost
->GetFramebufferAttachmentParameter(id
, attachment
, pname
);
334 IPCResult
WebGLParent::RecvGetFrontBuffer(
335 ObjectId fb
, const bool vr
, Maybe
<layers::SurfaceDescriptor
>* const ret
) {
337 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
340 *ret
= mHost
->GetFrontBuffer(fb
, vr
);
344 IPCResult
WebGLParent::RecvGetIndexedParameter(GLenum target
, GLuint index
,
345 Maybe
<double>* const ret
) {
347 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
350 *ret
= mHost
->GetIndexedParameter(target
, index
);
354 IPCResult
WebGLParent::RecvGetInternalformatParameter(
355 const GLenum target
, const GLuint format
, const GLuint pname
,
356 Maybe
<std::vector
<int32_t>>* const ret
) {
358 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
361 *ret
= mHost
->GetInternalformatParameter(target
, format
, pname
);
365 IPCResult
WebGLParent::RecvGetLinkResult(ObjectId id
,
366 webgl::LinkResult
* const ret
) {
368 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
371 *ret
= mHost
->GetLinkResult(id
);
375 IPCResult
WebGLParent::RecvGetNumber(GLenum pname
, Maybe
<double>* const ret
) {
377 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
380 *ret
= mHost
->GetNumber(pname
);
384 IPCResult
WebGLParent::RecvGetQueryParameter(ObjectId id
, GLenum pname
,
385 Maybe
<double>* const ret
) {
387 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
390 *ret
= mHost
->GetQueryParameter(id
, pname
);
394 IPCResult
WebGLParent::RecvGetRenderbufferParameter(ObjectId id
, GLenum pname
,
395 Maybe
<double>* const ret
) {
397 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
400 *ret
= mHost
->GetRenderbufferParameter(id
, pname
);
404 IPCResult
WebGLParent::RecvGetSamplerParameter(ObjectId id
, GLenum pname
,
405 Maybe
<double>* const ret
) {
407 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
410 *ret
= mHost
->GetSamplerParameter(id
, pname
);
414 IPCResult
WebGLParent::RecvGetShaderPrecisionFormat(
415 GLenum shaderType
, GLenum precisionType
,
416 Maybe
<webgl::ShaderPrecisionFormat
>* const ret
) {
418 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
421 *ret
= mHost
->GetShaderPrecisionFormat(shaderType
, precisionType
);
425 IPCResult
WebGLParent::RecvGetString(GLenum pname
,
426 Maybe
<std::string
>* const ret
) {
428 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
431 *ret
= mHost
->GetString(pname
);
435 IPCResult
WebGLParent::RecvGetTexParameter(ObjectId id
, GLenum pname
,
436 Maybe
<double>* const ret
) {
438 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
441 *ret
= mHost
->GetTexParameter(id
, pname
);
445 IPCResult
WebGLParent::RecvGetUniform(ObjectId id
, uint32_t loc
,
446 webgl::GetUniformData
* const ret
) {
448 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
451 *ret
= mHost
->GetUniform(id
, loc
);
455 IPCResult
WebGLParent::RecvGetVertexAttrib(GLuint index
, GLenum pname
,
456 Maybe
<double>* const ret
) {
458 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
461 *ret
= mHost
->GetVertexAttrib(index
, pname
);
465 IPCResult
WebGLParent::RecvOnMemoryPressure() {
467 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
470 mHost
->OnMemoryPressure();
474 IPCResult
WebGLParent::RecvValidateProgram(ObjectId id
, bool* const ret
) {
476 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
479 *ret
= mHost
->ValidateProgram(id
);
483 } // namespace mozilla::dom