Bug 1607940 - Stand up webgl.out-of-process:true path. r=handyman,nika,froydnj
* Use clearer pref names. * Default (and only support) IPDL dispatching. * Make DispatchCommands async-only. * Sync ipdl command per sync webgl entrypoint. * Eat the boilerplate cost, since there's not too many. * Run SerializedSize off same path as Serialize. * All shmem uploads go through normal DispatchCommands. * Defer pruning of dead code for now so we can iterate quickly. * Use Read/Write(begin,end) instead of (begin,size). * This would have prevented a bug where we read/wrote N*sizeof(T)*sizeof(T). Differential Revision: https://phabricator.services.mozilla.com/D81495
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -731,13 +731,12 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
|
||||
const RefPtr<ClientWebGLExtensionLoseContext> mExtLoseContext;
|
||||
|
||||
webgl::LossStatus mLossStatus = webgl::LossStatus::Ready;
|
||||
bool mAwaitingRestore = false;
|
||||
mutable std::shared_ptr<webgl::NotLostData> mNotLost;
|
||||
mutable GLenum mNextError = 0;
|
||||
mutable webgl::LossStatus mLossStatus = webgl::LossStatus::Ready;
|
||||
mutable bool mAwaitingRestore = false;
|
||||
|
||||
// -
|
||||
private:
|
||||
std::shared_ptr<webgl::NotLostData> mNotLost;
|
||||
mutable GLenum mNextError = 0;
|
||||
|
||||
public:
|
||||
const auto& Limits() const { return mNotLost->info.limits; }
|
||||
@@ -755,14 +754,14 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
// -
|
||||
|
||||
public:
|
||||
void EmulateLoseContext();
|
||||
void OnContextLoss(webgl::ContextLossReason);
|
||||
void RestoreContext(webgl::LossStatus requiredStatus);
|
||||
void EmulateLoseContext() const;
|
||||
void OnContextLoss(webgl::ContextLossReason) const;
|
||||
void RestoreContext(webgl::LossStatus requiredStatus) const;
|
||||
|
||||
private:
|
||||
bool DispatchEvent(const nsAString&) const;
|
||||
void Event_webglcontextlost();
|
||||
void Event_webglcontextrestored();
|
||||
void Event_webglcontextlost() const;
|
||||
void Event_webglcontextrestored() const;
|
||||
|
||||
bool CreateHostContext(const uvec2& requestedSize);
|
||||
void ThrowEvent_WebGLContextCreationError(const std::string&) const;
|
||||
@@ -853,6 +852,10 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
EnqueueErrorImpl(error, text);
|
||||
}
|
||||
|
||||
void EnqueueError(const webgl::ErrorInfo& info) const {
|
||||
EnqueueError(info.type, "%s", info.info.c_str());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void EnqueueWarning(const char* const format, const Args&... args) const {
|
||||
EnqueueError(0, format, args...);
|
||||
@@ -924,9 +927,6 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
layers::WebRenderCanvasData* aCanvasData) override;
|
||||
|
||||
bool UpdateCompositableHandle(LayerTransactionChild* aLayerTransaction,
|
||||
CompositableHandle aHandle) override;
|
||||
|
||||
// ------
|
||||
|
||||
int32_t GetWidth() override { return AutoAssertCast(DrawingBufferSize().x); }
|
||||
@@ -1026,6 +1026,11 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
void Enable(GLenum cap) const;
|
||||
bool IsEnabled(GLenum cap) const;
|
||||
|
||||
private:
|
||||
Maybe<double> GetNumber(GLenum pname);
|
||||
Maybe<std::string> GetString(GLenum pname);
|
||||
|
||||
public:
|
||||
void GetParameter(JSContext* cx, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval, ErrorResult& rv,
|
||||
bool debug = false);
|
||||
@@ -1703,6 +1708,10 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
}
|
||||
|
||||
// ------------------------ Uniforms and attributes ------------------------
|
||||
|
||||
private:
|
||||
Maybe<double> GetVertexAttribPriv(GLuint index, GLenum pname);
|
||||
|
||||
public:
|
||||
void GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval, ErrorResult& rv);
|
||||
@@ -2079,61 +2088,6 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
// The cross-process communication mechanism
|
||||
// -------------------------------------------------------------------------
|
||||
protected:
|
||||
/*
|
||||
template <size_t command, typename... Args>
|
||||
void DispatchAsync(Args&&... aArgs) const {
|
||||
const auto& oop = *mNotLost->outOfProcess;
|
||||
QueueStatus status = oop.mCommandSource->RunAsyncCommand(command,
|
||||
aArgs...);
|
||||
if (!IsSuccess(status)) { if (status == QueueStatus::kOOMError) {
|
||||
JsWarning("Ran out-of-memory during WebGL IPC.");
|
||||
}
|
||||
// Not much to do but shut down. Since this was a Pcq failure and
|
||||
// may have been catastrophic, we don't try to revive it. Make sure to
|
||||
// post "webglcontextlost"
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"TODO: Make this shut down the context, actors, everything.");
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t command, typename ReturnType, typename... Args>
|
||||
ReturnType DispatchSync(Args&&... aArgs) const {
|
||||
const auto& oop = *mNotLost->outOfProcess;
|
||||
ReturnType returnValue;
|
||||
QueueStatus status =
|
||||
oop.mCommandSource->RunSyncCommand(command, returnValue, aArgs...);
|
||||
|
||||
if (!IsSuccess(status)) {
|
||||
if (status == QueueStatus::kOOMError) {
|
||||
JsWarning("Ran out-of-memory during WebGL IPC.");
|
||||
}
|
||||
// Not much to do but shut down. Since this was a Pcq failure and
|
||||
// may have been catastrophic, we don't try to revive it. Make sure to
|
||||
// post "webglcontextlost"
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"TODO: Make this shut down the context, actors, everything.");
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
template <size_t command, typename... Args>
|
||||
void DispatchVoidSync(Args&&... aArgs) const {
|
||||
const auto& oop = *mNotLost->outOfProcess;
|
||||
const auto status =
|
||||
oop.mCommandSource->RunVoidSyncCommand(command, aArgs...);
|
||||
if (!IsSuccess(status)) {
|
||||
if (status == QueueStatus::kOOMError) {
|
||||
JsWarning("Ran out-of-memory during WebGL IPC.");
|
||||
}
|
||||
// Not much to do but shut down. Since this was a Pcq failure and
|
||||
// may have been catastrophic, we don't try to revive it. Make sure to
|
||||
// post "webglcontextlost"
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"TODO: Make this shut down the context, actors, everything.");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template <typename ReturnType>
|
||||
friend struct WebGLClientDispatcher;
|
||||
|
||||
@@ -2143,16 +2097,8 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
|
||||
// If we are running WebGL in this process then call the HostWebGLContext
|
||||
// method directly. Otherwise, dispatch over IPC.
|
||||
// template <typename MethodType, MethodType method,
|
||||
// typename ReturnType = typename
|
||||
// FunctionTypeTraits<MethodType>::ReturnType, size_t Id =
|
||||
// WebGLMethodDispatcher::Id<MethodType, method>(), typename... Args>
|
||||
// ReturnType Run(Args&&... aArgs) const;
|
||||
template <
|
||||
typename MethodType, MethodType method,
|
||||
typename ReturnType = typename FunctionTypeTraits<MethodType>::ReturnType,
|
||||
typename... Args>
|
||||
ReturnType Run(Args&&... aArgs) const;
|
||||
template <typename MethodType, MethodType method, typename... Args>
|
||||
void Run(Args&&... aArgs) const;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers for DOM operations, composition, actors, etc
|
||||
|
||||
@@ -191,11 +191,16 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(ObjectId xrFb,
|
||||
const bool webvr) const;
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot() const {
|
||||
return mContext->GetFrontBufferSnapshot();
|
||||
// -
|
||||
|
||||
uvec2 GetFrontBufferSize() const { return mContext->DrawingBufferSize(); }
|
||||
bool FrontBufferSnapshotInto(Range<uint8_t> dest) const {
|
||||
return mContext->FrontBufferSnapshotInto(dest);
|
||||
}
|
||||
|
||||
void ClearVRSwapChain() { mContext->ClearVRSwapChain(); }
|
||||
void ClearVRSwapChain() const { mContext->ClearVRSwapChain(); }
|
||||
|
||||
// -
|
||||
|
||||
void Resize(const uvec2& size) { return mContext->Resize(size); }
|
||||
|
||||
@@ -258,7 +263,7 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
|
||||
bool IsEnabled(GLenum cap) const { return mContext->IsEnabled(cap); }
|
||||
|
||||
Maybe<double> GetParameter(GLenum pname) const {
|
||||
Maybe<double> GetNumber(GLenum pname) const {
|
||||
return mContext->GetParameter(pname);
|
||||
}
|
||||
|
||||
@@ -477,21 +482,21 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
writeOffset, size);
|
||||
}
|
||||
|
||||
void GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
RawBuffer<uint8_t>& dest) const {
|
||||
const auto range = MakeRange(dest);
|
||||
GetWebGL2Context()->GetBufferSubData(target, srcByteOffset, range);
|
||||
bool GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
const Range<uint8_t>& dest) const {
|
||||
return GetWebGL2Context()->GetBufferSubData(target, srcByteOffset, dest);
|
||||
}
|
||||
|
||||
void BufferData(GLenum target, const RawBuffer<const uint8_t>& data,
|
||||
GLenum usage) const {
|
||||
mContext->BufferData(target, data.Length(), data.Data(), usage);
|
||||
void BufferData(GLenum target, const RawBuffer<>& data, GLenum usage) const {
|
||||
const auto& range = data.Data();
|
||||
mContext->BufferData(target, range.length(), range.begin().get(), usage);
|
||||
}
|
||||
|
||||
void BufferSubData(GLenum target, uint64_t dstByteOffset,
|
||||
const RawBuffer<const uint8_t>& srcData) const {
|
||||
mContext->BufferSubData(target, dstByteOffset, srcData.Length(),
|
||||
srcData.Data());
|
||||
const RawBuffer<>& srcData) const {
|
||||
const auto& range = srcData.Data();
|
||||
mContext->BufferSubData(target, dstByteOffset, range.length(),
|
||||
range.begin().get());
|
||||
}
|
||||
|
||||
// -------------------------- Framebuffer Objects --------------------------
|
||||
@@ -550,8 +555,7 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
// CompressedTexSubImage if `sub`
|
||||
void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level,
|
||||
GLenum format, const uvec3& offset, const uvec3& size,
|
||||
const RawBuffer<const uint8_t>& src,
|
||||
const uint32_t pboImageSize,
|
||||
const RawBuffer<>& src, const uint32_t pboImageSize,
|
||||
const Maybe<uint64_t>& pboOffset) const {
|
||||
mContext->CompressedTexImage(sub, imageTarget, level, format, offset, size,
|
||||
MakeRange(src), pboImageSize, pboOffset);
|
||||
@@ -602,8 +606,8 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
// ------------------------ Uniforms and attributes ------------------------
|
||||
|
||||
void UniformData(uint32_t loc, bool transpose,
|
||||
const RawBuffer<const uint8_t>& data) const {
|
||||
mContext->UniformData(loc, transpose, MakeRange(data));
|
||||
const RawBuffer<>& data) const {
|
||||
mContext->UniformData(loc, transpose, data.Data());
|
||||
}
|
||||
|
||||
void VertexAttrib4T(GLuint index, const webgl::TypedQuad& data) const {
|
||||
@@ -660,10 +664,9 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
||||
mContext->ReadPixelsPbo(desc, offset);
|
||||
}
|
||||
|
||||
void ReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
RawBuffer<uint8_t>& dest) const {
|
||||
const auto range = MakeRange(dest);
|
||||
mContext->ReadPixels(desc, range);
|
||||
webgl::ReadPixelsResult ReadPixelsInto(const webgl::ReadPixelsDesc& desc,
|
||||
const Range<uint8_t>& dest) const {
|
||||
return mContext->ReadPixelsInto(desc, dest);
|
||||
}
|
||||
|
||||
// ----------------------------- Sampler -----------------------------------
|
||||
|
||||
@@ -83,10 +83,6 @@ struct IpdlQueueBuffer {
|
||||
|
||||
using IpdlQueueBuffers = nsTArray<IpdlQueueBuffer>;
|
||||
|
||||
// Any object larger than this will be inserted into its own Shmem.
|
||||
// TODO: Base this on something.
|
||||
static constexpr size_t kMaxIpdlQueueArgSize = 256 * 1024;
|
||||
|
||||
static constexpr uint32_t kAsyncFlushWaitMs = 4; // 4ms
|
||||
|
||||
template <typename Derived>
|
||||
@@ -432,10 +428,6 @@ class IpdlProducer final : public SupportsWeakPtr<IpdlProducer<_Actor>> {
|
||||
arg, aArgSize);
|
||||
}
|
||||
|
||||
inline bool NeedsSharedMemory(size_t aRequested) {
|
||||
return aRequested >= kMaxIpdlQueueArgSize;
|
||||
}
|
||||
|
||||
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
|
||||
|
||||
protected:
|
||||
@@ -543,10 +535,6 @@ class IpdlConsumer final : public SupportsWeakPtr<IpdlConsumer<_Actor>> {
|
||||
mBuf.Elements(), mBuf.Length() + 1, aRead, aWrite, arg, aArgSize);
|
||||
}
|
||||
|
||||
static inline bool NeedsSharedMemory(size_t aRequested) {
|
||||
return aRequested >= kMaxIpdlQueueArgSize;
|
||||
}
|
||||
|
||||
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -9,10 +9,25 @@ include protocol PCompositorBridge;
|
||||
include protocol PLayerTransaction;
|
||||
|
||||
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::webgl::ContextLossReason from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::layers::SurfaceDescriptor from "mozilla/layers/LayersTypes.h";
|
||||
using std::string from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::uvec2 from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::CompileResult from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::ContextLossReason from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::FrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::GetUniformData from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::InitContextDesc from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::InitContextResult from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::Int32Vector from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::LinkResult from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::MaybeDouble from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::MaybeFrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::MaybeShaderPrecisionFormat from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::MaybeSurfaceDescriptor from "mozilla/dom/WebGLIpdl.h";
|
||||
using mozilla::webgl::MaybeString 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";
|
||||
@@ -37,20 +52,53 @@ parent:
|
||||
|
||||
async __delete__();
|
||||
|
||||
// DLP: TODO: Does this need to be sync?
|
||||
sync UpdateCompositableHandle(PLayerTransaction aLayerTrans,
|
||||
CompositableHandle aHandle);
|
||||
// -
|
||||
|
||||
sync ExchangeIpdlQueueData(IpdlQueueBuffer aMsg) returns (IpdlQueueBuffers aResponse);
|
||||
async DispatchCommands(Shmem commands, uint64_t size);
|
||||
|
||||
// -
|
||||
|
||||
sync GetFrontBufferSnapshot() returns (FrontBufferSnapshotIpc ret);
|
||||
sync ReadPixels(ReadPixelsDesc desc, uint64_t maxBytes) returns (ReadPixelsResultIpc ret);
|
||||
|
||||
// -
|
||||
|
||||
sync CheckFramebufferStatus(uint32_t target) returns (uint32_t ret);
|
||||
sync ClientWaitSync(uint64_t id, uint32_t flags, uint64_t timeout) returns (uint32_t ret);
|
||||
sync CreateOpaqueFramebuffer(uint64_t id, OpaqueFramebufferOptions options) returns (bool ret);
|
||||
sync DrawingBufferSize() returns (uvec2 ret);
|
||||
sync Finish();
|
||||
sync GetBufferParameter(uint32_t target, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetBufferSubData(uint32_t target, uint64_t srcByteOffset, uint64_t byteSize) returns (Shmem ret);
|
||||
sync GetCompileResult(uint64_t id) returns (CompileResult ret);
|
||||
sync GetError() returns (uint32_t ret);
|
||||
sync GetFragDataLocation(uint64_t id, string name) returns (int32_t ret);
|
||||
sync GetFramebufferAttachmentParameter(uint64_t id,
|
||||
uint32_t attachment,
|
||||
uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetFrontBuffer(uint64_t fb, bool vr) returns (MaybeSurfaceDescriptor ret);
|
||||
sync GetIndexedParameter(uint32_t target, uint32_t index) returns (MaybeDouble ret);
|
||||
sync GetInternalformatParameter(uint32_t target, uint32_t internalFormat, uint32_t pname) returns (Int32Vector? ret);
|
||||
sync GetLinkResult(uint64_t id) returns (LinkResult ret);
|
||||
sync GetNumber(uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetQueryParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetRenderbufferParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetSamplerParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetShaderPrecisionFormat(
|
||||
uint32_t shaderType, uint32_t precisionType) returns (MaybeShaderPrecisionFormat ret);
|
||||
sync GetString(uint32_t pname) returns (MaybeString ret);
|
||||
sync GetTexParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync GetUniform(uint64_t id, uint32_t loc) returns (GetUniformData ret);
|
||||
sync GetVertexAttrib(uint32_t index, uint32_t pname) returns (MaybeDouble ret);
|
||||
sync IsEnabled(uint32_t cap) returns (bool ret);
|
||||
sync OnMemoryPressure();
|
||||
sync ValidateProgram(uint64_t id) returns (bool ret);
|
||||
|
||||
child:
|
||||
async JsWarning(string text);
|
||||
|
||||
// Tell client that this queue needs to be shut down
|
||||
async OnContextLoss(ContextLossReason aReason);
|
||||
|
||||
both:
|
||||
async TransmitIpdlQueueData(IpdlQueueBuffer aData);
|
||||
};
|
||||
|
||||
} // dom
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
namespace mozilla {
|
||||
namespace webgl {
|
||||
|
||||
struct QueueStatus {
|
||||
enum EStatus {
|
||||
enum class QueueStatus {
|
||||
// Operation was successful
|
||||
kSuccess,
|
||||
// The operation failed because the queue isn't ready for it.
|
||||
@@ -38,19 +37,14 @@ struct QueueStatus {
|
||||
// Fatal error: Internal processing ran out of memory. This is likely e.g.
|
||||
// during de-serialization.
|
||||
kOOMError,
|
||||
} mValue;
|
||||
|
||||
MOZ_IMPLICIT QueueStatus(const EStatus status = kSuccess) : mValue(status) {}
|
||||
explicit operator bool() const { return mValue == kSuccess; }
|
||||
explicit operator int() const { return static_cast<int>(mValue); }
|
||||
bool operator==(const EStatus& o) const { return mValue == o; }
|
||||
bool operator!=(const EStatus& o) const { return !(*this == o); }
|
||||
};
|
||||
|
||||
inline bool IsSuccess(QueueStatus status) {
|
||||
return status == QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
inline bool operator!(const QueueStatus status) { return !IsSuccess(status); }
|
||||
|
||||
template <typename T>
|
||||
struct RemoveCVR {
|
||||
typedef typename std::remove_reference<typename std::remove_cv<T>::type>::type
|
||||
@@ -84,35 +78,19 @@ struct IsTriviallySerializable
|
||||
* goes for TryRemove, which fails when there isn't enough data in
|
||||
* the queue yet for them to complete.
|
||||
*
|
||||
* QueueParamTraits resolve this problem by allowing the Try... operations to
|
||||
* use QueueParamTraits<typename RemoveCVR<Arg>::Type>::MinSize() to get a
|
||||
* lower-bound on the amount of room in the queue required for Arg. If the
|
||||
* operation needs more than is available then the operation quickly fails.
|
||||
* Otherwise, (de)serialization will commence, although it may still fail if
|
||||
* MinSize() was too low.
|
||||
*
|
||||
* Their expected interface is:
|
||||
*
|
||||
* template<> struct QueueParamTraits<typename RemoveCVR<Arg>::Type> {
|
||||
* // Write data from aArg into the PCQ. It is an error to write less than
|
||||
* // is reported by MinSize(aArg).
|
||||
* // Write data from aArg into the PCQ.
|
||||
* static QueueStatus Write(ProducerView& aProducerView, const Arg& aArg)
|
||||
* {...};
|
||||
*
|
||||
* // Read data from the PCQ into aArg, or just skip the data if aArg is null.
|
||||
* // It is an error to read less than is reported by MinSize(aArg).
|
||||
* static QueueStatus Read(ConsumerView& aConsumerView, Arg* aArg) {...}
|
||||
*
|
||||
* // The minimum number of bytes needed to represent this object in the
|
||||
* // queue. It is intended to be a very fast estimate but most cases can
|
||||
* // easily compute the exact value.
|
||||
* // It is an error for the queue to require less room than MinSize()
|
||||
* // reports. A MinSize of 0 is always valid (albeit wasteful).
|
||||
* static size_t MinSize(const Arg& aArg) {...}
|
||||
* };
|
||||
*/
|
||||
template <typename Arg>
|
||||
struct QueueParamTraits;
|
||||
struct QueueParamTraits; // Todo: s/QueueParamTraits/SizedParamTraits/
|
||||
|
||||
/**
|
||||
* The marshaller handles all data insertion into the queue.
|
||||
@@ -182,15 +160,12 @@ class ProducerView {
|
||||
* Copy bytes from aBuffer to the producer if there is enough room.
|
||||
* aBufferSize must not be 0.
|
||||
*/
|
||||
inline QueueStatus Write(const void* aBuffer, size_t aBufferSize);
|
||||
inline QueueStatus Write(const uint8_t* begin, const uint8_t* end);
|
||||
|
||||
/**
|
||||
* Copy bytes from src (an array of Ts), to the producer if there is
|
||||
* enough room. count is the number of elements in the array.
|
||||
*/
|
||||
template <typename T>
|
||||
inline QueueStatus Write(const T* src, size_t count) {
|
||||
return Write(reinterpret_cast<const void*>(src), count * sizeof(T));
|
||||
inline QueueStatus Write(const T* begin, const T* end) {
|
||||
return Write(reinterpret_cast<const uint8_t*>(begin),
|
||||
reinterpret_cast<const uint8_t*>(end));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,17 +177,6 @@ class ProducerView {
|
||||
typename RemoveCVR<Arg>::Type>::Write(*this, aArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* MinSize of Arg using QueueParamTraits.
|
||||
*/
|
||||
template <typename Arg>
|
||||
size_t MinSizeParam(const Arg& aArg = nullptr) {
|
||||
return mozilla::webgl::QueueParamTraits<
|
||||
typename RemoveCVR<Arg>::Type>::MinSize(*this, aArg);
|
||||
}
|
||||
|
||||
inline size_t MinSizeBytes(size_t aNBytes);
|
||||
|
||||
QueueStatus GetStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
@@ -241,16 +205,12 @@ class ConsumerView {
|
||||
* Read bytes from the consumer if there is enough data. aBuffer may
|
||||
* be null (in which case the data is skipped)
|
||||
*/
|
||||
inline QueueStatus Read(void* aBuffer, size_t aBufferSize);
|
||||
inline QueueStatus Read(uint8_t* begin, uint8_t* end);
|
||||
|
||||
/**
|
||||
* Read bytes from the consumer into an array of Ts, if there is enough data.
|
||||
* aBuffer may be null (in which case the data is skipped). count is the
|
||||
* number of array elements to read.
|
||||
*/
|
||||
template <typename T>
|
||||
inline QueueStatus Read(T* dest, size_t count) {
|
||||
return Read(reinterpret_cast<void*>(dest), count * sizeof(T));
|
||||
inline QueueStatus Read(T* begin, T* end) {
|
||||
return Read(reinterpret_cast<uint8_t*>(begin),
|
||||
reinterpret_cast<uint8_t*>(end));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,22 +220,10 @@ class ConsumerView {
|
||||
template <typename Arg>
|
||||
QueueStatus ReadParam(Arg* aArg) {
|
||||
MOZ_ASSERT(aArg);
|
||||
return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>*>::Read(*this,
|
||||
return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>>::Read(*this,
|
||||
aArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* MinSize of Arg using QueueParamTraits. aArg may be null.
|
||||
*/
|
||||
template <typename Arg>
|
||||
size_t MinSizeParam(Arg& aArg) {
|
||||
MOZ_ASSERT(aArg);
|
||||
return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>&>::MinSize(
|
||||
*this, aArg);
|
||||
}
|
||||
|
||||
inline size_t MinSizeBytes(size_t aNBytes);
|
||||
|
||||
QueueStatus GetStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
@@ -286,62 +234,24 @@ class ConsumerView {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
QueueStatus ProducerView<T>::Write(const void* aBuffer, size_t aBufferSize) {
|
||||
MOZ_ASSERT(aBuffer && (aBufferSize > 0));
|
||||
if (!mStatus) {
|
||||
QueueStatus ProducerView<T>::Write(const uint8_t* begin, const uint8_t* end) {
|
||||
MOZ_ASSERT(begin);
|
||||
MOZ_ASSERT(begin < end);
|
||||
if (IsSuccess(mStatus)) {
|
||||
mStatus = mProducer->WriteObject(mRead, mWrite, begin, end - begin);
|
||||
}
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (mProducer->NeedsSharedMemory(aBufferSize)) {
|
||||
mozilla::ipc::Shmem shmem;
|
||||
QueueStatus status = mProducer->AllocShmem(&shmem, aBufferSize, aBuffer);
|
||||
if (!IsSuccess(status)) {
|
||||
return status;
|
||||
}
|
||||
return WriteParam(std::move(shmem));
|
||||
}
|
||||
|
||||
return mProducer->WriteObject(mRead, mWrite, aBuffer, aBufferSize);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t ProducerView<T>::MinSizeBytes(size_t aNBytes) {
|
||||
mozilla::ipc::Shmem shmem;
|
||||
return mProducer->NeedsSharedMemory(aNBytes) ? MinSizeParam(shmem) : aNBytes;
|
||||
QueueStatus ConsumerView<T>::Read(uint8_t* begin, uint8_t* end) {
|
||||
MOZ_ASSERT(begin < end);
|
||||
if (IsSuccess(mStatus)) {
|
||||
mStatus = mConsumer->ReadObject(mRead, mWrite, begin, end - begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QueueStatus ConsumerView<T>::Read(void* aBuffer, size_t aBufferSize) {
|
||||
MOZ_ASSERT(aBufferSize > 0);
|
||||
if (!mStatus) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (mConsumer->NeedsSharedMemory(aBufferSize)) {
|
||||
mozilla::ipc::Shmem shmem;
|
||||
QueueStatus status = ReadParam(&shmem);
|
||||
if (!IsSuccess(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((shmem.Size<uint8_t>() != aBufferSize) || (!shmem.get<uint8_t>())) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
|
||||
if (aBuffer) {
|
||||
memcpy(aBuffer, shmem.get<uint8_t>(), aBufferSize);
|
||||
}
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
return mConsumer->ReadObject(mRead, mWrite, aBuffer, aBufferSize);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t ConsumerView<T>::MinSizeBytes(size_t aNBytes) {
|
||||
mozilla::ipc::Shmem shmem;
|
||||
return mConsumer->NeedsSharedMemory(aNBytes) ? MinSizeParam(shmem) : aNBytes;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -355,7 +265,8 @@ struct QueueParamTraits {
|
||||
"No QueueParamTraits specialization was found for this type "
|
||||
"and it does not satisfy IsTriviallySerializable.");
|
||||
// Write self as binary
|
||||
return aProducerView.Write(&aArg, sizeof(Arg));
|
||||
const auto begin = &aArg;
|
||||
return aProducerView.Write(begin, begin + 1);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
@@ -364,15 +275,7 @@ struct QueueParamTraits {
|
||||
"No QueueParamTraits specialization was found for this type "
|
||||
"and it does not satisfy IsTriviallySerializable.");
|
||||
// Read self as binary
|
||||
return aConsumerView.Read(aArg, sizeof(Arg));
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static constexpr size_t MinSize(View& aView, const Arg& aArg) {
|
||||
static_assert(mozilla::webgl::template IsTriviallySerializable<Arg>::value,
|
||||
"No QueueParamTraits specialization was found for this type "
|
||||
"and it does not satisfy IsTriviallySerializable.");
|
||||
return sizeof(Arg);
|
||||
return aConsumerView.Read(aArg, aArg + 1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,9 +290,9 @@ struct EnumSerializer {
|
||||
typedef typename std::underlying_type<E>::type DataType;
|
||||
|
||||
template <typename U>
|
||||
static void Write(ProducerView<U>& aProducerView, const ParamType& aValue) {
|
||||
static auto Write(ProducerView<U>& aProducerView, const ParamType& aValue) {
|
||||
MOZ_RELEASE_ASSERT(EnumValidator::IsLegalValue(aValue));
|
||||
aProducerView.WriteParam(DataType(aValue));
|
||||
return aProducerView.WriteParam(DataType(aValue));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
@@ -398,21 +301,16 @@ struct EnumSerializer {
|
||||
if (!aConsumerView.ReadParam(&value)) {
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"_ns);
|
||||
return aConsumerView.GetStatus();
|
||||
return IsSuccess(aConsumerView.GetStatus());
|
||||
}
|
||||
if (!EnumValidator::IsLegalValue(ParamType(value))) {
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"_ns);
|
||||
return aConsumerView.GetStatus();
|
||||
return IsSuccess(aConsumerView.GetStatus());
|
||||
}
|
||||
|
||||
*aResult = ParamType(value);
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static constexpr size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(DataType(aArg));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -432,31 +330,9 @@ struct ContiguousEnumSerializerInclusive
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
template <>
|
||||
struct QueueParamTraits<QueueStatus::EStatus>
|
||||
struct QueueParamTraits<QueueStatus>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
QueueStatus::EStatus, QueueStatus::EStatus::kSuccess,
|
||||
QueueStatus::EStatus::kOOMError> {};
|
||||
|
||||
template <>
|
||||
struct QueueParamTraits<QueueStatus> {
|
||||
using ParamType = QueueStatus;
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Write(ProducerView<U>& aProducerView,
|
||||
const ParamType& aArg) {
|
||||
return aProducerView.WriteParam(aArg.mValue);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
|
||||
return aConsumerView.ReadParam(&aArg->mValue);
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSize(aArg.mValue);
|
||||
}
|
||||
};
|
||||
QueueStatus, QueueStatus::kSuccess, QueueStatus::kOOMError> {};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@@ -482,7 +358,7 @@ struct QueueParamTraits<nsACString> {
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
|
||||
bool isVoid = false;
|
||||
if (!aConsumerView.ReadParam(&isVoid)) {
|
||||
if (!IsSuccess(aConsumerView.ReadParam(&isVoid))) {
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
aArg->SetIsVoid(isVoid);
|
||||
@@ -491,7 +367,7 @@ struct QueueParamTraits<nsACString> {
|
||||
}
|
||||
|
||||
uint32_t len = 0;
|
||||
if (!aConsumerView.ReadParam(&len)) {
|
||||
if (!IsSuccess(aConsumerView.ReadParam(&len))) {
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
|
||||
@@ -504,24 +380,13 @@ struct QueueParamTraits<nsACString> {
|
||||
if (!buf) {
|
||||
return QueueStatus::kOOMError;
|
||||
}
|
||||
if (!aConsumerView.Read(buf, len)) {
|
||||
if (!IsSuccess(aConsumerView.Read(buf, len))) {
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
buf[len] = '\0';
|
||||
aArg->Adopt(buf, len);
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t minSize = aView.template MinSizeParam<bool>(aArg.IsVoid());
|
||||
if (aArg.IsVoid()) {
|
||||
return minSize;
|
||||
}
|
||||
minSize += aView.template MinSizeParam<uint32_t>(aArg.Length()) +
|
||||
aView.MinSizeBytes(aArg.Length());
|
||||
return minSize;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -581,18 +446,6 @@ struct QueueParamTraits<nsAString> {
|
||||
aArg->Adopt(buf, len);
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t minSize = aView.template MinSizeParam<bool>(aArg.IsVoid());
|
||||
if (aArg.IsVoid()) {
|
||||
return minSize;
|
||||
}
|
||||
uint32_t sizeofchar = sizeof(typename ParamType::char_type);
|
||||
minSize += aView.template MinSizeParam<uint32_t>(aArg.Length()) +
|
||||
aView.MinSizeBytes(aArg.Length() * sizeofchar);
|
||||
return minSize;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -645,15 +498,6 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> {
|
||||
}
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t ret = aView.MinSizeParam(aArg.Length());
|
||||
for (auto& elt : aArg) {
|
||||
ret += aView.MinSizeParam(elt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// For ElementTypes that are IsTriviallySerializable
|
||||
@@ -684,13 +528,6 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> {
|
||||
|
||||
return aConsumerView.Read(aArg->Elements(), arrayLen * sizeof(ElementType));
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t ret = aView.template MinSizeParam<size_t>(aArg.Length());
|
||||
ret += aView.MinSizeBytes(aArg.Length() * sizeof(ElementType));
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementType>
|
||||
@@ -728,15 +565,6 @@ struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> {
|
||||
}
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t ret = 0;
|
||||
for (const auto& elt : aArg) {
|
||||
ret += aView.MinSizeParam(elt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// For ElementTypes that are IsTriviallySerializable
|
||||
@@ -755,11 +583,6 @@ struct ArrayQueueParamTraits<Array<_ElementType, Length>, true> {
|
||||
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
|
||||
return aConsumerView.Read(aArg->begin(), sizeof(ElementType[Length]));
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeBytes(sizeof(ElementType[Length]));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementType, size_t Length>
|
||||
@@ -797,12 +620,6 @@ struct QueueParamTraits<Maybe<ElementType>> {
|
||||
aArg->emplace();
|
||||
return aConsumerView.ReadParam(aArg->ptr());
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.template MinSizeParam<bool>(aArg) +
|
||||
(aArg.isSome() ? aView.MinSizeParam(aArg.ref()) : 0);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -836,12 +653,6 @@ struct QueueParamTraits<Maybe<Variant<T, Ts...>>> {
|
||||
aArg->emplace(VariantType<T>());
|
||||
return aConsumerView.ReadParam(aArg->ptr());
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(aArg.mIsSome) +
|
||||
(aArg.isSome() ? aView.MinSizeParam(aArg.ref()) : 0);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -862,11 +673,6 @@ struct QueueParamTraits<std::pair<TypeA, TypeB>> {
|
||||
aConsumerView.ReadParam(aArg->first());
|
||||
return aConsumerView.ReadParam(aArg->second());
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(aArg.first()) + aView.MinSizeParam(aArg.second());
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -905,105 +711,10 @@ struct QueueParamTraits<UniquePtr<T>> {
|
||||
aArg->reset(obj);
|
||||
return aConsumerView.ReadParam(obj);
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
size_t ret = aView.template MinSizeParam<bool>(aArg);
|
||||
return ret + aView.MinSizeParam(*aArg);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// C++ does not allow this struct with a templated method to be local to
|
||||
// another struct (QueueParamTraits<Variant<...>>) so we put it here.
|
||||
template <typename U>
|
||||
struct PcqVariantWriter {
|
||||
ProducerView<U>& mView;
|
||||
template <typename T>
|
||||
QueueStatus match(const T& x) {
|
||||
return mView.WriteParam(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
struct QueueParamTraits<Variant<Types...>> {
|
||||
using ParamType = Variant<Types...>;
|
||||
using Tag = typename mozilla::detail::VariantTag<Types...>::Type;
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Write(ProducerView<U>& aProducerView,
|
||||
const ParamType& aArg) {
|
||||
aProducerView.WriteParam(aArg.tag);
|
||||
return aArg.match(PcqVariantWriter{aProducerView});
|
||||
}
|
||||
|
||||
// Check the N-1th tag. See ParamTraits<mozilla::Variant> for details.
|
||||
template <size_t N, typename dummy = void>
|
||||
struct VariantReader {
|
||||
using Next = VariantReader<N - 1>;
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& aView, Tag aTag, ParamType* aArg) {
|
||||
if (aTag == N - 1) {
|
||||
using EntryType = typename mozilla::detail::Nth<N - 1, Types...>::Type;
|
||||
return aView.ReadParam(*static_cast<EntryType*>(aArg->ptr()));
|
||||
}
|
||||
return Next::Read(aView, aTag, aArg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename dummy>
|
||||
struct VariantReader<0, dummy> {
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& aView, Tag aTag, ParamType* aArg) {
|
||||
MOZ_ASSERT_UNREACHABLE("Tag wasn't for an entry in this Variant");
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
|
||||
Tag tag;
|
||||
if (!aConsumerView.ReadParam(&tag)) {
|
||||
return aConsumerView.GetStatus();
|
||||
}
|
||||
aArg->tag = tag;
|
||||
return VariantReader<sizeof...(Types)>::Read(aConsumerView, tag, aArg);
|
||||
}
|
||||
|
||||
// Get the min size of the given variant or get the min size of all of the
|
||||
// variant's types.
|
||||
template <size_t N, typename View>
|
||||
struct MinSizeVariant {
|
||||
using Next = MinSizeVariant<N - 1, View>;
|
||||
static size_t MinSize(View& aView, const Tag* aTag, const ParamType& aArg) {
|
||||
using EntryType = typename mozilla::detail::Nth<N - 1, Types...>::Type;
|
||||
MOZ_ASSERT(aTag);
|
||||
if (*aTag == N - 1) {
|
||||
return aView.MinSizeParam(aArg.template as<EntryType>());
|
||||
}
|
||||
return Next::MinSize(aView, aTag, aArg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename View>
|
||||
struct MinSizeVariant<0, View> {
|
||||
// We've reached the end of the type list. We will legitimately get here
|
||||
// when calculating MinSize for a null Variant.
|
||||
static size_t MinSize(View& aView, const Tag* aTag, const ParamType& aArg) {
|
||||
MOZ_ASSERT_UNREACHABLE("Tag wasn't for an entry in this Variant");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(aArg.tag) +
|
||||
MinSizeVariant<sizeof...(Types), View>::MinSize(aView, aArg.tag,
|
||||
aArg);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QueueParamTraits<mozilla::ipc::Shmem> {
|
||||
using ParamType = mozilla::ipc::Shmem;
|
||||
@@ -1036,12 +747,6 @@ struct QueueParamTraits<mozilla::ipc::Shmem> {
|
||||
rawmem, id);
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(
|
||||
aArg.Id(mozilla::ipc::Shmem::PrivateIPDLCaller()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
@@ -36,7 +36,7 @@ class WebGL2Context final : public WebGLContext {
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
uint64_t readOffset, uint64_t writeOffset,
|
||||
uint64_t size) const;
|
||||
void GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
bool GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
const Range<uint8_t>& dest) const;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -78,23 +78,23 @@ void WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
writeBuffer->ResetLastUpdateFenceId();
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
bool WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
const Range<uint8_t>& dest) const {
|
||||
const FuncScope funcScope(*this, "getBufferSubData");
|
||||
if (IsContextLost()) return;
|
||||
if (IsContextLost()) return false;
|
||||
|
||||
const auto& buffer = ValidateBufferSelection(target);
|
||||
if (!buffer) return;
|
||||
if (!buffer) return false;
|
||||
|
||||
const auto byteLen = dest.length();
|
||||
if (!buffer->ValidateRange(srcByteOffset, byteLen)) return;
|
||||
if (!buffer->ValidateRange(srcByteOffset, byteLen)) return false;
|
||||
|
||||
////
|
||||
|
||||
if (!CheckedInt<GLintptr>(srcByteOffset).isValid() ||
|
||||
!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
|
||||
ErrorOutOfMemory("offset or size too large for platform.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const GLsizeiptr glByteLen(byteLen);
|
||||
|
||||
@@ -144,6 +144,7 @@ void WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -16,6 +16,45 @@ WebGLChild::WebGLChild(ClientWebGLContext& context)
|
||||
|
||||
WebGLChild::~WebGLChild() { (void)Send__delete__(this); }
|
||||
|
||||
// -
|
||||
|
||||
Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(const size_t size) {
|
||||
if (!mPendingCmds) {
|
||||
mPendingCmds.reset(new webgl::ShmemCmdBuffer);
|
||||
size_t capacity = 1000 * 1000;
|
||||
if (capacity < size) {
|
||||
capacity = size;
|
||||
}
|
||||
|
||||
if (!PWebGLChild::AllocShmem(
|
||||
capacity, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
|
||||
&(mPendingCmds->mShmem))) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
auto remaining = mPendingCmds->Remaining();
|
||||
if (size > remaining.length()) {
|
||||
FlushPendingCmds();
|
||||
return AllocPendingCmdBytes(size);
|
||||
}
|
||||
mPendingCmds->mPos += size;
|
||||
return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
|
||||
}
|
||||
|
||||
void WebGLChild::FlushPendingCmds() {
|
||||
if (!mPendingCmds) return;
|
||||
|
||||
const auto cmdBytes = mPendingCmds->mPos;
|
||||
SendDispatchCommands(std::move(mPendingCmds->mShmem), cmdBytes);
|
||||
mPendingCmds = nullptr;
|
||||
|
||||
mFlushedCmdInfo.flushes += 1;
|
||||
mFlushedCmdInfo.flushedCmdBytes += cmdBytes;
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
mozilla::ipc::IPCResult WebGLChild::RecvJsWarning(
|
||||
const std::string& text) const {
|
||||
mContext.JsWarning(text);
|
||||
|
||||
@@ -27,11 +27,17 @@ class ClientWebGLContext;
|
||||
|
||||
namespace dom {
|
||||
|
||||
struct FlushedCmdInfo final {
|
||||
size_t flushes = 0;
|
||||
size_t flushedCmdBytes = 0;
|
||||
};
|
||||
|
||||
class WebGLChild final : public PWebGLChild,
|
||||
public SyncProducerActor<WebGLChild>,
|
||||
public AsyncConsumerActor<WebGLChild>,
|
||||
public SupportsWeakPtr<WebGLChild>,
|
||||
public mozilla::webgl::PcqActor {
|
||||
std::unique_ptr<webgl::ShmemCmdBuffer> mPendingCmds;
|
||||
FlushedCmdInfo mFlushedCmdInfo;
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLChild)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGLChild, override);
|
||||
@@ -44,6 +50,9 @@ class WebGLChild final : public PWebGLChild,
|
||||
// For SyncProducerActor:
|
||||
static IpdlQueueProtocol GetIpdlQueueProtocol(size_t aCmd, ...);
|
||||
|
||||
Maybe<Range<uint8_t>> AllocPendingCmdBytes(size_t);
|
||||
void FlushPendingCmds();
|
||||
|
||||
private:
|
||||
friend PWebGLChild;
|
||||
virtual ~WebGLChild();
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#ifndef WEBGLCOMMANDQUEUE_H_
|
||||
#define WEBGLCOMMANDQUEUE_H_
|
||||
|
||||
#include <type_traits>
|
||||
#include "mozilla/FunctionTypeTraits.h"
|
||||
#include "mozilla/dom/ProducerConsumerQueue.h"
|
||||
#include "mozilla/ipc/IPDLParamTraits.h"
|
||||
#include <type_traits>
|
||||
#include "QueueParamTraits.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
// Get around a bug in Clang related to __thiscall method pointers
|
||||
#if defined(_M_IX86)
|
||||
@@ -20,8 +22,135 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using webgl::QueueStatus;
|
||||
|
||||
namespace webgl {
|
||||
|
||||
struct ShmemCmdBuffer final {
|
||||
mozilla::ipc::Shmem mShmem = {};
|
||||
size_t mPos = 0;
|
||||
|
||||
Range<uint8_t> Remaining() const {
|
||||
const auto range = ByteRange(mShmem);
|
||||
return {range.begin() + mPos, range.end()};
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
|
||||
RangedPtr<const uint8_t> mSrcItr;
|
||||
const RangedPtr<const uint8_t> mSrcEnd;
|
||||
|
||||
public:
|
||||
auto Remaining() const { return *MaybeAs<size_t>(mSrcEnd - mSrcItr); }
|
||||
|
||||
explicit RangeConsumerView(const Range<const uint8_t> range)
|
||||
: ConsumerView(this, nullptr, 0),
|
||||
mSrcItr(range.begin()),
|
||||
mSrcEnd(range.end()) {
|
||||
(void)Remaining(); // assert size non-negative
|
||||
}
|
||||
|
||||
QueueStatus ReadObject(size_t*, size_t, void* const src, const size_t size) {
|
||||
const auto remaining = Remaining();
|
||||
if (size > remaining) return QueueStatus::kTooSmall;
|
||||
|
||||
memcpy(src, mSrcItr.get(), size);
|
||||
mSrcItr += size;
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
namespace details {
|
||||
|
||||
class SizeOnlyProducerView final
|
||||
: public webgl::ProducerView<SizeOnlyProducerView> {
|
||||
size_t mRequiredSize = 0;
|
||||
|
||||
public:
|
||||
SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {}
|
||||
|
||||
QueueStatus WriteObject(size_t, size_t*, const void*, const size_t size) {
|
||||
mRequiredSize += size;
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
const auto& RequiredSize() const { return mRequiredSize; }
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
|
||||
RangedPtr<uint8_t> mDestItr;
|
||||
const RangedPtr<uint8_t> mDestEnd;
|
||||
|
||||
public:
|
||||
auto Remaining() const { return *MaybeAs<size_t>(mDestEnd - mDestItr); }
|
||||
|
||||
explicit RangeProducerView(const Range<uint8_t> range)
|
||||
: ProducerView(this, 0, nullptr),
|
||||
mDestItr(range.begin()),
|
||||
mDestEnd(range.end()) {
|
||||
(void)Remaining(); // assert size non-negative
|
||||
}
|
||||
|
||||
QueueStatus WriteObject(size_t, size_t*, const void* const src,
|
||||
const size_t size) {
|
||||
MOZ_ASSERT(size <= Remaining());
|
||||
|
||||
memcpy(mDestItr.get(), src, size);
|
||||
mDestItr += size;
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <typename ProducerViewT>
|
||||
inline void Serialize(ProducerViewT&) {}
|
||||
|
||||
template <typename ProducerViewT, typename Arg, typename... Args>
|
||||
inline void Serialize(ProducerViewT& view, const Arg& arg,
|
||||
const Args&... args) {
|
||||
MOZ_ALWAYS_TRUE(view.WriteParam(arg) == QueueStatus::kSuccess);
|
||||
Serialize(view, args...);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
// -
|
||||
|
||||
template <typename... Args>
|
||||
size_t SerializedSize(const Args&... args) {
|
||||
webgl::details::SizeOnlyProducerView sizeView;
|
||||
webgl::details::Serialize(sizeView, args...);
|
||||
return sizeView.RequiredSize();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Serialize(Range<uint8_t> dest, const Args&... args) {
|
||||
webgl::details::RangeProducerView view(dest);
|
||||
webgl::details::Serialize(view, args...);
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
inline bool Deserialize(RangeConsumerView& view) { return true; }
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
inline bool Deserialize(RangeConsumerView& view, Arg& arg, Args&... args) {
|
||||
if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) return false;
|
||||
return Deserialize(view, args...);
|
||||
}
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
// -
|
||||
|
||||
using mozilla::ipc::IPDLParamTraits;
|
||||
using mozilla::webgl::QueueStatus;
|
||||
|
||||
enum CommandResult { kSuccess, kTimeExpired, kQueueEmpty, kError };
|
||||
|
||||
@@ -528,41 +657,62 @@ class SyncCommandSink : public CommandSink<Command, _Sink> {
|
||||
template <template <size_t> typename Derived>
|
||||
class EmptyMethodDispatcher {
|
||||
public:
|
||||
template <typename SinkType, typename ObjectType>
|
||||
static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink,
|
||||
ObjectType& aObj) {
|
||||
template <typename ObjectT>
|
||||
static MOZ_ALWAYS_INLINE bool DispatchCommand(ObjectT&, const size_t,
|
||||
webgl::RangeConsumerView&) {
|
||||
MOZ_CRASH("Illegal ID in DispatchCommand");
|
||||
}
|
||||
static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
|
||||
static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t) {
|
||||
MOZ_CRASH("Illegal ID in SyncType");
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <typename ReturnT, typename ObjectT, typename... Args>
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple(
|
||||
ReturnT (ObjectT::*)(Args... args)) {
|
||||
return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{};
|
||||
}
|
||||
|
||||
template <typename ReturnT, typename ObjectT, typename... Args>
|
||||
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple(
|
||||
ReturnT (ObjectT::*)(Args... args) const) {
|
||||
return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{};
|
||||
}
|
||||
|
||||
// Derived type must be parameterized by the ID.
|
||||
template <template <size_t> typename Derived, size_t id, typename MethodType,
|
||||
template <template <size_t> typename Derived, size_t ID, typename MethodType,
|
||||
MethodType method, CommandSyncType syncType>
|
||||
class MethodDispatcher {
|
||||
using DerivedType = Derived<id>;
|
||||
using NextDispatcher = Derived<id + 1>;
|
||||
static constexpr size_t kId = ID;
|
||||
using DerivedType = Derived<ID>;
|
||||
using NextDispatcher = Derived<ID + 1>;
|
||||
|
||||
public:
|
||||
template <typename SinkType, typename ObjectType>
|
||||
static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink,
|
||||
ObjectType& aObj) {
|
||||
if (aId == id) {
|
||||
return (syncType == CommandSyncType::ASYNC)
|
||||
? aSink.DispatchAsyncMethod(aObj, Method())
|
||||
: aSink.DispatchSyncMethod(aObj, Method());
|
||||
template <typename ObjectT>
|
||||
static MOZ_ALWAYS_INLINE bool DispatchCommand(
|
||||
ObjectT& obj, const size_t id, webgl::RangeConsumerView& view) {
|
||||
if (id == kId) {
|
||||
auto argsTuple = ArgsTuple(method);
|
||||
|
||||
return std::apply(
|
||||
[&](auto&... args) {
|
||||
if (!webgl::Deserialize(view, args...)) return false;
|
||||
(obj.*method)(args...);
|
||||
return true;
|
||||
},
|
||||
argsTuple);
|
||||
}
|
||||
return NextDispatcher::DispatchCommand(aId, aSink, aObj);
|
||||
return Derived<kId + 1>::DispatchCommand(obj, id, view);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
|
||||
return (aId == id) ? syncType : NextDispatcher::SyncType(aId);
|
||||
return (aId == kId) ? syncType : NextDispatcher::SyncType(kId);
|
||||
}
|
||||
|
||||
static constexpr CommandSyncType SyncType() { return syncType; }
|
||||
static constexpr size_t Id() { return id; }
|
||||
static constexpr size_t Id() { return kId; }
|
||||
static constexpr MethodType Method() { return method; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1029,9 +1029,9 @@ Maybe<layers::SurfaceDescriptor> WebGLContext::GetFrontBuffer(
|
||||
return front->ToSurfaceDescriptor();
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> WebGLContext::GetFrontBufferSnapshot() {
|
||||
bool WebGLContext::FrontBufferSnapshotInto(Range<uint8_t> dest) {
|
||||
const auto& front = mSwapChain.FrontBuffer();
|
||||
if (!front) return nullptr;
|
||||
if (!front) return false;
|
||||
|
||||
// -
|
||||
|
||||
@@ -1076,32 +1076,13 @@ RefPtr<gfx::DataSourceSurface> WebGLContext::GetFrontBufferSnapshot() {
|
||||
});
|
||||
|
||||
const auto& size = front->mDesc.size;
|
||||
const auto surfFormat = mOptions.alpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
const auto stride = size.width * 4;
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateDataSourceSurfaceWithStride(size, surfFormat, stride,
|
||||
/*zero=*/true);
|
||||
MOZ_ASSERT(surf);
|
||||
if (NS_WARN_IF(!surf)) return nullptr;
|
||||
|
||||
// -
|
||||
|
||||
{
|
||||
const gfx::DataSourceSurface::ScopedMap map(
|
||||
surf, gfx::DataSourceSurface::READ_WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
MOZ_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(map.GetStride() == stride);
|
||||
|
||||
const size_t stride = size.width * 4;
|
||||
MOZ_ASSERT(dest.length() == stride * size.height);
|
||||
gl->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE, map.GetData());
|
||||
gfxUtils::ConvertBGRAtoRGBA(map.GetData(), stride * size.height);
|
||||
}
|
||||
LOCAL_GL_UNSIGNED_BYTE, dest.begin().get());
|
||||
gfxUtils::ConvertBGRAtoRGBA(dest.begin().get(), stride * size.height);
|
||||
|
||||
return surf;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebGLContext::ClearVRSwapChain() { mWebVRSwapChain.ClearPool(); }
|
||||
@@ -1212,6 +1193,7 @@ void WebGLContext::LoseContext(const webgl::ContextLossReason reason) {
|
||||
printf_stderr("WebGL(%p)::LoseContext(%u)\n", this,
|
||||
static_cast<uint32_t>(reason));
|
||||
mIsContextLost = true;
|
||||
mLruPosition = {};
|
||||
mHost->OnContextLoss(reason);
|
||||
}
|
||||
|
||||
@@ -2079,6 +2061,10 @@ webgl::LinkActiveInfo GetLinkActiveInfo(
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsCString ToCString(const std::string& s) {
|
||||
return nsCString(s.data(), s.size());
|
||||
}
|
||||
|
||||
webgl::CompileResult WebGLContext::GetCompileResult(
|
||||
const WebGLShader& shader) const {
|
||||
webgl::CompileResult ret;
|
||||
@@ -2087,11 +2073,12 @@ webgl::CompileResult WebGLContext::GetCompileResult(
|
||||
const auto& info = shader.CompileResults();
|
||||
if (!info) return;
|
||||
if (!info->mValid) {
|
||||
ret.log = info->mInfoLog;
|
||||
ret.log = info->mInfoLog.c_str();
|
||||
return;
|
||||
}
|
||||
ret.translatedSource = info->mObjectCode;
|
||||
ret.log = shader.CompileLog();
|
||||
// TODO: These could be large and should be made fallible.
|
||||
ret.translatedSource = ToCString(info->mObjectCode);
|
||||
ret.log = ToCString(shader.CompileLog());
|
||||
if (!shader.IsCompiled()) return;
|
||||
ret.success = true;
|
||||
}();
|
||||
@@ -2102,7 +2089,7 @@ webgl::LinkResult WebGLContext::GetLinkResult(const WebGLProgram& prog) const {
|
||||
webgl::LinkResult ret;
|
||||
[&]() {
|
||||
ret.pending = false; // Link status polling not yet implemented.
|
||||
ret.log = prog.LinkLog();
|
||||
ret.log = ToCString(prog.LinkLog());
|
||||
const auto& info = prog.LinkInfo();
|
||||
if (!info) return;
|
||||
ret.success = true;
|
||||
|
||||
@@ -265,6 +265,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
||||
LruPosition& operator=(LruPosition&& rhs) {
|
||||
reset();
|
||||
std::swap(mItr, rhs.mItr);
|
||||
rhs.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -491,10 +492,12 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
||||
public:
|
||||
void Present(WebGLFramebuffer*, layers::TextureType, const bool webvr);
|
||||
RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot();
|
||||
bool FrontBufferSnapshotInto(Range<uint8_t>);
|
||||
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(WebGLFramebuffer*,
|
||||
const bool webvr);
|
||||
|
||||
void ClearVRSwapChain();
|
||||
|
||||
void RunContextLossTimer();
|
||||
void CheckForContextLoss();
|
||||
|
||||
@@ -599,15 +602,16 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
||||
const webgl::FormatUsageInfo* usage) const;
|
||||
|
||||
protected:
|
||||
void ReadPixelsImpl(const webgl::ReadPixelsDesc&, uintptr_t data,
|
||||
uint64_t dataLen);
|
||||
webgl::ReadPixelsResult ReadPixelsImpl(const webgl::ReadPixelsDesc&,
|
||||
uintptr_t dest, uint64_t availBytes);
|
||||
bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat,
|
||||
const webgl::ReadPixelsDesc&, uintptr_t dest,
|
||||
uint64_t dataLen, uint32_t rowStride);
|
||||
|
||||
public:
|
||||
void ReadPixelsPbo(const webgl::ReadPixelsDesc&, uint64_t offset);
|
||||
void ReadPixels(const webgl::ReadPixelsDesc&, const Range<uint8_t>& dest);
|
||||
webgl::ReadPixelsResult ReadPixelsInto(const webgl::ReadPixelsDesc&,
|
||||
const Range<uint8_t>& dest);
|
||||
|
||||
////
|
||||
|
||||
|
||||
@@ -920,17 +920,17 @@ static bool ValidatePackSize(const WebGLContext& webgl,
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebGLContext::ReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
const Range<uint8_t>& dest) {
|
||||
webgl::ReadPixelsResult WebGLContext::ReadPixelsInto(
|
||||
const webgl::ReadPixelsDesc& desc, const Range<uint8_t>& dest) {
|
||||
const FuncScope funcScope(*this, "readPixels");
|
||||
if (IsContextLost()) return;
|
||||
if (IsContextLost()) return {};
|
||||
|
||||
if (mBoundPixelPackBuffer) {
|
||||
ErrorInvalidOperation("PIXEL_PACK_BUFFER must be null.");
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
ReadPixelsImpl(desc, reinterpret_cast<uintptr_t>(dest.begin().get()),
|
||||
return ReadPixelsImpl(desc, reinterpret_cast<uintptr_t>(dest.begin().get()),
|
||||
dest.length());
|
||||
}
|
||||
|
||||
@@ -1077,22 +1077,22 @@ static bool ValidateReadPixelsFormatAndType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
const uintptr_t dest,
|
||||
webgl::ReadPixelsResult WebGLContext::ReadPixelsImpl(
|
||||
const webgl::ReadPixelsDesc& desc, const uintptr_t dest,
|
||||
const uint64_t availBytes) {
|
||||
const webgl::FormatUsageInfo* srcFormat;
|
||||
uint32_t srcWidth;
|
||||
uint32_t srcHeight;
|
||||
if (!BindCurFBForColorRead(&srcFormat, &srcWidth, &srcHeight)) return;
|
||||
if (!BindCurFBForColorRead(&srcFormat, &srcWidth, &srcHeight)) return {};
|
||||
|
||||
//////
|
||||
|
||||
if (!ValidateReadPixelsFormatAndType(srcFormat, desc.pi, gl, this)) return;
|
||||
if (!ValidateReadPixelsFormatAndType(srcFormat, desc.pi, gl, this)) return {};
|
||||
|
||||
uint8_t bytesPerPixel;
|
||||
if (!webgl::GetBytesPerPixel(desc.pi, &bytesPerPixel)) {
|
||||
ErrorInvalidOperation("Unsupported format and type.");
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
//////
|
||||
@@ -1102,7 +1102,7 @@ void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
|
||||
if (!ivec2::From(size)) {
|
||||
ErrorInvalidValue("width and height must be non-negative.");
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& packing = desc.packState;
|
||||
@@ -1110,11 +1110,11 @@ void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
uint32_t bytesNeeded;
|
||||
if (!ValidatePackSize(*this, packing, size, bytesPerPixel, &rowStride,
|
||||
&bytesNeeded))
|
||||
return;
|
||||
return {};
|
||||
|
||||
if (bytesNeeded > availBytes) {
|
||||
ErrorInvalidOperation("buffer too small");
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
////
|
||||
@@ -1125,7 +1125,7 @@ void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
if (!Intersect(srcWidth, srcOffset.x, size.x, &readX, &writeX, &rwWidth) ||
|
||||
!Intersect(srcHeight, srcOffset.y, size.y, &readY, &writeY, &rwHeight)) {
|
||||
ErrorOutOfMemory("Bad subrect selection.");
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
////////////////
|
||||
@@ -1141,14 +1141,17 @@ void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
if (!rwWidth || !rwHeight) {
|
||||
// Disjoint rects, so we're done already.
|
||||
DummyReadFramebufferOperation();
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
const auto rwSize = *uvec2::From(rwWidth, rwHeight);
|
||||
|
||||
const auto res = webgl::ReadPixelsResult{
|
||||
{{writeX, writeY}, {rwSize.x, rwSize.y}}, rowStride};
|
||||
|
||||
if (rwSize == size) {
|
||||
DoReadPixelsAndConvert(srcFormat->format, desc, dest, bytesNeeded,
|
||||
rowStride);
|
||||
return;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Read request contains out-of-bounds pixels. Unfortunately:
|
||||
@@ -1195,6 +1198,8 @@ void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
row += rowStride;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void WebGLContext::RenderbufferStorageMultisample(WebGLRenderbuffer& rb,
|
||||
|
||||
@@ -6,8 +6,55 @@
|
||||
#ifndef WEBGLIPDL_H_
|
||||
#define WEBGLIPDL_H_
|
||||
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<mozilla::webgl::FrontBufferSnapshotIpc> final {
|
||||
using T = mozilla::webgl::FrontBufferSnapshotIpc;
|
||||
|
||||
static void Write(IPC::Message* const msg, IProtocol* actor, T& in) {
|
||||
WriteParam(msg, in.surfSize);
|
||||
WriteIPDLParam(msg, actor, std::move(in.shmem));
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* const msg, PickleIterator* const itr,
|
||||
IProtocol* actor, T* const out) {
|
||||
return ReadParam(msg, itr, &out->surfSize) &&
|
||||
ReadIPDLParam(msg, itr, actor, &out->shmem);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<mozilla::webgl::ReadPixelsResultIpc> final {
|
||||
using T = mozilla::webgl::ReadPixelsResultIpc;
|
||||
|
||||
static void Write(IPC::Message* const msg, IProtocol* actor, T& in) {
|
||||
WriteParam(msg, in.subrect);
|
||||
WriteParam(msg, in.byteStride);
|
||||
WriteIPDLParam(msg, actor, std::move(in.shmem));
|
||||
}
|
||||
|
||||
static bool Read(const IPC::Message* const msg, PickleIterator* const itr,
|
||||
IProtocol* actor, T* const out) {
|
||||
return ReadParam(msg, itr, &out->subrect) &&
|
||||
ReadParam(msg, itr, &out->byteStride) &&
|
||||
ReadIPDLParam(msg, itr, actor, &out->shmem);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
namespace webgl {
|
||||
using Int32Vector = std::vector<int32_t>;
|
||||
} // namespace webgl
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
@@ -17,6 +64,13 @@ struct ParamTraits<mozilla::webgl::ContextLossReason>
|
||||
mozilla::webgl::ContextLossReason::None,
|
||||
mozilla::webgl::ContextLossReason::Guilty> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::AttribBaseType>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
mozilla::webgl::AttribBaseType,
|
||||
mozilla::webgl::AttribBaseType::Boolean,
|
||||
mozilla::webgl::AttribBaseType::Uint> {};
|
||||
|
||||
// -
|
||||
|
||||
template <typename T>
|
||||
@@ -104,6 +158,333 @@ template <>
|
||||
struct ParamTraits<mozilla::webgl::Limits> final
|
||||
: public PlainOldDataSerializer<mozilla::webgl::Limits> {};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ReadPixelsDesc> final {
|
||||
using T = mozilla::webgl::ReadPixelsDesc;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.srcOffset);
|
||||
WriteParam(msg, in.size);
|
||||
WriteParam(msg, in.pi);
|
||||
WriteParam(msg, in.packState);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->srcOffset) &&
|
||||
ReadParam(msg, itr, &out->size) && ReadParam(msg, itr, &out->pi) &&
|
||||
ReadParam(msg, itr, &out->packState);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::PixelPackState> final {
|
||||
using T = mozilla::webgl::PixelPackState;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.alignment);
|
||||
WriteParam(msg, in.rowLength);
|
||||
WriteParam(msg, in.skipRows);
|
||||
WriteParam(msg, in.skipPixels);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->alignment) &&
|
||||
ReadParam(msg, itr, &out->rowLength) &&
|
||||
ReadParam(msg, itr, &out->skipRows) &&
|
||||
ReadParam(msg, itr, &out->skipPixels);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::PackingInfo> final {
|
||||
using T = mozilla::webgl::PackingInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.format);
|
||||
WriteParam(msg, in.type);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->format) && ReadParam(msg, itr, &out->type);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::CompileResult> final {
|
||||
using T = mozilla::webgl::CompileResult;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.pending);
|
||||
WriteParam(msg, in.log);
|
||||
WriteParam(msg, in.translatedSource);
|
||||
WriteParam(msg, in.success);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->pending) &&
|
||||
ReadParam(msg, itr, &out->log) &&
|
||||
ReadParam(msg, itr, &out->translatedSource) &&
|
||||
ReadParam(msg, itr, &out->success);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::LinkResult> final {
|
||||
using T = mozilla::webgl::LinkResult;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.pending);
|
||||
WriteParam(msg, in.log);
|
||||
WriteParam(msg, in.success);
|
||||
WriteParam(msg, in.active);
|
||||
WriteParam(msg, in.tfBufferMode);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->pending) &&
|
||||
ReadParam(msg, itr, &out->log) &&
|
||||
ReadParam(msg, itr, &out->success) &&
|
||||
ReadParam(msg, itr, &out->active) &&
|
||||
ReadParam(msg, itr, &out->tfBufferMode);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::LinkActiveInfo> final {
|
||||
using T = mozilla::webgl::LinkActiveInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.activeAttribs);
|
||||
WriteParam(msg, in.activeUniforms);
|
||||
WriteParam(msg, in.activeUniformBlocks);
|
||||
WriteParam(msg, in.activeTfVaryings);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->activeAttribs) &&
|
||||
ReadParam(msg, itr, &out->activeUniforms) &&
|
||||
ReadParam(msg, itr, &out->activeUniformBlocks) &&
|
||||
ReadParam(msg, itr, &out->activeTfVaryings);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ActiveInfo> final {
|
||||
using T = mozilla::webgl::ActiveInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.elemType);
|
||||
WriteParam(msg, in.elemCount);
|
||||
WriteParam(msg, in.name);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->elemType) &&
|
||||
ReadParam(msg, itr, &out->elemCount) &&
|
||||
ReadParam(msg, itr, &out->name);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ActiveAttribInfo> final {
|
||||
using T = mozilla::webgl::ActiveAttribInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, static_cast<const mozilla::webgl::ActiveInfo&>(in));
|
||||
WriteParam(msg, in.location);
|
||||
WriteParam(msg, in.baseType);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, static_cast<mozilla::webgl::ActiveInfo*>(out)) &&
|
||||
ReadParam(msg, itr, &out->location) &&
|
||||
ReadParam(msg, itr, &out->baseType);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ActiveUniformInfo> final {
|
||||
using T = mozilla::webgl::ActiveUniformInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, static_cast<const mozilla::webgl::ActiveInfo&>(in));
|
||||
WriteParam(msg, in.locByIndex);
|
||||
WriteParam(msg, in.block_index);
|
||||
WriteParam(msg, in.block_offset);
|
||||
WriteParam(msg, in.block_arrayStride);
|
||||
WriteParam(msg, in.block_matrixStride);
|
||||
WriteParam(msg, in.block_isRowMajor);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, static_cast<mozilla::webgl::ActiveInfo*>(out)) &&
|
||||
ReadParam(msg, itr, &out->locByIndex) &&
|
||||
ReadParam(msg, itr, &out->block_index) &&
|
||||
ReadParam(msg, itr, &out->block_offset) &&
|
||||
ReadParam(msg, itr, &out->block_arrayStride) &&
|
||||
ReadParam(msg, itr, &out->block_matrixStride) &&
|
||||
ReadParam(msg, itr, &out->block_isRowMajor);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ActiveUniformBlockInfo> final {
|
||||
using T = mozilla::webgl::ActiveUniformBlockInfo;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.name);
|
||||
WriteParam(msg, in.dataSize);
|
||||
WriteParam(msg, in.activeUniformIndices);
|
||||
WriteParam(msg, in.referencedByVertexShader);
|
||||
WriteParam(msg, in.referencedByFragmentShader);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->name) &&
|
||||
ReadParam(msg, itr, &out->dataSize) &&
|
||||
ReadParam(msg, itr, &out->activeUniformIndices) &&
|
||||
ReadParam(msg, itr, &out->referencedByVertexShader) &&
|
||||
ReadParam(msg, itr, &out->referencedByFragmentShader);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::ShaderPrecisionFormat> final {
|
||||
using T = mozilla::webgl::ShaderPrecisionFormat;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.rangeMin);
|
||||
WriteParam(msg, in.rangeMax);
|
||||
WriteParam(msg, in.precision);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->rangeMin) &&
|
||||
ReadParam(msg, itr, &out->rangeMax) &&
|
||||
ReadParam(msg, itr, &out->precision);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <typename U, size_t N>
|
||||
struct ParamTraits<U[N]> final {
|
||||
using T = U[N];
|
||||
static constexpr size_t kByteSize = sizeof(U) * N;
|
||||
|
||||
static_assert(std::is_trivial<U>::value);
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
msg->WriteBytes(in, kByteSize);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
if (!msg->HasBytesAvailable(itr, kByteSize)) {
|
||||
return false;
|
||||
}
|
||||
return msg->ReadBytesInto(itr, *out, kByteSize);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgl::GetUniformData> final {
|
||||
using T = mozilla::webgl::GetUniformData;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
ParamTraits<decltype(in.data)>::Write(msg, in.data);
|
||||
WriteParam(msg, in.type);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ParamTraits<decltype(out->data)>::Read(msg, itr, &out->data) &&
|
||||
ReadParam(msg, itr, &out->type);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <typename U>
|
||||
struct ParamTraits<mozilla::avec2<U>> final {
|
||||
using T = mozilla::avec2<U>;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.x);
|
||||
WriteParam(msg, in.y);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->x) && ReadParam(msg, itr, &out->y);
|
||||
}
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
template <typename U>
|
||||
struct ParamTraits<mozilla::avec3<U>> final {
|
||||
using T = mozilla::avec3<U>;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.x);
|
||||
WriteParam(msg, in.y);
|
||||
WriteParam(msg, in.z);
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
return ReadParam(msg, itr, &out->x) && ReadParam(msg, itr, &out->y) &&
|
||||
ReadParam(msg, itr, &out->z);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
namespace mozilla {
|
||||
namespace webgl {
|
||||
using MaybeDouble = Maybe<double>;
|
||||
using MaybeFrontBufferSnapshotIpc = Maybe<FrontBufferSnapshotIpc>;
|
||||
using MaybeSurfaceDescriptor = Maybe<layers::SurfaceDescriptor>;
|
||||
using MaybeReadPixelsResultIpc = Maybe<ReadPixelsResultIpc>;
|
||||
using MaybeShaderPrecisionFormat = Maybe<ShaderPrecisionFormat>;
|
||||
using MaybeString = Maybe<std::string>;
|
||||
} // namespace webgl
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,11 +19,18 @@ template <size_t id = 0>
|
||||
class WebGLMethodDispatcher
|
||||
: public EmptyMethodDispatcher<WebGLMethodDispatcher> {};
|
||||
|
||||
template <typename MethodT, MethodT Method>
|
||||
size_t IdByMethod() = delete;
|
||||
|
||||
#define DEFINE_METHOD_DISPATCHER(_ID, _METHOD, _SYNC) \
|
||||
template <> \
|
||||
class WebGLMethodDispatcher<_ID> \
|
||||
: public MethodDispatcher<WebGLMethodDispatcher, _ID, \
|
||||
decltype(&_METHOD), &_METHOD, _SYNC> {};
|
||||
decltype(&_METHOD), &_METHOD, _SYNC> {}; \
|
||||
template <> \
|
||||
inline size_t IdByMethod<decltype(&_METHOD), &_METHOD>() { \
|
||||
return _ID; \
|
||||
}
|
||||
|
||||
// Defines each method the WebGLMethodDispatcher handles. The COUNTER value
|
||||
// is used as a cross-process ID for each of the methods.
|
||||
@@ -31,12 +38,12 @@ class WebGLMethodDispatcher
|
||||
DEFINE_METHOD_DISPATCHER(__COUNTER__, _METHOD, _SYNC)
|
||||
#define DEFINE_ASYNC(_METHOD) \
|
||||
DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::ASYNC)
|
||||
#define DEFINE_SYNC(_METHOD) \
|
||||
DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::SYNC)
|
||||
//#define DEFINE_SYNC(_METHOD) \
|
||||
// DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::SYNC)
|
||||
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateBuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateFramebuffer)
|
||||
DEFINE_SYNC(HostWebGLContext::CreateOpaqueFramebuffer)
|
||||
// DEFINE_SYNC(HostWebGLContext::CreateOpaqueFramebuffer)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateProgram)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::CreateRenderbuffer)
|
||||
@@ -62,26 +69,26 @@ 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_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_SYNC(HostWebGLContext::DrawingBufferSize)
|
||||
// DEFINE_SYNC(HostWebGLContext::OnMemoryPressure)
|
||||
DEFINE_ASYNC(HostWebGLContext::DidRefresh)
|
||||
DEFINE_SYNC(HostWebGLContext::GetParameter)
|
||||
DEFINE_SYNC(HostWebGLContext::GetString)
|
||||
// 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_SYNC(HostWebGLContext::CheckFramebufferStatus)
|
||||
DEFINE_ASYNC(HostWebGLContext::Clear)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearColor)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearDepth)
|
||||
@@ -94,19 +101,19 @@ DEFINE_ASYNC(HostWebGLContext::DepthMask)
|
||||
DEFINE_ASYNC(HostWebGLContext::DepthRange)
|
||||
DEFINE_ASYNC(HostWebGLContext::DetachShader)
|
||||
DEFINE_ASYNC(HostWebGLContext::Flush)
|
||||
DEFINE_SYNC(HostWebGLContext::Finish)
|
||||
// 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_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)
|
||||
DEFINE_SYNC(HostWebGLContext::PixelStorei)
|
||||
DEFINE_ASYNC(HostWebGLContext::PixelStorei)
|
||||
DEFINE_ASYNC(HostWebGLContext::PolygonOffset)
|
||||
DEFINE_ASYNC(HostWebGLContext::Present)
|
||||
DEFINE_ASYNC(HostWebGLContext::SampleCoverage)
|
||||
@@ -135,18 +142,18 @@ DEFINE_ASYNC(HostWebGLContext::CopyTexImage)
|
||||
DEFINE_ASYNC(HostWebGLContext::TexStorage)
|
||||
// DEFINE_ASYNC(HostWebGLContext::TexImage)
|
||||
DEFINE_ASYNC(HostWebGLContext::CompressedTexImage)
|
||||
DEFINE_SYNC(HostWebGLContext::GetTexParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetTexParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::TexParameter_base)
|
||||
DEFINE_ASYNC(HostWebGLContext::UseProgram)
|
||||
DEFINE_SYNC(HostWebGLContext::ValidateProgram)
|
||||
// DEFINE_SYNC(HostWebGLContext::ValidateProgram)
|
||||
DEFINE_ASYNC(HostWebGLContext::UniformData)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttrib4T)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttribDivisor)
|
||||
DEFINE_SYNC(HostWebGLContext::GetIndexedParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetIndexedParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::UniformBlockBinding)
|
||||
DEFINE_ASYNC(HostWebGLContext::EnableVertexAttribArray)
|
||||
DEFINE_ASYNC(HostWebGLContext::DisableVertexAttribArray)
|
||||
DEFINE_SYNC(HostWebGLContext::GetVertexAttrib)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetVertexAttrib)
|
||||
DEFINE_ASYNC(HostWebGLContext::VertexAttribPointer)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearBufferTv)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearBufferfi)
|
||||
@@ -155,8 +162,8 @@ 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_SYNC(HostWebGLContext::GetSamplerParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::ClientWaitSync)
|
||||
DEFINE_ASYNC(HostWebGLContext::BindTransformFeedback)
|
||||
DEFINE_ASYNC(HostWebGLContext::BeginTransformFeedback)
|
||||
DEFINE_ASYNC(HostWebGLContext::EndTransformFeedback)
|
||||
@@ -170,13 +177,13 @@ DEFINE_ASYNC(HostWebGLContext::DrawElementsInstanced)
|
||||
DEFINE_ASYNC(HostWebGLContext::BeginQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::EndQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::QueryCounter)
|
||||
DEFINE_SYNC(HostWebGLContext::GetQueryParameter)
|
||||
// DEFINE_SYNC(HostWebGLContext::GetQueryParameter)
|
||||
DEFINE_ASYNC(HostWebGLContext::SetFramebufferIsInOpaqueRAF)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearVRSwapChain)
|
||||
|
||||
#undef DEFINE_METHOD_HELPER
|
||||
#undef DEFINE_ASYNC
|
||||
#undef DEFINE_SYNC
|
||||
//#undef DEFINE_SYNC
|
||||
#undef DEFINE_METHOD_DISPATCHER
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/layers/LayerTransactionParent.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "HostWebGLContext.h"
|
||||
#include "WebGLMethodDispatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -35,84 +36,37 @@ mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
|
||||
return IPC_FAIL(this, "Failed to create HostWebGLContext");
|
||||
}
|
||||
|
||||
if (!BeginCommandQueueDrain()) {
|
||||
return IPC_FAIL(this, "Failed to start WebGL command queue drain");
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
WebGLParent::WebGLParent() : PcqActor(this) {}
|
||||
WebGLParent::~WebGLParent() = default;
|
||||
|
||||
bool WebGLParent::BeginCommandQueueDrain() {
|
||||
if (mRunCommandsRunnable) {
|
||||
// already running
|
||||
return true;
|
||||
// -
|
||||
|
||||
using IPCResult = mozilla::ipc::IPCResult;
|
||||
|
||||
IPCResult WebGLParent::RecvDispatchCommands(Shmem&& shmem,
|
||||
const uint64_t cmdsByteSize) {
|
||||
MOZ_ASSERT(cmdsByteSize);
|
||||
const auto shmemBytes = ByteRange(shmem);
|
||||
const auto byteSize = std::min<uint64_t>(shmemBytes.length(), cmdsByteSize);
|
||||
const auto cmdsBytes =
|
||||
Range<const uint8_t>{shmemBytes.begin(), shmemBytes.begin() + byteSize};
|
||||
auto view = webgl::RangeConsumerView{cmdsBytes};
|
||||
|
||||
while (true) {
|
||||
size_t id = 0;
|
||||
const auto status = view.ReadParam(&id);
|
||||
if (status != QueueStatus::kSuccess) break;
|
||||
|
||||
WebGLMethodDispatcher<0>::DispatchCommand(*mHost, id, view);
|
||||
}
|
||||
|
||||
WeakPtr<WebGLParent> weakThis = this;
|
||||
mRunCommandsRunnable = NS_NewRunnableFunction(
|
||||
"RunWebGLCommands", [weakThis]() { MaybeRunCommandQueue(weakThis); });
|
||||
if (!mRunCommandsRunnable) {
|
||||
MOZ_ASSERT_UNREACHABLE("Failed to create RunWebGLCommands Runnable");
|
||||
return false;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Start the recurring runnable.
|
||||
return RunCommandQueue();
|
||||
}
|
||||
|
||||
/* static */ bool WebGLParent::MaybeRunCommandQueue(
|
||||
const WeakPtr<WebGLParent>& weakWebGLParent) {
|
||||
// We don't have to worry about WebGLParent being deleted from under us
|
||||
// as its not thread-safe so we must be the only thread using it. In fact,
|
||||
// WeakRef cannot atomically promote to a RefPtr so it is not thread safe
|
||||
// either.
|
||||
if (weakWebGLParent) {
|
||||
// This will re-issue the task if the queue is still running.
|
||||
return weakWebGLParent->RunCommandQueue();
|
||||
}
|
||||
|
||||
// Context was deleted. Do not re-issue the task.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLParent::RunCommandQueue() {
|
||||
if (!mRunCommandsRunnable) {
|
||||
// The actor finished. Do not re-issue the task.
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("todo");
|
||||
/*
|
||||
// Drain the queue for up to kMaxWebGLCommandTimeSliceMs, then
|
||||
// repeat no sooner than kDrainDelayMs later.
|
||||
// TODO: Tune these.
|
||||
static const uint32_t kMaxWebGLCommandTimeSliceMs = 1;
|
||||
static const uint32_t kDrainDelayMs = 0;
|
||||
|
||||
TimeDuration timeSlice =
|
||||
TimeDuration::FromMilliseconds(kMaxWebGLCommandTimeSliceMs);
|
||||
CommandResult result = mHost->RunCommandsForDuration(timeSlice);
|
||||
bool success = (result == CommandResult::Success) ||
|
||||
(result == CommandResult::QueueEmpty);
|
||||
if (!success) {
|
||||
// Tell client that this WebGLParent needs to be shut down
|
||||
WEBGL_BRIDGE_LOGE("WebGLParent failed while running commands");
|
||||
(void)SendOnContextLoss(webgl::ContextLossReason::None);
|
||||
mRunCommandsRunnable = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Re-issue the task
|
||||
MOZ_ASSERT(mRunCommandsRunnable);
|
||||
MOZ_ASSERT(GetCurrentSerialEventTarget());
|
||||
GetCurrentSerialEventTarget()->DelayedDispatch(do_AddRef(mRunCommandsRunnable),
|
||||
kDrainDelayMs);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
// -
|
||||
|
||||
mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
|
||||
mHost = nullptr;
|
||||
@@ -121,18 +75,224 @@ mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
|
||||
|
||||
void WebGLParent::ActorDestroy(ActorDestroyReason aWhy) { mHost = nullptr; }
|
||||
|
||||
mozilla::ipc::IPCResult WebGLParent::RecvUpdateCompositableHandle(
|
||||
layers::PLayerTransactionParent* aLayerTransaction,
|
||||
const CompositableHandle& aHandle) {
|
||||
auto layerTrans =
|
||||
static_cast<layers::LayerTransactionParent*>(aLayerTransaction);
|
||||
RefPtr<layers::CompositableHost> compositableHost(
|
||||
layerTrans->FindCompositable(aHandle));
|
||||
if (!compositableHost) {
|
||||
return IPC_FAIL(this, "Failed to find CompositableHost for WebGL instance");
|
||||
// -
|
||||
|
||||
IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
|
||||
webgl::FrontBufferSnapshotIpc* const ret) {
|
||||
*ret = {};
|
||||
|
||||
const auto surfSize = mHost->GetFrontBufferSize();
|
||||
const auto byteSize = 4 * surfSize.x * surfSize.y;
|
||||
|
||||
Shmem shmem;
|
||||
if (!PWebGLParent::AllocShmem(
|
||||
byteSize, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
|
||||
&shmem)) {
|
||||
return IPC_FAIL(this, "Failed to allocate shmem for result");
|
||||
}
|
||||
|
||||
mHost->SetCompositableHost(compositableHost);
|
||||
auto shmemBytes = ByteRange(shmem);
|
||||
if (!mHost->FrontBufferSnapshotInto(shmemBytes)) return IPC_OK();
|
||||
*ret = {surfSize, Some(std::move(shmem))};
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
|
||||
const uint64_t srcByteOffset,
|
||||
const uint64_t byteSize,
|
||||
Shmem* const ret) {
|
||||
Shmem shmem;
|
||||
if (!PWebGLParent::AllocShmem(
|
||||
byteSize, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
|
||||
&shmem)) {
|
||||
MOZ_ASSERT(false);
|
||||
return IPC_FAIL(this, "Failed to allocate shmem for result");
|
||||
}
|
||||
|
||||
const auto range = ByteRange(shmem);
|
||||
memset(range.begin().get(), 0,
|
||||
range.length()); // TODO: This is usually overkill.
|
||||
|
||||
if (mHost->GetBufferSubData(target, srcByteOffset, range)) {
|
||||
*ret = std::move(shmem);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
const uint64_t byteCount,
|
||||
webgl::ReadPixelsResultIpc* const ret) {
|
||||
*ret = {};
|
||||
|
||||
Shmem shmem;
|
||||
if (!PWebGLParent::AllocShmem(
|
||||
byteCount, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
|
||||
&shmem)) {
|
||||
MOZ_ASSERT(false);
|
||||
return IPC_FAIL(this, "Failed to allocate shmem for result");
|
||||
}
|
||||
|
||||
auto range = ByteRange(shmem);
|
||||
memset(range.begin().get(), 0,
|
||||
range.length()); // TODO: This is usually overkill.
|
||||
|
||||
const auto res = mHost->ReadPixelsInto(desc, range);
|
||||
*ret = {res, std::move(shmem)};
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
IPCResult WebGLParent::RecvCheckFramebufferStatus(GLenum target,
|
||||
GLenum* const ret) {
|
||||
*ret = mHost->CheckFramebufferStatus(target);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvClientWaitSync(ObjectId id, GLbitfield flags,
|
||||
GLuint64 timeout, GLenum* const ret) {
|
||||
*ret = mHost->ClientWaitSync(id, flags, timeout);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvCreateOpaqueFramebuffer(
|
||||
const ObjectId id, const OpaqueFramebufferOptions& options,
|
||||
bool* const ret) {
|
||||
*ret = mHost->CreateOpaqueFramebuffer(id, options);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvDrawingBufferSize(uvec2* const ret) {
|
||||
*ret = mHost->DrawingBufferSize();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvFinish() {
|
||||
mHost->Finish();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetBufferParameter(GLenum target, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetBufferParameter(target, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetCompileResult(ObjectId id,
|
||||
webgl::CompileResult* const ret) {
|
||||
*ret = mHost->GetCompileResult(id);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetError(GLenum* const ret) {
|
||||
*ret = mHost->GetError();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetFragDataLocation(ObjectId id,
|
||||
const std::string& name,
|
||||
GLint* const ret) {
|
||||
*ret = mHost->GetFragDataLocation(id, name);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetFramebufferAttachmentParameter(
|
||||
ObjectId id, GLenum attachment, GLenum pname, Maybe<double>* const ret) {
|
||||
*ret = mHost->GetFramebufferAttachmentParameter(id, attachment, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetFrontBuffer(
|
||||
ObjectId fb, const bool vr, Maybe<layers::SurfaceDescriptor>* const ret) {
|
||||
*ret = mHost->GetFrontBuffer(fb, vr);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetIndexedParameter(GLenum target, GLuint index,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetIndexedParameter(target, index);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetInternalformatParameter(
|
||||
const GLenum target, const GLuint format, const GLuint pname,
|
||||
Maybe<std::vector<int32_t>>* const ret) {
|
||||
*ret = mHost->GetInternalformatParameter(target, format, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetLinkResult(ObjectId id,
|
||||
webgl::LinkResult* const ret) {
|
||||
*ret = mHost->GetLinkResult(id);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetNumber(GLenum pname, Maybe<double>* const ret) {
|
||||
*ret = mHost->GetNumber(pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetQueryParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetQueryParameter(id, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetRenderbufferParameter(id, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetSamplerParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetSamplerParameter(id, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetShaderPrecisionFormat(
|
||||
GLenum shaderType, GLenum precisionType,
|
||||
Maybe<webgl::ShaderPrecisionFormat>* const ret) {
|
||||
*ret = mHost->GetShaderPrecisionFormat(shaderType, precisionType);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetString(GLenum pname,
|
||||
Maybe<std::string>* const ret) {
|
||||
*ret = mHost->GetString(pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetTexParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetTexParameter(id, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetUniform(ObjectId id, uint32_t loc,
|
||||
webgl::GetUniformData* const ret) {
|
||||
*ret = mHost->GetUniform(id, loc);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname,
|
||||
Maybe<double>* const ret) {
|
||||
*ret = mHost->GetVertexAttrib(index, pname);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvIsEnabled(GLenum cap, bool* const ret) {
|
||||
*ret = mHost->IsEnabled(cap);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvOnMemoryPressure() {
|
||||
mHost->OnMemoryPressure();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WebGLParent::RecvValidateProgram(ObjectId id, bool* const ret) {
|
||||
*ret = mHost->ValidateProgram(id);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,12 @@ class HostWebGLContext;
|
||||
|
||||
namespace layers {
|
||||
class SharedSurfaceTextureClient;
|
||||
class SurfaceDescriptor;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class WebGLParent : public PWebGLParent,
|
||||
public AsyncProducerActor<WebGLParent>,
|
||||
public SyncConsumerActor<WebGLParent>,
|
||||
public SupportsWeakPtr<WebGLParent>,
|
||||
public mozilla::webgl::PcqActor {
|
||||
friend PWebGLParent;
|
||||
@@ -37,22 +36,72 @@ class WebGLParent : public PWebGLParent,
|
||||
const webgl::InitContextDesc&, UniquePtr<HostWebGLCommandSinkP>&& aSinkP,
|
||||
UniquePtr<HostWebGLCommandSinkI>&& aSinkI, webgl::InitContextResult* out);
|
||||
|
||||
// Drain the command queue now. Used by synchronous IpdlQueue consumers.
|
||||
bool RunQueue(uint64_t) { return RunCommandQueue(); }
|
||||
|
||||
WebGLParent(); // For IPDL
|
||||
|
||||
using IPCResult = mozilla::ipc::IPCResult;
|
||||
|
||||
IPCResult RecvDispatchCommands(mozilla::ipc::Shmem&&, uint64_t);
|
||||
|
||||
IPCResult RecvGetFrontBufferSnapshot(webgl::FrontBufferSnapshotIpc* ret);
|
||||
IPCResult RecvReadPixels(const webgl::ReadPixelsDesc&, uint64_t byteSize,
|
||||
webgl::ReadPixelsResultIpc* ret);
|
||||
|
||||
// -
|
||||
|
||||
using ObjectId = webgl::ObjectId;
|
||||
|
||||
IPCResult RecvCheckFramebufferStatus(GLenum target, GLenum* ret);
|
||||
IPCResult RecvClientWaitSync(ObjectId id, GLbitfield flags, GLuint64 timeout,
|
||||
GLenum* ret);
|
||||
IPCResult RecvCreateOpaqueFramebuffer(ObjectId id,
|
||||
const OpaqueFramebufferOptions&,
|
||||
bool* ret);
|
||||
IPCResult RecvDrawingBufferSize(uvec2* ret);
|
||||
IPCResult RecvFinish();
|
||||
IPCResult RecvGetBufferParameter(GLenum target, GLenum pname,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
||||
uint64_t byteSize, mozilla::ipc::Shmem* ret);
|
||||
IPCResult RecvGetCompileResult(ObjectId id, webgl::CompileResult* ret);
|
||||
IPCResult RecvGetError(GLenum* ret);
|
||||
IPCResult RecvGetFragDataLocation(ObjectId id, const std::string& name,
|
||||
GLint* ret);
|
||||
IPCResult RecvGetFramebufferAttachmentParameter(ObjectId id,
|
||||
GLenum attachment,
|
||||
GLenum pname,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetFrontBuffer(ObjectId fb, bool vr,
|
||||
Maybe<layers::SurfaceDescriptor>* ret);
|
||||
IPCResult RecvGetIndexedParameter(GLenum target, GLuint index,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetInternalformatParameter(GLenum target, GLuint format,
|
||||
GLuint pname,
|
||||
Maybe<std::vector<int32_t>>* ret);
|
||||
IPCResult RecvGetLinkResult(ObjectId id, webgl::LinkResult* ret);
|
||||
IPCResult RecvGetNumber(GLenum pname, Maybe<double>* ret);
|
||||
IPCResult RecvGetQueryParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetSamplerParameter(ObjectId id, GLenum pname,
|
||||
Maybe<double>* ret);
|
||||
IPCResult RecvGetShaderPrecisionFormat(
|
||||
GLenum shaderType, GLenum precisionType,
|
||||
Maybe<webgl::ShaderPrecisionFormat>* ret);
|
||||
IPCResult RecvGetString(GLenum pname, Maybe<std::string>* ret);
|
||||
IPCResult RecvGetTexParameter(ObjectId id, GLenum pname, Maybe<double>* ret);
|
||||
IPCResult RecvGetUniform(ObjectId id, uint32_t loc,
|
||||
webgl::GetUniformData* ret);
|
||||
IPCResult RecvGetVertexAttrib(GLuint index, GLenum pname, Maybe<double>* ret);
|
||||
IPCResult RecvIsEnabled(GLenum cap, bool* ret);
|
||||
IPCResult RecvOnMemoryPressure();
|
||||
IPCResult RecvValidateProgram(ObjectId id, bool* ret);
|
||||
|
||||
// -
|
||||
|
||||
private:
|
||||
~WebGLParent();
|
||||
|
||||
bool BeginCommandQueueDrain();
|
||||
static bool MaybeRunCommandQueue(const WeakPtr<WebGLParent>& weakWebGLParent);
|
||||
bool RunCommandQueue();
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateCompositableHandle(
|
||||
layers::PLayerTransactionParent* aLayerTransaction,
|
||||
const CompositableHandle& aHandle);
|
||||
|
||||
mozilla::ipc::IPCResult Recv__delete__() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
@@ -70,62 +70,52 @@ struct QueueParamTraits<RawBuffer<T>> {
|
||||
using ParamType = RawBuffer<T>;
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Write(ProducerView<U>& aProducerView,
|
||||
const ParamType& aArg) {
|
||||
aProducerView.WriteParam(aArg.mLength);
|
||||
return (aArg.mLength > 0)
|
||||
? aProducerView.Write(aArg.mData, aArg.mLength * sizeof(T))
|
||||
: aProducerView.GetStatus();
|
||||
}
|
||||
static QueueStatus Write(ProducerView<U>& view, const ParamType& in) {
|
||||
const auto range = in.Data();
|
||||
|
||||
template <typename U, typename ElementType = typename std::remove_cv_t<
|
||||
typename ParamType::ElementType>>
|
||||
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
|
||||
size_t len;
|
||||
QueueStatus status = aConsumerView.ReadParam(&len);
|
||||
if (!status) {
|
||||
const auto elemCount = range.length();
|
||||
auto status = view.WriteParam(elemCount);
|
||||
if (!status) return status;
|
||||
if (!elemCount) return status;
|
||||
|
||||
const bool hasData = bool(range.begin().get());
|
||||
status = view.WriteParam(hasData);
|
||||
if (!status) return status;
|
||||
if (!hasData) return status;
|
||||
|
||||
status = view.Write(range.begin().get(), range.end().get());
|
||||
return status;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
aArg->mLength = 0;
|
||||
aArg->mData = nullptr;
|
||||
template <typename U>
|
||||
static QueueStatus Read(ConsumerView<U>& view, ParamType* const out) {
|
||||
size_t elemCount = 0;
|
||||
auto status = view.ReadParam(&elemCount);
|
||||
if (!status) return status;
|
||||
if (!elemCount) {
|
||||
*out = {};
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
struct RawBufferReadMatcher {
|
||||
QueueStatus operator()(RefPtr<mozilla::ipc::SharedMemoryBasic>& smem) {
|
||||
if (!smem) {
|
||||
return QueueStatus::kFatalError;
|
||||
}
|
||||
mArg->mSmem = smem;
|
||||
mArg->mData = static_cast<ElementType*>(smem->memory());
|
||||
mArg->mLength = mLength;
|
||||
mArg->mOwnsData = false;
|
||||
bool hasData = false;
|
||||
status = view.ReadParam(&hasData);
|
||||
if (!status) return status;
|
||||
if (!hasData) {
|
||||
auto temp = RawBuffer<T>{Range<T>{nullptr, elemCount}};
|
||||
*out = std::move(temp);
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
QueueStatus operator()() {
|
||||
mArg->mSmem = nullptr;
|
||||
ElementType* buf = new ElementType[mLength];
|
||||
mArg->mData = buf;
|
||||
mArg->mLength = mLength;
|
||||
mArg->mOwnsData = true;
|
||||
return mConsumerView.Read(buf, mLength * sizeof(T));
|
||||
}
|
||||
|
||||
ConsumerView<U>& mConsumerView;
|
||||
ParamType* mArg;
|
||||
size_t mLength;
|
||||
};
|
||||
auto buffer = UniqueBuffer::Alloc(elemCount * sizeof(T));
|
||||
if (!buffer) return QueueStatus::kOOMError;
|
||||
|
||||
return aConsumerView.ReadVariant(
|
||||
len * sizeof(T), RawBufferReadMatcher{aConsumerView, aArg, len});
|
||||
}
|
||||
using MutT = std::remove_cv_t<T>;
|
||||
const auto begin = reinterpret_cast<MutT*>(buffer.get());
|
||||
const auto range = Range<MutT>{begin, elemCount};
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const ParamType& aArg) {
|
||||
return aView.MinSizeParam(aArg.mLength) +
|
||||
aView.MinSizeBytes(aArg.mLength * sizeof(T));
|
||||
auto temp = RawBuffer<T>{range, std::move(buffer)};
|
||||
*out = std::move(temp);
|
||||
return view.Read(range.begin().get(), range.end().get());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -168,19 +158,6 @@ struct QueueParamTraits<Result<V, E>> {
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const T& aArg) {
|
||||
auto size = aView.template MinSizeParam<bool>();
|
||||
if (aArg.isOk()) {
|
||||
const auto& val = aArg.unwrap();
|
||||
size += aView.MinSizeParam(val);
|
||||
} else {
|
||||
const auto& val = aArg.unwrapErr();
|
||||
size += aView.MinSizeParam(val);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -191,7 +168,7 @@ struct QueueParamTraits<std::string> {
|
||||
static QueueStatus Write(ProducerView<U>& aProducerView, const T& aArg) {
|
||||
auto status = aProducerView.WriteParam(aArg.size());
|
||||
if (!status) return status;
|
||||
status = aProducerView.Write(aArg.data(), aArg.size());
|
||||
status = aProducerView.Write(aArg.data(), aArg.data() + aArg.size());
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -205,17 +182,10 @@ struct QueueParamTraits<std::string> {
|
||||
const auto dest = static_cast<char*>(temp.get());
|
||||
if (!dest) return QueueStatus::kFatalError;
|
||||
|
||||
status = aConsumerView.Read(dest, size);
|
||||
status = aConsumerView.Read(dest, dest + size);
|
||||
aArg->assign(dest, size);
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const T& aArg) {
|
||||
auto size = aView.MinSizeParam(aArg.size());
|
||||
size += aView.MinSizeBytes(aArg.size());
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
@@ -226,7 +196,7 @@ struct QueueParamTraits<std::vector<U>> {
|
||||
static QueueStatus Write(ProducerView<V>& aProducerView, const T& aArg) {
|
||||
auto status = aProducerView.WriteParam(aArg.size());
|
||||
if (!status) return status;
|
||||
status = aProducerView.Write(aArg.data(), aArg.size());
|
||||
status = aProducerView.Write(aArg.data(), aArg.data() + aArg.size());
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -238,16 +208,9 @@ struct QueueParamTraits<std::vector<U>> {
|
||||
if (!status) return status;
|
||||
|
||||
aArg->resize(size);
|
||||
status = aConsumerView.Read(aArg->data(), size);
|
||||
status = aConsumerView.Read(aArg->data(), aArg->data() + size);
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const T& aArg) {
|
||||
auto size = aView.MinSizeParam(aArg.size());
|
||||
size += aView.MinSizeBytes(aArg.size() * sizeof(U));
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -275,13 +238,6 @@ struct QueueParamTraits<CompileResult> {
|
||||
aConsumerView.ReadParam(&aArg->translatedSource);
|
||||
return aConsumerView.ReadParam(&aArg->success);
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
static size_t MinSize(View& aView, const T& aArg) {
|
||||
return aView.MinSizeParam(aArg.pending) + aView.MinSizeParam(aArg.log) +
|
||||
aView.MinSizeParam(aArg.translatedSource) +
|
||||
aView.MinSizeParam(aArg.success);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
@@ -256,6 +257,10 @@ class UniqueBuffer {
|
||||
void* mBuffer;
|
||||
|
||||
public:
|
||||
static inline UniqueBuffer Alloc(const size_t byteSize) {
|
||||
return {malloc(byteSize)};
|
||||
}
|
||||
|
||||
UniqueBuffer() : mBuffer(nullptr) {}
|
||||
|
||||
MOZ_IMPLICIT UniqueBuffer(void* buffer) : mBuffer(buffer) {}
|
||||
@@ -610,21 +615,18 @@ enum class LossStatus {
|
||||
|
||||
struct CompileResult final {
|
||||
bool pending = true;
|
||||
std::string log;
|
||||
std::string translatedSource;
|
||||
nsCString log;
|
||||
nsCString translatedSource;
|
||||
bool success = false;
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
struct OpaqueFramebufferOptions {
|
||||
struct OpaqueFramebufferOptions final {
|
||||
bool depthStencil = true;
|
||||
bool antialias = true;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
|
||||
OpaqueFramebufferOptions() = default;
|
||||
OpaqueFramebufferOptions(const OpaqueFramebufferOptions&) = default;
|
||||
};
|
||||
|
||||
// -
|
||||
@@ -668,7 +670,7 @@ struct LinkActiveInfo final {
|
||||
|
||||
struct LinkResult final {
|
||||
bool pending = true;
|
||||
std::string log;
|
||||
nsCString log;
|
||||
bool success = false;
|
||||
LinkActiveInfo active;
|
||||
GLenum tfBufferMode = 0;
|
||||
@@ -688,6 +690,20 @@ struct GetUniformData final {
|
||||
GLenum type = 0;
|
||||
};
|
||||
|
||||
struct FrontBufferSnapshotIpc final {
|
||||
uvec2 surfSize = {};
|
||||
Maybe<mozilla::ipc::Shmem> shmem;
|
||||
};
|
||||
|
||||
struct ReadPixelsResult {
|
||||
gfx::IntRect subrect = {};
|
||||
size_t byteStride = 0;
|
||||
};
|
||||
|
||||
struct ReadPixelsResultIpc final : public ReadPixelsResult {
|
||||
mozilla::ipc::Shmem shmem = {};
|
||||
};
|
||||
|
||||
struct VertAttribPointerDesc final {
|
||||
bool intFunc = false;
|
||||
uint8_t channels = 4;
|
||||
@@ -714,23 +730,13 @@ struct ICRData {
|
||||
|
||||
/**
|
||||
* Represents a block of memory that it may or may not own. The
|
||||
* inner data type must be trivially copyable by memcpy. A RawBuffer
|
||||
* may be backed by local memory or shared memory.
|
||||
* inner data type must be trivially copyable by memcpy.
|
||||
*/
|
||||
template <typename T = uint8_t, typename nonCV = std::remove_cv_t<T>,
|
||||
std::enable_if_t<std::is_trivially_assignable<nonCV&, nonCV>::value,
|
||||
int> = 0>
|
||||
template <typename T = uint8_t>
|
||||
class RawBuffer {
|
||||
// The SharedMemoryBasic that owns mData, if any.
|
||||
RefPtr<mozilla::ipc::SharedMemoryBasic> mSmem;
|
||||
// Pointer to the raw memory block
|
||||
T* mData = nullptr;
|
||||
// Length is the number of elements of size T in the array
|
||||
size_t mLength = 0;
|
||||
// true if we should delete[] the mData on destruction
|
||||
bool mOwnsData = false;
|
||||
|
||||
friend struct mozilla::webgl::QueueParamTraits<RawBuffer<T>>;
|
||||
const T* mBegin = nullptr;
|
||||
size_t mLen = 0;
|
||||
UniqueBuffer mOwned;
|
||||
|
||||
public:
|
||||
using ElementType = T;
|
||||
@@ -738,69 +744,30 @@ class RawBuffer {
|
||||
/**
|
||||
* If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
|
||||
*/
|
||||
RawBuffer(size_t len, T* data, bool aTakeData = false)
|
||||
: mData(data), mLength(len), mOwnsData(aTakeData) {}
|
||||
explicit RawBuffer(const Range<const T>& data, UniqueBuffer&& owned = {})
|
||||
: mBegin(data.begin().get()),
|
||||
mLen(data.length()),
|
||||
mOwned(std::move(owned)) {}
|
||||
|
||||
RawBuffer(size_t len, RefPtr<mozilla::ipc::SharedMemoryBasic>& aSmem)
|
||||
: mSmem(aSmem), mData(aSmem->memory()), mLength(len), mOwnsData(false) {
|
||||
MOZ_ASSERT(mData && mLength);
|
||||
}
|
||||
~RawBuffer() = default;
|
||||
|
||||
~RawBuffer() {
|
||||
// If we have a SharedMemoryBasic then it must own mData.
|
||||
MOZ_ASSERT((!mSmem) || (!mOwnsData));
|
||||
if (mOwnsData) {
|
||||
delete[] mData;
|
||||
}
|
||||
if (mSmem) {
|
||||
mSmem->CloseHandle();
|
||||
}
|
||||
}
|
||||
|
||||
auto Length() const { return mLength; }
|
||||
|
||||
T* Data() { return mData; }
|
||||
const T* Data() const { return mData; }
|
||||
|
||||
T& operator[](size_t idx) {
|
||||
MOZ_ASSERT(mData && (idx < mLength));
|
||||
return mData[idx];
|
||||
}
|
||||
const T& operator[](size_t idx) const {
|
||||
MOZ_ASSERT(mData && (idx < mLength));
|
||||
return mData[idx];
|
||||
}
|
||||
Range<const T> Data() const { return {mBegin, mLen}; }
|
||||
|
||||
RawBuffer() = default;
|
||||
|
||||
RawBuffer(const RawBuffer&) = delete;
|
||||
RawBuffer& operator=(const RawBuffer&) = delete;
|
||||
|
||||
RawBuffer(RawBuffer&& o)
|
||||
: mSmem(o.mSmem),
|
||||
mData(o.mData),
|
||||
mLength(o.mLength),
|
||||
mOwnsData(o.mOwnsData) {
|
||||
o.mSmem = nullptr;
|
||||
o.mData = nullptr;
|
||||
o.mLength = 0;
|
||||
o.mOwnsData = false;
|
||||
}
|
||||
|
||||
RawBuffer& operator=(RawBuffer&& o) {
|
||||
mSmem = o.mSmem;
|
||||
mData = o.mData;
|
||||
mLength = o.mLength;
|
||||
mOwnsData = o.mOwnsData;
|
||||
o.mSmem = nullptr;
|
||||
o.mData = nullptr;
|
||||
o.mLength = 0;
|
||||
o.mOwnsData = false;
|
||||
return *this;
|
||||
}
|
||||
RawBuffer(RawBuffer&&) = default;
|
||||
RawBuffer& operator=(RawBuffer&&) = default;
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
struct CopyableRange final : public Range<const uint8_t> {};
|
||||
|
||||
// -
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define FOREACH_ID(X) \
|
||||
@@ -928,6 +895,12 @@ struct TexImageSource {
|
||||
// ---------------------------------------
|
||||
// MakeRange
|
||||
|
||||
inline Range<uint8_t> ByteRange(const mozilla::ipc::Shmem& shmem) {
|
||||
return {shmem.get<uint8_t>(), shmem.Size<uint8_t>()};
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline Range<const T> MakeRange(T (&arr)[N]) {
|
||||
return {arr, N};
|
||||
@@ -940,12 +913,7 @@ inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
|
||||
|
||||
template <typename T>
|
||||
inline Range<const T> MakeRange(const RawBuffer<T>& from) {
|
||||
return {from.Data(), from.Length()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Range<T> MakeRange(RawBuffer<T>& from) {
|
||||
return {from.Data(), from.Length()};
|
||||
return from.Data();
|
||||
}
|
||||
|
||||
// abv = ArrayBufferView
|
||||
@@ -964,7 +932,7 @@ Maybe<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
|
||||
|
||||
template <typename T>
|
||||
RawBuffer<T> RawBufferView(const Range<T>& range) {
|
||||
return {range.length(), range.begin().get()};
|
||||
return RawBuffer<T>{range};
|
||||
}
|
||||
|
||||
// -
|
||||
@@ -989,6 +957,16 @@ inline std::string ToString(const nsACString& text) {
|
||||
return {text.BeginReading(), text.Length()};
|
||||
}
|
||||
|
||||
inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
|
||||
const RangedPtr<const uint8_t>& srcBytes,
|
||||
const size_t byteSize) {
|
||||
// Trigger range asserts
|
||||
(void)(srcBytes + byteSize);
|
||||
(void)(destBytes + byteSize);
|
||||
|
||||
memcpy(destBytes.get(), srcBytes.get(), byteSize);
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -209,11 +209,6 @@ class nsICanvasRenderingContextInternal : public nsISupports,
|
||||
|
||||
virtual void OnMemoryPressure() {}
|
||||
|
||||
virtual bool UpdateCompositableHandle(
|
||||
LayerTransactionChild* aLayerTransaction, CompositableHandle aHandle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void OnBeforePaintTransaction() {}
|
||||
virtual void OnDidPaintTransaction() {}
|
||||
virtual mozilla::layers::PersistentBufferProvider* GetBufferProvider() {
|
||||
|
||||
@@ -51,6 +51,7 @@ void GPUChild::Init() {
|
||||
devicePrefs.advancedLayers() = gfxConfig::GetValue(Feature::ADVANCED_LAYERS);
|
||||
devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
|
||||
devicePrefs.webGPU() = gfxConfig::GetValue(Feature::WEBGPU);
|
||||
devicePrefs.d3d11HwAngle() = gfxConfig::GetValue(Feature::D3D11_HW_ANGLE);
|
||||
|
||||
nsTArray<LayerTreeIdMapping> mappings;
|
||||
LayerTreeOwnerTracker::Get()->Iterate(
|
||||
|
||||
@@ -187,6 +187,7 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
|
||||
gfxConfig::Inherit(Feature::ADVANCED_LAYERS, devicePrefs.advancedLayers());
|
||||
gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
|
||||
gfxConfig::Inherit(Feature::WEBGPU, devicePrefs.webGPU());
|
||||
gfxConfig::Inherit(Feature::D3D11_HW_ANGLE, devicePrefs.d3d11HwAngle());
|
||||
|
||||
{ // Let the crash reporter know if we've got WR enabled or not. For other
|
||||
// processes this happens in gfxPlatform::InitWebRenderConfig.
|
||||
|
||||
@@ -35,6 +35,7 @@ struct DevicePrefs
|
||||
FeatureStatus advancedLayers;
|
||||
FeatureStatus useD2D1;
|
||||
FeatureStatus webGPU;
|
||||
FeatureStatus d3d11HwAngle;
|
||||
};
|
||||
|
||||
struct ContentDeviceData
|
||||
|
||||
@@ -53,36 +53,6 @@ struct ParamTraits<mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry>
|
||||
: public PlainOldDataSerializer<
|
||||
mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry> {};
|
||||
|
||||
template <class KeyType, class DataType>
|
||||
struct ParamTraits<std::unordered_map<KeyType, DataType>> {
|
||||
typedef std::unordered_map<KeyType, DataType> paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.size());
|
||||
for (auto i = aParam.begin(); i != aParam.end(); ++i) {
|
||||
WriteParam(aMsg, i->first);
|
||||
WriteParam(aMsg, i->second);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
paramType* aResult) {
|
||||
size_t count;
|
||||
if (!ReadParam(aMsg, aIter, &count)) {
|
||||
return false;
|
||||
}
|
||||
for (; count > 0; --count) {
|
||||
KeyType k;
|
||||
DataType v;
|
||||
if (!ReadParam(aMsg, aIter, &k) || !ReadParam(aMsg, aIter, &v)) {
|
||||
return false;
|
||||
}
|
||||
aResult->insert(std::make_pair(std::move(k), std::move(v)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "mozilla/EnumTypeTraits.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/net/WebSocketFrame.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "nsDebug.h"
|
||||
@@ -797,6 +799,38 @@ struct ParamTraits<std::vector<E>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct ParamTraits<std::unordered_map<K, V>> final {
|
||||
using T = std::unordered_map<K, V>;
|
||||
|
||||
static void Write(Message* const msg, const T& in) {
|
||||
WriteParam(msg, in.size());
|
||||
for (const auto& pair : in) {
|
||||
WriteParam(msg, pair.first);
|
||||
WriteParam(msg, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* const msg, PickleIterator* const itr,
|
||||
T* const out) {
|
||||
size_t size = 0;
|
||||
if (!ReadParam(msg, itr, &size)) return false;
|
||||
T map;
|
||||
map.reserve(size);
|
||||
for (const auto i : mozilla::IntegerRange(size)) {
|
||||
std::pair<K, V> pair;
|
||||
mozilla::Unused << i;
|
||||
if (!ReadParam(msg, itr, &(pair.first)) ||
|
||||
!ReadParam(msg, itr, &(pair.second))) {
|
||||
return false;
|
||||
}
|
||||
map.insert(std::move(pair));
|
||||
}
|
||||
*out = std::move(map);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<float> {
|
||||
typedef float paramType;
|
||||
|
||||
@@ -1032,12 +1032,70 @@ description = bug 1363126
|
||||
description = Synchronous ping allowing worker thread to confirm actor is created. Necessary to avoid racing with ClientHandle actors on main thread.
|
||||
[PRemoteSandboxBroker::LaunchApp]
|
||||
description = Synchronous launch of a child process that in turn launches and sandboxes another process. Called on a dedicated thread and targets a dedicated process, so this shouldn't block anything.
|
||||
[PWebGL::UpdateCompositableHandle]
|
||||
description = Compositing WebGL is synchronous by spec. Updates to WebGL canvas contents must be updated in lockstep with other DOM updates.
|
||||
# WebGL internals
|
||||
[PWebGL::Initialize]
|
||||
description = Initialization of WebGL contexts is synchronous by spec.
|
||||
[PWebGL::ExchangeIpdlQueueData]
|
||||
description = Synchronous RPC to allow WebGL to run graphics commands in compositor process and return results to be used in JS return values.
|
||||
[PWebGL::GetFrontBuffer]
|
||||
description = Publishing a WebGL frame for compositing is synchronous for now to ensure DOM transaction atomicity.
|
||||
[PWebGL::OnMemoryPressure]
|
||||
description = Synchronous to ensure immediate memory pressure relief.
|
||||
# WebGL spec-synchronous functions
|
||||
[PWebGL::CheckFramebufferStatus]
|
||||
description = Checking framebuffer completenss must ask the driver.
|
||||
[PWebGL::ClientWaitSync]
|
||||
description = Checking fence-sync completenss must ask the driver.
|
||||
[PWebGL::CreateOpaqueFramebuffer]
|
||||
description = Must synchronously check for allocation success.
|
||||
[PWebGL::DrawingBufferSize]
|
||||
description = The returned size might be smaller than requested due to allocation failure.
|
||||
[PWebGL::Finish]
|
||||
description = Synchronous by spec, but not generally used.
|
||||
[PWebGL::GetBufferSubData]
|
||||
description = Retrieving buffer contents is synchronous in the worst case.
|
||||
[PWebGL::GetFrontBufferSnapshot]
|
||||
description = Retrieving canvas contents is synchronous.
|
||||
[PWebGL::ReadPixels]
|
||||
description = Retrieving WebGL framebuffer contents is synchronous.
|
||||
# WebGL reflection functions
|
||||
[PWebGL::GetBufferParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetCompileResult]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetError]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetFragDataLocation]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetFramebufferAttachmentParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetIndexedParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetInternalformatParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetLinkResult]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetNumber]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetQueryParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetRenderbufferParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetSamplerParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetShaderPrecisionFormat]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetString]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetTexParameter]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetUniform]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::GetVertexAttrib]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::IsEnabled]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
[PWebGL::ValidateProgram]
|
||||
description = Reflection is cold code, but synchronous by spec.
|
||||
# -
|
||||
[PSocketProcess::GetTLSClientCert]
|
||||
description = Synchronously get client certificate and key from parent process. Once bug 696976 has been fixed, this can be removed.
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ namespace mozilla {
|
||||
// Range<T> is a tuple containing a pointer and a length.
|
||||
template <typename T>
|
||||
class Range {
|
||||
template <typename U>
|
||||
friend class Range;
|
||||
|
||||
// Reassignment of RangedPtrs is so (subtly) restrictive that we just make
|
||||
// Range immutable.
|
||||
const RangedPtr<T> mStart;
|
||||
const RangedPtr<T> mEnd;
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace mozilla {
|
||||
*/
|
||||
template <typename T>
|
||||
class RangedPtr {
|
||||
template <typename U>
|
||||
friend class RangedPtr;
|
||||
|
||||
T* mPtr;
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -119,7 +122,19 @@ class RangedPtr {
|
||||
checkSanity();
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT RangedPtr(const RangedPtr<T>& aOther)
|
||||
RangedPtr(const RangedPtr& aOther)
|
||||
: mPtr(aOther.mPtr)
|
||||
#ifdef DEBUG
|
||||
,
|
||||
mRangeStart(aOther.mRangeStart),
|
||||
mRangeEnd(aOther.mRangeEnd)
|
||||
#endif
|
||||
{
|
||||
checkSanity();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
MOZ_IMPLICIT RangedPtr(const RangedPtr<U>& aOther)
|
||||
: mPtr(aOther.mPtr)
|
||||
#ifdef DEBUG
|
||||
,
|
||||
|
||||
@@ -20,5 +20,10 @@ void test_RangeToBoolConversionShouldCompile() {
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
void test_RangeT_To_RangeConstT_ShouldCompile() {
|
||||
auto dummy = Range<const int>{Range<int>{}};
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
// We need a proper program so we have someplace to hang the static_asserts.
|
||||
int main() { return 0; }
|
||||
|
||||
@@ -9634,7 +9634,7 @@
|
||||
mirror: always
|
||||
|
||||
- name: webgl.force-layers-readback
|
||||
type: bool
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
@@ -9684,14 +9684,14 @@
|
||||
mirror: always
|
||||
|
||||
- name: webgl.power-preference-override
|
||||
type: int32_t
|
||||
type: RelaxedAtomicInt32
|
||||
value: 0
|
||||
mirror: always
|
||||
|
||||
- name: webgl.prefer-16bpp
|
||||
type: bool
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: never
|
||||
mirror: always
|
||||
|
||||
- name: webgl.allow-immediate-queries
|
||||
type: RelaxedAtomicBool
|
||||
@@ -9719,10 +9719,9 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# value is 0 for PCQ, 1 for Ipdl
|
||||
- name: webgl.prototype.ipc-pcq
|
||||
type: uint32_t
|
||||
value: 0
|
||||
- name: webgl.oop.via-pcq
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,7 @@ Classes = [
|
||||
'type': 'mozilla::widget::ScreenManager',
|
||||
'constructor': 'mozilla::widget::ScreenManager::GetAddRefedSingleton',
|
||||
'headers': ['/widget/ScreenManager.h'],
|
||||
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
|
||||
'processes': ProcessSelector.ALLOW_IN_GPU_AND_MAIN_PROCESS,
|
||||
},
|
||||
{
|
||||
'cid': '{2d96b3df-c051-11d1-a827-0040959a28c9}',
|
||||
|
||||
@@ -54,6 +54,7 @@ struct Module {
|
||||
ALLOW_IN_VR_PROCESS = 0x8,
|
||||
ALLOW_IN_SOCKET_PROCESS = 0x10,
|
||||
ALLOW_IN_RDD_PROCESS = 0x20,
|
||||
ALLOW_IN_GPU_AND_MAIN_PROCESS = ALLOW_IN_GPU_PROCESS | MAIN_PROCESS_ONLY,
|
||||
ALLOW_IN_GPU_AND_VR_PROCESS = ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS,
|
||||
ALLOW_IN_GPU_AND_SOCKET_PROCESS =
|
||||
ALLOW_IN_GPU_PROCESS | ALLOW_IN_SOCKET_PROCESS,
|
||||
|
||||
@@ -63,6 +63,8 @@ class ProcessSelector:
|
||||
ALLOW_IN_VR_PROCESS = 0x8
|
||||
ALLOW_IN_SOCKET_PROCESS = 0x10
|
||||
ALLOW_IN_RDD_PROCESS = 0x20
|
||||
ALLOW_IN_GPU_AND_MAIN_PROCESS = (ALLOW_IN_GPU_PROCESS |
|
||||
MAIN_PROCESS_ONLY)
|
||||
ALLOW_IN_GPU_AND_SOCKET_PROCESS = (ALLOW_IN_GPU_PROCESS |
|
||||
ALLOW_IN_SOCKET_PROCESS)
|
||||
ALLOW_IN_GPU_AND_VR_PROCESS = ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS
|
||||
@@ -90,6 +92,7 @@ PROCESSES = {
|
||||
ProcessSelector.ALLOW_IN_VR_PROCESS: 'ALLOW_IN_VR_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_SOCKET_PROCESS: 'ALLOW_IN_SOCKET_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_RDD_PROCESS: 'ALLOW_IN_RDD_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_GPU_AND_MAIN_PROCESS: 'ALLOW_IN_GPU_AND_MAIN_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_GPU_AND_SOCKET_PROCESS: 'ALLOW_IN_GPU_AND_SOCKET_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_GPU_AND_VR_PROCESS: 'ALLOW_IN_GPU_AND_VR_PROCESS',
|
||||
ProcessSelector.ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS: 'ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS',
|
||||
|
||||
@@ -395,6 +395,8 @@ nsresult nsComponentManagerImpl::Init() {
|
||||
ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
|
||||
gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_RDD_PROCESS)] =
|
||||
ProcessSelectorMatches(ProcessSelector::ALLOW_IN_RDD_PROCESS);
|
||||
gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS)] =
|
||||
ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_MAIN_PROCESS);
|
||||
gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
|
||||
ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
|
||||
gProcessMatchTable[size_t(
|
||||
|
||||
Reference in New Issue
Block a user