Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / canvas / WebGLParent.cpp
blobd2501a0511499865149bc624d6c201c5cd102aaf
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() = default;
28 WebGLParent::~WebGLParent() = default;
30 // -
32 using IPCResult = mozilla::ipc::IPCResult;
34 IPCResult WebGLParent::RecvDispatchCommands(BigBuffer&& shmem,
35 const uint64_t cmdsByteSize) {
36 AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS);
37 if (!mHost) {
38 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
41 const auto& gl = mHost->mContext->GL();
42 const gl::GLContext::TlsScope tlsIsCurrent(gl);
44 MOZ_ASSERT(cmdsByteSize);
45 const auto shmemBytes = Range<uint8_t>{shmem.AsSpan()};
46 const auto byteSize = std::min<uint64_t>(shmemBytes.length(), cmdsByteSize);
47 const auto cmdsBytes =
48 Range<const uint8_t>{shmemBytes.begin(), shmemBytes.begin() + byteSize};
49 auto view = webgl::RangeConsumerView{cmdsBytes};
51 if (kIsDebug) {
52 const auto initialOffset =
53 AlignmentOffset(kUniversalAlignment, cmdsBytes.begin().get());
54 MOZ_ALWAYS_TRUE(!initialOffset);
57 while (true) {
58 view.AlignTo(kUniversalAlignment);
59 size_t id = 0;
60 if (!view.ReadParam(&id)) break;
62 const auto ok = WebGLMethodDispatcher<0>::DispatchCommand(*mHost, id, view);
63 if (!ok) {
64 const nsPrintfCString cstr(
65 "DispatchCommand(id: %i) failed. Please file a bug!", int(id));
66 const auto str = ToString(cstr);
67 gfxCriticalError() << str;
68 mHost->JsWarning(str);
69 mHost->OnContextLoss(webgl::ContextLossReason::None);
70 break;
74 return IPC_OK();
77 IPCResult WebGLParent::RecvTexImage(const uint32_t level,
78 const uint32_t respecFormat,
79 const uvec3& offset,
80 const webgl::PackingInfo& pi,
81 webgl::TexUnpackBlobDesc&& desc) {
82 if (!mHost) {
83 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
86 mHost->TexImage(level, respecFormat, offset, pi, desc);
87 return IPC_OK();
90 // -
92 mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
93 mHost = nullptr;
94 return IPC_OK();
97 void WebGLParent::ActorDestroy(ActorDestroyReason aWhy) { mHost = nullptr; }
99 // -
101 IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
102 webgl::FrontBufferSnapshotIpc* const ret) {
103 return GetFrontBufferSnapshot(ret, this);
106 IPCResult WebGLParent::GetFrontBufferSnapshot(
107 webgl::FrontBufferSnapshotIpc* const ret, IProtocol* aProtocol) {
108 AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS);
109 *ret = {};
110 if (!mHost) {
111 return IPC_FAIL(aProtocol, "HostWebGLContext is not initialized.");
114 const bool ok = [&]() {
115 const auto maybeSize = mHost->FrontBufferSnapshotInto({});
116 if (maybeSize) {
117 const auto& surfSize = *maybeSize;
118 const auto byteSize = 4 * surfSize.x * surfSize.y;
120 auto shmem = webgl::RaiiShmem::Alloc(aProtocol, byteSize);
121 if (!shmem) {
122 NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
123 return false;
125 const auto range = shmem.ByteRange();
126 *ret = {surfSize, Some(shmem.Extract())};
128 if (!mHost->FrontBufferSnapshotInto(Some(range))) {
129 gfxCriticalNote << "WebGLParent::RecvGetFrontBufferSnapshot: "
130 "FrontBufferSnapshotInto(some) failed after "
131 "FrontBufferSnapshotInto(none)";
132 return false;
135 return true;
136 }();
137 if (!ok) {
138 // Zero means failure, as we still need to send any shmem we alloc.
139 ret->surfSize = {0, 0};
141 return IPC_OK();
144 IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
145 const uint64_t srcByteOffset,
146 const uint64_t byteSize,
147 Shmem* const ret) {
148 AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS);
149 if (!mHost) {
150 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
153 const auto allocSize = 1 + byteSize;
154 auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
155 if (!shmem) {
156 NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
157 return IPC_OK();
160 const auto shmemRange = shmem.ByteRange();
161 const auto dataRange =
162 Range<uint8_t>{shmemRange.begin() + 1, shmemRange.end()};
164 // We need to always send the shmem:
165 // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
166 const auto ok = mHost->GetBufferSubData(target, srcByteOffset, dataRange);
167 *(shmemRange.begin().get()) = ok;
168 *ret = shmem.Extract();
169 return IPC_OK();
172 IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
173 ReadPixelsBuffer&& buffer,
174 webgl::ReadPixelsResultIpc* const ret) {
175 AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS);
176 *ret = {};
177 if (!mHost) {
178 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
181 if (buffer.type() == ReadPixelsBuffer::TShmem) {
182 const auto& shmem = buffer.get_Shmem();
183 const auto range = shmem.Range<uint8_t>();
184 const auto res = mHost->ReadPixelsInto(desc, range);
185 *ret = {res, {}};
186 return IPC_OK();
189 const uint64_t byteSize = buffer.get_uint64_t();
190 const auto allocSize = std::max<uint64_t>(1, byteSize);
191 auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
192 if (!shmem) {
193 NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
194 return IPC_OK();
197 const auto range = shmem.ByteRange();
199 const auto res = mHost->ReadPixelsInto(desc, range);
200 *ret = {res, Some(shmem.Extract())};
201 return IPC_OK();
204 // -
206 IPCResult WebGLParent::RecvCheckFramebufferStatus(GLenum target,
207 GLenum* const ret) {
208 if (!mHost) {
209 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
212 *ret = mHost->CheckFramebufferStatus(target);
213 return IPC_OK();
216 IPCResult WebGLParent::RecvClientWaitSync(ObjectId id, GLbitfield flags,
217 GLuint64 timeout, GLenum* const ret) {
218 if (!mHost) {
219 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
222 *ret = mHost->ClientWaitSync(id, flags, timeout);
223 return IPC_OK();
226 IPCResult WebGLParent::RecvCreateOpaqueFramebuffer(
227 const ObjectId id, const OpaqueFramebufferOptions& options,
228 bool* const ret) {
229 if (!mHost) {
230 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
233 *ret = mHost->CreateOpaqueFramebuffer(id, options);
234 return IPC_OK();
237 IPCResult WebGLParent::RecvDrawingBufferSize(uvec2* const ret) {
238 if (!mHost) {
239 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
242 *ret = mHost->DrawingBufferSize();
243 return IPC_OK();
246 IPCResult WebGLParent::RecvFinish() {
247 if (!mHost) {
248 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
251 mHost->Finish();
252 return IPC_OK();
255 IPCResult WebGLParent::RecvGetBufferParameter(GLenum target, GLenum pname,
256 Maybe<double>* const ret) {
257 if (!mHost) {
258 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
261 *ret = mHost->GetBufferParameter(target, pname);
262 return IPC_OK();
265 IPCResult WebGLParent::RecvGetCompileResult(ObjectId id,
266 webgl::CompileResult* const ret) {
267 if (!mHost) {
268 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
271 *ret = mHost->GetCompileResult(id);
272 return IPC_OK();
275 IPCResult WebGLParent::RecvGetError(GLenum* const ret) {
276 if (!mHost) {
277 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
280 *ret = mHost->GetError();
281 return IPC_OK();
284 IPCResult WebGLParent::RecvGetFragDataLocation(ObjectId id,
285 const std::string& name,
286 GLint* const ret) {
287 if (!mHost) {
288 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
291 *ret = mHost->GetFragDataLocation(id, name);
292 return IPC_OK();
295 IPCResult WebGLParent::RecvGetFramebufferAttachmentParameter(
296 ObjectId id, GLenum attachment, GLenum pname, Maybe<double>* const ret) {
297 if (!mHost) {
298 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
301 *ret = mHost->GetFramebufferAttachmentParameter(id, attachment, pname);
302 return IPC_OK();
305 IPCResult WebGLParent::RecvGetFrontBuffer(
306 ObjectId fb, const bool vr, Maybe<layers::SurfaceDescriptor>* const ret) {
307 if (!mHost) {
308 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
311 *ret = mHost->GetFrontBuffer(fb, vr);
312 return IPC_OK();
315 IPCResult WebGLParent::RecvGetIndexedParameter(GLenum target, GLuint index,
316 Maybe<double>* const ret) {
317 if (!mHost) {
318 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
321 *ret = mHost->GetIndexedParameter(target, index);
322 return IPC_OK();
325 IPCResult WebGLParent::RecvGetInternalformatParameter(
326 const GLenum target, const GLuint format, const GLuint pname,
327 Maybe<std::vector<int32_t>>* const ret) {
328 if (!mHost) {
329 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
332 *ret = mHost->GetInternalformatParameter(target, format, pname);
333 return IPC_OK();
336 IPCResult WebGLParent::RecvGetLinkResult(ObjectId id,
337 webgl::LinkResult* const ret) {
338 if (!mHost) {
339 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
342 *ret = mHost->GetLinkResult(id);
343 return IPC_OK();
346 IPCResult WebGLParent::RecvGetNumber(GLenum pname, Maybe<double>* const ret) {
347 if (!mHost) {
348 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
351 *ret = mHost->GetNumber(pname);
352 return IPC_OK();
355 IPCResult WebGLParent::RecvGetQueryParameter(ObjectId id, GLenum pname,
356 Maybe<double>* const ret) {
357 if (!mHost) {
358 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
361 *ret = mHost->GetQueryParameter(id, pname);
362 return IPC_OK();
365 IPCResult WebGLParent::RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
366 Maybe<double>* const ret) {
367 if (!mHost) {
368 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
371 *ret = mHost->GetRenderbufferParameter(id, pname);
372 return IPC_OK();
375 IPCResult WebGLParent::RecvGetSamplerParameter(ObjectId id, GLenum pname,
376 Maybe<double>* const ret) {
377 if (!mHost) {
378 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
381 *ret = mHost->GetSamplerParameter(id, pname);
382 return IPC_OK();
385 IPCResult WebGLParent::RecvGetShaderPrecisionFormat(
386 GLenum shaderType, GLenum precisionType,
387 Maybe<webgl::ShaderPrecisionFormat>* const ret) {
388 if (!mHost) {
389 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
392 *ret = mHost->GetShaderPrecisionFormat(shaderType, precisionType);
393 return IPC_OK();
396 IPCResult WebGLParent::RecvGetString(GLenum pname,
397 Maybe<std::string>* const ret) {
398 if (!mHost) {
399 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
402 *ret = mHost->GetString(pname);
403 return IPC_OK();
406 IPCResult WebGLParent::RecvGetTexParameter(ObjectId id, GLenum pname,
407 Maybe<double>* const ret) {
408 if (!mHost) {
409 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
412 *ret = mHost->GetTexParameter(id, pname);
413 return IPC_OK();
416 IPCResult WebGLParent::RecvGetUniform(ObjectId id, uint32_t loc,
417 webgl::GetUniformData* const ret) {
418 if (!mHost) {
419 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
422 *ret = mHost->GetUniform(id, loc);
423 return IPC_OK();
426 IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname,
427 Maybe<double>* const ret) {
428 if (!mHost) {
429 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
432 *ret = mHost->GetVertexAttrib(index, pname);
433 return IPC_OK();
436 IPCResult WebGLParent::RecvIsEnabled(GLenum cap, bool* const ret) {
437 if (!mHost) {
438 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
441 *ret = mHost->IsEnabled(cap);
442 return IPC_OK();
445 IPCResult WebGLParent::RecvOnMemoryPressure() {
446 if (!mHost) {
447 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
450 mHost->OnMemoryPressure();
451 return IPC_OK();
454 IPCResult WebGLParent::RecvValidateProgram(ObjectId id, bool* const ret) {
455 if (!mHost) {
456 return IPC_FAIL(this, "HostWebGLContext is not initialized.");
459 *ret = mHost->ValidateProgram(id);
460 return IPC_OK();
463 } // namespace mozilla::dom