Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / canvas / WebGLParent.cpp
blob51a5ba43b899d2f55800b14d5e3b801816dd7790
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);
20 if (!mHost) {
21 MOZ_ASSERT(!out->error->empty());
24 return IPC_OK();
27 WebGLParent::WebGLParent(const dom::ContentParentId& aContentId)
28 : mContentId(aContentId) {}
30 WebGLParent::~WebGLParent() = default;
32 // -
34 using IPCResult = mozilla::ipc::IPCResult;
36 IPCResult WebGLParent::RecvDispatchCommands(BigBuffer&& shmem,
37 const uint64_t cmdsByteSize) {
38 AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS);
39 if (!mHost) {
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};
53 if (kIsDebug) {
54 const auto initialOffset =
55 AlignmentOffset(kUniversalAlignment, cmdsBytes.begin().get());
56 MOZ_ALWAYS_TRUE(!initialOffset);
59 while (true) {
60 view.AlignTo(kUniversalAlignment);
61 size_t id = 0;
62 if (!view.ReadParam(&id)) break;
64 const auto ok = WebGLMethodDispatcher<0>::DispatchCommand(*mHost, id, view);
65 if (!ok) {
66 const nsPrintfCString cstr(
67 "DispatchCommand(id: %i) failed. Please file a bug!", int(id));
68 const auto str = ToString(cstr);
69 gfxCriticalError() << str;
70 mHost->JsWarning(str);
71 mHost->OnContextLoss(webgl::ContextLossReason::None);
72 break;
76 return IPC_OK();
79 IPCResult WebGLParent::RecvTexImage(const uint32_t level,
80 const uint32_t respecFormat,
81 const uvec3& offset,
82 const webgl::PackingInfo& pi,
83 webgl::TexUnpackBlobDesc&& desc) {
84 if (!mHost) {
85 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
88 mHost->TexImage(level, respecFormat, offset, pi, desc);
89 return IPC_OK();
92 // -
94 mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
95 mHost = nullptr;
96 return IPC_OK();
99 void WebGLParent::ActorDestroy(ActorDestroyReason aWhy) { mHost = nullptr; }
101 // -
103 IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
104 webgl::FrontBufferSnapshotIpc* const ret) {
105 return GetFrontBufferSnapshot(ret, this);
108 IPCResult WebGLParent::GetFrontBufferSnapshot(
109 webgl::FrontBufferSnapshotIpc* const ret, IProtocol* aProtocol) {
110 AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS);
111 *ret = {};
112 if (!mHost) {
113 return IPC_FAIL(aProtocol, "HostWebGLContext is not initialized.");
116 const bool ok = [&]() {
117 const auto maybeSize = mHost->FrontBufferSnapshotInto({});
118 if (maybeSize) {
119 const auto& surfSize = *maybeSize;
120 const auto byteSize = 4 * surfSize.x * surfSize.y;
122 auto shmem = webgl::RaiiShmem::Alloc(aProtocol, byteSize);
123 if (!shmem) {
124 NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
125 return false;
127 const auto range = shmem.ByteRange();
128 *ret = {surfSize, Some(shmem.Extract())};
130 if (!mHost->FrontBufferSnapshotInto(Some(range))) {
131 gfxCriticalNote << "WebGLParent::RecvGetFrontBufferSnapshot: "
132 "FrontBufferSnapshotInto(some) failed after "
133 "FrontBufferSnapshotInto(none)";
134 return false;
137 return true;
138 }();
139 if (!ok) {
140 // Zero means failure, as we still need to send any shmem we alloc.
141 ret->surfSize = {0, 0};
143 return IPC_OK();
146 IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
147 const uint64_t srcByteOffset,
148 const uint64_t byteSize,
149 Shmem* const ret) {
150 AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS);
151 if (!mHost) {
152 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
155 const auto allocSize = 1 + byteSize;
156 auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
157 if (!shmem) {
158 NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
159 return IPC_OK();
162 const auto shmemRange = shmem.ByteRange();
163 const auto dataRange =
164 Range<uint8_t>{shmemRange.begin() + 1, shmemRange.end()};
166 // We need to always send the shmem:
167 // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
168 const auto ok = mHost->GetBufferSubData(target, srcByteOffset, dataRange);
169 *(shmemRange.begin().get()) = ok;
170 *ret = shmem.Extract();
171 return IPC_OK();
174 IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
175 ReadPixelsBuffer&& buffer,
176 webgl::ReadPixelsResultIpc* const ret) {
177 AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS);
178 *ret = {};
179 if (!mHost) {
180 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
183 if (buffer.type() == ReadPixelsBuffer::TShmem) {
184 const auto& shmem = buffer.get_Shmem();
185 const auto range = shmem.Range<uint8_t>();
186 const auto res = mHost->ReadPixelsInto(desc, range);
187 *ret = {res, {}};
188 return IPC_OK();
191 const uint64_t byteSize = buffer.get_uint64_t();
192 const auto allocSize = std::max<uint64_t>(1, byteSize);
193 auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
194 if (!shmem) {
195 NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
196 return IPC_OK();
199 const auto range = shmem.ByteRange();
201 const auto res = mHost->ReadPixelsInto(desc, range);
202 *ret = {res, Some(shmem.Extract())};
203 return IPC_OK();
206 // -
208 IPCResult WebGLParent::RecvCheckFramebufferStatus(GLenum target,
209 GLenum* const ret) {
210 if (!mHost) {
211 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
214 *ret = mHost->CheckFramebufferStatus(target);
215 return IPC_OK();
218 IPCResult WebGLParent::RecvClientWaitSync(ObjectId id, GLbitfield flags,
219 GLuint64 timeout, GLenum* const ret) {
220 if (!mHost) {
221 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
224 *ret = mHost->ClientWaitSync(id, flags, timeout);
225 return IPC_OK();
228 IPCResult WebGLParent::RecvCreateOpaqueFramebuffer(
229 const ObjectId id, const OpaqueFramebufferOptions& options,
230 bool* const ret) {
231 if (!mHost) {
232 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
235 *ret = mHost->CreateOpaqueFramebuffer(id, options);
236 return IPC_OK();
239 IPCResult WebGLParent::RecvDrawingBufferSize(uvec2* const ret) {
240 if (!mHost) {
241 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
244 *ret = mHost->DrawingBufferSize();
245 return IPC_OK();
248 IPCResult WebGLParent::RecvFinish() {
249 if (!mHost) {
250 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
253 mHost->Finish();
254 return IPC_OK();
257 IPCResult WebGLParent::RecvGetBufferParameter(GLenum target, GLenum pname,
258 Maybe<double>* const ret) {
259 if (!mHost) {
260 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
263 *ret = mHost->GetBufferParameter(target, pname);
264 return IPC_OK();
267 IPCResult WebGLParent::RecvGetCompileResult(ObjectId id,
268 webgl::CompileResult* const ret) {
269 if (!mHost) {
270 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
273 *ret = mHost->GetCompileResult(id);
274 return IPC_OK();
277 IPCResult WebGLParent::RecvGetError(GLenum* const ret) {
278 if (!mHost) {
279 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
282 *ret = mHost->GetError();
283 return IPC_OK();
286 IPCResult WebGLParent::RecvGetFragDataLocation(ObjectId id,
287 const std::string& name,
288 GLint* const ret) {
289 if (!mHost) {
290 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
293 *ret = mHost->GetFragDataLocation(id, name);
294 return IPC_OK();
297 IPCResult WebGLParent::RecvGetFramebufferAttachmentParameter(
298 ObjectId id, GLenum attachment, GLenum pname, Maybe<double>* const ret) {
299 if (!mHost) {
300 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
303 *ret = mHost->GetFramebufferAttachmentParameter(id, attachment, pname);
304 return IPC_OK();
307 IPCResult WebGLParent::RecvGetFrontBuffer(
308 ObjectId fb, const bool vr, Maybe<layers::SurfaceDescriptor>* const ret) {
309 if (!mHost) {
310 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
313 *ret = mHost->GetFrontBuffer(fb, vr);
314 return IPC_OK();
317 IPCResult WebGLParent::RecvGetIndexedParameter(GLenum target, GLuint index,
318 Maybe<double>* const ret) {
319 if (!mHost) {
320 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
323 *ret = mHost->GetIndexedParameter(target, index);
324 return IPC_OK();
327 IPCResult WebGLParent::RecvGetInternalformatParameter(
328 const GLenum target, const GLuint format, const GLuint pname,
329 Maybe<std::vector<int32_t>>* const ret) {
330 if (!mHost) {
331 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
334 *ret = mHost->GetInternalformatParameter(target, format, pname);
335 return IPC_OK();
338 IPCResult WebGLParent::RecvGetLinkResult(ObjectId id,
339 webgl::LinkResult* const ret) {
340 if (!mHost) {
341 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
344 *ret = mHost->GetLinkResult(id);
345 return IPC_OK();
348 IPCResult WebGLParent::RecvGetNumber(GLenum pname, Maybe<double>* const ret) {
349 if (!mHost) {
350 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
353 *ret = mHost->GetNumber(pname);
354 return IPC_OK();
357 IPCResult WebGLParent::RecvGetQueryParameter(ObjectId id, GLenum pname,
358 Maybe<double>* const ret) {
359 if (!mHost) {
360 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
363 *ret = mHost->GetQueryParameter(id, pname);
364 return IPC_OK();
367 IPCResult WebGLParent::RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
368 Maybe<double>* const ret) {
369 if (!mHost) {
370 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
373 *ret = mHost->GetRenderbufferParameter(id, pname);
374 return IPC_OK();
377 IPCResult WebGLParent::RecvGetSamplerParameter(ObjectId id, GLenum pname,
378 Maybe<double>* const ret) {
379 if (!mHost) {
380 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
383 *ret = mHost->GetSamplerParameter(id, pname);
384 return IPC_OK();
387 IPCResult WebGLParent::RecvGetShaderPrecisionFormat(
388 GLenum shaderType, GLenum precisionType,
389 Maybe<webgl::ShaderPrecisionFormat>* const ret) {
390 if (!mHost) {
391 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
394 *ret = mHost->GetShaderPrecisionFormat(shaderType, precisionType);
395 return IPC_OK();
398 IPCResult WebGLParent::RecvGetString(GLenum pname,
399 Maybe<std::string>* const ret) {
400 if (!mHost) {
401 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
404 *ret = mHost->GetString(pname);
405 return IPC_OK();
408 IPCResult WebGLParent::RecvGetTexParameter(ObjectId id, GLenum pname,
409 Maybe<double>* const ret) {
410 if (!mHost) {
411 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
414 *ret = mHost->GetTexParameter(id, pname);
415 return IPC_OK();
418 IPCResult WebGLParent::RecvGetUniform(ObjectId id, uint32_t loc,
419 webgl::GetUniformData* const ret) {
420 if (!mHost) {
421 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
424 *ret = mHost->GetUniform(id, loc);
425 return IPC_OK();
428 IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname,
429 Maybe<double>* const ret) {
430 if (!mHost) {
431 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
434 *ret = mHost->GetVertexAttrib(index, pname);
435 return IPC_OK();
438 IPCResult WebGLParent::RecvIsEnabled(GLenum cap, bool* const ret) {
439 if (!mHost) {
440 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
443 *ret = mHost->IsEnabled(cap);
444 return IPC_OK();
447 IPCResult WebGLParent::RecvOnMemoryPressure() {
448 if (!mHost) {
449 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
452 mHost->OnMemoryPressure();
453 return IPC_OK();
456 IPCResult WebGLParent::RecvValidateProgram(ObjectId id, bool* const ret) {
457 if (!mHost) {
458 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
461 *ret = mHost->ValidateProgram(id);
462 return IPC_OK();
465 } // namespace mozilla::dom