зеркало из https://github.com/mozilla/gecko-dev.git
484 строки
14 KiB
C++
484 строки
14 KiB
C++
/* -*- 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::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
|