mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1691606 - Clean up dead code following WebGL out-of-process stabilization. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D104495
This commit is contained in:
parent
b850ece2f9
commit
09bc72760a
@ -41,8 +41,7 @@ webgl::NotLostData::NotLostData(ClientWebGLContext& _context)
|
||||
|
||||
webgl::NotLostData::~NotLostData() {
|
||||
if (outOfProcess) {
|
||||
const auto& pwebgl = outOfProcess->mWebGLChild;
|
||||
Unused << dom::WebGLChild::Send__delete__(pwebgl.get());
|
||||
Unused << dom::WebGLChild::Send__delete__(outOfProcess.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +211,6 @@ void ClientWebGLContext::OnContextLoss(
|
||||
}
|
||||
|
||||
void ClientWebGLContext::Event_webglcontextlost() const {
|
||||
WEBGL_BRIDGE_LOGD("[%p] Posting webglcontextlost event", this);
|
||||
const bool useDefaultHandler = DispatchEvent(u"webglcontextlost"_ns);
|
||||
if (useDefaultHandler) {
|
||||
mLossStatus = webgl::LossStatus::LostForever;
|
||||
@ -263,7 +261,6 @@ void ClientWebGLContext::Event_webglcontextrestored() const {
|
||||
return;
|
||||
}
|
||||
|
||||
WEBGL_BRIDGE_LOGD("[%p] Posting webglcontextrestored event", this);
|
||||
(void)DispatchEvent(u"webglcontextrestored"_ns);
|
||||
}
|
||||
|
||||
@ -282,7 +279,6 @@ void ClientWebGLContext::ThrowEvent_WebGLContextCreationError(
|
||||
return;
|
||||
}
|
||||
|
||||
WEBGL_BRIDGE_LOGD("[%p] Posting webglcontextcreationerror event", this);
|
||||
const auto kEventName = u"webglcontextcreationerror"_ns;
|
||||
|
||||
dom::WebGLContextEventInit eventInit;
|
||||
@ -311,7 +307,7 @@ void ClientWebGLContext::Run(Args&&... args) const {
|
||||
return (inProcess.get()->*method)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
|
||||
const auto id = IdByMethod<MethodType, method>();
|
||||
|
||||
@ -371,7 +367,7 @@ Maybe<layers::SurfaceDescriptor> ClientWebGLContext::GetFrontBuffer(
|
||||
return inProcess->GetFrontBuffer(fb ? fb->mId : 0, vr);
|
||||
}
|
||||
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<layers::SurfaceDescriptor> ret;
|
||||
if (!child->SendGetFrontBuffer(fb ? fb->mId : 0, vr, &ret)) return {};
|
||||
@ -389,8 +385,6 @@ already_AddRefed<layers::Layer> ClientWebGLContext::GetCanvasLayer(
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
WEBGL_BRIDGE_LOGI("[%p] Creating WebGL CanvasLayer/Renderer", this);
|
||||
|
||||
RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
|
||||
if (!canvasLayer) {
|
||||
NS_WARNING("CreateCanvasLayer returned null!");
|
||||
@ -418,7 +412,6 @@ bool ClientWebGLContext::UpdateWebRenderCanvasData(
|
||||
return true;
|
||||
}
|
||||
|
||||
WEBGL_BRIDGE_LOGI("[%p] Creating WebGL WR CanvasLayer/Renderer", this);
|
||||
renderer = aCanvasData->CreateCanvasRenderer();
|
||||
if (!InitializeCanvasRenderer(aBuilder, renderer)) {
|
||||
// Clear CanvasRenderer of WebRenderCanvasData
|
||||
@ -522,9 +515,6 @@ NS_IMETHODIMP
|
||||
ClientWebGLContext::SetDimensions(const int32_t signedWidth,
|
||||
const int32_t signedHeight) {
|
||||
const FuncScope funcScope(*this, "<SetDimensions>");
|
||||
WEBGL_BRIDGE_LOGI("[%p] SetDimensions: (%d, %d)", this, signedWidth,
|
||||
signedHeight);
|
||||
|
||||
MOZ_ASSERT(mInitialOptions);
|
||||
|
||||
if (mLossStatus != webgl::LossStatus::Ready) {
|
||||
@ -626,10 +616,7 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
|
||||
}
|
||||
|
||||
if (!useOop) {
|
||||
auto ownerData = HostWebGLContext::OwnerData{
|
||||
Some(this),
|
||||
};
|
||||
notLost.inProcess = HostWebGLContext::Create(std::move(ownerData),
|
||||
notLost.inProcess = HostWebGLContext::Create({this, nullptr},
|
||||
initDesc, ¬Lost.info);
|
||||
return Ok();
|
||||
}
|
||||
@ -638,61 +625,25 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
|
||||
|
||||
ScopedGfxFeatureReporter reporter("IpcWebGL");
|
||||
|
||||
webgl::RemotingData outOfProcess;
|
||||
|
||||
auto* const cbc = layers::CompositorBridgeChild::Get();
|
||||
MOZ_ASSERT(cbc);
|
||||
if (!cbc) {
|
||||
return Err("!CompositorBridgeChild::Get()");
|
||||
}
|
||||
|
||||
outOfProcess.mWebGLChild = new dom::WebGLChild(*this);
|
||||
outOfProcess.mWebGLChild = static_cast<dom::WebGLChild*>(
|
||||
cbc->SendPWebGLConstructor(outOfProcess.mWebGLChild));
|
||||
if (!outOfProcess.mWebGLChild) {
|
||||
RefPtr<dom::WebGLChild> outOfProcess = new dom::WebGLChild(*this);
|
||||
outOfProcess = static_cast<dom::WebGLChild*>(
|
||||
cbc->SendPWebGLConstructor(outOfProcess));
|
||||
if (!outOfProcess) {
|
||||
return Err("SendPWebGLConstructor failed");
|
||||
}
|
||||
|
||||
UniquePtr<HostWebGLCommandSinkP> sinkP;
|
||||
UniquePtr<HostWebGLCommandSinkI> sinkI;
|
||||
if (StaticPrefs::webgl_oop_via_pcq()) {
|
||||
using mozilla::webgl::ProducerConsumerQueue;
|
||||
static constexpr size_t CommandQueueSize = 256 * 1024; // 256K
|
||||
static constexpr size_t ResponseQueueSize = 8 * 1024; // 8K
|
||||
auto command = ProducerConsumerQueue::Create(cbc, CommandQueueSize);
|
||||
auto response = ProducerConsumerQueue::Create(cbc, ResponseQueueSize);
|
||||
if (!command || !response) {
|
||||
return Err("Failed to create command/response PCQ");
|
||||
}
|
||||
|
||||
outOfProcess.mCommandSourcePcq = MakeUnique<ClientWebGLCommandSourceP>(
|
||||
command->TakeProducer(), response->TakeConsumer());
|
||||
sinkP = MakeUnique<HostWebGLCommandSinkP>(command->TakeConsumer(),
|
||||
response->TakeProducer());
|
||||
|
||||
} else {
|
||||
using mozilla::IpdlWebGLCommandQueue;
|
||||
using mozilla::IpdlWebGLResponseQueue;
|
||||
auto command =
|
||||
IpdlWebGLCommandQueue::Create(outOfProcess.mWebGLChild.get());
|
||||
auto response =
|
||||
IpdlWebGLResponseQueue::Create(outOfProcess.mWebGLChild.get());
|
||||
if (!command || !response) {
|
||||
return Err("Failed to create command/response IpdlQueue");
|
||||
}
|
||||
|
||||
outOfProcess.mCommandSourceIpdl = MakeUnique<ClientWebGLCommandSourceI>(
|
||||
command->TakeProducer(), response->TakeConsumer());
|
||||
sinkI = MakeUnique<HostWebGLCommandSinkI>(command->TakeConsumer(),
|
||||
response->TakeProducer());
|
||||
}
|
||||
|
||||
if (!outOfProcess.mWebGLChild->SendInitialize(
|
||||
initDesc, std::move(sinkP), std::move(sinkI), ¬Lost.info)) {
|
||||
if (!outOfProcess->SendInitialize(
|
||||
initDesc, ¬Lost.info)) {
|
||||
return Err("WebGL actor Initialize failed");
|
||||
}
|
||||
|
||||
notLost.outOfProcess = Some(std::move(outOfProcess));
|
||||
notLost.outOfProcess = outOfProcess;
|
||||
reporter.SetSuccessful();
|
||||
return Ok();
|
||||
}();
|
||||
@ -771,7 +722,7 @@ uvec2 ClientWebGLContext::DrawingBufferSize() {
|
||||
if (inProcess) {
|
||||
size = Some(inProcess->DrawingBufferSize());
|
||||
} else {
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
uvec2 actual = {};
|
||||
if (!child->SendDrawingBufferSize(&actual)) return {};
|
||||
@ -789,7 +740,7 @@ void ClientWebGLContext::OnMemoryPressure() {
|
||||
if (inProcess) {
|
||||
return inProcess->OnMemoryPressure();
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
(void)child->SendOnMemoryPressure();
|
||||
}
|
||||
|
||||
@ -933,7 +884,7 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
|
||||
}
|
||||
return surf;
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
webgl::FrontBufferSnapshotIpc res;
|
||||
if (!child->SendGetFrontBufferSnapshot(&res)) {
|
||||
@ -1137,7 +1088,7 @@ ClientWebGLContext::CreateOpaqueFramebuffer(
|
||||
}
|
||||
return ret.forget();
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
bool ok = false;
|
||||
if (!child->SendCreateOpaqueFramebuffer(ret->mId, options, &ok))
|
||||
@ -1669,7 +1620,7 @@ bool ClientWebGLContext::IsEnabled(GLenum cap) const {
|
||||
if (inProcess) {
|
||||
return inProcess->IsEnabled(cap);
|
||||
}
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
bool ret = {};
|
||||
if (!child->SendIsEnabled(cap, &ret)) return false;
|
||||
@ -1691,7 +1642,7 @@ void ClientWebGLContext::GetInternalformatParameter(
|
||||
maybe = inProcessContext->GetInternalformatParameter(target, internalformat,
|
||||
pname);
|
||||
} else {
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
if (!child->SendGetInternalformatParameter(target, internalformat, pname,
|
||||
&maybe)) {
|
||||
@ -1757,7 +1708,7 @@ Maybe<double> ClientWebGLContext::GetNumber(const GLenum pname) {
|
||||
return inProcess->GetNumber(pname);
|
||||
}
|
||||
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
|
||||
Maybe<double> ret;
|
||||
@ -1775,7 +1726,7 @@ Maybe<std::string> ClientWebGLContext::GetString(const GLenum pname) {
|
||||
return inProcess->GetString(pname);
|
||||
}
|
||||
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
|
||||
Maybe<std::string> ret;
|
||||
@ -2203,7 +2154,7 @@ void ClientWebGLContext::GetBufferParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetBufferParameter(target, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetBufferParameter(target, pname, &ret)) {
|
||||
@ -2257,7 +2208,7 @@ void ClientWebGLContext::GetFramebufferAttachmentParameter(
|
||||
return inProcess->GetFramebufferAttachmentParameter(fbId, attachment,
|
||||
pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetFramebufferAttachmentParameter(fbId, attachment, pname,
|
||||
@ -2332,7 +2283,7 @@ void ClientWebGLContext::GetRenderbufferParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetRenderbufferParameter(rbId, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetRenderbufferParameter(rbId, pname, &ret)) {
|
||||
@ -2384,7 +2335,7 @@ void ClientWebGLContext::GetIndexedParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetIndexedParameter(target, index);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetIndexedParameter(target, index, &ret)) {
|
||||
@ -2424,7 +2375,7 @@ void ClientWebGLContext::GetUniform(JSContext* const cx,
|
||||
if (inProcess) {
|
||||
return inProcess->GetUniform(prog.mId, loc.mLocation);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
webgl::GetUniformData ret;
|
||||
if (!child->SendGetUniform(prog.mId, loc.mLocation, &ret)) {
|
||||
@ -2540,7 +2491,7 @@ ClientWebGLContext::GetShaderPrecisionFormat(const GLenum shadertype,
|
||||
if (inProcess) {
|
||||
return inProcess->GetShaderPrecisionFormat(shadertype, precisiontype);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<webgl::ShaderPrecisionFormat> ret;
|
||||
if (!child->SendGetShaderPrecisionFormat(shadertype, precisiontype, &ret)) {
|
||||
@ -2585,7 +2536,7 @@ GLenum ClientWebGLContext::CheckFramebufferStatus(GLenum target) {
|
||||
if (inProcess) {
|
||||
return inProcess->CheckFramebufferStatus(target);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
GLenum ret = 0;
|
||||
if (!child->SendCheckFramebufferStatus(target, &ret)) {
|
||||
@ -2711,7 +2662,7 @@ void ClientWebGLContext::Flush() {
|
||||
Run<RPROC(Flush)>();
|
||||
|
||||
if (notLost->inProcess) return;
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
}
|
||||
|
||||
@ -2723,7 +2674,7 @@ void ClientWebGLContext::Finish() {
|
||||
inProcess->Finish();
|
||||
return;
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
(void)child->SendFinish();
|
||||
}
|
||||
@ -2743,7 +2694,7 @@ GLenum ClientWebGLContext::GetError() {
|
||||
if (inProcess) {
|
||||
return inProcess->GetError();
|
||||
}
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
GLenum ret = 0;
|
||||
if (!child->SendGetError(&ret)) {
|
||||
@ -3116,7 +3067,7 @@ void ClientWebGLContext::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
mozilla::ipc::Shmem rawShmem;
|
||||
if (!child->SendGetBufferSubData(target, srcByteOffset, destView.length(),
|
||||
@ -3688,7 +3639,7 @@ void ClientWebGLContext::GetTexParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetTexParameter(tex->mId, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetTexParameter(tex->mId, pname, &ret)) {
|
||||
@ -4198,7 +4149,7 @@ void ClientWebGLContext::ValidateProgram(WebGLProgramJS& prog) const {
|
||||
if (inProcess) {
|
||||
return inProcess->ValidateProgram(prog.mId);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
bool ret = {};
|
||||
if (!child->SendValidateProgram(prog.mId, &ret)) {
|
||||
@ -4216,7 +4167,7 @@ Maybe<double> ClientWebGLContext::GetVertexAttribPriv(const GLuint index,
|
||||
if (inProcess) {
|
||||
return inProcess->GetVertexAttrib(index, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetVertexAttrib(index, pname, &ret)) {
|
||||
@ -4613,7 +4564,7 @@ void ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
inProcess->ReadPixelsInto(desc, dest);
|
||||
return;
|
||||
}
|
||||
const auto& child = notLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = notLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
webgl::ReadPixelsResultIpc res = {};
|
||||
if (!child->SendReadPixels(desc, dest.length(), &res)) {
|
||||
@ -4738,7 +4689,7 @@ void ClientWebGLContext::GetQueryParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetQueryParameter(query.mId, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetQueryParameter(query.mId, pname, &ret)) {
|
||||
@ -4871,7 +4822,7 @@ void ClientWebGLContext::GetSamplerParameter(
|
||||
if (inProcess) {
|
||||
return inProcess->GetSamplerParameter(sampler.mId, pname);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
Maybe<double> ret;
|
||||
if (!child->SendGetSamplerParameter(sampler.mId, pname, &ret)) {
|
||||
@ -4977,7 +4928,7 @@ GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync,
|
||||
if (inProcess) {
|
||||
return inProcess->ClientWaitSync(sync.mId, flags, timeout);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
GLenum ret = {};
|
||||
if (!child->SendClientWaitSync(sync.mId, flags, timeout, &ret)) {
|
||||
@ -5672,7 +5623,7 @@ GLint ClientWebGLContext::GetFragDataLocation(const WebGLProgramJS& prog,
|
||||
if (inProcess) {
|
||||
return inProcess->GetFragDataLocation(prog.mId, nameU8);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
GLint ret = {};
|
||||
if (!child->SendGetFragDataLocation(prog.mId, nameU8, &ret)) {
|
||||
@ -6019,7 +5970,7 @@ const webgl::CompileResult& ClientWebGLContext::GetCompileResult(
|
||||
if (inProcess) {
|
||||
return inProcess->GetCompileResult(shader.mId);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
webgl::CompileResult ret = {};
|
||||
if (!child->SendGetCompileResult(shader.mId, &ret)) {
|
||||
@ -6043,7 +5994,7 @@ const webgl::LinkResult& ClientWebGLContext::GetLinkResult(
|
||||
if (inProcess) {
|
||||
return inProcess->GetLinkResult(prog.mId);
|
||||
}
|
||||
const auto& child = mNotLost->outOfProcess->mWebGLChild;
|
||||
const auto& child = mNotLost->outOfProcess;
|
||||
child->FlushPendingCmds();
|
||||
webgl::LinkResult ret;
|
||||
if (!child->SendGetLinkResult(prog.mId, &ret)) {
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "WebGLCrossProcessCommandQueue.h"
|
||||
#include "WebGLCommandQueue.h"
|
||||
|
||||
#include <memory>
|
||||
@ -28,19 +27,10 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef WEBGL_BRIDGE_LOG_
|
||||
# define WEBGL_BRIDGE_LOG_(lvl, ...) \
|
||||
MOZ_LOG(mozilla::gWebGLBridgeLog, lvl, (__VA_ARGS__))
|
||||
# define WEBGL_BRIDGE_LOGV(...) \
|
||||
WEBGL_BRIDGE_LOG_(LogLevel::Verbose, __VA_ARGS__)
|
||||
# define WEBGL_BRIDGE_LOGD(...) WEBGL_BRIDGE_LOG_(LogLevel::Debug, __VA_ARGS__)
|
||||
# define WEBGL_BRIDGE_LOGI(...) WEBGL_BRIDGE_LOG_(LogLevel::Info, __VA_ARGS__)
|
||||
# define WEBGL_BRIDGE_LOGE(...) WEBGL_BRIDGE_LOG_(LogLevel::Error, __VA_ARGS__)
|
||||
#endif // WEBGL_BRIDGE_LOG_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ClientWebGLExtensionBase;
|
||||
class HostWebGLContext;
|
||||
|
||||
namespace dom {
|
||||
class WebGLChild;
|
||||
@ -186,24 +176,19 @@ class ContextGenerationInfo final {
|
||||
|
||||
// -
|
||||
|
||||
struct RemotingData final {
|
||||
// In the cross process case, the WebGL actor's ownership relationship looks
|
||||
// like this:
|
||||
// ---------------------------------------------------------------------
|
||||
// | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// where 'A -> B' means "A owns B"
|
||||
RefPtr<mozilla::dom::WebGLChild> mWebGLChild;
|
||||
UniquePtr<ClientWebGLCommandSourceP> mCommandSourcePcq;
|
||||
UniquePtr<ClientWebGLCommandSourceI> mCommandSourceIpdl;
|
||||
};
|
||||
// In the cross process case, the WebGL actor's ownership relationship looks
|
||||
// like this:
|
||||
// ---------------------------------------------------------------------
|
||||
// | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// where 'A -> B' means "A owns B"
|
||||
|
||||
struct NotLostData final {
|
||||
ClientWebGLContext& context;
|
||||
webgl::InitContextResult info;
|
||||
|
||||
Maybe<RemotingData> outOfProcess;
|
||||
RefPtr<mozilla::dom::WebGLChild> outOfProcess;
|
||||
UniquePtr<HostWebGLContext> inProcess;
|
||||
|
||||
webgl::ContextGenerationInfo state;
|
||||
@ -793,7 +778,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
mozilla::dom::WebGLChild* GetChild() const {
|
||||
if (!mNotLost) return nullptr;
|
||||
if (!mNotLost->outOfProcess) return nullptr;
|
||||
return mNotLost->outOfProcess->mWebGLChild.get();
|
||||
return mNotLost->outOfProcess.get();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "WebGL2Context.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLCrossProcessCommandQueue.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLMemoryTracker.h"
|
||||
#include "WebGLParent.h"
|
||||
@ -32,8 +31,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
LazyLogModule gWebGLBridgeLog("webglbridge");
|
||||
|
||||
// -
|
||||
|
||||
static StaticMutex sContextSetLock;
|
||||
@ -56,30 +53,19 @@ LockedOutstandingContexts::~LockedOutstandingContexts() {
|
||||
|
||||
/*static*/
|
||||
UniquePtr<HostWebGLContext> HostWebGLContext::Create(
|
||||
OwnerData&& ownerData, const webgl::InitContextDesc& desc,
|
||||
const OwnerData& ownerData, const webgl::InitContextDesc& desc,
|
||||
webgl::InitContextResult* const out) {
|
||||
auto host = WrapUnique(new HostWebGLContext(std::move(ownerData)));
|
||||
auto host = WrapUnique(new HostWebGLContext(ownerData));
|
||||
auto webgl = WebGLContext::Create(*host, desc, out);
|
||||
if (!webgl) return nullptr;
|
||||
return host;
|
||||
}
|
||||
|
||||
HostWebGLContext::HostWebGLContext(OwnerData&& ownerData)
|
||||
: mOwnerData(std::move(ownerData)) {
|
||||
if (mOwnerData.outOfProcess) {
|
||||
if (mOwnerData.outOfProcess->mCommandSinkP) {
|
||||
mOwnerData.outOfProcess->mCommandSinkP->mHostContext = this;
|
||||
}
|
||||
if (mOwnerData.outOfProcess->mCommandSinkI) {
|
||||
mOwnerData.outOfProcess->mCommandSinkI->mHostContext = this;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
StaticMutexAutoLock lock(sContextSetLock);
|
||||
auto& contexts = DeferredStaticContextSet();
|
||||
(void)contexts.insert(this);
|
||||
}
|
||||
HostWebGLContext::HostWebGLContext(const OwnerData& ownerData)
|
||||
: mOwnerData(ownerData) {
|
||||
StaticMutexAutoLock lock(sContextSetLock);
|
||||
auto& contexts = DeferredStaticContextSet();
|
||||
(void)contexts.insert(this);
|
||||
}
|
||||
|
||||
HostWebGLContext::~HostWebGLContext() {
|
||||
@ -92,18 +78,18 @@ HostWebGLContext::~HostWebGLContext() {
|
||||
|
||||
void HostWebGLContext::OnContextLoss(const webgl::ContextLossReason reason) {
|
||||
if (mOwnerData.inProcess) {
|
||||
(*mOwnerData.inProcess)->OnContextLoss(reason);
|
||||
mOwnerData.inProcess->OnContextLoss(reason);
|
||||
} else {
|
||||
(void)mOwnerData.outOfProcess->mParent.SendOnContextLoss(reason);
|
||||
(void)mOwnerData.outOfProcess->SendOnContextLoss(reason);
|
||||
}
|
||||
}
|
||||
|
||||
void HostWebGLContext::JsWarning(const std::string& text) const {
|
||||
if (mOwnerData.inProcess) {
|
||||
(*mOwnerData.inProcess)->JsWarning(text);
|
||||
mOwnerData.inProcess->JsWarning(text);
|
||||
return;
|
||||
}
|
||||
(void)mOwnerData.outOfProcess->mParent.SendJsWarning(text);
|
||||
(void)mOwnerData.outOfProcess->SendJsWarning(text);
|
||||
}
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> HostWebGLContext::GetFrontBuffer(
|
||||
|
@ -17,25 +17,14 @@
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLTypes.h"
|
||||
#include "WebGLCommandQueue.h"
|
||||
#include "WebGLCrossProcessCommandQueue.h"
|
||||
#include "ProducerConsumerQueue.h"
|
||||
#include "IpdlQueue.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef WEBGL_BRIDGE_LOG_
|
||||
# define WEBGL_BRIDGE_LOG_(lvl, ...) \
|
||||
MOZ_LOG(mozilla::gWebGLBridgeLog, lvl, (__VA_ARGS__))
|
||||
# define WEBGL_BRIDGE_LOGD(...) WEBGL_BRIDGE_LOG_(LogLevel::Debug, __VA_ARGS__)
|
||||
# define WEBGL_BRIDGE_LOGE(...) WEBGL_BRIDGE_LOG_(LogLevel::Error, __VA_ARGS__)
|
||||
#endif // WEBGL_BRIDGE_LOG_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern LazyLogModule gWebGLBridgeLog;
|
||||
|
||||
namespace dom {
|
||||
class WebGLParent;
|
||||
}
|
||||
@ -80,22 +69,17 @@ class HostWebGLContext final : public SupportsWeakPtr {
|
||||
}
|
||||
|
||||
public:
|
||||
struct RemotingData final {
|
||||
dom::WebGLParent& mParent;
|
||||
UniquePtr<HostWebGLCommandSinkP> mCommandSinkP;
|
||||
UniquePtr<HostWebGLCommandSinkI> mCommandSinkI;
|
||||
};
|
||||
struct OwnerData final {
|
||||
Maybe<ClientWebGLContext*> inProcess;
|
||||
Maybe<RemotingData> outOfProcess;
|
||||
ClientWebGLContext* inProcess = nullptr;
|
||||
dom::WebGLParent* outOfProcess = nullptr;
|
||||
};
|
||||
|
||||
static UniquePtr<HostWebGLContext> Create(OwnerData&&,
|
||||
static UniquePtr<HostWebGLContext> Create(const OwnerData&,
|
||||
const webgl::InitContextDesc&,
|
||||
webgl::InitContextResult* out);
|
||||
|
||||
private:
|
||||
explicit HostWebGLContext(OwnerData&&);
|
||||
explicit HostWebGLContext(const OwnerData&);
|
||||
|
||||
public:
|
||||
virtual ~HostWebGLContext();
|
||||
@ -794,9 +778,6 @@ class HostWebGLContext final : public SupportsWeakPtr {
|
||||
MOZ_RELEASE_ASSERT(mContext->IsWebGL2(), "Requires WebGL2 context");
|
||||
return static_cast<WebGL2Context*>(mContext.get());
|
||||
}
|
||||
|
||||
// mozilla::ipc::Shmem PopShmem() { return mShmemStack.PopLastElement(); }
|
||||
// nsTArray<mozilla::ipc::Shmem> mShmemStack;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -25,8 +25,6 @@ using mozilla::webgl::ShaderPrecisionFormat from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::OpaqueFramebufferOptions from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::ReadPixelsDesc from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::ReadPixelsResultIpc from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::HostWebGLCommandSinkP from "mozilla/dom/WebGLCrossProcessCommandQueue.h";
|
||||
using mozilla::HostWebGLCommandSinkI from "mozilla/dom/WebGLCrossProcessCommandQueue.h";
|
||||
using mozilla::dom::IpdlQueueBuffer from "mozilla/dom/IpdlQueue.h";
|
||||
using mozilla::dom::IpdlQueueBuffers from "mozilla/dom/IpdlQueue.h";
|
||||
|
||||
@ -43,8 +41,7 @@ sync refcounted protocol PWebGL
|
||||
manager PCompositorBridge;
|
||||
|
||||
parent:
|
||||
sync Initialize(InitContextDesc desc, UniquePtr<HostWebGLCommandSinkP> sinkP,
|
||||
UniquePtr<HostWebGLCommandSinkI> sinkI)
|
||||
sync Initialize(InitContextDesc desc)
|
||||
returns (InitContextResult res);
|
||||
|
||||
async __delete__();
|
||||
|
@ -1,989 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=4 et :
|
||||
*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_ProducerConsumerQueue_h
|
||||
#define mozilla_ipc_ProducerConsumerQueue_h 1
|
||||
|
||||
#include <atomic>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/QueueParamTraits.h"
|
||||
#include "mozilla/ipc/ShmemMessageUtils.h"
|
||||
#include "CrossProcessSemaphore.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace IPC {
|
||||
template <typename T>
|
||||
struct ParamTraits;
|
||||
} // namespace IPC
|
||||
|
||||
namespace mozilla {
|
||||
namespace webgl {
|
||||
|
||||
using mozilla::ipc::IProtocol;
|
||||
using mozilla::ipc::Shmem;
|
||||
|
||||
extern LazyLogModule gPCQLog;
|
||||
#define PCQ_LOG_(lvl, ...) MOZ_LOG(mozilla::webgl::gPCQLog, lvl, (__VA_ARGS__))
|
||||
#define PCQ_LOGD(...) PCQ_LOG_(LogLevel::Debug, __VA_ARGS__)
|
||||
#define PCQ_LOGE(...) PCQ_LOG_(LogLevel::Error, __VA_ARGS__)
|
||||
|
||||
class ProducerConsumerQueue;
|
||||
class PcqProducer;
|
||||
class PcqConsumer;
|
||||
|
||||
/**
|
||||
* PcqActor is an actor base-class that is used as a static map that
|
||||
* provides casting from an IProtocol to a PcqActor. PcqActors delegate
|
||||
* all needed IProtocol operations and also support weak references.
|
||||
* Actors used to construct a PCQ must implement this class.
|
||||
* Example:
|
||||
* class MyActorParent : public PMyActorParent, public PcqActor {
|
||||
* MyActorParent() : PcqActor(this) {}
|
||||
* // ...
|
||||
* }
|
||||
* Implementations of abstract methods will typically just forward to IProtocol.
|
||||
*/
|
||||
class PcqActor : public SupportsWeakPtr {
|
||||
// The IProtocol part of `this`.
|
||||
IProtocol* mProtocol;
|
||||
|
||||
using PcqActorMap = std::unordered_map<IProtocol*, PcqActor*>;
|
||||
// uses StaticAutoPtr to placate anti-static-ctor static analysis
|
||||
inline static StaticAutoPtr<PcqActorMap> sMap;
|
||||
|
||||
static bool IsActorThread() {
|
||||
static nsIThread* sActorThread = [] { return NS_GetCurrentThread(); }();
|
||||
return sActorThread == NS_GetCurrentThread();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit PcqActor(IProtocol* aProtocol) : mProtocol(aProtocol) {
|
||||
MOZ_ASSERT(IsActorThread());
|
||||
if (!sMap) {
|
||||
sMap = new PcqActorMap();
|
||||
}
|
||||
sMap->insert({mProtocol, this});
|
||||
}
|
||||
~PcqActor() {
|
||||
MOZ_ASSERT(IsActorThread());
|
||||
sMap->erase(mProtocol);
|
||||
if (sMap->empty()) {
|
||||
delete sMap;
|
||||
sMap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Shmem::SharedMemory* LookupSharedMemory(int32_t aId) {
|
||||
return mProtocol->LookupSharedMemory(aId);
|
||||
}
|
||||
int32_t Id() const { return mProtocol->Id(); }
|
||||
base::ProcessId OtherPid() const { return mProtocol->OtherPid(); }
|
||||
bool AllocShmem(size_t aSize,
|
||||
mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
|
||||
mozilla::ipc::Shmem* aShmem) {
|
||||
return mProtocol->AllocShmem(aSize, aShmType, aShmem);
|
||||
}
|
||||
|
||||
static PcqActor* LookupProtocol(IProtocol* aProtocol) {
|
||||
MOZ_ASSERT(IsActorThread());
|
||||
MOZ_ASSERT(sMap);
|
||||
if (!sMap) {
|
||||
return nullptr;
|
||||
}
|
||||
auto it = sMap->find(aProtocol);
|
||||
return (it != sMap->end()) ? it->second : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
// NB: detail is in mozilla instead of mozilla::webgl because many points in
|
||||
// existing code get confused if mozilla::detail and mozilla::webgl::detail
|
||||
// exist.
|
||||
namespace detail {
|
||||
using mozilla::ipc::IProtocol;
|
||||
using mozilla::ipc::Shmem;
|
||||
using mozilla::webgl::IsSuccess;
|
||||
using mozilla::webgl::PcqActor;
|
||||
using mozilla::webgl::ProducerConsumerQueue;
|
||||
using mozilla::webgl::QueueStatus;
|
||||
|
||||
constexpr size_t GetCacheLineSize() { return 64; }
|
||||
|
||||
// NB: The header may end up consuming fewer bytes than this. This value
|
||||
// guarantees that we can always byte-align the header contents.
|
||||
constexpr size_t GetMaxHeaderSize() {
|
||||
// Recall that the Shmem contents are laid out like this:
|
||||
// -----------------------------------------------------------------------
|
||||
// queue contents | align1 | mRead | align2 | mWrite | align3 | User Data
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
constexpr size_t alignment =
|
||||
std::max(std::alignment_of<size_t>::value, GetCacheLineSize());
|
||||
static_assert(alignment >= sizeof(size_t),
|
||||
"alignment expected to be large enough to hold a size_t");
|
||||
|
||||
// We may need up to this many bytes to properly align mRead
|
||||
constexpr size_t maxAlign1 = alignment - 1;
|
||||
constexpr size_t readAndAlign2 = alignment;
|
||||
constexpr size_t writeAndAlign3 = alignment;
|
||||
return maxAlign1 + readAndAlign2 + writeAndAlign3;
|
||||
}
|
||||
|
||||
template <typename View, typename Arg, typename... Args>
|
||||
size_t MinSizeofArgs(View& aView, const Arg& aArg, const Args&... aArgs) {
|
||||
return aView.MinSizeParam(aArg) + MinSizeofArgs(aView, aArgs...);
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
size_t MinSizeofArgs(View&) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class PcqRCSemaphore {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PcqRCSemaphore)
|
||||
explicit PcqRCSemaphore(CrossProcessSemaphore* aSem) : mSem(aSem) {
|
||||
MOZ_ASSERT(mSem);
|
||||
}
|
||||
|
||||
bool Wait(const Maybe<TimeDuration>& aTime) { return mSem->Wait(aTime); }
|
||||
void Signal() { mSem->Signal(); }
|
||||
bool IsAvailable() {
|
||||
MOZ_ASSERT_UNREACHABLE("Unimplemented");
|
||||
return false;
|
||||
}
|
||||
CrossProcessSemaphoreHandle ShareToProcess(base::ProcessId aTargetPid) {
|
||||
return mSem->ShareToProcess(aTargetPid);
|
||||
}
|
||||
void CloseHandle() { mSem->CloseHandle(); }
|
||||
|
||||
private:
|
||||
~PcqRCSemaphore() { delete mSem; }
|
||||
CrossProcessSemaphore* mSem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Common base class for PcqProducer and Consumer.
|
||||
*/
|
||||
class PcqBase {
|
||||
public:
|
||||
/**
|
||||
* Bytes used in the queue if the parameters are the read/write heads.
|
||||
*/
|
||||
size_t UsedBytes(size_t aRead, size_t aWrite) {
|
||||
MOZ_ASSERT(ValidState(aRead, aWrite));
|
||||
return mozilla::webgl::UsedBytes(QueueBufferSize(), aRead, aWrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bytes free in the queue if the parameters are the read/write heads.
|
||||
*/
|
||||
size_t FreeBytes(size_t aRead, size_t aWrite) {
|
||||
MOZ_ASSERT(ValidState(aRead, aWrite));
|
||||
return mozilla::webgl::FreeBytes(QueueBufferSize(), aRead, aWrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* True when this queue is valid with the parameters as the read/write heads.
|
||||
*/
|
||||
bool ValidState(size_t aRead, size_t aWrite) {
|
||||
return (aRead < QueueBufferSize()) && (aWrite < QueueBufferSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* True when this queue is empty with the parameters as the read/write heads.
|
||||
*/
|
||||
bool IsEmpty(size_t aRead, size_t aWrite) {
|
||||
MOZ_ASSERT(ValidState(aRead, aWrite));
|
||||
return UsedBytes(aRead, aWrite) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* True when this queue is full with the parameters as the read/write heads.
|
||||
*/
|
||||
bool IsFull(size_t aRead, size_t aWrite) {
|
||||
MOZ_ASSERT(ValidState(aRead, aWrite));
|
||||
return FreeBytes(aRead, aWrite) == 0;
|
||||
}
|
||||
|
||||
// Cheaply get the used size of the current queue. This does no
|
||||
// synchronization so the information may be stale. On the PcqProducer
|
||||
// side, it will never underestimate the number of bytes used and,
|
||||
// on the Consumer side, it will never overestimate them.
|
||||
// (The reciprocal is true of FreeBytes.)
|
||||
size_t UsedBytes() {
|
||||
size_t write = mWrite->load(std::memory_order_relaxed);
|
||||
size_t read = mRead->load(std::memory_order_relaxed);
|
||||
return UsedBytes(read, write);
|
||||
}
|
||||
|
||||
// This does no synchronization so the information may be stale.
|
||||
size_t FreeBytes() { return QueueSize() - UsedBytes(); }
|
||||
|
||||
// This does no synchronization so the information may be stale.
|
||||
bool IsEmpty() { return IsEmpty(GetReadRelaxed(), GetWriteRelaxed()); }
|
||||
|
||||
// This does no synchronization so the information may be stale.
|
||||
bool IsFull() { return IsFull(GetReadRelaxed(), GetWriteRelaxed()); }
|
||||
|
||||
protected:
|
||||
friend struct mozilla::ipc::IPDLParamTraits<PcqBase>;
|
||||
friend ProducerConsumerQueue;
|
||||
|
||||
PcqBase() = default;
|
||||
|
||||
PcqBase(Shmem& aShmem, IProtocol* aProtocol, size_t aQueueSize,
|
||||
RefPtr<PcqRCSemaphore> aMaybeNotEmptySem,
|
||||
RefPtr<PcqRCSemaphore> aMaybeNotFullSem) {
|
||||
Set(aShmem, aProtocol, aQueueSize, aMaybeNotEmptySem, aMaybeNotFullSem);
|
||||
}
|
||||
|
||||
PcqBase(const PcqBase&) = delete;
|
||||
PcqBase(PcqBase&&) = default;
|
||||
PcqBase& operator=(const PcqBase&) = delete;
|
||||
PcqBase& operator=(PcqBase&&) = default;
|
||||
|
||||
void Set(Shmem& aShmem, IProtocol* aProtocol, size_t aQueueSize,
|
||||
RefPtr<PcqRCSemaphore> aMaybeNotEmptySem,
|
||||
RefPtr<PcqRCSemaphore> aMaybeNotFullSem) {
|
||||
mActor = PcqActor::LookupProtocol(aProtocol);
|
||||
MOZ_RELEASE_ASSERT(mActor);
|
||||
|
||||
mOtherPid = mActor->OtherPid();
|
||||
mShmem = aShmem;
|
||||
mQueue = aShmem.get<uint8_t>();
|
||||
|
||||
// NB: The buffer needs one extra byte for the queue contents
|
||||
mQueueBufferSize = aQueueSize + 1;
|
||||
|
||||
// Recall that the Shmem contents are laid out like this:
|
||||
// -----------------------------------------------------------------------
|
||||
// queue contents | align1 | mRead | align2 | mWrite | align3 | User Data
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
size_t shmemSize = aShmem.Size<uint8_t>();
|
||||
uint8_t* header = mQueue + mQueueBufferSize;
|
||||
|
||||
constexpr size_t alignment =
|
||||
std::max(std::alignment_of<size_t>::value, GetCacheLineSize());
|
||||
static_assert(alignment >= sizeof(size_t),
|
||||
"alignment expected to be large enough to hold a size_t");
|
||||
|
||||
static_assert((alignment & (alignment - 1)) == 0,
|
||||
"alignment must be a power of 2");
|
||||
|
||||
// We may need up to this many bytes to properly align mRead
|
||||
constexpr size_t maxAlign1 = alignment - 1;
|
||||
|
||||
// Find the lowest value of align1 that assures proper byte-alignment.
|
||||
uintptr_t alignValue = reinterpret_cast<uintptr_t>(header + maxAlign1);
|
||||
alignValue &= ~(alignment - 1);
|
||||
uint8_t* metadata = reinterpret_cast<uint8_t*>(alignValue);
|
||||
|
||||
// NB: We do not call the nontrivial constructor here (we do not write
|
||||
// `new std::atomic_size_t()`) because it would zero the read/write values
|
||||
// in the shared memory, which may already represent data in the queue.
|
||||
mRead = new (metadata) std::atomic_size_t;
|
||||
mWrite = new (metadata + alignment) std::atomic_size_t;
|
||||
|
||||
// The actual number of bytes we needed to properly align mRead
|
||||
size_t align1 = metadata - header;
|
||||
MOZ_ASSERT(align1 <= maxAlign1);
|
||||
|
||||
// The rest of the memory is the user reserved memory
|
||||
size_t headerSize = align1 + 2 * alignment;
|
||||
size_t userSize = shmemSize - mQueueBufferSize - headerSize;
|
||||
if (userSize > 0) {
|
||||
mUserReservedMemory = mQueue + mQueueBufferSize + headerSize;
|
||||
mUserReservedSize = userSize;
|
||||
} else {
|
||||
mUserReservedMemory = nullptr;
|
||||
mUserReservedSize = 0;
|
||||
}
|
||||
|
||||
// We use Monitors to wait for data when reading from an empty queue
|
||||
// and to wait for free space when writing to a full one.
|
||||
MOZ_ASSERT(aMaybeNotEmptySem && aMaybeNotFullSem);
|
||||
mMaybeNotEmptySem = aMaybeNotEmptySem;
|
||||
mMaybeNotFullSem = aMaybeNotFullSem;
|
||||
|
||||
PCQ_LOGD("Created queue (%p) with size: %zu, alignment: %zu, align1: %zu",
|
||||
this, aQueueSize, alignment, align1);
|
||||
}
|
||||
|
||||
~PcqBase() {
|
||||
PCQ_LOGD("Destroying queue (%p).", this);
|
||||
// NB: We would call the destructors for mRead and mWrite here (but not
|
||||
// delete since their memory belongs to the shmem) but the std library's
|
||||
// type aliases make this tricky and, by the spec for std::atomic, their
|
||||
// destructors are trivial (i.e. no-ops) anyway.
|
||||
}
|
||||
|
||||
size_t GetReadRelaxed() { return mRead->load(std::memory_order_relaxed); }
|
||||
|
||||
size_t GetWriteRelaxed() { return mWrite->load(std::memory_order_relaxed); }
|
||||
|
||||
/**
|
||||
* The QueueSize is the number of bytes the queue can hold. The queue is
|
||||
* backed by a buffer that is one byte larger than this, meaning that one
|
||||
* byte of the buffer is always wasted.
|
||||
* This is usually the right method to use when testing queue capacity.
|
||||
*/
|
||||
size_t QueueSize() { return QueueBufferSize() - 1; }
|
||||
|
||||
/**
|
||||
* The QueueBufferSize is the number of bytes in the buffer that the queue
|
||||
* uses for storage.
|
||||
* This is usually the right method to use when calculating read/write head
|
||||
* positions.
|
||||
*/
|
||||
size_t QueueBufferSize() { return mQueueBufferSize; }
|
||||
|
||||
// Actor used for making Shmems.
|
||||
WeakPtr<PcqActor> mActor;
|
||||
|
||||
// PID of process on the other end. Both ends may run on the same process.
|
||||
base::ProcessId mOtherPid = 0;
|
||||
|
||||
uint8_t* mQueue = nullptr;
|
||||
size_t mQueueBufferSize = 0;
|
||||
|
||||
// Pointer to memory reserved for use by the user, or null if none
|
||||
uint8_t* mUserReservedMemory = nullptr;
|
||||
size_t mUserReservedSize = 0;
|
||||
|
||||
// These std::atomics are in shared memory so DO NOT DELETE THEM! We should,
|
||||
// however, call their destructors.
|
||||
std::atomic_size_t* mRead = nullptr;
|
||||
std::atomic_size_t* mWrite = nullptr;
|
||||
|
||||
// The Shmem contents are laid out like this:
|
||||
// -----------------------------------------------------------------------
|
||||
// queue contents | align1 | mRead | align2 | mWrite | align3 | User Data
|
||||
// -----------------------------------------------------------------------
|
||||
// where align1 is chosen so that mRead is properly aligned for a
|
||||
// std_atomic_size_t and is on a cache line separate from the queue contents
|
||||
// align2 and align3 is chosen to separate mRead/mWrite and mWrite/User Data
|
||||
// similarly.
|
||||
Shmem mShmem;
|
||||
|
||||
// Two semaphores that are signaled when the queue goes from a state
|
||||
// where it definitely is empty/full to a state where it "may not be".
|
||||
// Therefore, we can wait on them and know that we will be awakened if
|
||||
// there may be work to do.
|
||||
// Our use of these semaphores leans heavily on the assumption that
|
||||
// the queue is used by one producer and one consumer.
|
||||
RefPtr<PcqRCSemaphore> mMaybeNotEmptySem;
|
||||
RefPtr<PcqRCSemaphore> mMaybeNotFullSem;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace webgl {
|
||||
|
||||
using mozilla::ipc::Shmem;
|
||||
|
||||
/**
|
||||
* The PcqProducer is the endpoint that inserts elements into the queue. It
|
||||
* should only be used from one thread at a time.
|
||||
*/
|
||||
class PcqProducer : public detail::PcqBase {
|
||||
public:
|
||||
PcqProducer(PcqProducer&& aOther) = default;
|
||||
PcqProducer& operator=(PcqProducer&&) = default;
|
||||
PcqProducer() = default; // for IPDL
|
||||
|
||||
/**
|
||||
* The number of bytes that the queue can hold.
|
||||
*/
|
||||
size_t Size() { return QueueSize(); }
|
||||
|
||||
/**
|
||||
* Attempts to insert aArgs into the queue. If the operation does not
|
||||
* succeed then the queue is unchanged.
|
||||
*/
|
||||
template <typename... Args>
|
||||
QueueStatus TryInsert(Args&&... aArgs) {
|
||||
size_t write = mWrite->load(std::memory_order_relaxed);
|
||||
const size_t initWrite = write;
|
||||
size_t read = mRead->load(std::memory_order_acquire);
|
||||
|
||||
if (!ValidState(read, write)) {
|
||||
PCQ_LOGE(
|
||||
"Queue was found in an invalid state. Queue Size: %zu. "
|
||||
"Read: %zu. Write: %zu",
|
||||
Size(), read, write);
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
ProducerView view(this, read, &write);
|
||||
|
||||
// Check that the queue has enough unoccupied room for all Args types.
|
||||
// This is based on the user's size estimate for args from QueueParamTraits.
|
||||
size_t bytesNeeded = detail::MinSizeofArgs(view, aArgs...);
|
||||
|
||||
if (Size() < bytesNeeded) {
|
||||
PCQ_LOGE(
|
||||
"Queue is too small for objects. Queue Size: %zu. "
|
||||
"Needed: %zu",
|
||||
Size(), bytesNeeded);
|
||||
return QueueStatus::kTooSmall;
|
||||
}
|
||||
|
||||
if (FreeBytes(read, write) < bytesNeeded) {
|
||||
PCQ_LOGD(
|
||||
"Not enough room to insert. Has: %zu (%zu,%zu). "
|
||||
"Needed: %zu",
|
||||
FreeBytes(read, write), read, write, bytesNeeded);
|
||||
return QueueStatus::kNotReady;
|
||||
}
|
||||
|
||||
// Try to insert args in sequence. Only update the queue if the
|
||||
// operation was successful. We already checked all normal means of
|
||||
// failure but we can expect occasional failure here if the user's
|
||||
// QueueParamTraits::MinSize method was inexact.
|
||||
QueueStatus status = TryInsertHelper(view, aArgs...);
|
||||
if (!status) {
|
||||
PCQ_LOGD(
|
||||
"Failed to insert with error (%d). Has: %zu (%zu,%zu). "
|
||||
"Estimate of bytes needed: %zu",
|
||||
(int)status, FreeBytes(read, write), read, write, bytesNeeded);
|
||||
return status;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(ValidState(read, write));
|
||||
|
||||
// Check that at least bytesNeeded were produced. Failing this means
|
||||
// that some QueueParamTraits::MinSize estimated too many bytes.
|
||||
bool enoughBytes =
|
||||
UsedBytes(read, write) >=
|
||||
UsedBytes(read, (initWrite + bytesNeeded) % QueueBufferSize());
|
||||
MOZ_ASSERT(enoughBytes);
|
||||
if (!enoughBytes) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
// Commit the transaction.
|
||||
PCQ_LOGD(
|
||||
"Successfully inserted. PcqProducer used %zu bytes total. "
|
||||
"Write index: %zu -> %zu",
|
||||
bytesNeeded, initWrite, write);
|
||||
mWrite->store(write, std::memory_order_release);
|
||||
|
||||
// Set the semaphore (unless it is already set) to let the consumer know
|
||||
// that the queue may not be empty. We just need to guarantee that it
|
||||
// was set (i.e. non-zero) at some time after mWrite was updated.
|
||||
if (!mMaybeNotEmptySem->IsAvailable()) {
|
||||
mMaybeNotEmptySem->Signal();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to insert aArgs into the queue. If the operation does not
|
||||
* succeed in the time allotted then the queue is unchanged.
|
||||
*/
|
||||
template <typename... Args>
|
||||
QueueStatus TryWaitInsert(const Maybe<TimeDuration>& aDuration,
|
||||
Args&&... aArgs) {
|
||||
return TryWaitInsertImpl(false, aDuration, std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
QueueStatus AllocShmem(mozilla::ipc::Shmem* aShmem, size_t aBufferSize,
|
||||
const void* aBuffer = nullptr) {
|
||||
if (!mActor) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
if (!mActor->AllocShmem(
|
||||
aBufferSize,
|
||||
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC, aShmem)) {
|
||||
return QueueStatus::kOOMError;
|
||||
}
|
||||
|
||||
if (aBuffer) {
|
||||
memcpy(aShmem->get<uint8_t>(), aBuffer, aBufferSize);
|
||||
}
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend ProducerConsumerQueue;
|
||||
friend ProducerView<PcqProducer>;
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
QueueStatus TryInsertHelper(ProducerView<PcqProducer>& aView, Arg&& aArg,
|
||||
Args&&... aArgs) {
|
||||
QueueStatus status = TryInsertItem(aView, std::forward<Arg>(aArg));
|
||||
return IsSuccess(status) ? TryInsertHelper(aView, aArgs...) : status;
|
||||
}
|
||||
|
||||
QueueStatus TryInsertHelper(ProducerView<PcqProducer>&) {
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
QueueStatus TryInsertItem(ProducerView<PcqProducer>& aView, Arg&& aArg) {
|
||||
return QueueParamTraits<typename RemoveCVR<Arg>::Type>::Write(
|
||||
aView, std::forward<Arg>(aArg));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus TryWaitInsertImpl(bool aRecursed,
|
||||
const Maybe<TimeDuration>& aDuration,
|
||||
Args&&... aArgs) {
|
||||
// Wait up to aDuration for the not-full semaphore to be signaled.
|
||||
// If we run out of time then quit.
|
||||
TimeStamp start(TimeStamp::Now());
|
||||
if (aRecursed && (!mMaybeNotFullSem->Wait(aDuration))) {
|
||||
return QueueStatus::kNotReady;
|
||||
}
|
||||
|
||||
// Attempt to insert all args. No waiting is done here.
|
||||
QueueStatus status = TryInsert(std::forward<Args>(aArgs)...);
|
||||
|
||||
TimeStamp now;
|
||||
if (aRecursed && IsSuccess(status)) {
|
||||
// If our local view of the queue is that it is still not full then
|
||||
// we know it won't get full without us (we are the only producer).
|
||||
// So re-set the not-full semaphore unless it's already set.
|
||||
// (We are also the only not-full semaphore decrementer so it can't
|
||||
// become 0.)
|
||||
if ((!IsFull()) && (!mMaybeNotFullSem->IsAvailable())) {
|
||||
mMaybeNotFullSem->Signal();
|
||||
}
|
||||
} else if ((status == QueueStatus::kNotReady) &&
|
||||
(aDuration.isNothing() ||
|
||||
((now = TimeStamp::Now()) - start) < aDuration.value())) {
|
||||
// We don't have enough room but still have time, e.g. because
|
||||
// the consumer read some data but not enough or because the
|
||||
// not-full semaphore gave a false positive. Either way, retry.
|
||||
status =
|
||||
aDuration.isNothing()
|
||||
? TryWaitInsertImpl(true, aDuration, std::forward<Args>(aArgs)...)
|
||||
: TryWaitInsertImpl(true, Some(aDuration.value() - (now - start)),
|
||||
std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
QueueStatus WriteObject(size_t aRead, size_t* aWrite, const Arg& arg,
|
||||
size_t aArgSize) {
|
||||
return Marshaller::WriteObject(mQueue, QueueBufferSize(), aRead, aWrite,
|
||||
arg, aArgSize);
|
||||
}
|
||||
|
||||
// Currently, the PCQ requires any parameters expected to need more than
|
||||
// 1/16 the total number of bytes in the command queue to use their own
|
||||
// SharedMemory.
|
||||
bool NeedsSharedMemory(size_t aRequested) {
|
||||
return (Size() / 16) < aRequested;
|
||||
}
|
||||
|
||||
PcqProducer(Shmem& aShmem, IProtocol* aProtocol, size_t aQueueSize,
|
||||
RefPtr<detail::PcqRCSemaphore> aMaybeNotEmptySem,
|
||||
RefPtr<detail::PcqRCSemaphore> aMaybeNotFullSem)
|
||||
: PcqBase(aShmem, aProtocol, aQueueSize, aMaybeNotEmptySem,
|
||||
aMaybeNotFullSem) {
|
||||
// Since they are shared, this initializes mRead/mWrite in the PcqConsumer
|
||||
// as well.
|
||||
*mRead = 0;
|
||||
*mWrite = 0;
|
||||
}
|
||||
|
||||
PcqProducer(const PcqProducer&) = delete;
|
||||
PcqProducer& operator=(const PcqProducer&) = delete;
|
||||
};
|
||||
|
||||
class PcqConsumer : public detail::PcqBase {
|
||||
public:
|
||||
PcqConsumer(PcqConsumer&& aOther) = default;
|
||||
PcqConsumer& operator=(PcqConsumer&&) = default;
|
||||
PcqConsumer() = default; // for IPDL
|
||||
|
||||
/**
|
||||
* The number of bytes that the queue can hold.
|
||||
*/
|
||||
size_t Size() { return QueueSize(); }
|
||||
|
||||
/**
|
||||
* Attempts to copy and remove aArgs from the queue. If the operation does
|
||||
* not succeed then the queue is unchanged.
|
||||
*/
|
||||
template <typename... Args>
|
||||
QueueStatus TryRemove(Args&... aArgs) {
|
||||
return TryRemoveImpl(aArgs...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for up to aDuration to remove the requested data from the queue.
|
||||
* Pass Nothing to wait until removal succeeds.
|
||||
*/
|
||||
template <typename... Args>
|
||||
QueueStatus TryWaitRemove(const Maybe<TimeDuration>& aDuration,
|
||||
Args&... aArgs) {
|
||||
return TryWaitRemoveImpl(false, aDuration, aArgs...);
|
||||
}
|
||||
|
||||
mozilla::ipc::Shmem::SharedMemory* LookupSharedMemory(uint32_t aId) {
|
||||
if (!mActor) {
|
||||
return nullptr;
|
||||
}
|
||||
return mActor->LookupSharedMemory(aId);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend ProducerConsumerQueue;
|
||||
friend ConsumerView<PcqConsumer>;
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus TryRemoveImpl(Args&... aArgs) {
|
||||
size_t write = mWrite->load(std::memory_order_acquire);
|
||||
size_t read = mRead->load(std::memory_order_relaxed);
|
||||
const size_t initRead = read;
|
||||
|
||||
if (!ValidState(read, write)) {
|
||||
PCQ_LOGE(
|
||||
"Queue was found in an invalid state. Queue Size: %zu. "
|
||||
"Read: %zu. Write: %zu",
|
||||
Size(), read, write);
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
ConsumerView<PcqConsumer> view(this, &read, write);
|
||||
|
||||
// Check that the queue has enough unoccupied room for all Args types.
|
||||
// This is based on the user's size estimate for Args from QueueParamTraits.
|
||||
size_t bytesNeeded = detail::MinSizeofArgs(view, aArgs...);
|
||||
|
||||
if (Size() < bytesNeeded) {
|
||||
PCQ_LOGE(
|
||||
"Queue is too small for objects. Queue Size: %zu. "
|
||||
"Bytes needed: %zu.",
|
||||
Size(), bytesNeeded);
|
||||
return QueueStatus::kTooSmall;
|
||||
}
|
||||
|
||||
if (UsedBytes(read, write) < bytesNeeded) {
|
||||
PCQ_LOGD(
|
||||
"Not enough data in queue. Has: %zu (%zu,%zu). "
|
||||
"Bytes needed: %zu",
|
||||
UsedBytes(read, write), read, write, bytesNeeded);
|
||||
return QueueStatus::kNotReady;
|
||||
}
|
||||
|
||||
// Only update the queue if the operation was successful.
|
||||
QueueStatus status = TryRemoveArgs(view, aArgs...);
|
||||
if (!status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Check that at least bytesNeeded were consumed. Failing this means
|
||||
// that some QueueParamTraits::MinSize estimated too many bytes.
|
||||
bool enoughBytes =
|
||||
FreeBytes(read, write) >=
|
||||
FreeBytes((initRead + bytesNeeded) % QueueBufferSize(), write);
|
||||
MOZ_ASSERT(enoughBytes);
|
||||
if (!enoughBytes) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(ValidState(read, write));
|
||||
|
||||
PCQ_LOGD(
|
||||
"Successfully removed. PcqConsumer used %zu bytes total. "
|
||||
"Read index: %zu -> %zu",
|
||||
bytesNeeded, initRead, read);
|
||||
|
||||
// Commit the transaction.
|
||||
mRead->store(read, std::memory_order_release);
|
||||
// Set the semaphore (unless it is already set) to let the producer know
|
||||
// that the queue may not be full. We just need to guarantee that it
|
||||
// was set (i.e. non-zero) at some time after mRead was updated.
|
||||
if (!mMaybeNotFullSem->IsAvailable()) {
|
||||
mMaybeNotFullSem->Signal();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus TryWaitRemoveImpl(bool aRecursed,
|
||||
const Maybe<TimeDuration>& aDuration,
|
||||
Args&... aArgs) {
|
||||
// Wait up to aDuration for the not-empty semaphore to be signaled.
|
||||
// If we run out of time then quit.
|
||||
TimeStamp start(TimeStamp::Now());
|
||||
if (aRecursed && (!mMaybeNotEmptySem->Wait(aDuration))) {
|
||||
return QueueStatus::kNotReady;
|
||||
}
|
||||
|
||||
// Attempt to read all args. No waiting is done here.
|
||||
QueueStatus status = TryRemove(aArgs...);
|
||||
|
||||
TimeStamp now;
|
||||
if (aRecursed && IsSuccess(status)) {
|
||||
// If our local view of the queue is that it is still not empty then
|
||||
// we know it won't get empty without us (we are the only consumer).
|
||||
// So re-set the not-empty semaphore unless it's already set.
|
||||
// (We are also the only not-empty semaphore decrementer so it can't
|
||||
// become 0.)
|
||||
if ((!IsEmpty()) && (!mMaybeNotEmptySem->IsAvailable())) {
|
||||
mMaybeNotEmptySem->Signal();
|
||||
}
|
||||
} else if ((status == QueueStatus::kNotReady) &&
|
||||
(aDuration.isNothing() ||
|
||||
((now = TimeStamp::Now()) - start) < aDuration.value())) {
|
||||
// We don't have enough data but still have time, e.g. because
|
||||
// the producer wrote some data but not enough or because the
|
||||
// not-empty semaphore gave a false positive. Either way, retry.
|
||||
status =
|
||||
aDuration.isNothing()
|
||||
? TryWaitRemoveImpl(true, aDuration, aArgs...)
|
||||
: TryWaitRemoveImpl(true, Some(aDuration.value() - (now - start)),
|
||||
aArgs...);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Version of the helper for copying values out of the queue.
|
||||
template <typename... Args>
|
||||
QueueStatus TryRemoveArgs(ConsumerView<PcqConsumer>& aView, Args&... aArgs);
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
QueueStatus TryRemoveArgs(ConsumerView<PcqConsumer>& aView, Arg& aArg,
|
||||
Args&... aArgs) {
|
||||
QueueStatus status = TryCopyItem(aView, aArg);
|
||||
return IsSuccess(status) ? TryRemoveArgs(aView, aArgs...) : status;
|
||||
}
|
||||
|
||||
QueueStatus TryRemoveArgs(ConsumerView<PcqConsumer>&) {
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
// If an item is available then it is copied into aArg. The item is skipped
|
||||
// over if aArg is null.
|
||||
template <typename Arg>
|
||||
QueueStatus TryCopyItem(ConsumerView<PcqConsumer>& aView, Arg& aArg) {
|
||||
MOZ_ASSERT(aArg);
|
||||
return QueueParamTraits<typename RemoveCVR<Arg>::Type>::Read(
|
||||
aView, const_cast<std::remove_cv_t<Arg>*>(&aArg));
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
QueueStatus ReadObject(size_t* aRead, size_t aWrite, Arg* arg,
|
||||
size_t aArgSize) {
|
||||
return Marshaller::ReadObject(mQueue, QueueBufferSize(), aRead, aWrite, arg,
|
||||
aArgSize);
|
||||
}
|
||||
|
||||
// Currently, the PCQ requires any parameters expected to need more than
|
||||
// 1/16 the total number of bytes in the command queue to use their own
|
||||
// SharedMemory.
|
||||
bool NeedsSharedMemory(size_t aRequested) {
|
||||
return (Size() / 16) < aRequested;
|
||||
}
|
||||
|
||||
PcqConsumer(Shmem& aShmem, IProtocol* aProtocol, size_t aQueueSize,
|
||||
RefPtr<detail::PcqRCSemaphore> aMaybeNotEmptySem,
|
||||
RefPtr<detail::PcqRCSemaphore> aMaybeNotFullSem)
|
||||
: PcqBase(aShmem, aProtocol, aQueueSize, aMaybeNotEmptySem,
|
||||
aMaybeNotFullSem) {}
|
||||
|
||||
PcqConsumer(const PcqConsumer&) = delete;
|
||||
PcqConsumer& operator=(const PcqConsumer&) = delete;
|
||||
};
|
||||
|
||||
using mozilla::detail::GetCacheLineSize;
|
||||
using mozilla::detail::GetMaxHeaderSize;
|
||||
|
||||
/**
|
||||
* A single producer + single consumer queue, implemented as a
|
||||
* circular queue. The object is backed with a Shmem, which allows
|
||||
* it to be used across processes.
|
||||
*
|
||||
* This is a single-producer/single-consumer queue. Another way of saying that
|
||||
* is to say that the PcqProducer and PcqConsumer objects are not thread-safe.
|
||||
*/
|
||||
class ProducerConsumerQueue {
|
||||
public:
|
||||
/**
|
||||
* Create a queue whose endpoints are the same as those of aProtocol.
|
||||
* In choosing a queueSize, be aware that both the queue and the Shmem will
|
||||
* allocate additional shared memory for internal accounting (see
|
||||
* GetMaxHeaderSize) and that Shmem sizes are a multiple of the operating
|
||||
* system's page sizes.
|
||||
*
|
||||
* aAdditionalBytes of shared memory will also be allocated.
|
||||
* Clients may use this shared memory for their own purposes.
|
||||
* See GetUserReservedMemory() and GetUserReservedMemorySize()
|
||||
*/
|
||||
static UniquePtr<ProducerConsumerQueue> Create(IProtocol* aProtocol,
|
||||
size_t aQueueSize,
|
||||
size_t aAdditionalBytes = 0) {
|
||||
MOZ_ASSERT(aProtocol);
|
||||
// Protocol must subclass PcqActor
|
||||
MOZ_ASSERT(PcqActor::LookupProtocol(aProtocol));
|
||||
Shmem shmem;
|
||||
|
||||
// NB: We need one extra byte for the queue contents (hence the "+1").
|
||||
uint32_t totalShmemSize =
|
||||
aQueueSize + 1 + GetMaxHeaderSize() + aAdditionalBytes;
|
||||
|
||||
if (!aProtocol->AllocUnsafeShmem(
|
||||
totalShmemSize, mozilla::ipc::SharedMemory::TYPE_BASIC, &shmem)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NB: We need one extra byte for the queue contents (hence the "+1").
|
||||
if ((!shmem.IsWritable()) || (!shmem.IsReadable()) ||
|
||||
((GetMaxHeaderSize() + aQueueSize + 1) > totalShmemSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WrapUnique(new ProducerConsumerQueue(shmem, aProtocol, aQueueSize,
|
||||
aAdditionalBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* The queue needs a few bytes for 2 shared counters. It takes these from the
|
||||
* underlying Shmem. This will still work if the cache line size is incorrect
|
||||
* for some architecture but operations may be less efficient.
|
||||
*/
|
||||
static constexpr size_t GetMaxHeaderSize() {
|
||||
return mozilla::detail::GetMaxHeaderSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache line size for the machine. We assume a 64-byte cache line size.
|
||||
*/
|
||||
static constexpr size_t GetCacheLineSize() {
|
||||
return mozilla::detail::GetCacheLineSize();
|
||||
}
|
||||
|
||||
using Producer = PcqProducer;
|
||||
using Consumer = PcqConsumer;
|
||||
|
||||
UniquePtr<Producer> TakeProducer() { return std::move(mProducer); }
|
||||
UniquePtr<Consumer> TakeConsumer() { return std::move(mConsumer); }
|
||||
|
||||
private:
|
||||
ProducerConsumerQueue(Shmem& aShmem, IProtocol* aProtocol, size_t aQueueSize,
|
||||
size_t aAdditionalBytes) {
|
||||
auto notempty = MakeRefPtr<detail::PcqRCSemaphore>(
|
||||
CrossProcessSemaphore::Create("webgl-notempty", 0));
|
||||
auto notfull = MakeRefPtr<detail::PcqRCSemaphore>(
|
||||
CrossProcessSemaphore::Create("webgl-notfull", 1));
|
||||
|
||||
mProducer = WrapUnique(
|
||||
new Producer(aShmem, aProtocol, aQueueSize, notempty, notfull));
|
||||
mConsumer = WrapUnique(
|
||||
new Consumer(aShmem, aProtocol, aQueueSize, notempty, notfull));
|
||||
|
||||
// The system may have reserved more bytes than the user asked for.
|
||||
// Make sure they aren't given access to the extra.
|
||||
MOZ_ASSERT(mProducer->mUserReservedSize >= aAdditionalBytes);
|
||||
mProducer->mUserReservedSize = aAdditionalBytes;
|
||||
mConsumer->mUserReservedSize = aAdditionalBytes;
|
||||
if (aAdditionalBytes == 0) {
|
||||
mProducer->mUserReservedMemory = nullptr;
|
||||
mConsumer->mUserReservedMemory = nullptr;
|
||||
}
|
||||
|
||||
PCQ_LOGD(
|
||||
"Constructed PCQ (%p). Shmem Size = %zu. Queue Size = %zu. "
|
||||
"Other process ID: %08x.",
|
||||
this, aShmem.Size<uint8_t>(), aQueueSize,
|
||||
(uint32_t)aProtocol->OtherPid());
|
||||
}
|
||||
|
||||
UniquePtr<Producer> mProducer;
|
||||
UniquePtr<Consumer> mConsumer;
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
namespace ipc {
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<mozilla::detail::PcqBase> {
|
||||
typedef mozilla::detail::PcqBase paramType;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor, paramType& aParam) {
|
||||
// Must be sent using the queue's underlying actor, which must still exist!
|
||||
MOZ_RELEASE_ASSERT(aParam.mActor && aActor->Id() == aParam.mActor->Id());
|
||||
WriteIPDLParam(aMsg, aActor, aParam.mActor->Id());
|
||||
WriteIPDLParam(aMsg, aActor, aParam.QueueSize());
|
||||
WriteIPDLParam(aMsg, aActor, std::move(aParam.mShmem));
|
||||
|
||||
// May not currently share a PcqProducer or PcqConsumer with a process that
|
||||
// it's Shmem is not related to.
|
||||
MOZ_ASSERT(aActor->OtherPid() == aParam.mOtherPid);
|
||||
WriteIPDLParam(
|
||||
aMsg, aActor,
|
||||
aParam.mMaybeNotEmptySem->ShareToProcess(aActor->OtherPid()));
|
||||
|
||||
WriteIPDLParam(aMsg, aActor,
|
||||
aParam.mMaybeNotFullSem->ShareToProcess(aActor->OtherPid()));
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aResult) {
|
||||
int32_t iProtocolId;
|
||||
size_t queueSize;
|
||||
Shmem shmem;
|
||||
CrossProcessSemaphoreHandle notEmptyHandle;
|
||||
CrossProcessSemaphoreHandle notFullHandle;
|
||||
|
||||
if (!ReadIPDLParam(aMsg, aIter, aActor, &iProtocolId) ||
|
||||
(iProtocolId != aActor->Id()) ||
|
||||
!ReadIPDLParam(aMsg, aIter, aActor, &queueSize) ||
|
||||
!ReadIPDLParam(aMsg, aIter, aActor, &shmem) ||
|
||||
!ReadIPDLParam(aMsg, aIter, aActor, ¬EmptyHandle) ||
|
||||
!ReadIPDLParam(aMsg, aIter, aActor, ¬FullHandle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsHandleValid(notEmptyHandle) && IsHandleValid(notFullHandle));
|
||||
aResult->Set(shmem, aActor, queueSize,
|
||||
MakeRefPtr<detail::PcqRCSemaphore>(
|
||||
CrossProcessSemaphore::Create(notEmptyHandle)),
|
||||
MakeRefPtr<detail::PcqRCSemaphore>(
|
||||
CrossProcessSemaphore::Create(notFullHandle)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog) {
|
||||
IPDLParamTraits<Shmem>::Log(aParam.mShmem, aLog);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<mozilla::webgl::PcqProducer>
|
||||
: public IPDLParamTraits<mozilla::detail::PcqBase> {
|
||||
typedef mozilla::webgl::PcqProducer paramType;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<mozilla::webgl::PcqConsumer>
|
||||
: public IPDLParamTraits<mozilla::detail::PcqBase> {
|
||||
typedef mozilla::webgl::PcqConsumer paramType;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_ProducerConsumerQueue_h
|
@ -1,13 +0,0 @@
|
||||
/* -*- 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 "ProducerConsumerQueue.h"
|
||||
|
||||
namespace mozilla::webgl {
|
||||
|
||||
mozilla::LazyLogModule gPCQLog("pcq");
|
||||
mozilla::LazyLogModule gIpdlQueueLog("ipdlqueue");
|
||||
|
||||
} // namespace mozilla::webgl
|
@ -8,18 +8,10 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include "mozilla/FunctionTypeTraits.h"
|
||||
#include "mozilla/dom/ProducerConsumerQueue.h"
|
||||
#include "mozilla/ipc/IPDLParamTraits.h"
|
||||
#include "QueueParamTraits.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
// Get around a bug in Clang related to __thiscall method pointers
|
||||
#if defined(_M_IX86)
|
||||
# define SINK_FCN_CC __thiscall
|
||||
#else
|
||||
# define SINK_FCN_CC
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using webgl::QueueStatus;
|
||||
@ -169,486 +161,6 @@ inline bool Deserialize(RangeConsumerView& view, Arg& arg, Args&... args) {
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
// -
|
||||
|
||||
using mozilla::ipc::IPDLParamTraits;
|
||||
|
||||
enum CommandResult { kSuccess, kTimeExpired, kQueueEmpty, kError };
|
||||
|
||||
enum CommandSyncType { ASYNC, SYNC };
|
||||
|
||||
/**
|
||||
* A CommandSource is obtained from a CommandQueue. Use it by inserting a
|
||||
* command (represented by type Command) using InsertCommand, which also
|
||||
* needs all parameters to the command. They are then serialized and sent
|
||||
* to the CommandSink, which must understand the Command+Args combination
|
||||
* to execute it.
|
||||
*/
|
||||
template <typename Command, typename _Source>
|
||||
class CommandSource {
|
||||
using Source = _Source;
|
||||
|
||||
public:
|
||||
explicit CommandSource(UniquePtr<Source>&& aSource)
|
||||
: mSource(std::move(aSource)) {
|
||||
MOZ_ASSERT(mSource);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus InsertCommand(Command aCommand, Args&&... aArgs) {
|
||||
return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand,
|
||||
aArgs...);
|
||||
}
|
||||
|
||||
QueueStatus InsertCommand(Command aCommand) {
|
||||
return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus RunCommand(Command aCommand, Args&&... aArgs) {
|
||||
return InsertCommand(aCommand, std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
// For IPDL:
|
||||
CommandSource() = default;
|
||||
|
||||
protected:
|
||||
friend struct IPDLParamTraits<mozilla::CommandSource<Command, Source>>;
|
||||
|
||||
UniquePtr<Source> mSource;
|
||||
};
|
||||
|
||||
/**
|
||||
* A CommandSink is obtained from a CommandQueue. It executes commands that
|
||||
* originated in its CommandSource. Use this class by calling one of the
|
||||
* Process methods, which will autonomously deserialize, dispatch and
|
||||
* post-process the execution. This class handles deserialization -- dispatch
|
||||
* and processing are to be provided by a subclass in its implementation of the
|
||||
* pure-virtual DispatchCommand method. DispatchCommand implementations can
|
||||
* easily run functions and methods using arguments taken from the command
|
||||
* queue by calling the Dispatch methods in this class.
|
||||
*/
|
||||
template <typename Command, typename _Sink>
|
||||
class CommandSink {
|
||||
using Sink = _Sink;
|
||||
|
||||
public:
|
||||
explicit CommandSink(UniquePtr<Sink>&& aSink) : mSink(std::move(aSink)) {
|
||||
MOZ_ASSERT(mSink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to process the next command in the queue, if one is available.
|
||||
*/
|
||||
CommandResult ProcessOne(const Maybe<TimeDuration>& aTimeout) {
|
||||
Command command;
|
||||
QueueStatus status = (aTimeout.isNothing() || aTimeout.value())
|
||||
? this->mSink->TryWaitRemove(aTimeout, command)
|
||||
: this->mSink->TryRemove(command);
|
||||
|
||||
if (status == QueueStatus::kSuccess) {
|
||||
if (DispatchCommand(command)) {
|
||||
return CommandResult::kSuccess;
|
||||
}
|
||||
return CommandResult::kError;
|
||||
}
|
||||
|
||||
if (status == QueueStatus::kNotReady) {
|
||||
return CommandResult::kQueueEmpty;
|
||||
}
|
||||
|
||||
if (status == QueueStatus::kOOMError) {
|
||||
ReportOOM();
|
||||
}
|
||||
return CommandResult::kError;
|
||||
}
|
||||
|
||||
CommandResult ProcessOneNow() { return ProcessOne(Some(TimeDuration(0))); }
|
||||
|
||||
/**
|
||||
* Drains the queue until the queue is empty or an error occurs, whichever
|
||||
* comes first.
|
||||
* Returns the result of the last attempt to process a command, which will
|
||||
* be either QueueEmpty or Error.
|
||||
*/
|
||||
CommandResult ProcessAll() {
|
||||
CommandResult result;
|
||||
do {
|
||||
result = ProcessOneNow();
|
||||
} while (result == CommandResult::kSuccess);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drains the queue until aDuration expires, the queue is empty, or an error
|
||||
* occurs, whichever comes first.
|
||||
* Returns the result of the last attempt to process a command.
|
||||
*/
|
||||
CommandResult ProcessUpToDuration(TimeDuration aDuration) {
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
TimeStamp now = start;
|
||||
CommandResult result;
|
||||
|
||||
do {
|
||||
result = ProcessOne(Some(aDuration - (now - start)));
|
||||
now = TimeStamp::Now();
|
||||
} while ((result == CommandResult::kSuccess) &&
|
||||
((now - start) < aDuration));
|
||||
return result;
|
||||
}
|
||||
|
||||
// For IPDL:
|
||||
CommandSink() = default;
|
||||
|
||||
// non-void return value, non-const method variant
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchAsyncMethod(T& aObj, ReturnType (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!ReadArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
// non-void return value, const method variant
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchAsyncMethod(const T& aObj,
|
||||
ReturnType (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!ReadArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
// void return value, non-const method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchAsyncMethod(T* aObj, void (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!ReadArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
// void return value, const method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchAsyncMethod(const T* aObj, void (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!ReadArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>>;
|
||||
|
||||
/**
|
||||
* Implementations will usually be something like a big switch statement
|
||||
* that calls one of the Dispatch methods in this class.
|
||||
*/
|
||||
virtual bool DispatchCommand(Command command) = 0;
|
||||
|
||||
/**
|
||||
* Implementations can override this to detect out-of-memory during
|
||||
* deserialization.
|
||||
*/
|
||||
virtual void ReportOOM() {}
|
||||
|
||||
template <typename... Args, size_t... Indices>
|
||||
QueueStatus CallTryRemove(std::tuple<Args...>& aArgs,
|
||||
std::index_sequence<Indices...>) {
|
||||
QueueStatus status = mSink->TryRemove(std::get<Indices>(aArgs)...);
|
||||
// The CommandQueue inserts the command and the args together as an atomic
|
||||
// operation. We already read the command so the args must also be
|
||||
// available.
|
||||
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
||||
return status;
|
||||
}
|
||||
|
||||
QueueStatus CallTryRemove(std::tuple<>& aArgs,
|
||||
std::make_integer_sequence<size_t, 0>) {
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename T, typename MethodType, typename... Args,
|
||||
size_t... Indices,
|
||||
typename ReturnType =
|
||||
typename mozilla::FunctionTypeTraits<MethodType>::ReturnType>
|
||||
ReturnType CallMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs,
|
||||
std::index_sequence<Indices...>) {
|
||||
return (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
|
||||
}
|
||||
|
||||
template <typename T, typename MethodType, typename... Args,
|
||||
size_t... Indices>
|
||||
void CallVoidMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs,
|
||||
std::index_sequence<Indices...>) {
|
||||
(aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
bool ReadArgs(std::tuple<Args...>& aArgs) {
|
||||
QueueStatus status =
|
||||
CallTryRemove(aArgs, std::index_sequence_for<Args...>{});
|
||||
return IsSuccess(status);
|
||||
}
|
||||
|
||||
UniquePtr<Sink> mSink;
|
||||
};
|
||||
|
||||
enum SyncResponse : uint8_t { RESPONSE_NAK, RESPONSE_ACK };
|
||||
|
||||
/**
|
||||
* This is the Source for a SyncCommandSink. It takes an extra queue,
|
||||
* the ResponseQueue, and uses it to receive synchronous responses from
|
||||
* the sink. The ResponseQueue is a regular queue, not a CommandQueue.
|
||||
*/
|
||||
template <typename Command, typename _Source, typename _ResponseQueue>
|
||||
class SyncCommandSource : public CommandSource<Command, _Source> {
|
||||
public:
|
||||
using BaseType = CommandSource<Command, _Source>;
|
||||
using Source = _Source;
|
||||
using ResponseQueue = _ResponseQueue;
|
||||
using ResponseSink = typename ResponseQueue::Consumer;
|
||||
|
||||
SyncCommandSource(UniquePtr<Source>&& aSource,
|
||||
UniquePtr<ResponseSink>&& aResponseSink)
|
||||
: CommandSource<Command, Source>(std::move(aSource)),
|
||||
mResponseSink(std::move(aResponseSink)) {}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus RunAsyncCommand(Command aCommand, Args&&... aArgs) {
|
||||
return this->RunCommand(aCommand, std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
QueueStatus RunVoidSyncCommand(Command aCommand, Args&&... aArgs) {
|
||||
QueueStatus status =
|
||||
RunAsyncCommand(aCommand, std::forward<Args>(aArgs)...);
|
||||
return IsSuccess(status) ? this->ReadSyncResponse() : status;
|
||||
}
|
||||
|
||||
template <typename ResultType, typename... Args>
|
||||
QueueStatus RunSyncCommand(Command aCommand, ResultType& aReturn,
|
||||
Args&&... aArgs) {
|
||||
QueueStatus status =
|
||||
RunVoidSyncCommand(aCommand, std::forward<Args>(aArgs)...);
|
||||
return IsSuccess(status) ? this->ReadResult(aReturn) : status;
|
||||
}
|
||||
|
||||
// for IPDL:
|
||||
SyncCommandSource() = default;
|
||||
friend struct mozilla::ipc::IPDLParamTraits<
|
||||
SyncCommandSource<Command, Source, ResponseQueue>>;
|
||||
|
||||
protected:
|
||||
QueueStatus ReadSyncResponse() {
|
||||
SyncResponse response;
|
||||
QueueStatus status =
|
||||
mResponseSink->TryWaitRemove(Nothing() /* wait forever */, response);
|
||||
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
||||
|
||||
if (IsSuccess(status) && response != RESPONSE_ACK) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QueueStatus ReadResult(T& aResult) {
|
||||
QueueStatus status = mResponseSink->TryRemove(aResult);
|
||||
// The Sink posts the response code and result as an atomic transaction. We
|
||||
// already read the response code so the result must be available.
|
||||
MOZ_ASSERT(status != QueueStatus::kNotReady);
|
||||
return status;
|
||||
}
|
||||
|
||||
UniquePtr<ResponseSink> mResponseSink;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the Sink for a SyncCommandSource. It takes an extra queue, the
|
||||
* ResponseQueue, and uses it to issue synchronous responses to the client.
|
||||
* Subclasses can use the DispatchSync methods in this class in their
|
||||
* DispatchCommand implementations.
|
||||
* The ResponseQueue is not a CommandQueue.
|
||||
*/
|
||||
template <typename Command, typename _Sink, typename _ResponseQueue>
|
||||
class SyncCommandSink : public CommandSink<Command, _Sink> {
|
||||
using BaseType = CommandSink<Command, _Sink>;
|
||||
using ResponseQueue = _ResponseQueue;
|
||||
using Sink = _Sink;
|
||||
using ResponseSource = typename ResponseQueue::Producer;
|
||||
|
||||
public:
|
||||
SyncCommandSink(UniquePtr<Sink>&& aSink,
|
||||
UniquePtr<ResponseSource>&& aResponseSource)
|
||||
: CommandSink<Command, Sink>(std::move(aSink)),
|
||||
mResponseSource(std::move(aResponseSource)) {
|
||||
MOZ_ASSERT(mResponseSource);
|
||||
}
|
||||
|
||||
// for IPDL:
|
||||
SyncCommandSink() = default;
|
||||
friend struct mozilla::ipc::IPDLParamTraits<
|
||||
SyncCommandSink<Command, Sink, ResponseQueue>>;
|
||||
|
||||
// Places RESPONSE_ACK and the typed return value, or RESPONSE_NAK, in
|
||||
// the response queue,
|
||||
// __cdecl/__thiscall non-const method variant.
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchSyncMethod(T& aObj,
|
||||
ReturnType SINK_FCN_CC (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnType response = BaseType::CallMethod(
|
||||
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
|
||||
return WriteACK(response);
|
||||
}
|
||||
|
||||
// __cdecl/__thiscall const method variant.
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchSyncMethod(const T& aObj,
|
||||
ReturnType SINK_FCN_CC (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnType response = BaseType::CallMethod(
|
||||
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
|
||||
return WriteACK(response);
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
// __stdcall non-const method variant.
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchSyncMethod(T& aObj,
|
||||
ReturnType __stdcall (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnType response = BaseType::CallMethod(
|
||||
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
|
||||
return WriteACK(response);
|
||||
}
|
||||
|
||||
// __stdcall const method variant.
|
||||
template <typename T, typename ReturnType, typename... Args>
|
||||
bool DispatchSyncMethod(const T& aObj,
|
||||
ReturnType __stdcall (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnType response = BaseType::CallMethod(
|
||||
aObj, aMethod, args, std::index_sequence_for<Args...>{});
|
||||
|
||||
return WriteACK(response);
|
||||
}
|
||||
#endif
|
||||
|
||||
// __cdecl/__thiscall non-const void method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchSyncMethod(T& aObj, void SINK_FCN_CC (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseType::CallVoidMethod(aObj, aMethod, args,
|
||||
std::index_sequence_for<Args...>{});
|
||||
return WriteACK();
|
||||
}
|
||||
|
||||
// __cdecl/__thiscall const void method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchSyncMethod(const T& aObj,
|
||||
void SINK_FCN_CC (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseType::CallVoidMethod(aObj, aMethod, args,
|
||||
std::index_sequence_for<Args...>{});
|
||||
return WriteACK();
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
// __stdcall non-const void method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchSyncMethod(T& aObj, void __stdcall (T::*aMethod)(Args...)) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseType::CallVoidMethod(aObj, aMethod, args,
|
||||
std::index_sequence_for<Args...>{});
|
||||
return WriteACK();
|
||||
}
|
||||
|
||||
// __stdcall const void method variant
|
||||
template <typename T, typename... Args>
|
||||
bool DispatchSyncMethod(const T& aObj,
|
||||
void __stdcall (T::*aMethod)(Args...) const) {
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
|
||||
if (!BaseType::ReadArgs(args)) {
|
||||
WriteNAK();
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseType::CallVoidMethod(aObj, aMethod, args,
|
||||
std::index_sequence_for<Args...>{});
|
||||
return WriteACK();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
template <typename... Args>
|
||||
bool WriteArgs(const Args&... aArgs) {
|
||||
return IsSuccess(mResponseSource->TryInsert(aArgs...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
bool WriteACK(const Args&... aArgs) {
|
||||
SyncResponse ack = RESPONSE_ACK;
|
||||
return WriteArgs(ack, aArgs...);
|
||||
}
|
||||
|
||||
bool WriteNAK() {
|
||||
SyncResponse nak = RESPONSE_NAK;
|
||||
return WriteArgs(nak);
|
||||
}
|
||||
|
||||
UniquePtr<ResponseSource> mResponseSource;
|
||||
};
|
||||
|
||||
// The MethodDispatcher setup uses a CommandSink to read parameters, call the
|
||||
// given method using the given synchronization protocol, and provide
|
||||
// compile-time lookup of the ID by class method.
|
||||
@ -667,8 +179,7 @@ class SyncCommandSink : public CommandSink<Command, _Sink> {
|
||||
// template <>
|
||||
// class MyDispatcher<0>
|
||||
// : public MethodDispatcher<MyDispatcher, 0,
|
||||
// decltype(&MyClass::MyMethod), MyClass::MyMethod,
|
||||
// CommandSyncType::ASYNC> {};
|
||||
// decltype(&MyClass::MyMethod), MyClass::MyMethod> {};
|
||||
//
|
||||
// The method may then be called from the source and run on the sink.
|
||||
//
|
||||
@ -683,9 +194,6 @@ class EmptyMethodDispatcher {
|
||||
webgl::RangeConsumerView&) {
|
||||
MOZ_CRASH("Illegal ID in DispatchCommand");
|
||||
}
|
||||
static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t) {
|
||||
MOZ_CRASH("Illegal ID in SyncType");
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
@ -704,7 +212,7 @@ std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple(
|
||||
|
||||
// Derived type must be parameterized by the ID.
|
||||
template <template <size_t> typename Derived, size_t ID, typename MethodType,
|
||||
MethodType method, CommandSyncType syncType>
|
||||
MethodType method>
|
||||
class MethodDispatcher {
|
||||
static constexpr size_t kId = ID;
|
||||
using DerivedType = Derived<ID>;
|
||||
@ -728,97 +236,10 @@ class MethodDispatcher {
|
||||
return Derived<kId + 1>::DispatchCommand(obj, id, view);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
|
||||
return (aId == kId) ? syncType : NextDispatcher::SyncType(kId);
|
||||
}
|
||||
|
||||
static constexpr CommandSyncType SyncType() { return syncType; }
|
||||
static constexpr size_t Id() { return kId; }
|
||||
static constexpr MethodType Method() { return method; }
|
||||
};
|
||||
|
||||
namespace ipc {
|
||||
template <typename T>
|
||||
struct IPDLParamTraits;
|
||||
|
||||
template <typename Command, typename Source>
|
||||
struct IPDLParamTraits<mozilla::CommandSource<Command, Source>> {
|
||||
public:
|
||||
typedef mozilla::CommandSource<Command, Source> paramType;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
const paramType& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, aParam.mSource);
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aResult) {
|
||||
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSource);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Command, typename Sink>
|
||||
struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>> {
|
||||
public:
|
||||
typedef mozilla::CommandSink<Command, Sink> paramType;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
const paramType& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, aParam.mSink);
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aResult) {
|
||||
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSink);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Command, typename Source, typename ResponseQueue>
|
||||
struct IPDLParamTraits<
|
||||
mozilla::SyncCommandSource<Command, Source, ResponseQueue>>
|
||||
: public IPDLParamTraits<mozilla::CommandSource<Command, Source>> {
|
||||
public:
|
||||
typedef mozilla::SyncCommandSource<Command, Source, ResponseQueue> paramType;
|
||||
typedef typename paramType::BaseType paramBaseType;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
const paramType& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
|
||||
WriteIPDLParam(aMsg, aActor, aParam.mResponseSink);
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aParam) {
|
||||
bool result =
|
||||
ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
|
||||
return result && ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSink);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Command, typename Sink, typename ResponseQueue>
|
||||
struct IPDLParamTraits<mozilla::SyncCommandSink<Command, Sink, ResponseQueue>>
|
||||
: public IPDLParamTraits<mozilla::CommandSink<Command, Sink>> {
|
||||
public:
|
||||
typedef mozilla::SyncCommandSink<Command, Sink, ResponseQueue> paramType;
|
||||
typedef typename paramType::BaseType paramBaseType;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
const paramType& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
|
||||
WriteIPDLParam(aMsg, aActor, aParam.mResponseSource);
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aParam) {
|
||||
bool result =
|
||||
ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
|
||||
return result &&
|
||||
ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSource);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGLCOMMANDQUEUE_H_
|
||||
|
@ -1,21 +0,0 @@
|
||||
/* -*- 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 "WebGLCrossProcessCommandQueue.h"
|
||||
#include "WebGLMethodDispatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#if 0
|
||||
bool HostWebGLCommandSink<Consumer, Queue>::DispatchCommand(size_t command) {
|
||||
if (!mHostContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WebGLMethodDispatcher::DispatchCommand(command, *this, *mHostContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
@ -1,97 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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/. */
|
||||
|
||||
#ifndef WEBGLCROSSPROCESSCOMMANDQUEUE_H_
|
||||
#define WEBGLCROSSPROCESSCOMMANDQUEUE_H_
|
||||
|
||||
#include "mozilla/dom/WebGLCommandQueue.h"
|
||||
#include "ProducerConsumerQueue.h"
|
||||
#include "IpdlQueue.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class WebGLParent;
|
||||
class WebGLChild;
|
||||
} // namespace dom
|
||||
|
||||
namespace layers {
|
||||
class PCompositorBridgeParent;
|
||||
}
|
||||
|
||||
class HostWebGLContext;
|
||||
|
||||
using mozilla::webgl::ProducerConsumerQueue;
|
||||
|
||||
/**
|
||||
* The source for the WebGL Command Queue.
|
||||
*/
|
||||
using ClientWebGLCommandSourceP =
|
||||
SyncCommandSource<size_t, mozilla::webgl::PcqProducer,
|
||||
mozilla::webgl::ProducerConsumerQueue>;
|
||||
|
||||
/**
|
||||
* The sink for the WebGL Command Queue. This object is created in the client
|
||||
* and sent to the host, where it needs to be given a HostWebGLContext that it
|
||||
* then uses for executing methods. Add new commands to DispatchCommand using
|
||||
* the WEBGL_SYNC_COMMAND and WEBGL_ASYNC_COMMAND macros.
|
||||
*/
|
||||
template <typename Consumer, typename Queue>
|
||||
class HostWebGLCommandSink final
|
||||
: public SyncCommandSink<size_t, Consumer, Queue> {
|
||||
public:
|
||||
HostWebGLCommandSink(UniquePtr<Consumer>&& aConsumer,
|
||||
UniquePtr<typename Queue::Producer>&& aResponseProducer)
|
||||
: SyncCommandSink<size_t, Consumer, Queue>(
|
||||
std::move(aConsumer), std::move(aResponseProducer)) {}
|
||||
|
||||
HostWebGLContext* mHostContext = nullptr;
|
||||
|
||||
// For IPDL:
|
||||
HostWebGLCommandSink() = default;
|
||||
|
||||
protected:
|
||||
friend struct mozilla::ipc::IPDLParamTraits<HostWebGLCommandSink>;
|
||||
friend class mozilla::layers::PCompositorBridgeParent;
|
||||
|
||||
bool DispatchCommand(size_t command) override {
|
||||
MOZ_CRASH("TODO:");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
using HostWebGLCommandSinkP =
|
||||
HostWebGLCommandSink<mozilla::webgl::PcqConsumer,
|
||||
mozilla::webgl::ProducerConsumerQueue>;
|
||||
|
||||
using IpdlWebGLCommandQueue =
|
||||
mozilla::dom::IpdlQueue<mozilla::dom::WebGLChild,
|
||||
mozilla::dom::WebGLParent>;
|
||||
using IpdlWebGLResponseQueue =
|
||||
mozilla::dom::IpdlQueue<mozilla::dom::WebGLParent,
|
||||
mozilla::dom::WebGLChild>;
|
||||
|
||||
using ClientWebGLCommandSourceI =
|
||||
SyncCommandSource<size_t, typename IpdlWebGLCommandQueue::Producer,
|
||||
IpdlWebGLResponseQueue>;
|
||||
using HostWebGLCommandSinkI =
|
||||
HostWebGLCommandSink<typename IpdlWebGLCommandQueue::Consumer,
|
||||
IpdlWebGLResponseQueue>;
|
||||
|
||||
namespace ipc {
|
||||
|
||||
template <typename Consumer, typename Queue>
|
||||
struct IPDLParamTraits<mozilla::HostWebGLCommandSink<Consumer, Queue>>
|
||||
: public IPDLParamTraits<
|
||||
mozilla::SyncCommandSink<size_t, Consumer, Queue>> {
|
||||
public:
|
||||
typedef mozilla::HostWebGLCommandSink<Consumer, Queue> paramType;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGLCROSSPROCESSCOMMANDQUEUE_H_
|
@ -7,6 +7,8 @@
|
||||
#define WEBGLIPDL_H_
|
||||
|
||||
#include "ipc/EnumSerializer.h"
|
||||
#include "mozilla/ipc/IPDLParamTraits.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
@ -24,7 +26,7 @@ class RaiiShmem final {
|
||||
/// Returns zeroed data.
|
||||
static RaiiShmem Alloc(mozilla::ipc::IProtocol* const allocator,
|
||||
const size_t size,
|
||||
const Shmem::SharedMemory::SharedMemoryType type) {
|
||||
const mozilla::ipc::SharedMemory::SharedMemoryType type) {
|
||||
mozilla::ipc::Shmem shmem;
|
||||
if (!allocator->AllocShmem(size, type, &shmem)) return {};
|
||||
return {allocator, shmem};
|
||||
|
@ -7,14 +7,11 @@
|
||||
#define WEBGLMETHODDISPATCHER_H_
|
||||
|
||||
#include "TexUnpackBlob.h"
|
||||
#include "WebGLCrossProcessCommandQueue.h"
|
||||
#include "HostWebGLContext.h"
|
||||
#include "WebGLQueueParamTraits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// The WebGLMethodDispatcher will dispatch commands read from the
|
||||
// HostWebGLCommandSink and issue them to a given HostWebGLContext.
|
||||
template <size_t id = 0>
|
||||
class WebGLMethodDispatcher
|
||||
: public EmptyMethodDispatcher<WebGLMethodDispatcher> {};
|
||||
@ -22,11 +19,11 @@ class WebGLMethodDispatcher
|
||||
template <typename MethodT, MethodT Method>
|
||||
size_t IdByMethod() = delete;
|
||||
|
||||
#define DEFINE_METHOD_DISPATCHER(_ID, _METHOD, _SYNC) \
|
||||
#define DEFINE_METHOD_DISPATCHER(_ID, _METHOD) \
|
||||
template <> \
|
||||
class WebGLMethodDispatcher<_ID> \
|
||||
: public MethodDispatcher<WebGLMethodDispatcher, _ID, \
|
||||
decltype(&_METHOD), &_METHOD, _SYNC> {}; \
|
||||
decltype(&_METHOD), &_METHOD> {}; \
|
||||
template <> \
|
||||
inline size_t IdByMethod<decltype(&_METHOD), &_METHOD>() { \
|
||||
return _ID; \
|
||||
@ -34,14 +31,11 @@ size_t IdByMethod() = delete;
|
||||
|
||||
// Defines each method the WebGLMethodDispatcher handles. The COUNTER value
|
||||
// is used as a cross-process ID for each of the methods.
|
||||
#define DEFINE_METHOD_HELPER(_METHOD, _SYNC) \
|
||||
DEFINE_METHOD_DISPATCHER(__COUNTER__, _METHOD, _SYNC)
|
||||
#define DEFINE_ASYNC(_METHOD) \
|
||||
DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::ASYNC)
|
||||
DEFINE_METHOD_DISPATCHER(__COUNTER__, _METHOD)
|
||||
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateBuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateFramebuffer)
|
||||
// DEFINE_SYNC(HostWebGLContext::CreateOpaqueFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateProgram)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateRenderbuffer)
|
||||
@ -67,26 +61,15 @@ DEFINE_ASYNC(HostWebGLContext::DeleteVertexArray)
|
||||
DEFINE_ASYNC(HostWebGLContext::Disable)
|
||||
DEFINE_ASYNC(HostWebGLContext::Enable)
|
||||
DEFINE_ASYNC(HostWebGLContext::GenerateError)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetCompileResult)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetFrontBufferSnapshot)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetFragDataLocation)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetFrontBuffer)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetLinkResult)
|
||||
// DEFINE_SYNC(HostWebGLContext::IsEnabled)
|
||||
DEFINE_ASYNC(HostWebGLContext::Resize)
|
||||
DEFINE_ASYNC(HostWebGLContext::RequestExtension)
|
||||
// DEFINE_SYNC(HostWebGLContext::DrawingBufferSize)
|
||||
// DEFINE_SYNC(HostWebGLContext::OnMemoryPressure)
|
||||
DEFINE_ASYNC(HostWebGLContext::DidRefresh)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetString)
|
||||
DEFINE_ASYNC(HostWebGLContext::AttachShader)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindAttribLocation)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::BlendColor)
|
||||
DEFINE_ASYNC(HostWebGLContext::BlendEquationSeparate)
|
||||
DEFINE_ASYNC(HostWebGLContext::BlendFuncSeparate)
|
||||
// DEFINE_SYNC(HostWebGLContext::CheckFramebufferStatus)
|
||||
DEFINE_ASYNC(HostWebGLContext::Clear)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearColor)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearDepth)
|
||||
@ -99,15 +82,8 @@ DEFINE_ASYNC(HostWebGLContext::DepthMask)
|
||||
DEFINE_ASYNC(HostWebGLContext::DepthRange)
|
||||
DEFINE_ASYNC(HostWebGLContext::DetachShader)
|
||||
DEFINE_ASYNC(HostWebGLContext::Flush)
|
||||
// DEFINE_SYNC(HostWebGLContext::Finish)
|
||||
DEFINE_ASYNC(HostWebGLContext::FramebufferAttach)
|
||||
DEFINE_ASYNC(HostWebGLContext::FrontFace)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetBufferParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetError)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetFramebufferAttachmentParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetRenderbufferParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetShaderPrecisionFormat)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetUniform)
|
||||
DEFINE_ASYNC(HostWebGLContext::Hint)
|
||||
DEFINE_ASYNC(HostWebGLContext::LineWidth)
|
||||
DEFINE_ASYNC(HostWebGLContext::LinkProgram)
|
||||
@ -123,14 +99,12 @@ DEFINE_ASYNC(HostWebGLContext::Viewport)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindBuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindBufferRange)
|
||||
DEFINE_ASYNC(HostWebGLContext::CopyBufferSubData)
|
||||
// DEFINE_ASYNC(HostWebGLContext::GetBufferSubData)
|
||||
DEFINE_ASYNC(HostWebGLContext::BufferData)
|
||||
DEFINE_ASYNC(HostWebGLContext::BufferSubData)
|
||||
DEFINE_ASYNC(HostWebGLContext::BlitFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::InvalidateFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::InvalidateSubFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::ReadBuffer)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetInternalformatParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::RenderbufferStorageMultisample)
|
||||
DEFINE_ASYNC(HostWebGLContext::ActiveTexture)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindTexture)
|
||||
@ -139,28 +113,21 @@ DEFINE_ASYNC(HostWebGLContext::CopyTexImage)
|
||||
DEFINE_ASYNC(HostWebGLContext::TexStorage)
|
||||
DEFINE_ASYNC(HostWebGLContext::TexImage)
|
||||
DEFINE_ASYNC(HostWebGLContext::CompressedTexImage)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetTexParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::TexParameter_base)
|
||||
DEFINE_ASYNC(HostWebGLContext::UseProgram)
|
||||
// DEFINE_SYNC(HostWebGLContext::ValidateProgram)
|
||||
DEFINE_ASYNC(HostWebGLContext::UniformData)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttrib4T)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttribDivisor)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetIndexedParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::UniformBlockBinding)
|
||||
DEFINE_ASYNC(HostWebGLContext::EnableVertexAttribArray)
|
||||
DEFINE_ASYNC(HostWebGLContext::DisableVertexAttribArray)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetVertexAttrib)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttribPointer)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearBufferTv)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearBufferfi)
|
||||
// DEFINE_SYNC(HostWebGLContext::ReadPixels)
|
||||
DEFINE_ASYNC(HostWebGLContext::ReadPixelsPbo)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindSampler)
|
||||
DEFINE_ASYNC(HostWebGLContext::SamplerParameteri)
|
||||
DEFINE_ASYNC(HostWebGLContext::SamplerParameterf)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetSamplerParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::ClientWaitSync)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindTransformFeedback)
|
||||
DEFINE_ASYNC(HostWebGLContext::BeginTransformFeedback)
|
||||
DEFINE_ASYNC(HostWebGLContext::EndTransformFeedback)
|
||||
@ -174,13 +141,10 @@ DEFINE_ASYNC(HostWebGLContext::DrawElementsInstanced)
|
||||
DEFINE_ASYNC(HostWebGLContext::BeginQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::EndQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::QueryCounter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetQueryParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::SetFramebufferIsInOpaqueRAF)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearVRSwapChain)
|
||||
|
||||
#undef DEFINE_METHOD_HELPER
|
||||
#undef DEFINE_ASYNC
|
||||
//#undef DEFINE_SYNC
|
||||
#undef DEFINE_METHOD_DISPATCHER
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "WebGLParent.h"
|
||||
|
||||
#include "WebGLChild.h"
|
||||
#include "mozilla/dom/WebGLCrossProcessCommandQueue.h"
|
||||
#include "mozilla/layers/LayerTransactionParent.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "ImageContainer.h"
|
||||
@ -17,19 +16,9 @@ namespace mozilla::dom {
|
||||
|
||||
mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
|
||||
const webgl::InitContextDesc& desc,
|
||||
UniquePtr<HostWebGLCommandSinkP>&& aSinkP,
|
||||
UniquePtr<HostWebGLCommandSinkI>&& aSinkI,
|
||||
webgl::InitContextResult* const out) {
|
||||
auto remotingData = Some(HostWebGLContext::RemotingData{
|
||||
*this, {}, // std::move(commandSink),
|
||||
});
|
||||
|
||||
mHost = HostWebGLContext::Create(
|
||||
{
|
||||
{},
|
||||
std::move(remotingData),
|
||||
},
|
||||
desc, out);
|
||||
{nullptr, this}, desc, out);
|
||||
|
||||
if (!mHost && !out->error.size()) {
|
||||
return IPC_FAIL(this, "Abnormally failed to create HostWebGLContext.");
|
||||
|
@ -14,6 +14,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
class HostWebGLContext;
|
||||
class WebGLChild;
|
||||
|
||||
namespace layers {
|
||||
class SharedSurfaceTextureClient;
|
||||
@ -30,8 +31,7 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr {
|
||||
using OtherSideActor = WebGLChild;
|
||||
|
||||
mozilla::ipc::IPCResult RecvInitialize(
|
||||
const webgl::InitContextDesc&, UniquePtr<HostWebGLCommandSinkP>&& aSinkP,
|
||||
UniquePtr<HostWebGLCommandSinkI>&& aSinkI, webgl::InitContextResult* out);
|
||||
const webgl::InitContextDesc&, webgl::InitContextResult* out);
|
||||
|
||||
WebGLParent(); // For IPDL
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "ipc/EnumSerializer.h"
|
||||
#include "mozilla/dom/ProducerConsumerQueue.h"
|
||||
#include "TexUnpackBlob.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
@ -61,12 +61,10 @@ EXPORTS.mozilla.dom += [
|
||||
"ImageUtils.h",
|
||||
"IpdlQueue.h",
|
||||
"OffscreenCanvas.h",
|
||||
"ProducerConsumerQueue.h",
|
||||
"QueueParamTraits.h",
|
||||
"TextMetrics.h",
|
||||
"WebGLChild.h",
|
||||
"WebGLCommandQueue.h",
|
||||
"WebGLCrossProcessCommandQueue.h",
|
||||
"WebGLIpdl.h",
|
||||
"WebGLParent.h",
|
||||
"WebGLTypes.h",
|
||||
@ -100,7 +98,6 @@ UNIFIED_SOURCES += [
|
||||
"ClientWebGLContext.cpp",
|
||||
"ClientWebGLExtensions.cpp",
|
||||
"HostWebGLContext.cpp",
|
||||
"Queue.cpp",
|
||||
"TexUnpackBlob.cpp",
|
||||
"WebGL2Context.cpp",
|
||||
"WebGL2ContextBuffers.cpp",
|
||||
@ -128,7 +125,6 @@ UNIFIED_SOURCES += [
|
||||
"WebGLContextValidate.cpp",
|
||||
"WebGLContextVertexArray.cpp",
|
||||
"WebGLContextVertices.cpp",
|
||||
"WebGLCrossProcessCommandQueue.cpp",
|
||||
"WebGLExtensionColorBufferFloat.cpp",
|
||||
"WebGLExtensionColorBufferHalfFloat.cpp",
|
||||
"WebGLExtensionCompressedTextureASTC.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user