Bug 1730282 - Cleanup IPC WebGL code. r=gfx-reviewers,lsalzman

* Replace QueueStatus with bool
* Remove unused structs and code
* Add some MOZ_LIKELY to (de)serialization branches

Differential Revision: https://phabricator.services.mozilla.com/D125295
This commit is contained in:
Jeff Gilbert 2021-09-11 02:11:11 +00:00
Родитель ebdc13da8f
Коммит 67e6fce4dd
14 изменённых файлов: 145 добавлений и 1003 удалений

Просмотреть файл

@ -27,6 +27,7 @@
#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/layers/WebRenderCanvasRenderer.h"
#include "mozilla/Preferences.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_webgl.h"
#include "nsContentUtils.h"

Просмотреть файл

@ -17,7 +17,6 @@
#include "WebGLFramebuffer.h"
#include "WebGLTypes.h"
#include "WebGLCommandQueue.h"
#include "IpdlQueue.h"
#include <unordered_map>
#include <unordered_set>

Просмотреть файл

@ -1,669 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IPDLQUEUE_H_
#define IPDLQUEUE_H_ 1
#include <atomic>
#include <tuple>
#include <vector>
#include <unordered_map>
#include "ipc/IPCMessageUtilsSpecializations.h"
#include "mozilla/dom/QueueParamTraits.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/Assertions.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypeTraits.h"
#include "nsString.h"
#include "mozilla/WeakPtr.h"
namespace IPC {
template <typename T>
struct ParamTraits;
} // namespace IPC
namespace mozilla {
namespace dom {
using mozilla::webgl::QueueStatus;
extern LazyLogModule gIpdlQueueLog;
#define IPDLQUEUE_LOG_(lvl, ...) \
MOZ_LOG(mozilla::dom::gIpdlQueueLog, lvl, (__VA_ARGS__))
#define IPDLQUEUE_LOGD(...) IPDLQUEUE_LOG_(LogLevel::Debug, __VA_ARGS__)
#define IPDLQUEUE_LOGE(...) IPDLQUEUE_LOG_(LogLevel::Error, __VA_ARGS__)
template <typename ActorP, typename ActorC>
class IpdlQueue;
template <typename Derived>
class SyncConsumerActor;
enum IpdlQueueProtocol {
/**
* Sends the message immediately. Does not wait for a response.
*/
kAsync,
/**
* Sends the message immediately or caches it for a later batch
* send. Messages may be sent at any point in the future but
* will always be processed in order. kSync messages always force
* a flush of the cache but other mechanisms (e.g. periodic tasks)
* can do this as well.
*/
kBufferedAsync,
/**
* Sends the message immediately. Waits for any response message,
* which can immediately be read upon completion of the send.
*/
kSync
};
constexpr uint64_t kIllegalQueueId = 0;
inline uint64_t NewIpdlQueueId() {
static std::atomic<uint64_t> sNextIpdlQueueId = 1;
return sNextIpdlQueueId++;
}
struct IpdlQueueBuffer {
uint64_t id = kIllegalQueueId;
nsTArray<uint8_t> data;
IpdlQueueBuffer() = default;
IpdlQueueBuffer(const IpdlQueueBuffer&) = delete;
IpdlQueueBuffer(IpdlQueueBuffer&&) = default;
IpdlQueueBuffer(uint64_t aId, nsTArray<uint8_t>&& aData)
: id(aId), data(std::move(aData)) {}
};
using IpdlQueueBuffers = nsTArray<IpdlQueueBuffer>;
static constexpr uint32_t kAsyncFlushWaitMs = 4; // 4ms
template <typename Derived>
class AsyncProducerActor {
public:
virtual bool TransmitIpdlQueueData(IpdlQueueProtocol aProtocol,
IpdlQueueBuffer&& aData) {
MOZ_ASSERT((aProtocol == IpdlQueueProtocol::kAsync) ||
(aProtocol == IpdlQueueProtocol::kBufferedAsync));
if (mResponseBuffers || (aProtocol == IpdlQueueProtocol::kBufferedAsync)) {
// Always use response buffer if set.
auto& buffers = mResponseBuffers ? *mResponseBuffers : mAsyncBuffers;
// We are in the middle of a sync transaction. Store the data so
// that we can return it with the response.
const uint64_t id = aData.id;
for (auto& elt : buffers) {
if (elt.id == id) {
elt.data.AppendElements(aData.data);
return true;
}
}
buffers.AppendElement(std::move(aData));
if (!mResponseBuffers) {
PostFlushAsyncCache(kAsyncFlushWaitMs);
}
return true;
}
// We are not inside of a transaction. Send normally, but first send any
// cached messages.
FlushAsyncCache();
Derived* self = static_cast<Derived*>(this);
return self->SendTransmitIpdlQueueData(std::move(aData));
}
// This can be called at any time to flush all queued async messages.
bool FlushAsyncCache() {
Derived* self = static_cast<Derived*>(this);
for (auto& elt : mAsyncBuffers) {
if (!elt.data.IsEmpty()) {
if (!self->SendTransmitIpdlQueueData(std::move(elt))) {
return false;
}
}
}
mAsyncBuffers.Clear();
return true;
}
bool PostFlushAsyncCache(uint32_t aEstWaitTimeMs) {
if (mPostedFlushRunnable) {
// Already scheduled a flush for later.
return true;
}
MOZ_ASSERT(GetCurrentSerialEventTarget(),
"No message loop for IpdlQueue flush task");
Derived* self = static_cast<Derived*>(this);
// IpdlProducer/IpdlConsumer guarantees the actor supports WeakPtr.
auto weak = WeakPtr<Derived>(self);
already_AddRefed<mozilla::Runnable> flushRunnable =
NS_NewRunnableFunction("FlushAsyncCache", [weak] {
auto strong = RefPtr<Derived>(weak);
if (!strong) {
return;
}
strong->FlushAsyncCache();
strong->ClearFlushRunnable();
});
NS_ENSURE_SUCCESS(GetCurrentSerialEventTarget()->DelayedDispatch(
std::move(flushRunnable), aEstWaitTimeMs),
false);
mPostedFlushRunnable = true;
return true;
}
void ClearFlushRunnable() { mPostedFlushRunnable = false; }
template <typename... Args>
IpdlQueueProtocol GetIpdlQueueProtocol(const Args&...) {
return IpdlQueueProtocol::kAsync;
}
protected:
friend SyncConsumerActor<Derived>;
void SetResponseBuffers(IpdlQueueBuffers* aResponse) {
MOZ_ASSERT(!mResponseBuffers);
mResponseBuffers = aResponse;
// Response should include any cached async transmissions.
*mResponseBuffers = std::move(mAsyncBuffers);
}
void ClearResponseBuffers() {
MOZ_ASSERT(mResponseBuffers);
mResponseBuffers = nullptr;
}
// Stores response when inside of a kSync transaction.
IpdlQueueBuffers* mResponseBuffers = nullptr;
// For kBufferedAsync transmissions that occur outside of a response to a
// kSync message.
IpdlQueueBuffers mAsyncBuffers;
bool mPostedFlushRunnable = false;
};
template <typename Derived>
class SyncProducerActor : public AsyncProducerActor<Derived> {
public:
bool TransmitIpdlQueueData(IpdlQueueProtocol aProtocol,
IpdlQueueBuffer&& aData) override {
Derived* self = static_cast<Derived*>(this);
if (mResponseBuffers || (aProtocol != IpdlQueueProtocol::kSync)) {
return AsyncProducerActor<Derived>::TransmitIpdlQueueData(
aProtocol, std::forward<IpdlQueueBuffer>(aData));
}
IpdlQueueBuffers responses;
if (!self->SendExchangeIpdlQueueData(std::forward<IpdlQueueBuffer>(aData),
&responses)) {
return false;
}
for (auto& buf : responses) {
if (!self->StoreIpdlQueueData(std::move(buf))) {
return false;
}
}
return true;
}
protected:
using AsyncProducerActor<Derived>::mResponseBuffers;
};
template <typename Derived>
class AsyncConsumerActor {
public:
// Returns the ipdlQueue contents that were Recv'ed in a prior IPDL
// transmission. No new data is received via IPDL during this operation.
nsTArray<uint8_t> TakeIpdlQueueData(uint64_t aId) {
auto it = mIpdlQueueBuffers.find(aId);
if (it != mIpdlQueueBuffers.end()) {
return std::move(it->second.data);
}
return nsTArray<uint8_t>();
}
protected:
friend SyncProducerActor<Derived>;
// Store data received from the producer, to be read by local IpdlConsumers.
bool StoreIpdlQueueData(IpdlQueueBuffer&& aBuffer) {
auto it = mIpdlQueueBuffers.find(aBuffer.id);
if (it == mIpdlQueueBuffers.end()) {
return mIpdlQueueBuffers.insert({aBuffer.id, std::move(aBuffer)}).second;
}
return it->second.data.AppendElements(aBuffer.data, fallible);
}
mozilla::ipc::IPCResult RecvTransmitIpdlQueueData(IpdlQueueBuffer&& aBuffer) {
if (StoreIpdlQueueData(std::forward<IpdlQueueBuffer>(aBuffer))) {
return IPC_OK();
}
return IPC_FAIL_NO_REASON(static_cast<Derived*>(this));
}
std::unordered_map<uint64_t, IpdlQueueBuffer> mIpdlQueueBuffers;
};
template <typename Derived>
class SyncConsumerActor : public AsyncConsumerActor<Derived> {
protected:
using AsyncConsumerActor<Derived>::StoreIpdlQueueData;
mozilla::ipc::IPCResult RecvExchangeIpdlQueueData(
IpdlQueueBuffer&& aBuffer, IpdlQueueBuffers* aResponse) {
uint64_t id = aBuffer.id;
if (!StoreIpdlQueueData(std::forward<IpdlQueueBuffer>(aBuffer))) {
return IPC_FAIL_NO_REASON(static_cast<Derived*>(this));
}
// Mark the actor as in a sync operation, then calls handler.
// During handler, if actor is used as producer (for ALL queues)
// then instead of immediately sending, it writes the data into
// aResponse. When handler is done, we unmark the actor.
// Note that we must buffer for _all_ queues associated with the
// actor as the intended response queue is indistinguishable from
// the rest from our vantage point.
Derived* actor = static_cast<Derived*>(this);
actor->SetResponseBuffers(aResponse);
auto clearResponseBuffer =
MakeScopeExit([&] { actor->ClearResponseBuffers(); });
#if defined(DEBUG)
// Response now includes any cached async transmissions. It is
// illegal to have a response queue also used for other purposes
// so the cache for that queue must be empty.
DebugOnly<bool> responseBufferIsEmpty = [&] {
for (auto& elt : *aResponse) {
if (elt.id == id) {
return elt.data.IsEmpty();
}
}
return true;
}();
MOZ_ASSERT(responseBufferIsEmpty);
#endif
return actor->RunQueue(id) ? IPC_OK() : IPC_FAIL_NO_REASON(actor);
}
};
template <typename _Actor>
class IpdlProducer final : public SupportsWeakPtr {
nsTArray<uint8_t> mSerializedData;
WeakPtr<_Actor> mActor;
uint64_t mId;
public:
using Actor = _Actor;
using SelfType = IpdlProducer<Actor>;
// For IPDL:
IpdlProducer() : mId(kIllegalQueueId) {}
/**
* Insert aArgs into the queue. If the operation does not succeed then
* the queue is unchanged.
*/
template <typename... Args>
QueueStatus TryInsert(Args&&... aArgs) {
MOZ_ASSERT(mId != kIllegalQueueId);
if (!mActor) {
NS_WARNING("TryInsert with actor that was already freed.");
return QueueStatus::kFatalError;
}
// Fill mSerializedData with the data to send. Clear it when done.
MOZ_ASSERT(mSerializedData.IsEmpty());
auto self = *this;
auto clearData = MakeScopeExit([&] { self.mSerializedData.Clear(); });
const IpdlQueueProtocol protocol = mActor->GetIpdlQueueProtocol(aArgs...);
QueueStatus status = SerializeAllArgs(std::forward<Args>(aArgs)...);
if (status != QueueStatus::kSuccess) {
return status;
}
return mActor->TransmitIpdlQueueData(
protocol, IpdlQueueBuffer(mId, std::move(mSerializedData)))
? QueueStatus::kSuccess
: QueueStatus::kFatalError;
}
/**
* Same as TryInsert. IPDL send failures are considered fatal to the
* IpdlQueue.
*/
template <typename... Args>
QueueStatus TryWaitInsert(const Maybe<TimeDuration>&, Args&&... aArgs) {
return TryInsert(std::forward<Args>(aArgs)...);
}
QueueStatus AllocShmem(mozilla::ipc::Shmem* aShmem, size_t aBufferSize,
const void* aBuffer = nullptr) {
if (!mActor) {
return QueueStatus::kFatalError;
}
if (!mActor->AllocShmem(
aBufferSize,
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC, aShmem)) {
return QueueStatus::kOOMError;
}
if (aBuffer) {
memcpy(aShmem->get<uint8_t>(), aBuffer, aBufferSize);
}
return QueueStatus::kSuccess;
}
protected:
template <typename T1, typename T2>
friend class IpdlQueue;
friend struct mozilla::ipc::IPDLParamTraits<SelfType>;
explicit IpdlProducer(uint64_t aId, Actor* aActor = nullptr)
: mActor(aActor), mId(aId) {}
template <typename... Args>
QueueStatus SerializeAllArgs(Args&&... aArgs) {
size_t read = 0;
size_t write = 0;
mozilla::webgl::ProducerView<SelfType> view(this, read, &write);
size_t bytesNeeded = MinSizeofArgs(view, aArgs...);
if (!mSerializedData.SetLength(bytesNeeded, fallible)) {
return QueueStatus::kOOMError;
}
return SerializeArgs(view, aArgs...);
}
QueueStatus SerializeArgs(mozilla::webgl::ProducerView<SelfType>& aView) {
return QueueStatus::kSuccess;
}
template <typename Arg, typename... Args>
QueueStatus SerializeArgs(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg, const Args&... aArgs) {
QueueStatus status = SerializeArg(aView, aArg);
if (!IsSuccess(status)) {
return status;
}
return SerializeArgs(aView, aArgs...);
}
template <typename Arg>
QueueStatus SerializeArg(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg) {
return mozilla::webgl::QueueParamTraits<
typename std::remove_volatile<Arg>::type>::Write(aView, aArg);
}
public:
template <typename Arg>
QueueStatus WriteObject(size_t aRead, size_t* aWrite, const Arg& arg,
size_t aArgSize) {
if (mSerializedData.Length() < (*aWrite) + aArgSize) {
// Previous MinSizeOfArgs estimate was insufficient. Resize the
// buffer to accomodate our real needs.
mSerializedData.SetLength(*aWrite + aArgSize);
}
return mozilla::webgl::Marshaller::WriteObject(
mSerializedData.Elements(), mSerializedData.Length() + 1, aRead, aWrite,
arg, aArgSize);
}
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
protected:
size_t MinSizeofArgs(mozilla::webgl::ProducerView<SelfType>& aView) {
return 0;
}
template <typename Arg, typename... Args>
size_t MinSizeofArgs(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg, const Args&... aArgs) {
return aView.MinSizeParam(aArg) + MinSizeofArgs(aView, aArgs...);
}
};
template <typename _Actor>
class IpdlConsumer final : public SupportsWeakPtr {
public:
using Actor = _Actor;
using SelfType = IpdlConsumer<Actor>;
// For IPDL
IpdlConsumer() : mId(kIllegalQueueId) {}
/**
* Attempts to copy and remove aArgs from the queue. If the operation does
* not succeed then the queue is unchanged. If the operation returns
* kQueueNotReady then the consumer does not yet have enough data to satisfy
* the request. In this case, the IPDL MessageQueue should be given the
* opportunity to run, at which point TryRemove can be attempted again.
*/
template <typename... Args>
QueueStatus TryRemove(Args&... aArgs) {
MOZ_ASSERT(mId != kIllegalQueueId);
if (!mActor) {
NS_WARNING("TryRemove with actor that was already freed.");
return QueueStatus::kFatalError;
}
mBuf.AppendElements(mActor->TakeIpdlQueueData(mId));
return DeserializeAllArgs(aArgs...);
}
/**
* Equivalent to TryRemove. Duration is ignored as it would need to
* allow the IPDL queue to run to be useful.
*/
template <typename... Args>
QueueStatus TryWaitRemove(const Maybe<TimeDuration>&, Args&... aArgs) {
return TryRemove(aArgs...);
}
mozilla::ipc::Shmem::SharedMemory* LookupSharedMemory(uint32_t aId) {
return mActor ? mActor->LookupSharedMemory(aId) : nullptr;
}
protected:
template <typename T1, typename T2>
friend class IpdlQueue;
friend struct mozilla::ipc::IPDLParamTraits<SelfType>;
explicit IpdlConsumer(uint64_t aId, Actor* aActor = nullptr)
: mActor(aActor), mId(aId) {}
template <typename... Args>
QueueStatus DeserializeAllArgs(Args&... aArgs) {
size_t read = 0;
size_t write = mBuf.Length();
mozilla::webgl::ConsumerView<SelfType> view(this, &read, write);
QueueStatus status = DeserializeArgs(view, aArgs...);
if (IsSuccess(status) && (read > 0)) {
mBuf.RemoveElementsAt(0, read);
}
return status;
}
QueueStatus DeserializeArgs(mozilla::webgl::ConsumerView<SelfType>& aView) {
return QueueStatus::kSuccess;
}
template <typename Arg, typename... Args>
QueueStatus DeserializeArgs(mozilla::webgl::ConsumerView<SelfType>& aView,
Arg& aArg, Args&... aArgs) {
QueueStatus status = DeserializeArg(aView, aArg);
if (!IsSuccess(status)) {
return status;
}
return DeserializeArgs(aView, aArgs...);
}
template <typename Arg>
QueueStatus DeserializeArg(mozilla::webgl::ConsumerView<SelfType>& aView,
Arg& aArg) {
return mozilla::webgl::
QueueParamTraits<typename mozilla::webgl::RemoveCVR<Arg>::Type>::Read(
aView, const_cast<std::remove_cv_t<Arg>*>(&aArg));
}
public:
template <typename Arg>
QueueStatus ReadObject(size_t* aRead, size_t aWrite, Arg* arg,
size_t aArgSize) {
// TODO: Queue needs one extra byte for PCQ (fixme).
return mozilla::webgl::Marshaller::ReadObject(
mBuf.Elements(), mBuf.Length() + 1, aRead, aWrite, arg, aArgSize);
}
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
protected:
WeakPtr<Actor> mActor;
uint64_t mId;
nsTArray<uint8_t> mBuf;
};
/**
* An IpdlQueue is a queue that uses an actor of type ActorP to send data and
* its reciprocal (i.e. child to its parent or vice-versa) to receive data.
* ActorP must derive from one of:
* AsyncProducerActor, SyncProducerActor
* ActorC must derive from one of:
* AsyncConsumerActor, SyncConsumerActor
*/
template <typename _ActorP, typename _ActorC>
class IpdlQueue final {
public:
using ActorP = _ActorP;
using ActorC = _ActorC;
using Producer = IpdlProducer<ActorP>;
using Consumer = IpdlConsumer<ActorC>;
UniquePtr<Producer> TakeProducer() { return std::move(mProducer); }
UniquePtr<Consumer> TakeConsumer() { return std::move(mConsumer); }
/**
* Create an IpdlQueue where the given actor is a producer and its
* reciprocal is the consumer.
* The reciprocal actor type must be typedefed in ActorC as OtherSideActor.
* For example, WebGLChild::OtherSideActor is WebGLParent.
*/
static UniquePtr<IpdlQueue<ActorP, ActorC>> Create(ActorP* aProducerActor) {
static_assert(std::is_same<typename ActorP::OtherSideActor, ActorC>::value,
"ActorP's reciprocal must be ActorC");
static_assert(std::is_same<typename ActorC::OtherSideActor, ActorP>::value,
"ActorC's reciprocal must be ActorP");
auto id = NewIpdlQueueId();
return WrapUnique(new IpdlQueue<ActorP, ActorC>(
std::move(WrapUnique(new Producer(id, aProducerActor))),
std::move(WrapUnique(new Consumer(id)))));
}
/**
* Create an IpdlQueue where the given actor is a consumer and its
* reciprocal is the producer.
* The reciprocal actor type must be typedefed in ActorC as OtherSideActor.
* For example, WebGLChild::OtherSideActor is WebGLParent.
*/
static UniquePtr<IpdlQueue<ActorP, ActorC>> Create(ActorC* aConsumerActor) {
static_assert(std::is_same<typename ActorP::OtherSideActor, ActorC>::value,
"ActorP's reciprocal must be ActorC");
static_assert(std::is_same<typename ActorC::OtherSideActor, ActorP>::value,
"ActorC's reciprocal must be ActorP");
auto id = NewIpdlQueueId();
return WrapUnique(new IpdlQueue<ActorP, ActorC>(
std::move(WrapUnique(new Producer(id))),
std::move(WrapUnique(new Consumer(id, aConsumerActor)))));
}
private:
IpdlQueue(UniquePtr<Producer>&& aProducer, UniquePtr<Consumer>&& aConsumer)
: mProducer(std::move(aProducer)), mConsumer(std::move(aConsumer)) {}
UniquePtr<Producer> mProducer;
UniquePtr<Consumer> mConsumer;
};
} // namespace dom
namespace ipc {
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlProducer<Actor>> {
using paramType = mozilla::dom::IpdlProducer<Actor>;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
MOZ_ASSERT(aParam.mActor == nullptr);
WriteIPDLParam(aMsg, aActor, aParam.mId);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
aResult->mActor = static_cast<Actor*>(aActor);
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mId);
}
};
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlConsumer<Actor>> {
using paramType = mozilla::dom::IpdlConsumer<Actor>;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
MOZ_ASSERT(aParam.mActor == nullptr);
WriteIPDLParam(aMsg, aActor, aParam.mId);
WriteIPDLParam(aMsg, aActor, aParam.mBuf);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
aResult->mActor = static_cast<Actor*>(aActor);
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mId) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mBuf);
}
};
template <>
struct IPDLParamTraits<mozilla::dom::IpdlQueueBuffer> {
using paramType = mozilla::dom::IpdlQueueBuffer;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
WriteParam(aMsg, aParam.id);
WriteParam(aMsg, aParam.data);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->id) &&
ReadParam(aMsg, aIter, &aResult->data);
}
};
} // namespace ipc
} // namespace mozilla
#endif // IPDLQUEUE_H_

