mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 04:38:02 +00:00
Bug 1665280 - For RawBuffer reads, return a view into the shmem. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D90354
This commit is contained in:
parent
c95f299299
commit
7f28f17f33
@ -141,6 +141,13 @@ class Marshaller {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline Range<T> AsRange(T* const begin, T* const end) {
|
||||
const auto size = MaybeAs<size_t>(end - begin);
|
||||
MOZ_RELEASE_ASSERT(size);
|
||||
return {begin, *size};
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to give QueueParamTraits a way to write to the Producer without
|
||||
* actually altering it, in case the transaction fails.
|
||||
@ -158,16 +165,22 @@ class ProducerView {
|
||||
mWrite(aWrite),
|
||||
mStatus(QueueStatus::kSuccess) {}
|
||||
|
||||
template <typename T>
|
||||
QueueStatus WriteFromRange(const Range<const T>& src) {
|
||||
if (!mStatus) return mStatus;
|
||||
mProducer->WriteFromRange(src);
|
||||
return mStatus;
|
||||
}
|
||||
/**
|
||||
* Copy bytes from aBuffer to the producer if there is enough room.
|
||||
* aBufferSize must not be 0.
|
||||
*/
|
||||
inline QueueStatus Write(const uint8_t* begin, const uint8_t* end);
|
||||
|
||||
template <typename T>
|
||||
inline QueueStatus Write(const T* begin, const T* end) {
|
||||
return Write(reinterpret_cast<const uint8_t*>(begin),
|
||||
reinterpret_cast<const uint8_t*>(end));
|
||||
MOZ_RELEASE_ASSERT(begin <= end);
|
||||
if (!mStatus) return mStatus;
|
||||
WriteFromRange(AsRange(begin, end));
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -214,12 +227,31 @@ 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(uint8_t* begin, uint8_t* end);
|
||||
|
||||
template <typename T>
|
||||
inline QueueStatus Read(T* begin, T* end) {
|
||||
return Read(reinterpret_cast<uint8_t*>(begin),
|
||||
reinterpret_cast<uint8_t*>(end));
|
||||
inline QueueStatus 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;
|
||||
const auto byteSize = ByteSize(dest);
|
||||
if (byteSize) {
|
||||
memcpy(dest.begin().get(), view->begin().get(), byteSize);
|
||||
}
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
/// Return a view wrapping the shmem.
|
||||
template <typename T>
|
||||
inline Maybe<Range<const T>> ReadRange(const size_t elemCount) {
|
||||
if (!mStatus) return {};
|
||||
const auto view = mConsumer->template ReadRange<T>(elemCount);
|
||||
if (!view) {
|
||||
mStatus = QueueStatus::kTooSmall;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -249,29 +281,6 @@ class ConsumerView {
|
||||
QueueStatus mStatus;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
QueueStatus ProducerView<T>::Write(const uint8_t* const begin,
|
||||
const uint8_t* const end) {
|
||||
MOZ_ASSERT(begin <= end);
|
||||
if (!mStatus) return mStatus;
|
||||
if (begin < end) {
|
||||
MOZ_ASSERT(begin);
|
||||
mStatus = mProducer->WriteObject(mRead, mWrite, begin, end - begin);
|
||||
}
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QueueStatus ConsumerView<T>::Read(uint8_t* const begin, uint8_t* const end) {
|
||||
MOZ_ASSERT(begin <= end);
|
||||
if (!mStatus) return mStatus;
|
||||
if (begin < end) {
|
||||
MOZ_ASSERT(begin);
|
||||
mStatus = mConsumer->ReadObject(mRead, mWrite, begin, end - begin);
|
||||
}
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -41,15 +41,18 @@ Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(const size_t size) {
|
||||
mPendingCmdsShmem = std::move(shmem);
|
||||
mPendingCmdsPos = 0;
|
||||
}
|
||||
|
||||
const auto range = mPendingCmdsShmem.ByteRange();
|
||||
|
||||
const auto remaining =
|
||||
Range<uint8_t>{range.begin() + mPendingCmdsPos, range.end()};
|
||||
if (size > remaining.length()) {
|
||||
auto itr = range.begin() + mPendingCmdsPos;
|
||||
const auto offset = AlignmentOffset(kUniversalAlignment, itr.get());
|
||||
mPendingCmdsPos += offset;
|
||||
const auto required = mPendingCmdsPos + size;
|
||||
if (required > range.length()) {
|
||||
FlushPendingCmds();
|
||||
return AllocPendingCmdBytes(size);
|
||||
}
|
||||
itr = range.begin() + mPendingCmdsPos;
|
||||
const auto remaining = Range<uint8_t>{itr, range.end()};
|
||||
mPendingCmdsPos += size;
|
||||
return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
|
||||
}
|
||||
|
@ -40,13 +40,30 @@ class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
|
||||
(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;
|
||||
void AlignTo(const size_t alignment) {
|
||||
const auto offset = AlignmentOffset(alignment, mSrcItr.get());
|
||||
if (offset > Remaining()) {
|
||||
mSrcItr = mSrcEnd;
|
||||
return;
|
||||
}
|
||||
mSrcItr += offset;
|
||||
}
|
||||
|
||||
memcpy(src, mSrcItr.get(), size);
|
||||
mSrcItr += size;
|
||||
return QueueStatus::kSuccess;
|
||||
template <typename T>
|
||||
Maybe<Range<const T>> ReadRange(const size_t elemCount) {
|
||||
AlignTo(alignof(T));
|
||||
|
||||
constexpr auto elemSize = sizeof(T);
|
||||
const auto byteSizeChecked = CheckedInt<size_t>(elemCount) * elemSize;
|
||||
MOZ_RELEASE_ASSERT(byteSizeChecked.isValid());
|
||||
const auto& byteSize = byteSizeChecked.value();
|
||||
|
||||
const auto remaining = Remaining();
|
||||
if (byteSize > remaining) return {};
|
||||
|
||||
const auto begin = reinterpret_cast<const T*>(mSrcItr.get());
|
||||
mSrcItr += byteSize;
|
||||
return Some(Range<const T>{begin, elemCount});
|
||||
}
|
||||
};
|
||||
|
||||
@ -61,9 +78,16 @@ class SizeOnlyProducerView final
|
||||
public:
|
||||
SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {}
|
||||
|
||||
QueueStatus WriteObject(size_t, size_t*, const void*, const size_t size) {
|
||||
mRequiredSize += size;
|
||||
return QueueStatus::kSuccess;
|
||||
template <typename T>
|
||||
void 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);
|
||||
|
||||
const auto offset = AlignmentOffset(alignment, mRequiredSize);
|
||||
mRequiredSize += offset;
|
||||
|
||||
mRequiredSize += byteSize;
|
||||
}
|
||||
|
||||
const auto& RequiredSize() const { return mRequiredSize; }
|
||||
@ -72,26 +96,35 @@ class SizeOnlyProducerView final
|
||||
// -
|
||||
|
||||
class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
|
||||
RangedPtr<uint8_t> mDestItr;
|
||||
const RangedPtr<uint8_t> mDestBegin;
|
||||
const RangedPtr<uint8_t> mDestEnd;
|
||||
RangedPtr<uint8_t> mDestItr;
|
||||
|
||||
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()) {
|
||||
mDestBegin(range.begin()),
|
||||
mDestEnd(range.end()),
|
||||
mDestItr(mDestBegin) {
|
||||
(void)Remaining(); // assert size non-negative
|
||||
}
|
||||
|
||||
QueueStatus WriteObject(size_t, size_t*, const void* const src,
|
||||
const size_t size) {
|
||||
MOZ_ASSERT(size <= Remaining());
|
||||
template <typename T>
|
||||
void 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);
|
||||
|
||||
memcpy(mDestItr.get(), src, size);
|
||||
mDestItr += size;
|
||||
return QueueStatus::kSuccess;
|
||||
const auto offset = AlignmentOffset(alignment, mDestItr.get());
|
||||
mDestItr += offset;
|
||||
|
||||
MOZ_ASSERT(byteSize <= Remaining());
|
||||
if (byteSize) {
|
||||
memcpy(mDestItr.get(), src.begin().get(), byteSize);
|
||||
}
|
||||
mDestItr += byteSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -61,6 +61,7 @@ IPCResult WebGLParent::RecvDispatchCommands(Shmem&& rawShmem,
|
||||
auto view = webgl::RangeConsumerView{cmdsBytes};
|
||||
|
||||
while (true) {
|
||||
view.AlignTo(kUniversalAlignment);
|
||||
size_t id = 0;
|
||||
const auto status = view.ReadParam(&id);
|
||||
if (status != QueueStatus::kSuccess) break;
|
||||
|
@ -85,7 +85,7 @@ struct QueueParamTraits<RawBuffer<T>> {
|
||||
if (!status) return status;
|
||||
if (!hasData) return status;
|
||||
|
||||
status = view.Write(begin, begin + elemCount);
|
||||
status = view.WriteFromRange(in.Data());
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -108,16 +108,10 @@ struct QueueParamTraits<RawBuffer<T>> {
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
|
||||
auto buffer = UniqueBuffer::Alloc(elemCount * sizeof(T));
|
||||
if (!buffer) return QueueStatus::kOOMError;
|
||||
|
||||
using MutT = std::remove_cv_t<T>;
|
||||
const auto begin = reinterpret_cast<MutT*>(buffer.get());
|
||||
const auto range = Range<MutT>{begin, elemCount};
|
||||
|
||||
auto temp = RawBuffer<T>{range, std::move(buffer)};
|
||||
*out = std::move(temp);
|
||||
return view.Read(range.begin().get(), range.end().get());
|
||||
auto data = view.template ReadRange<T>(elemCount);
|
||||
if (!data) return QueueStatus::kTooSmall;
|
||||
*out = std::move(RawBuffer<T>{*data});
|
||||
return QueueStatus::kSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
@ -168,9 +162,10 @@ struct QueueParamTraits<std::string> {
|
||||
|
||||
template <typename U>
|
||||
static QueueStatus Write(ProducerView<U>& aProducerView, const T& aArg) {
|
||||
auto status = aProducerView.WriteParam(aArg.size());
|
||||
const auto size = aArg.size();
|
||||
auto status = aProducerView.WriteParam(size);
|
||||
if (!status) return status;
|
||||
status = aProducerView.Write(aArg.data(), aArg.data() + aArg.size());
|
||||
status = aProducerView.WriteFromRange(Range<const char>{aArg.data(), size});
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -180,12 +175,9 @@ struct QueueParamTraits<std::string> {
|
||||
auto status = aConsumerView.ReadParam(&size);
|
||||
if (!status) return status;
|
||||
|
||||
const UniqueBuffer temp = malloc(size);
|
||||
const auto dest = static_cast<char*>(temp.get());
|
||||
if (!dest) return QueueStatus::kFatalError;
|
||||
|
||||
status = aConsumerView.Read(dest, dest + size);
|
||||
aArg->assign(dest, size);
|
||||
const auto view = aConsumerView.template ReadRange<char>(size);
|
||||
if (!view) return QueueStatus::kFatalError;
|
||||
aArg->assign(view->begin().get(), size);
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
@ -990,6 +990,24 @@ inline auto MakeRangeAbv(const T& abv)
|
||||
return {abv.Data(), abv.Length()};
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
constexpr auto kUniversalAlignment = alignof(std::max_align_t);
|
||||
|
||||
template <typename T>
|
||||
inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
|
||||
MOZ_ASSERT(alignment);
|
||||
const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
|
||||
const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
|
||||
const auto aligned = wholeMultiples * alignment;
|
||||
return aligned - begin;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t ByteSize(const Range<T>& range) {
|
||||
return range.length() * sizeof(T);
|
||||
}
|
||||
|
||||
Maybe<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
|
||||
GLuint elemOffset,
|
||||
GLuint elemCountOverride);
|
||||
|
Loading…
x
Reference in New Issue
Block a user