summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLParent.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /dom/canvas/WebGLParent.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/WebGLParent.cpp')
-rw-r--r--dom/canvas/WebGLParent.cpp492
1 files changed, 492 insertions, 0 deletions
diff --git a/dom/canvas/WebGLParent.cpp b/dom/canvas/WebGLParent.cpp
new file mode 100644
index 0000000000..44a0692b3f
--- /dev/null
+++ b/dom/canvas/WebGLParent.cpp
@@ -0,0 +1,492 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLParent.h"
+
+#include "WebGLChild.h"
+#include "mozilla/layers/TextureClientSharedSurface.h"
+#include "ImageContainer.h"
+#include "HostWebGLContext.h"
+#include "WebGLMethodDispatcher.h"
+
+namespace mozilla::dom {
+
+mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
+ const webgl::InitContextDesc& desc, webgl::InitContextResult* const out) {
+ mHost = HostWebGLContext::Create({nullptr, this}, desc, out);
+
+ if (!mHost) {
+ MOZ_ASSERT(!out->error->empty());
+ }
+
+ return IPC_OK();
+}
+
+WebGLParent::WebGLParent(const dom::ContentParentId& aContentId)
+ : mContentId(aContentId) {}
+
+WebGLParent::~WebGLParent() = default;
+
+// -
+
+using IPCResult = mozilla::ipc::IPCResult;
+
+IPCResult WebGLParent::RecvDispatchCommands(BigBuffer&& shmem,
+ const uint64_t cmdsByteSize) {
+ AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS);
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ const auto& gl = mHost->mContext->GL();
+ const gl::GLContext::TlsScope tlsIsCurrent(gl);
+
+ MOZ_ASSERT(cmdsByteSize);
+ const auto shmemBytes = Range<uint8_t>{shmem.AsSpan()};
+ const auto byteSize = std::min<uint64_t>(shmemBytes.length(), cmdsByteSize);
+ const auto cmdsBytes =
+ Range<const uint8_t>{shmemBytes.begin(), shmemBytes.begin() + byteSize};
+ auto view = webgl::RangeConsumerView{cmdsBytes};
+
+ if (kIsDebug) {
+ const auto initialOffset =
+ AlignmentOffset(kUniversalAlignment, cmdsBytes.begin().get());
+ MOZ_ALWAYS_TRUE(!initialOffset);
+ }
+
+ std::optional<std::string> fatalError;
+
+ while (true) {
+ view.AlignTo(kUniversalAlignment);
+ size_t id = 0;
+ if (!view.ReadParam(&id)) break;
+
+ // We split this up so that we don't end up in a long callstack chain of
+ // WebGLMethodDispatcher<i>|i=0->N. First get the lambda for dispatch, then
+ // invoke the lambda with our args.
+ const auto pfn =
+ WebGLMethodDispatcher<0>::DispatchCommandFuncById<HostWebGLContext>(id);
+ if (!pfn) {
+ const nsPrintfCString cstr(
+ "MethodDispatcher<%zu> not found. Please file a bug!", id);
+ fatalError = ToString(cstr);
+ gfxCriticalError() << *fatalError;
+ break;
+ };
+
+ const auto ok = (*pfn)(*mHost, view);
+ if (!ok) {
+ const nsPrintfCString cstr(
+ "DispatchCommand(id: %zu) failed. Please file a bug!", id);
+ fatalError = ToString(cstr);
+ gfxCriticalError() << *fatalError;
+ break;
+ }
+ }
+
+ if (fatalError) {
+ mHost->JsWarning(*fatalError);
+ mHost->OnContextLoss(webgl::ContextLossReason::None);
+ }
+
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvTexImage(const uint32_t level,
+ const uint32_t respecFormat,
+ const uvec3& offset,
+ const webgl::PackingInfo& pi,
+ webgl::TexUnpackBlobDesc&& desc) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ mHost->TexImage(level, respecFormat, offset, pi, desc);
+ return IPC_OK();
+}
+
+// -
+
+mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
+ mHost = nullptr;
+ return IPC_OK();
+}
+
+void WebGLParent::ActorDestroy(ActorDestroyReason aWhy) { mHost = nullptr; }
+
+mozilla::ipc::IPCResult WebGLParent::RecvWaitForTxn(
+ layers::RemoteTextureOwnerId aOwnerId,
+ layers::RemoteTextureTxnType aTxnType, layers::RemoteTextureTxnId aTxnId) {
+ if (mHost) {
+ mHost->WaitForTxn(aOwnerId, aTxnType, aTxnId);
+ }
+ return IPC_OK();
+}
+
+// -
+
+IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
+ webgl::FrontBufferSnapshotIpc* const ret) {
+ return GetFrontBufferSnapshot(ret, this);
+}
+
+IPCResult WebGLParent::GetFrontBufferSnapshot(
+ webgl::FrontBufferSnapshotIpc* const ret, IProtocol* aProtocol) {
+ AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS);
+ *ret = {};
+ if (!mHost) {
+ return IPC_FAIL(aProtocol, "HostWebGLContext is not initialized.");
+ }
+
+ const bool ok = [&]() {
+ const auto maybeSize = mHost->FrontBufferSnapshotInto({});
+ if (maybeSize) {
+ const auto& surfSize = *maybeSize;
+ const auto byteSize = 4 * surfSize.x * surfSize.y;
+
+ auto shmem = webgl::RaiiShmem::Alloc(aProtocol, byteSize);
+ if (!shmem) {
+ NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
+ return false;
+ }
+ const auto range = shmem.ByteRange();
+ *ret = {surfSize, Some(shmem.Extract())};
+
+ if (!mHost->FrontBufferSnapshotInto(Some(range))) {
+ gfxCriticalNote << "WebGLParent::RecvGetFrontBufferSnapshot: "
+ "FrontBufferSnapshotInto(some) failed after "
+ "FrontBufferSnapshotInto(none)";
+ return false;
+ }
+ }
+ return true;
+ }();
+ if (!ok) {
+ // Zero means failure, as we still need to send any shmem we alloc.
+ ret->surfSize = {0, 0};
+ }
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
+ const uint64_t srcByteOffset,
+ const uint64_t byteSize,
+ Shmem* const ret) {
+ AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS);
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ const auto allocSize = 1 + byteSize;
+ auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
+ if (!shmem) {
+ NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
+ return IPC_OK();
+ }
+
+ const auto shmemRange = shmem.ByteRange();
+ const auto dataRange =
+ Range<uint8_t>{shmemRange.begin() + 1, shmemRange.end()};
+
+ // We need to always send the shmem:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
+ const auto ok = mHost->GetBufferSubData(target, srcByteOffset, dataRange);
+ *(shmemRange.begin().get()) = ok;
+ *ret = shmem.Extract();
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
+ ReadPixelsBuffer&& buffer,
+ webgl::ReadPixelsResultIpc* const ret) {
+ AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS);
+ *ret = {};
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ if (buffer.type() == ReadPixelsBuffer::TShmem) {
+ const auto& shmem = buffer.get_Shmem();
+ const auto range = shmem.Range<uint8_t>();
+ const auto res = mHost->ReadPixelsInto(desc, range);
+ *ret = {res, {}};
+ return IPC_OK();
+ }
+
+ const uint64_t byteSize = buffer.get_uint64_t();
+ const auto allocSize = std::max<uint64_t>(1, byteSize);
+ auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
+ if (!shmem) {
+ NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
+ return IPC_OK();
+ }
+
+ const auto range = shmem.ByteRange();
+
+ const auto res = mHost->ReadPixelsInto(desc, range);
+ *ret = {res, Some(shmem.Extract())};
+ return IPC_OK();
+}
+
+// -
+
+IPCResult WebGLParent::RecvCheckFramebufferStatus(GLenum target,
+ GLenum* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->CheckFramebufferStatus(target);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvClientWaitSync(ObjectId id, GLbitfield flags,
+ GLuint64 timeout, GLenum* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->ClientWaitSync(id, flags, timeout);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvCreateOpaqueFramebuffer(
+ const ObjectId id, const OpaqueFramebufferOptions& options,
+ bool* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->CreateOpaqueFramebuffer(id, options);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvDrawingBufferSize(uvec2* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->DrawingBufferSize();
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvFinish() {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ mHost->Finish();
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetBufferParameter(GLenum target, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetBufferParameter(target, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetCompileResult(ObjectId id,
+ webgl::CompileResult* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetCompileResult(id);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetError(GLenum* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetError();
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetFragDataLocation(ObjectId id,
+ const std::string& name,
+ GLint* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetFragDataLocation(id, name);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetFramebufferAttachmentParameter(
+ ObjectId id, GLenum attachment, GLenum pname, Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetFramebufferAttachmentParameter(id, attachment, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetFrontBuffer(
+ ObjectId fb, const bool vr, Maybe<layers::SurfaceDescriptor>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetFrontBuffer(fb, vr);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetIndexedParameter(GLenum target, GLuint index,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetIndexedParameter(target, index);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetInternalformatParameter(
+ const GLenum target, const GLuint format, const GLuint pname,
+ Maybe<std::vector<int32_t>>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetInternalformatParameter(target, format, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetLinkResult(ObjectId id,
+ webgl::LinkResult* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetLinkResult(id);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetNumber(GLenum pname, Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetNumber(pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetQueryParameter(ObjectId id, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetQueryParameter(id, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetRenderbufferParameter(id, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetSamplerParameter(ObjectId id, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetSamplerParameter(id, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetShaderPrecisionFormat(
+ GLenum shaderType, GLenum precisionType,
+ Maybe<webgl::ShaderPrecisionFormat>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetShaderPrecisionFormat(shaderType, precisionType);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetString(GLenum pname,
+ Maybe<std::string>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetString(pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetTexParameter(ObjectId id, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetTexParameter(id, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetUniform(ObjectId id, uint32_t loc,
+ webgl::GetUniformData* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetUniform(id, loc);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname,
+ Maybe<double>* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->GetVertexAttrib(index, pname);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvIsEnabled(GLenum cap, bool* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->IsEnabled(cap);
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvOnMemoryPressure() {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ mHost->OnMemoryPressure();
+ return IPC_OK();
+}
+
+IPCResult WebGLParent::RecvValidateProgram(ObjectId id, bool* const ret) {
+ if (!mHost) {
+ return IPC_FAIL(this, "HostWebGLContext is not initialized.");
+ }
+
+ *ret = mHost->ValidateProgram(id);
+ return IPC_OK();
+}
+
+} // namespace mozilla::dom