Просмотреть файл

@ -24,8 +24,6 @@ using mozilla::webgl::ShaderPrecisionFormat from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::OpaqueFramebufferOptions from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ReadPixelsDesc from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ReadPixelsResultIpc from "mozilla/dom/WebGLIpdl.h";
using mozilla::dom::IpdlQueueBuffer from "mozilla/dom/IpdlQueue.h";
using mozilla::dom::IpdlQueueBuffers from "mozilla/dom/IpdlQueue.h";
namespace mozilla {
namespace dom {

Просмотреть файл

@ -25,46 +25,12 @@
namespace mozilla {
namespace webgl {
enum class QueueStatus {
// Operation was successful
kSuccess,
// The operation failed because the queue isn't ready for it.
// Either the queue is too full for an insert or too empty for a remove.
// The operation may succeed if retried.
kNotReady,
// The operation required more room than the queue supports.
// It should not be retried -- it will always fail.
kTooSmall,
// The operation failed for some reason that is unrecoverable.
// All values below this value indicate a fata error.
kFatalError,
// Fatal error: Internal processing ran out of memory. This is likely e.g.
// during de-serialization.
kOOMError,
};
inline bool IsSuccess(QueueStatus status) {
return status == QueueStatus::kSuccess;
}
inline bool operator!(const QueueStatus status) { return !IsSuccess(status); }
template <typename T>
struct RemoveCVR {
using Type =
typename std::remove_reference<typename std::remove_cv<T>::type>::type;
};
inline size_t UsedBytes(size_t aQueueBufferSize, size_t aRead, size_t aWrite) {
return (aRead <= aWrite) ? aWrite - aRead
: (aQueueBufferSize - aRead) + aWrite;
}
inline size_t FreeBytes(size_t aQueueBufferSize, size_t aRead, size_t aWrite) {
// Remember, queueSize is queueBufferSize-1
return (aQueueBufferSize - 1) - UsedBytes(aQueueBufferSize, aRead, aWrite);
}
template <typename T>
struct IsTriviallySerializable
: public std::integral_constant<bool, std::is_arithmetic<T>::value &&
@ -96,53 +62,6 @@ struct IsTriviallySerializable
template <typename Arg>
struct QueueParamTraits; // Todo: s/QueueParamTraits/SizedParamTraits/
/**
* The marshaller handles all data insertion into the queue.
*/
class Marshaller {
public:
static QueueStatus WriteObject(uint8_t* aQueue, size_t aQueueBufferSize,
size_t aRead, size_t* aWrite, const void* aArg,
size_t aArgLength) {
const uint8_t* buf = reinterpret_cast<const uint8_t*>(aArg);
if (FreeBytes(aQueueBufferSize, aRead, *aWrite) < aArgLength) {
return QueueStatus::kNotReady;
}
if (*aWrite + aArgLength <= aQueueBufferSize) {
memcpy(aQueue + *aWrite, buf, aArgLength);
} else {
size_t firstLen = aQueueBufferSize - *aWrite;
memcpy(aQueue + *aWrite, buf, firstLen);
memcpy(aQueue, &buf[firstLen], aArgLength - firstLen);
}
*aWrite = (*aWrite + aArgLength) % aQueueBufferSize;
return QueueStatus::kSuccess;
}
static QueueStatus ReadObject(const uint8_t* aQueue, size_t aQueueBufferSize,
size_t* aRead, size_t aWrite, void* aArg,
size_t aArgLength) {
if (UsedBytes(aQueueBufferSize, *aRead, aWrite) < aArgLength) {
return QueueStatus::kNotReady;
}
if (aArg) {
uint8_t* buf = reinterpret_cast<uint8_t*>(aArg);
if (*aRead + aArgLength <= aQueueBufferSize) {
memcpy(buf, aQueue + *aRead, aArgLength);
} else {
size_t firstLen = aQueueBufferSize - *aRead;
memcpy(buf, aQueue + *aRead, firstLen);
memcpy(&buf[firstLen], aQueue, aArgLength - firstLen);
}
}
*aRead = (*aRead + aArgLength) % aQueueBufferSize;
return QueueStatus::kSuccess;
}
};
template <typename T>
inline Range<T> AsRange(T* const begin, T* const end) {
const auto size = MaybeAs<size_t>(end - begin);
@ -161,53 +80,48 @@ class ProducerView {
public:
using Producer = _Producer;
ProducerView(Producer* aProducer, size_t aRead, size_t* aWrite)
: mProducer(aProducer),
mRead(aRead),
mWrite(aWrite),
mStatus(QueueStatus::kSuccess) {}
explicit ProducerView(Producer* aProducer)
: mProducer(aProducer) {}
template <typename T>
QueueStatus WriteFromRange(const Range<const T>& src) {
if (!mStatus) return mStatus;
mProducer->WriteFromRange(src);
return mStatus;
bool WriteFromRange(const Range<const T>& src) {
if (MOZ_LIKELY(mOk)) {
mOk &= mProducer->WriteFromRange(src);
}
return mOk;
}
/**
* Copy bytes from aBuffer to the producer if there is enough room.
* aBufferSize must not be 0.
*/
template <typename T>
inline QueueStatus Write(const T* begin, const T* end) {
inline bool Write(const T* begin, const T* end) {
MOZ_RELEASE_ASSERT(begin <= end);
if (!mStatus) return mStatus;
WriteFromRange(AsRange(begin, end));
return mStatus;
return WriteFromRange(AsRange(begin, end));
}
template <typename T>
inline QueueStatus WritePod(const T& in) {
inline bool WritePod(const T& in) {
static_assert(std::is_trivially_copyable_v<T>);
const auto begin = reinterpret_cast<const uint8_t*>(&in);
return Write(begin, begin + sizeof(T));
const auto begin = &in;
return Write(begin, begin + 1);
}
/**
* Serialize aArg using Arg's QueueParamTraits.
*/
template <typename Arg>
QueueStatus WriteParam(const Arg& aArg) {
bool WriteParam(const Arg& aArg) {
return mozilla::webgl::QueueParamTraits<
typename RemoveCVR<Arg>::Type>::Write(*this, aArg);
}
QueueStatus GetStatus() { return mStatus; }
bool Ok() const { return mOk; }
private:
Producer* mProducer;
size_t mRead;
size_t* mWrite;
QueueStatus mStatus;
Producer* const mProducer;
bool mOk = true;
};
/**
@ -219,48 +133,42 @@ class ConsumerView {
public:
using Consumer = _Consumer;
ConsumerView(Consumer* aConsumer, size_t* aRead, size_t aWrite)
: mConsumer(aConsumer),
mRead(aRead),
mWrite(aWrite),
mStatus(QueueStatus::kSuccess) {}
explicit ConsumerView(Consumer* aConsumer)
: mConsumer(aConsumer) {}
/**
* Read bytes from the consumer if there is enough data. aBuffer may
* be null (in which case the data is skipped)
*/
template <typename T>
inline QueueStatus Read(T* const destBegin, T* const destEnd) {
inline bool Read(T* const destBegin, T* const destEnd) {
MOZ_ASSERT(destBegin);
MOZ_RELEASE_ASSERT(destBegin <= destEnd);
if (!mStatus) return mStatus;
const auto dest = AsRange(destBegin, destEnd);
const auto view = ReadRange<T>(dest.length());
if (!view) return mStatus;
if (MOZ_LIKELY(view)) {
const auto byteSize = ByteSize(dest);
if (byteSize) {
if (MOZ_LIKELY(byteSize)) {
memcpy(dest.begin().get(), view->begin().get(), byteSize);
}
return mStatus;
}
return mOk;
}
/// Return a view wrapping the shmem.
template <typename T>
inline Maybe<Range<const T>> ReadRange(const size_t elemCount) {
if (!mStatus) return {};
if (MOZ_UNLIKELY(!mOk)) return {};
const auto view = mConsumer->template ReadRange<T>(elemCount);
if (!view) {
mStatus = QueueStatus::kTooSmall;
}
mOk &= bool(view);
return view;
}
template <typename T>
inline QueueStatus ReadPod(T* out) {
inline bool ReadPod(T* out) {
static_assert(std::is_trivially_copyable_v<T>);
const auto begin = reinterpret_cast<uint8_t*>(out);
return Read(begin, begin + sizeof(T));
return Read(out, out + 1);
}
/**
@ -268,19 +176,17 @@ class ConsumerView {
* If the return value is not Success then aArg is not changed.
*/
template <typename Arg>
QueueStatus ReadParam(Arg* aArg) {
bool ReadParam(Arg* aArg) {
MOZ_ASSERT(aArg);
return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>>::Read(*this,
aArg);
}
QueueStatus GetStatus() { return mStatus; }
bool Ok() const { return mOk; }
private:
Consumer* mConsumer;
size_t* mRead;
size_t mWrite;
QueueStatus mStatus;
Consumer* const mConsumer;
bool mOk = true;
};
// ---------------------------------------------------------------
@ -291,7 +197,7 @@ class ConsumerView {
template <typename Arg>
struct QueueParamTraits {
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView, const Arg& aArg) {
static bool Write(ProducerView<U>& aProducerView, 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.");
@ -301,7 +207,7 @@ struct QueueParamTraits {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, Arg* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, Arg* aArg) {
static_assert(mozilla::webgl::template IsTriviallySerializable<Arg>::value,
"No QueueParamTraits specialization was found for this type "
"and it does not satisfy IsTriviallySerializable.");
@ -317,20 +223,20 @@ struct QueueParamTraits<bool> {
using ParamType = bool;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static auto Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
uint8_t temp = aArg ? 1 : 0;
return aProducerView.WriteParam(temp);
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
uint8_t temp;
if (IsSuccess(aConsumerView.ReadParam(&temp))) {
if (aConsumerView.ReadParam(&temp)) {
MOZ_ASSERT(temp == 1 || temp == 0);
*aArg = temp ? true : false;
}
return aConsumerView.GetStatus();
return aConsumerView.Ok();
}
};
@ -345,7 +251,7 @@ struct EnumSerializer {
using DataType = typename std::underlying_type<E>::type;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static auto Write(ProducerView<U>& aProducerView,
const ParamType& aValue) {
MOZ_RELEASE_ASSERT(
EnumValidator::IsLegalValue(static_cast<DataType>(aValue)));
@ -353,21 +259,21 @@ struct EnumSerializer {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aResult) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aResult) {
DataType value;
if (!aConsumerView.ReadParam(&value)) {
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"_ns);
return aConsumerView.GetStatus();
return false;
}
if (!EnumValidator::IsLegalValue(static_cast<DataType>(value))) {
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"_ns);
return QueueStatus::kFatalError;
return false;
}
*aResult = ParamType(value);
return QueueStatus::kSuccess;
return true;
}
};
@ -386,19 +292,12 @@ struct ContiguousEnumSerializerInclusive
// ---------------------------------------------------------------
template <>
struct QueueParamTraits<QueueStatus>
: public ContiguousEnumSerializerInclusive<
QueueStatus, QueueStatus::kSuccess, QueueStatus::kOOMError> {};
// ---------------------------------------------------------------
template <>
struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
using ParamType = webgl::TexUnpackBlobDesc;
template <typename U>
static QueueStatus Write(ProducerView<U>& view, const ParamType& in) {
static bool Write(ProducerView<U>& view, const ParamType& in) {
MOZ_RELEASE_ASSERT(!in.image);
const bool isDataSurf = bool(in.dataSurf);
if (!view.WriteParam(in.imageTarget) || !view.WriteParam(in.size) ||
@ -407,33 +306,33 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
!view.WriteParam(in.imageSize) || !view.WriteParam(in.sd) ||
!view.WriteParam(in.applyUnpackTransforms) ||
!view.WriteParam(isDataSurf)) {
return view.GetStatus();
return false;
}
if (isDataSurf) {
const auto& surf = in.dataSurf;
gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::READ);
if (!map.IsMapped()) {
return QueueStatus::kOOMError;
return false;
}
const auto& surfSize = surf->GetSize();
const auto stride = *MaybeAs<size_t>(map.GetStride());
if (!view.WriteParam(surfSize) || !view.WriteParam(surf->GetFormat()) ||
!view.WriteParam(stride)) {
return view.GetStatus();
return false;
}
const size_t dataSize = stride * surfSize.height;
const auto& begin = map.GetData();
const auto range = Range<const uint8_t>{begin, dataSize};
if (!view.WriteFromRange(range)) {
return view.GetStatus();
return false;
}
}
return QueueStatus::kSuccess;
return true;
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& view, ParamType* const out) {
static bool Read(ConsumerView<U>& view, ParamType* const out) {
bool isDataSurf;
if (!view.ReadParam(&out->imageTarget) || !view.ReadParam(&out->size) ||
!view.ReadParam(&out->srcAlphaType) ||
@ -442,7 +341,7 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
!view.ReadParam(&out->sd) ||
!view.ReadParam(&out->applyUnpackTransforms) ||
!view.ReadParam(&isDataSurf)) {
return view.GetStatus();
return false;
}
if (isDataSurf) {
gfx::IntSize surfSize;
@ -450,11 +349,11 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
size_t stride;
if (!view.ReadParam(&surfSize) || !view.ReadParam(&format) ||
!view.ReadParam(&stride)) {
return view.GetStatus();
return false;
}
const size_t dataSize = stride * surfSize.height;
const auto range = view.template ReadRange<uint8_t>(dataSize);
if (!range) return view.GetStatus();
if (!range) return false;
// DataSourceSurface demands pointer-to-mutable.
const auto bytes = const_cast<uint8_t*>(range->begin().get());
@ -462,7 +361,7 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
bytes, stride, surfSize, format);
MOZ_ASSERT(out->dataSurf);
}
return QueueStatus::kSuccess;
return true;
}
};
@ -473,51 +372,51 @@ struct QueueParamTraits<nsACString> {
using ParamType = nsACString;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
if ((!aProducerView.WriteParam(aArg.IsVoid())) || aArg.IsVoid()) {
return aProducerView.GetStatus();
return false;
}
uint32_t len = aArg.Length();
if ((!aProducerView.WriteParam(len)) || (len == 0)) {
return aProducerView.GetStatus();
return false;
}
return aProducerView.Write(aArg.BeginReading(), len);
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
bool isVoid = false;
if (!IsSuccess(aConsumerView.ReadParam(&isVoid))) {
return aConsumerView.GetStatus();
if (!aConsumerView.ReadParam(&isVoid)) {
return false;
}
aArg->SetIsVoid(isVoid);
if (isVoid) {
return QueueStatus::kSuccess;
return true;
}
uint32_t len = 0;
if (!IsSuccess(aConsumerView.ReadParam(&len))) {
return aConsumerView.GetStatus();
if (!aConsumerView.ReadParam(&len)) {
return false;
}
if (len == 0) {
*aArg = "";
return QueueStatus::kSuccess;
return true;
}
char* buf = new char[len + 1];
if (!buf) {
return QueueStatus::kOOMError;
return false;
}
if (!IsSuccess(aConsumerView.Read(buf, len))) {
return aConsumerView.GetStatus();
if (!aConsumerView.Read(buf, len)) {
return false;
}
buf[len] = '\0';
aArg->Adopt(buf, len);
return QueueStatus::kSuccess;
return true;
}
};
@ -526,40 +425,40 @@ struct QueueParamTraits<nsAString> {
using ParamType = nsAString;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
if ((!aProducerView.WriteParam(aArg.IsVoid())) || (aArg.IsVoid())) {
return aProducerView.GetStatus();
return false;
}
// DLP: No idea if this includes null terminator
uint32_t len = aArg.Length();
if ((!aProducerView.WriteParam(len)) || (len == 0)) {
return aProducerView.GetStatus();
return false;
}
constexpr const uint32_t sizeofchar = sizeof(typename ParamType::char_type);
return aProducerView.Write(aArg.BeginReading(), len * sizeofchar);
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
bool isVoid = false;
if (!aConsumerView.ReadParam(&isVoid)) {
return aConsumerView.GetStatus();
return false;
}
aArg->SetIsVoid(isVoid);
if (isVoid) {
return QueueStatus::kSuccess;
return true;
}
// DLP: No idea if this includes null terminator
uint32_t len = 0;
if (!aConsumerView.ReadParam(&len)) {
return aConsumerView.GetStatus();
return false;
}
if (len == 0) {
*aArg = nsString();
return QueueStatus::kSuccess;
return true;
}
uint32_t sizeofchar = sizeof(typename ParamType::char_type);
@ -567,16 +466,16 @@ struct QueueParamTraits<nsAString> {
buf = static_cast<typename ParamType::char_type*>(
malloc((len + 1) * sizeofchar));
if (!buf) {
return QueueStatus::kOOMError;
return false;
}
if (!aConsumerView.Read(buf, len * sizeofchar)) {
return aConsumerView.GetStatus();
return false;
}
buf[len] = L'\0';
aArg->Adopt(buf, len);
return QueueStatus::kSuccess;
return true;
}
};
@ -604,31 +503,31 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> {
using ParamType = nsTArray<ElementType>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
aProducerView.WriteParam(aArg.Length());
for (auto& elt : aArg) {
aProducerView.WriteParam(elt);
}
return aProducerView.GetStatus();
return true;
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
size_t arrayLen;
if (!aConsumerView.ReadParam(&arrayLen)) {
return aConsumerView.GetStatus();
return false;
}
if (!aArg->AppendElements(arrayLen, fallible)) {
return QueueStatus::kOOMError;
return false;
}
for (auto i : IntegerRange(arrayLen)) {
ElementType& elt = aArg->ElementAt(i);
aConsumerView.ReadParam(elt);
}
return aConsumerView.GetStatus();
return aConsumerView.Ok();
}
};
@ -640,7 +539,7 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> {
// TODO: Are there alignment issues?
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
size_t arrayLen = aArg.Length();
aProducerView.WriteParam(arrayLen);
@ -648,14 +547,14 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
size_t arrayLen;
if (!aConsumerView.ReadParam(&arrayLen)) {
return aConsumerView.GetStatus();
return false;
}
if (!aArg->AppendElements(arrayLen, fallible)) {
return QueueStatus::kOOMError;
return false;
}
return aConsumerView.Read(aArg->Elements(), arrayLen * sizeof(ElementType));
@ -682,20 +581,20 @@ struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> {
using ParamType = Array<ElementType, Length>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static auto Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
for (const auto& elt : aArg) {
aProducerView.WriteParam(elt);
}
return aProducerView.GetStatus();
return aProducerView.Ok();
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
for (auto& elt : *aArg) {
aConsumerView.ReadParam(elt);
}
return aConsumerView.GetStatus();
return aConsumerView.Ok();
}
};
@ -706,13 +605,13 @@ struct ArrayQueueParamTraits<Array<_ElementType, Length>, true> {
using ParamType = Array<ElementType, Length>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static auto Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
return aProducerView.Write(aArg.begin(), sizeof(ElementType[Length]));
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
return aConsumerView.Read(aArg->begin(), sizeof(ElementType[Length]));
}
};
@ -730,23 +629,25 @@ struct QueueParamTraits<Maybe<ElementType>> {
using ParamType = Maybe<ElementType>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
aProducerView.WriteParam(static_cast<bool>(aArg));
return aArg ? aProducerView.WriteParam(aArg.ref())
: aProducerView.GetStatus();
if (aArg) {
aProducerView.WriteParam(aArg.ref());
}
return aProducerView.Ok();
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
bool isSome;
if (!aConsumerView.ReadParam(&isSome)) {
return aConsumerView.GetStatus();
return false;
}
if (!isSome) {
aArg->reset();
return QueueStatus::kSuccess;
return true;
}
aArg->emplace();
@ -756,52 +657,19 @@ struct QueueParamTraits<Maybe<ElementType>> {
// ---------------------------------------------------------------
// Maybe<Variant> needs special behavior since Variant is not default
// constructable. The Variant's first type must be default constructible.
template <typename T, typename... Ts>
struct QueueParamTraits<Maybe<Variant<T, Ts...>>> {
using ParamType = Maybe<Variant<T, Ts...>>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
aProducerView.WriteParam(aArg.mIsSome);
return (aArg.mIsSome) ? aProducerView.WriteParam(aArg.ref())
: aProducerView.GetStatus();
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
bool isSome;
if (!aConsumerView.ReadParam(&isSome)) {
return aConsumerView.GetStatus();
}
if (!isSome) {
aArg->reset();
return QueueStatus::kSuccess;
}
aArg->emplace(VariantType<T>());
return aConsumerView.ReadParam(aArg->ptr());
}
};
// ---------------------------------------------------------------
template <typename TypeA, typename TypeB>
struct QueueParamTraits<std::pair<TypeA, TypeB>> {
using ParamType = std::pair<TypeA, TypeB>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
static bool Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
aProducerView.WriteParam(aArg.first());
return aProducerView.WriteParam(aArg.second());
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
aConsumerView.ReadParam(aArg->first());
return aConsumerView.ReadParam(aArg->second());
}
@ -809,49 +677,15 @@ struct QueueParamTraits<std::pair<TypeA, TypeB>> {
// ---------------------------------------------------------------
template <typename T>
struct QueueParamTraits<UniquePtr<T>> {
using ParamType = UniquePtr<T>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView,
const ParamType& aArg) {
// TODO: Clean up move with PCQ
aProducerView.WriteParam(!static_cast<bool>(aArg));
if (aArg && aProducerView.WriteParam(*aArg.get())) {
const_cast<ParamType&>(aArg).reset();
}
return aProducerView.GetStatus();
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
bool isNull;
if (!aConsumerView.ReadParam(&isNull)) {
return aConsumerView.GetStatus();
}
if (isNull) {
aArg->reset(nullptr);
return QueueStatus::kSuccess;
}
T* obj = new T();
aArg->reset(obj);
return aConsumerView.ReadParam(obj);
}
};
// ---------------------------------------------------------------
template <>
struct QueueParamTraits<mozilla::ipc::Shmem> {
using ParamType = mozilla::ipc::Shmem;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView, ParamType&& aParam) {
static bool Write(ProducerView<U>& aProducerView, ParamType&& aParam) {
if (!aProducerView.WriteParam(
aParam.Id(mozilla::ipc::Shmem::PrivateIPDLCaller()))) {
return aProducerView.GetStatus();
return false;
}
aParam.RevokeRights(mozilla::ipc::Shmem::PrivateIPDLCaller());
@ -859,21 +693,21 @@ struct QueueParamTraits<mozilla::ipc::Shmem> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, ParamType* aResult) {
static bool Read(ConsumerView<U>& aConsumerView, ParamType* aResult) {
ParamType::id_t id;
if (!aConsumerView.ReadParam(&id)) {
return aConsumerView.GetStatus();
return false;
}
mozilla::ipc::Shmem::SharedMemory* rawmem =
aConsumerView.LookupSharedMemory(id);
if (!rawmem) {
return QueueStatus::kFatalError;
return false;
}
*aResult = mozilla::ipc::Shmem(mozilla::ipc::Shmem::PrivateIPDLCaller(),
rawmem, id);
return QueueStatus::kSuccess;
return true;
}
};

Просмотреть файл

@ -6,20 +6,9 @@
#ifndef WEBGLCHILD_H_
#define WEBGLCHILD_H_
#include <string>
#include "mozilla/dom/PWebGLChild.h"
#include "mozilla/dom/IpdlQueue.h"
// This is a bit weird. Nothing directly in WebGLChild.h necessitates including
// WebGLParent.h, but if we don't do this, we get compiler errors in the
// generated code inside PWebGLChild.cpp. The error is due to a complex
// dependency chain involving IpdlQueue, which I won't go into here. Including
// WebGLParent.h inside WebGLChild.h is the simplest way we could think of to
// avoid this issue. Including it in any of the code more directly involved in
// the breaking dependency chain unfortunately introduces a cyclical dependency
// between WebGLParent.h and PWebGLParent.h.
#include "mozilla/dom/WebGLParent.h"
#include <string>
namespace mozilla {
@ -41,7 +30,6 @@ class WebGLChild final : public PWebGLChild, public SupportsWeakPtr {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGLChild, override);
using OtherSideActor = WebGLParent;
explicit WebGLChild(ClientWebGLContext&);

Просмотреть файл

@ -15,8 +15,6 @@
namespace mozilla {
using webgl::QueueStatus;
namespace webgl {
class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
@ -27,7 +25,7 @@ class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
auto Remaining() const { return *MaybeAs<size_t>(mSrcEnd - mSrcItr); }
explicit RangeConsumerView(const Range<const uint8_t> range)
: ConsumerView(this, nullptr, 0),
: ConsumerView(this),
mSrcItr(range.begin()),
mSrcEnd(range.end()) {
(void)Remaining(); // assert size non-negative
@ -35,7 +33,7 @@ class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
void AlignTo(const size_t alignment) {
const auto offset = AlignmentOffset(alignment, mSrcItr.get());
if (offset > Remaining()) {
if (MOZ_UNLIKELY(offset > Remaining())) {
mSrcItr = mSrcEnd;
return;
}
@ -52,7 +50,7 @@ class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
const auto& byteSize = byteSizeChecked.value();
const auto remaining = Remaining();
if (byteSize > remaining) return {};
if (MOZ_UNLIKELY(byteSize > remaining)) return {};
const auto begin = reinterpret_cast<const T*>(mSrcItr.get());
mSrcItr += byteSize;
@ -69,10 +67,10 @@ class SizeOnlyProducerView final
size_t mRequiredSize = 0;
public:
SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {}
SizeOnlyProducerView() : ProducerView(this) {}
template <typename T>
void WriteFromRange(const Range<const T>& src) {
bool WriteFromRange(const Range<const T>& src) {
constexpr auto alignment = alignof(T);
const size_t byteSize = ByteSize(src);
// printf_stderr("SizeOnlyProducerView: @%zu +%zu\n", alignment, byteSize);
@ -81,6 +79,7 @@ class SizeOnlyProducerView final
mRequiredSize += offset;
mRequiredSize += byteSize;
return true;
}
const auto& RequiredSize() const { return mRequiredSize; }
@ -97,7 +96,7 @@ class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
auto Remaining() const { return *MaybeAs<size_t>(mDestEnd - mDestItr); }
explicit RangeProducerView(const Range<uint8_t> range)
: ProducerView(this, 0, nullptr),
: ProducerView(this),
mDestBegin(range.begin()),
mDestEnd(range.end()),
mDestItr(mDestBegin) {
@ -105,7 +104,7 @@ class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
}
template <typename T>
void WriteFromRange(const Range<const T>& src) {
bool WriteFromRange(const Range<const T>& src) {
constexpr auto alignment = alignof(T);
const size_t byteSize = ByteSize(src);
// printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize);
@ -114,10 +113,11 @@ class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
mDestItr += offset;
MOZ_ASSERT(byteSize <= Remaining());
if (byteSize) {
if (MOZ_LIKELY(byteSize)) {
memcpy(mDestItr.get(), src.begin().get(), byteSize);
}
mDestItr += byteSize;
return true;
}
};
@ -129,7 +129,7 @@ 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);
MOZ_ALWAYS_TRUE(view.WriteParam(arg));
Serialize(view, args...);
}

Просмотреть файл

@ -39,6 +39,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProcessPriorityManager.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_webgl.h"

Просмотреть файл

@ -18,6 +18,7 @@
#include "WebGLVertexArray.h"
#include "mozilla/Casting.h"
#include "mozilla/ResultVariant.h"
namespace mozilla {

Просмотреть файл

@ -54,8 +54,7 @@ IPCResult WebGLParent::RecvDispatchCommands(Shmem&& rawShmem,
while (true) {
view.AlignTo(kUniversalAlignment);
size_t id = 0;
const auto status = view.ReadParam(&id);
if (status != QueueStatus::kSuccess) break;
if (!view.ReadParam(&id)) break;
const auto ok = WebGLMethodDispatcher<0>::DispatchCommand(*mHost, id, view);
if (!ok) {

Просмотреть файл

@ -9,7 +9,6 @@
#include "mozilla/GfxMessageUtils.h"
#include "mozilla/dom/PWebGLParent.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/IpdlQueue.h"
namespace mozilla {
@ -28,7 +27,6 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGLParent, override);
using OtherSideActor = WebGLChild;
mozilla::ipc::IPCResult RecvInitialize(const webgl::InitContextDesc&,
webgl::InitContextResult* out);

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -75,7 +76,7 @@ struct QueueParamTraits<RawBuffer<T>> {
using ParamType = RawBuffer<T>;
template <typename U>
static QueueStatus Write(ProducerView<U>& view, const ParamType& in) {
static bool Write(ProducerView<U>& view, const ParamType& in) {
const auto& elemCount = in.size();
auto status = view.WriteParam(elemCount);
if (!status) return status;
@ -92,13 +93,13 @@ struct QueueParamTraits<RawBuffer<T>> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& view, ParamType* const out) {
static bool 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;
return true;
}
uint8_t hasData = 0;
@ -107,13 +108,13 @@ struct QueueParamTraits<RawBuffer<T>> {
if (!hasData) {
auto temp = RawBuffer<T>{elemCount};
*out = std::move(temp);
return QueueStatus::kSuccess;
return true;
}
auto data = view.template ReadRange<T>(elemCount);
if (!data) return QueueStatus::kTooSmall;
if (!data) return false;
*out = std::move(RawBuffer<T>{*data});
return QueueStatus::kSuccess;
return true;
}
};
@ -128,7 +129,7 @@ struct QueueParamTraits<Result<V, E>> {
using T = Result<V, E>;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView, const T& aArg) {
static bool Write(ProducerView<U>& aProducerView, const T& aArg) {
const auto ok = aArg.isOk();
auto status = aProducerView.WriteParam(ok);
if (!status) return status;
@ -141,7 +142,7 @@ struct QueueParamTraits<Result<V, E>> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, T* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, T* aArg) {
bool ok;
auto status = aConsumerView.ReadParam(&ok);
if (!status) return status;
@ -163,7 +164,7 @@ struct QueueParamTraits<std::string> {
using T = std::string;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView, const T& aArg) {
static bool Write(ProducerView<U>& aProducerView, const T& aArg) {
const auto size = aArg.size();
auto status = aProducerView.WriteParam(size);
if (!status) return status;
@ -172,13 +173,13 @@ struct QueueParamTraits<std::string> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, T* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, T* aArg) {
size_t size;
auto status = aConsumerView.ReadParam(&size);
if (!status) return status;
const auto view = aConsumerView.template ReadRange<char>(size);
if (!view) return QueueStatus::kFatalError;
if (!view) return false;
aArg->assign(view->begin().get(), size);
return status;
}
@ -189,7 +190,7 @@ struct QueueParamTraits<std::vector<U>> {
using T = std::vector<U>;
template <typename V>
static QueueStatus Write(ProducerView<V>& aProducerView, const T& aArg) {
static bool Write(ProducerView<V>& aProducerView, const T& aArg) {
auto status = aProducerView.WriteParam(aArg.size());
if (!status) return status;
@ -201,7 +202,7 @@ struct QueueParamTraits<std::vector<U>> {
}
template <typename V>
static QueueStatus Read(ConsumerView<V>& aConsumerView, T* aArg) {
static bool Read(ConsumerView<V>& aConsumerView, T* aArg) {
size_t size;
auto status = aConsumerView.ReadParam(&size);
if (!status) return status;
@ -226,7 +227,7 @@ struct QueueParamTraits<CompileResult> {
using T = CompileResult;
template <typename U>
static QueueStatus Write(ProducerView<U>& aProducerView, const T& aArg) {
static bool Write(ProducerView<U>& aProducerView, const T& aArg) {
aProducerView.WriteParam(aArg.pending);
aProducerView.WriteParam(aArg.log);
aProducerView.WriteParam(aArg.translatedSource);
@ -234,7 +235,7 @@ struct QueueParamTraits<CompileResult> {
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& aConsumerView, T* aArg) {
static bool Read(ConsumerView<U>& aConsumerView, T* aArg) {
aConsumerView.ReadParam(&aArg->pending);
aConsumerView.ReadParam(&aArg->log);
aConsumerView.ReadParam(&aArg->translatedSource);

Просмотреть файл

@ -18,7 +18,6 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Range.h"
#include "mozilla/RefCounted.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/BuildConstants.h"
#include "mozilla/gfx/Point.h"
@ -355,13 +354,6 @@ struct FloatOrInt final // For TexParameter[fi] and friends.
}
};
using WebGLTexUnpackVariant =
Variant<UniquePtr<webgl::TexUnpackBytes>,
UniquePtr<webgl::TexUnpackSurface>,
UniquePtr<webgl::TexUnpackImage>, WebGLTexPboOffset>;
using MaybeWebGLTexUnpackVariant = Maybe<WebGLTexUnpackVariant>;
struct WebGLContextOptions {
bool alpha = true;
bool depth = true;

Просмотреть файл

@ -59,7 +59,6 @@ EXPORTS.mozilla.dom += [
"ImageBitmapSource.h",
"ImageData.h",
"ImageUtils.h",
"IpdlQueue.h",
"OffscreenCanvas.h",
"QueueParamTraits.h",
"TextMetrics.h",