mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1120271 - Add compacting support for SourceBuffer. r=tn
This commit is contained in:
parent
34613cd799
commit
80905be95c
@ -22,6 +22,13 @@ namespace image {
|
||||
// SourceBufferIterator implementation.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SourceBufferIterator::~SourceBufferIterator()
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->OnIteratorRelease();
|
||||
}
|
||||
}
|
||||
|
||||
SourceBufferIterator::State
|
||||
SourceBufferIterator::AdvanceOrScheduleResume(IResumable* aConsumer)
|
||||
{
|
||||
@ -43,8 +50,15 @@ SourceBufferIterator::RemainingBytesIsNoMoreThan(size_t aBytes) const
|
||||
|
||||
SourceBuffer::SourceBuffer()
|
||||
: mMutex("image::SourceBuffer")
|
||||
, mConsumerCount(0)
|
||||
{ }
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
{
|
||||
MOZ_ASSERT(mConsumerCount == 0,
|
||||
"SourceBuffer destroyed with active consumers");
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBuffer::AppendChunk(Maybe<Chunk>&& aChunk)
|
||||
{
|
||||
@ -72,16 +86,87 @@ SourceBuffer::AppendChunk(Maybe<Chunk>&& aChunk)
|
||||
}
|
||||
|
||||
Maybe<SourceBuffer::Chunk>
|
||||
SourceBuffer::CreateChunk(size_t aCapacity)
|
||||
SourceBuffer::CreateChunk(size_t aCapacity, bool aRoundUp /* = true */)
|
||||
{
|
||||
if (MOZ_UNLIKELY(aCapacity == 0)) {
|
||||
MOZ_ASSERT_UNREACHABLE("Appending a chunk of zero size?");
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
// Round up if requested.
|
||||
size_t finalCapacity = aRoundUp ? RoundedUpCapacity(aCapacity)
|
||||
: aCapacity;
|
||||
|
||||
// Use the size of the SurfaceCache as an additional heuristic to avoid
|
||||
// allocating huge buffers. Generally images do not get smaller when decoded,
|
||||
// so if we could store the source data in the SurfaceCache, we assume that
|
||||
// there's no way we'll be able to store the decoded version.
|
||||
if (MOZ_UNLIKELY(!SurfaceCache::CanHold(finalCapacity))) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(Chunk(finalCapacity));
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBuffer::Compact()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
MOZ_ASSERT(mConsumerCount == 0, "Should have no consumers here");
|
||||
MOZ_ASSERT(mWaitingConsumers.Length() == 0, "Shouldn't have waiters");
|
||||
MOZ_ASSERT(mStatus, "Should be complete here");
|
||||
|
||||
// Compact our waiting consumers list, since we're complete and no future
|
||||
// consumer will ever have to wait.
|
||||
mWaitingConsumers.Compact();
|
||||
|
||||
// If we have no more than one chunk, then we can't compact further.
|
||||
if (mChunks.Length() < 2) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We can compact our buffer. Determine the total length.
|
||||
size_t length = 0;
|
||||
for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
|
||||
length += mChunks[i].Length();
|
||||
}
|
||||
|
||||
Maybe<Chunk> newChunk = CreateChunk(length, /* aRoundUp = */ false);
|
||||
if (MOZ_UNLIKELY(!newChunk || newChunk->AllocationFailed())) {
|
||||
NS_WARNING("Failed to allocate chunk for SourceBuffer compacting - OOM?");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Copy our old chunks into the new chunk.
|
||||
for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
|
||||
size_t offset = newChunk->Length();
|
||||
MOZ_ASSERT(offset < newChunk->Capacity());
|
||||
MOZ_ASSERT(offset + mChunks[i].Length() <= newChunk->Capacity());
|
||||
|
||||
memcpy(newChunk->Data() + offset, mChunks[i].Data(), mChunks[i].Length());
|
||||
newChunk->AddLength(mChunks[i].Length());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(newChunk->Length() == newChunk->Capacity(),
|
||||
"Compacted chunk has slack space");
|
||||
|
||||
// Replace the old chunks with the new, compact chunk.
|
||||
mChunks.Clear();
|
||||
if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(Move(newChunk))))) {
|
||||
return HandleError(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
mChunks.Compact();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
SourceBuffer::RoundedUpCapacity(size_t aCapacity)
|
||||
{
|
||||
// Protect against overflow.
|
||||
if (MOZ_UNLIKELY(SIZE_MAX - aCapacity < MIN_CHUNK_CAPACITY)) {
|
||||
return Nothing();
|
||||
return aCapacity;
|
||||
}
|
||||
|
||||
// Round up to the next multiple of MIN_CHUNK_CAPACITY (which should be the
|
||||
@ -91,15 +176,7 @@ SourceBuffer::CreateChunk(size_t aCapacity)
|
||||
MOZ_ASSERT(roundedCapacity >= aCapacity, "Bad math?");
|
||||
MOZ_ASSERT(roundedCapacity - aCapacity < MIN_CHUNK_CAPACITY, "Bad math?");
|
||||
|
||||
// Use the size of the SurfaceCache as an additional heuristic to avoid
|
||||
// allocating huge buffers. Generally images do not get smaller when decoded,
|
||||
// so if we could store the source data in the SurfaceCache, we assume that
|
||||
// there's no way we'll be able to store the decoded version.
|
||||
if (MOZ_UNLIKELY(!SurfaceCache::CanHold(roundedCapacity))) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(Chunk(roundedCapacity));
|
||||
return roundedCapacity;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -291,6 +368,14 @@ SourceBuffer::Complete(nsresult aStatus)
|
||||
|
||||
// Resume any waiting consumers now that we're complete.
|
||||
ResumeWaitingConsumers();
|
||||
|
||||
// If we still have active consumers, just return.
|
||||
if (mConsumerCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to compact our buffer down to a single chunk.
|
||||
Compact();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -323,6 +408,34 @@ SourceBuffer::SizeOfIncludingThisWithComputedFallback(MallocSizeOf
|
||||
return n;
|
||||
}
|
||||
|
||||
SourceBufferIterator
|
||||
SourceBuffer::Iterator()
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mConsumerCount++;
|
||||
}
|
||||
|
||||
return SourceBufferIterator(this);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::OnIteratorRelease()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
MOZ_ASSERT(mConsumerCount > 0, "Consumer count doesn't add up");
|
||||
mConsumerCount--;
|
||||
|
||||
// If we still have active consumers, or we're not complete yet, then return.
|
||||
if (mConsumerCount > 0 || !mStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to compact our buffer down to a single chunk.
|
||||
Compact();
|
||||
}
|
||||
|
||||
bool
|
||||
SourceBuffer::RemainingBytesIsNoMoreThan(const SourceBufferIterator& aIterator,
|
||||
size_t aBytes) const
|
||||
|
@ -91,6 +91,8 @@ public:
|
||||
, mData(aOther.mData)
|
||||
{ }
|
||||
|
||||
~SourceBufferIterator();
|
||||
|
||||
SourceBufferIterator& operator=(SourceBufferIterator&& aOther)
|
||||
{
|
||||
mOwner = Move(aOther.mOwner);
|
||||
@ -250,13 +252,13 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns an iterator to this SourceBuffer.
|
||||
SourceBufferIterator Iterator() { return SourceBufferIterator(this); }
|
||||
SourceBufferIterator Iterator();
|
||||
|
||||
|
||||
private:
|
||||
friend class SourceBufferIterator;
|
||||
|
||||
~SourceBuffer() { }
|
||||
~SourceBuffer();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Chunk type and chunk-related methods.
|
||||
@ -321,7 +323,9 @@ private:
|
||||
};
|
||||
|
||||
nsresult AppendChunk(Maybe<Chunk>&& aChunk);
|
||||
Maybe<Chunk> CreateChunk(size_t aCapacity);
|
||||
Maybe<Chunk> CreateChunk(size_t aCapacity, bool aRoundUp = true);
|
||||
nsresult Compact();
|
||||
static size_t RoundedUpCapacity(size_t aCapacity);
|
||||
size_t FibonacciCapacityWithMinimum(size_t aMinCapacity);
|
||||
|
||||
|
||||
@ -339,6 +343,7 @@ private:
|
||||
bool RemainingBytesIsNoMoreThan(const SourceBufferIterator& aIterator,
|
||||
size_t aBytes) const;
|
||||
|
||||
void OnIteratorRelease();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods.
|
||||
@ -366,6 +371,9 @@ private:
|
||||
|
||||
/// If present, marks this SourceBuffer complete with the given final status.
|
||||
Maybe<nsresult> mStatus;
|
||||
|
||||
/// Count of active consumers.
|
||||
uint32_t mConsumerCount;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
|
Loading…
Reference in New Issue
Block a user