mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
0f0eb9d111
@ -1836,9 +1836,9 @@ pref("ui.key.menuAccessKeyFocuses", true);
|
||||
// Encrypted media extensions.
|
||||
pref("media.eme.enabled", true);
|
||||
pref("media.eme.apiVisible", true);
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
|
||||
#ifdef MOZ_ADOBE_EME
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
pref("media.gmp-eme-adobe.enabled", true);
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s # Bug 1170385 - csp-on-violate-policy message not sent in browser tests with e10s
|
||||
[browser_test_web_manifest.js]
|
||||
[browser_test_web_manifest_mixed_content.js]
|
||||
|
@ -4670,6 +4670,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
|
||||
if (!sw || !sh) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> thebes;
|
||||
RefPtr<DrawTarget> drawDT;
|
||||
// Rendering directly is faster and can be done if mTarget supports Azure
|
||||
@ -4818,6 +4819,51 @@ CanvasRenderingContext2D::AsyncDrawXULElement(nsXULElement& elem,
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::DrawWidgetAsOnScreen(nsGlobalWindow& aWindow,
|
||||
mozilla::ErrorResult& error)
|
||||
{
|
||||
EnsureTarget();
|
||||
|
||||
// This is an internal API.
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
error.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsPresContext> presContext;
|
||||
nsIDocShell* docshell = aWindow.GetDocShell();
|
||||
if (docshell) {
|
||||
docshell->GetPresContext(getter_AddRefs(presContext));
|
||||
}
|
||||
if (!presContext) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
nsIWidget* widget = presContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
RefPtr<SourceSurface> snapshot = widget->SnapshotWidgetOnScreen();
|
||||
if (!snapshot) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
mgfx::Rect sourceRect(mgfx::Point(0, 0), mgfx::Size(snapshot->GetSize()));
|
||||
mTarget->DrawSurface(snapshot, sourceRect, sourceRect,
|
||||
DrawSurfaceOptions(mgfx::Filter::POINT),
|
||||
DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER,
|
||||
AntialiasMode::NONE));
|
||||
mTarget->Flush();
|
||||
|
||||
RedrawUser(gfxRect(0, 0,
|
||||
std::min(mWidth, snapshot->GetSize().width),
|
||||
std::min(mHeight, snapshot->GetSize().height)));
|
||||
}
|
||||
|
||||
//
|
||||
// device pixel getting/setting
|
||||
//
|
||||
|
@ -402,6 +402,7 @@ public:
|
||||
void DrawWindow(nsGlobalWindow& window, double x, double y, double w, double h,
|
||||
const nsAString& bgColor, uint32_t flags,
|
||||
mozilla::ErrorResult& error);
|
||||
void DrawWidgetAsOnScreen(nsGlobalWindow& aWindow, mozilla::ErrorResult& error);
|
||||
void AsyncDrawXULElement(nsXULElement& elem, double x, double y, double w,
|
||||
double h, const nsAString& bgColor, uint32_t flags,
|
||||
mozilla::ErrorResult& error);
|
||||
|
@ -1806,8 +1806,8 @@ SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
|
||||
{
|
||||
if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
// Just memset the rows.
|
||||
uint8_t* row = static_cast<uint8_t*>(data);
|
||||
for (size_t j = 0; j < height; ++j) {
|
||||
uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
|
||||
memset(row, 0xff, width);
|
||||
row += stride;
|
||||
}
|
||||
|
@ -734,10 +734,8 @@ skip-if = os == 'android'
|
||||
[webgl-conformance/_wrappers/test_conformance__rendering__gl-scissor-test.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__rendering__more-than-65536-indices.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__rendering__point-size.html]
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[webgl-conformance/_wrappers/test_conformance__rendering__triangle.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__rendering__line-loop-tri-fan.html]
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[webgl-conformance/_wrappers/test_conformance__state__gl-enable-enum-test.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__state__gl-enum-tests.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__state__gl-get-calls.html]
|
||||
@ -746,7 +744,6 @@ fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[webgl-conformance/_wrappers/test_conformance__state__gl-object-get-calls.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__textures__compressed-tex-image.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html]
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[webgl-conformance/_wrappers/test_conformance__textures__gl-pixelstorei.html]
|
||||
[webgl-conformance/_wrappers/test_conformance__textures__gl-teximage.html]
|
||||
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
|
||||
|
@ -108,15 +108,6 @@ fail-if = (os == 'linux')
|
||||
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
|
||||
# Intermittent crash on OSX.
|
||||
skip-if = os == 'mac'
|
||||
[_wrappers/test_conformance__rendering__line-loop-tri-fan.html]
|
||||
# Fails on OS X 10.10
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[_wrappers/test_conformance__rendering__point-size.html]
|
||||
# Fails on OS X 10.10
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
[_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html]
|
||||
# Fails on OS X 10.10
|
||||
fail-if = (os == 'mac' && os_version == '10.10')
|
||||
|
||||
########################################################################
|
||||
# Win
|
||||
|
@ -140,6 +140,10 @@ public:
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() == aOther.mValue.value();
|
||||
}
|
||||
bool operator != (const TimeUnit& aOther) const {
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() != aOther.mValue.value();
|
||||
}
|
||||
bool operator >= (const TimeUnit& aOther) const {
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() >= aOther.mValue.value();
|
||||
|
@ -41,7 +41,7 @@ class AppendDataRunnable : public nsRunnable {
|
||||
public:
|
||||
AppendDataRunnable(SourceBuffer* aSourceBuffer,
|
||||
MediaLargeByteBuffer* aData,
|
||||
double aTimestampOffset,
|
||||
TimeUnit aTimestampOffset,
|
||||
uint32_t aUpdateID)
|
||||
: mSourceBuffer(aSourceBuffer)
|
||||
, mData(aData)
|
||||
@ -60,7 +60,7 @@ public:
|
||||
private:
|
||||
nsRefPtr<SourceBuffer> mSourceBuffer;
|
||||
nsRefPtr<MediaLargeByteBuffer> mData;
|
||||
double mTimestampOffset;
|
||||
TimeUnit mTimestampOffset;
|
||||
uint32_t mUpdateID;
|
||||
};
|
||||
|
||||
@ -140,10 +140,7 @@ SourceBuffer::GetBuffered(ErrorResult& aRv)
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
// We only manage a single trackbuffer in our source buffer.
|
||||
// As such, there's no need to adjust the end of the trackbuffers as per
|
||||
// Step 4: http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
|
||||
media::TimeIntervals ranges = mTrackBuffer->Buffered();
|
||||
TimeIntervals ranges = mContentManager->Buffered();
|
||||
MSE_DEBUGV("ranges=%s", DumpTimeRanges(ranges).get());
|
||||
nsRefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
|
||||
ranges.ToTimeRanges(tr);
|
||||
@ -175,8 +172,7 @@ SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (IsNaN(aAppendWindowEnd) ||
|
||||
aAppendWindowEnd <= mAppendWindowStart) {
|
||||
if (IsNaN(aAppendWindowEnd) || aAppendWindowEnd <= mAppendWindowStart) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
@ -215,12 +211,9 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
AbortBufferAppend();
|
||||
mTrackBuffer->ResetParserState();
|
||||
mContentManager->ResetParserState();
|
||||
mAppendWindowStart = 0;
|
||||
mAppendWindowEnd = PositiveInfinity<double>();
|
||||
// Discard the current decoder so no new data will be added to it.
|
||||
MSE_DEBUG("Discarding decoder");
|
||||
mTrackBuffer->DiscardCurrentDecoder();
|
||||
}
|
||||
|
||||
void
|
||||
@ -230,7 +223,7 @@ SourceBuffer::AbortBufferAppend()
|
||||
mPendingAppend.DisconnectIfExists();
|
||||
// TODO: Abort segment parser loop, and stream append loop algorithms.
|
||||
// cancel any pending buffer append.
|
||||
mTrackBuffer->AbortAppendData();
|
||||
mContentManager->AbortAppendData();
|
||||
AbortUpdating();
|
||||
}
|
||||
}
|
||||
@ -277,9 +270,9 @@ void
|
||||
SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
|
||||
{
|
||||
MSE_DEBUG("DoRangeRemoval(%f, %f)", aStart, aEnd);
|
||||
if (mTrackBuffer && !IsInfinite(aStart)) {
|
||||
mTrackBuffer->RangeRemoval(media::TimeUnit::FromSeconds(aStart),
|
||||
media::TimeUnit::FromSeconds(aEnd));
|
||||
if (mContentManager && !IsInfinite(aStart)) {
|
||||
mContentManager->RangeRemoval(TimeUnit::FromSeconds(aStart),
|
||||
TimeUnit::FromSeconds(aEnd));
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,10 +282,10 @@ SourceBuffer::Detach()
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("Detach");
|
||||
AbortBufferAppend();
|
||||
if (mTrackBuffer) {
|
||||
mTrackBuffer->Detach();
|
||||
if (mContentManager) {
|
||||
mContentManager->Detach();
|
||||
}
|
||||
mTrackBuffer = nullptr;
|
||||
mContentManager = nullptr;
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
@ -302,7 +295,7 @@ SourceBuffer::Ended()
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsAttached());
|
||||
MSE_DEBUG("Ended");
|
||||
mTrackBuffer->EndCurrentDecoder();
|
||||
mContentManager->Ended();
|
||||
}
|
||||
|
||||
SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
||||
@ -321,9 +314,9 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
||||
MOZ_ASSERT(aMediaSource);
|
||||
mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
|
||||
75 * (1 << 20));
|
||||
mTrackBuffer = new TrackBuffer(aMediaSource->GetDecoder(), aType);
|
||||
MSE_DEBUG("Create mTrackBuffer=%p",
|
||||
mTrackBuffer.get());
|
||||
mContentManager = SourceBufferContentManager::CreateManager(aMediaSource->GetDecoder(), aType);
|
||||
MSE_DEBUG("Create mContentManager=%p",
|
||||
mContentManager.get());
|
||||
}
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
@ -425,12 +418,12 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
|
||||
"We don't handle timestampOffset for sequence mode yet");
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
new AppendDataRunnable(this, data, mTimestampOffset, mUpdateID);
|
||||
new AppendDataRunnable(this, data, TimeUnit::FromSeconds(mTimestampOffset), mUpdateID);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
|
||||
SourceBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
|
||||
uint32_t aUpdateID)
|
||||
{
|
||||
if (!mUpdating || aUpdateID != mUpdateID) {
|
||||
@ -451,14 +444,14 @@ SourceBuffer::AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
|
||||
return;
|
||||
}
|
||||
|
||||
mPendingAppend.Begin(mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)
|
||||
mPendingAppend.Begin(mContentManager->AppendData(aData, aTimestampOffset)
|
||||
->Then(AbstractThread::MainThread(), __func__, this,
|
||||
&SourceBuffer::AppendDataCompletedWithSuccess,
|
||||
&SourceBuffer::AppendDataErrored));
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
|
||||
SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
|
||||
{
|
||||
mPendingAppend.Complete();
|
||||
if (!mUpdating) {
|
||||
@ -466,7 +459,7 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTrackBuffer->HasInitSegment()) {
|
||||
if (aHasActiveTracks) {
|
||||
if (!mActive) {
|
||||
mActive = true;
|
||||
mMediaSource->SourceBufferIsActive(this);
|
||||
@ -474,9 +467,7 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
|
||||
}
|
||||
}
|
||||
|
||||
if (aGotMedia) {
|
||||
CheckEndTime();
|
||||
}
|
||||
CheckEndTime();
|
||||
|
||||
StopUpdating();
|
||||
}
|
||||
@ -504,7 +495,7 @@ SourceBuffer::AppendError(bool aDecoderError)
|
||||
// The buffer append algorithm has been interrupted by abort().
|
||||
return;
|
||||
}
|
||||
mTrackBuffer->ResetParserState();
|
||||
mContentManager->ResetParserState();
|
||||
|
||||
mUpdating = false;
|
||||
|
||||
@ -522,6 +513,8 @@ SourceBuffer::AppendError(bool aDecoderError)
|
||||
already_AddRefed<MediaLargeByteBuffer>
|
||||
SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
|
||||
{
|
||||
typedef SourceBufferContentManager::EvictDataResult Result;
|
||||
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
@ -538,29 +531,29 @@ SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult&
|
||||
// TODO: Make the eviction threshold smaller for audio-only streams.
|
||||
// TODO: Drive evictions off memory pressure notifications.
|
||||
// TODO: Consider a global eviction threshold rather than per TrackBuffer.
|
||||
double newBufferStartTime = 0.0;
|
||||
TimeUnit newBufferStartTime;
|
||||
// Attempt to evict the amount of data we are about to add by lowering the
|
||||
// threshold.
|
||||
uint32_t toEvict =
|
||||
(mEvictionThreshold > aLength) ? mEvictionThreshold - aLength : aLength;
|
||||
bool evicted =
|
||||
mTrackBuffer->EvictData(mMediaSource->GetDecoder()->GetCurrentTime(),
|
||||
toEvict, &newBufferStartTime);
|
||||
if (evicted) {
|
||||
Result evicted =
|
||||
mContentManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()),
|
||||
toEvict, &newBufferStartTime);
|
||||
if (evicted == Result::DATA_EVICTED) {
|
||||
MSE_DEBUG("AppendData Evict; current buffered start=%f",
|
||||
GetBufferedStart());
|
||||
|
||||
// We notify that we've evicted from the time range 0 through to
|
||||
// the current start point.
|
||||
mMediaSource->NotifyEvicted(0.0, newBufferStartTime);
|
||||
mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds());
|
||||
}
|
||||
|
||||
// See if we have enough free space to append our new data.
|
||||
// As we can only evict once we have playable data, we must give a chance
|
||||
// to the DASH player to provide a complete media segment.
|
||||
if (aLength > mEvictionThreshold ||
|
||||
((mTrackBuffer->GetSize() > mEvictionThreshold - aLength) &&
|
||||
!mTrackBuffer->HasOnlyIncompleteMedia())) {
|
||||
((mContentManager->GetSize() > mEvictionThreshold - aLength) &&
|
||||
evicted != Result::CANT_EVICT)) {
|
||||
aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
@ -603,15 +596,15 @@ SourceBuffer::Evict(double aStart, double aEnd)
|
||||
if (currentTime + safety_threshold >= evictTime) {
|
||||
evictTime -= safety_threshold;
|
||||
}
|
||||
mTrackBuffer->EvictBefore(evictTime);
|
||||
mContentManager->EvictBefore(TimeUnit::FromSeconds(evictTime));
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
SourceBuffer::Dump(const char* aPath)
|
||||
{
|
||||
if (mTrackBuffer) {
|
||||
mTrackBuffer->Dump(aPath);
|
||||
if (mContentManager) {
|
||||
mContentManager->Dump(aPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -620,9 +613,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
|
||||
// Tell the TrackBuffer to end its current SourceBufferResource.
|
||||
TrackBuffer* track = tmp->mTrackBuffer;
|
||||
if (track) {
|
||||
track->Detach();
|
||||
SourceBufferContentManager* manager = tmp->mContentManager;
|
||||
if (manager) {
|
||||
manager->Detach();
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nsISupports.h"
|
||||
#include "nsString.h"
|
||||
#include "nscore.h"
|
||||
#include "SourceBufferContentManager.h"
|
||||
|
||||
class JSObject;
|
||||
struct JSContext;
|
||||
@ -33,10 +34,12 @@ class ErrorResult;
|
||||
class MediaLargeByteBuffer;
|
||||
class TrackBuffer;
|
||||
template <typename T> class AsyncEventRunner;
|
||||
typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> TrackBufferAppendPromise;
|
||||
|
||||
namespace dom {
|
||||
|
||||
using media::TimeUnit;
|
||||
using media::TimeIntervals;
|
||||
|
||||
class TimeRanges;
|
||||
|
||||
class SourceBuffer final : public DOMEventTargetHelper
|
||||
@ -147,7 +150,7 @@ private:
|
||||
|
||||
// Shared implementation of AppendBuffer overloads.
|
||||
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
|
||||
void AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
|
||||
void AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
|
||||
uint32_t aAppendID);
|
||||
|
||||
// Implement the "Append Error Algorithm".
|
||||
@ -162,14 +165,14 @@ private:
|
||||
uint32_t aLength,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void AppendDataCompletedWithSuccess(bool aValue);
|
||||
void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
|
||||
void AppendDataErrored(nsresult aError);
|
||||
|
||||
nsRefPtr<MediaSource> mMediaSource;
|
||||
|
||||
uint32_t mEvictionThreshold;
|
||||
|
||||
nsRefPtr<TrackBuffer> mTrackBuffer;
|
||||
nsRefPtr<SourceBufferContentManager> mContentManager;
|
||||
|
||||
double mAppendWindowStart;
|
||||
double mAppendWindowEnd;
|
||||
@ -186,7 +189,7 @@ private:
|
||||
// aborted and another AppendData queued.
|
||||
uint32_t mUpdateID;
|
||||
|
||||
MediaPromiseRequestHolder<TrackBufferAppendPromise> mPendingAppend;
|
||||
MediaPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
|
||||
const nsCString mType;
|
||||
};
|
||||
|
||||
|
20
dom/media/mediasource/SourceBufferContentManager.cpp
Normal file
20
dom/media/mediasource/SourceBufferContentManager.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SourceBufferContentManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
already_AddRefed<SourceBufferContentManager>
|
||||
SourceBufferContentManager::CreateManager(MediaSourceDecoder* aParentDecoder,
|
||||
const nsACString &aType)
|
||||
{
|
||||
nsRefPtr<SourceBufferContentManager> manager;
|
||||
manager = new TrackBuffer(aParentDecoder, aType);
|
||||
return manager.forget();
|
||||
}
|
||||
|
||||
}
|
89
dom/media/mediasource/SourceBufferContentManager.h
Normal file
89
dom/media/mediasource/SourceBufferContentManager.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_
|
||||
#define MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_
|
||||
|
||||
#include "MediaData.h"
|
||||
#include "MediaPromise.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "SourceBuffer.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using media::TimeUnit;
|
||||
using media::TimeIntervals;
|
||||
|
||||
class SourceBufferContentManager {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferContentManager);
|
||||
|
||||
typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> AppendPromise;
|
||||
|
||||
static already_AddRefed<SourceBufferContentManager>
|
||||
CreateManager(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
|
||||
|
||||
// Append data to the current decoder. Also responsible for calling
|
||||
// NotifyDataArrived on the decoder to keep buffered range computation up
|
||||
// to date. Returns false if the append failed.
|
||||
virtual nsRefPtr<AppendPromise>
|
||||
AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset /* microseconds */) = 0;
|
||||
|
||||
// Abort any pending AppendData.
|
||||
virtual void AbortAppendData() = 0;
|
||||
|
||||
// Run MSE Reset Parser State Algorithm.
|
||||
// 3.5.2 Reset Parser State
|
||||
// http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
|
||||
virtual void ResetParserState() = 0;
|
||||
|
||||
// Runs MSE range removal algorithm.
|
||||
// http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
|
||||
virtual bool RangeRemoval(TimeUnit aStart, TimeUnit aEnd) = 0;
|
||||
|
||||
enum class EvictDataResult : int8_t
|
||||
{
|
||||
NO_DATA_EVICTED,
|
||||
DATA_EVICTED,
|
||||
CANT_EVICT,
|
||||
};
|
||||
|
||||
// Evicts data up to aPlaybackTime. aThreshold is used to
|
||||
// bound the data being evicted. It will not evict more than aThreshold
|
||||
// bytes. aBufferStartTime contains the new start time of the data after the
|
||||
// eviction.
|
||||
virtual EvictDataResult
|
||||
EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) = 0;
|
||||
|
||||
// Evicts data up to aTime.
|
||||
virtual void EvictBefore(TimeUnit aTime) = 0;
|
||||
|
||||
// Returns the buffered range currently managed.
|
||||
// This may be called on any thread.
|
||||
// Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
|
||||
virtual media::TimeIntervals Buffered() = 0;
|
||||
|
||||
// Return the size of the data managed by this SourceBufferContentManager.
|
||||
virtual int64_t GetSize() = 0;
|
||||
|
||||
// Indicate that the MediaSource parent object got into "ended" state.
|
||||
virtual void Ended() = 0;
|
||||
|
||||
// The parent SourceBuffer is about to be destroyed.
|
||||
virtual void Detach() = 0;
|
||||
|
||||
#if defined(DEBUG)
|
||||
virtual void Dump(const char* aPath) { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual ~SourceBufferContentManager() { }
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_ */
|
@ -42,8 +42,6 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a
|
||||
: mParentDecoder(aParentDecoder)
|
||||
, mType(aType)
|
||||
, mLastStartTimestamp(0)
|
||||
, mLastTimestampOffset(0)
|
||||
, mAdjustedTimestamp(0)
|
||||
, mIsWaitingOnCDM(false)
|
||||
, mShutdown(false)
|
||||
{
|
||||
@ -75,7 +73,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool NewDecoder(int64_t aTimestampOffset)
|
||||
bool NewDecoder(TimeUnit aTimestampOffset)
|
||||
{
|
||||
nsRefPtr<SourceBufferDecoder> decoder = mOwner->NewDecoder(aTimestampOffset);
|
||||
if (!decoder) {
|
||||
@ -140,14 +138,14 @@ TrackBuffer::ContinueShutdown()
|
||||
mShutdownPromise.Resolve(true, __func__);
|
||||
}
|
||||
|
||||
nsRefPtr<TrackBufferAppendPromise>
|
||||
TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
|
||||
nsRefPtr<TrackBuffer::AppendPromise>
|
||||
TrackBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInitializationPromise.IsEmpty());
|
||||
|
||||
DecodersToInitialize decoders(this);
|
||||
nsRefPtr<TrackBufferAppendPromise> p = mInitializationPromise.Ensure(__func__);
|
||||
nsRefPtr<AppendPromise> p = mInitializationPromise.Ensure(__func__);
|
||||
bool hadInitData = mParser->HasInitData();
|
||||
bool hadCompleteInitData = mParser->HasCompleteInitData();
|
||||
nsRefPtr<MediaLargeByteBuffer> oldInit = mParser->InitData();
|
||||
@ -221,11 +219,13 @@ TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
|
||||
mLastEndTimestamp.emplace(end);
|
||||
}
|
||||
|
||||
if (gotMedia && start != mAdjustedTimestamp &&
|
||||
((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && start < mAdjustedTimestamp) ||
|
||||
(start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || start < mAdjustedTimestamp)))) {
|
||||
AdjustDecodersTimestampOffset(mAdjustedTimestamp - start);
|
||||
mAdjustedTimestamp = start;
|
||||
TimeUnit starttu{TimeUnit::FromMicroseconds(start)};
|
||||
|
||||
if (gotMedia && starttu != mAdjustedTimestamp &&
|
||||
((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && starttu < mAdjustedTimestamp) ||
|
||||
(start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || starttu < mAdjustedTimestamp)))) {
|
||||
AdjustDecodersTimestampOffset(mAdjustedTimestamp - starttu);
|
||||
mAdjustedTimestamp = starttu;
|
||||
}
|
||||
|
||||
if (!AppendDataToCurrentResource(aData, end - start)) {
|
||||
@ -243,7 +243,7 @@ TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
|
||||
// required when data is appended.
|
||||
NotifyTimeRangesChanged();
|
||||
|
||||
mInitializationPromise.Resolve(gotMedia, __func__);
|
||||
mInitializationPromise.Resolve(HasInitSegment(), __func__);
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -282,48 +282,49 @@ class DecoderSorter
|
||||
public:
|
||||
bool LessThan(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const
|
||||
{
|
||||
media::TimeIntervals first = aFirst->GetBuffered();
|
||||
media::TimeIntervals second = aSecond->GetBuffered();
|
||||
TimeIntervals first = aFirst->GetBuffered();
|
||||
TimeIntervals second = aSecond->GetBuffered();
|
||||
|
||||
return first.GetStart() < second.GetStart();
|
||||
}
|
||||
|
||||
bool Equals(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const
|
||||
{
|
||||
media::TimeIntervals first = aFirst->GetBuffered();
|
||||
media::TimeIntervals second = aSecond->GetBuffered();
|
||||
TimeIntervals first = aFirst->GetBuffered();
|
||||
TimeIntervals second = aSecond->GetBuffered();
|
||||
|
||||
return first.GetStart() == second.GetStart();
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
TrackBuffer::EvictData(double aPlaybackTime,
|
||||
TrackBuffer::EvictDataResult
|
||||
TrackBuffer::EvictData(TimeUnit aPlaybackTime,
|
||||
uint32_t aThreshold,
|
||||
double* aBufferStartTime)
|
||||
TimeUnit* aBufferStartTime)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
if (!mCurrentDecoder) {
|
||||
return false;
|
||||
if (!mCurrentDecoder || mInitializedDecoders.IsEmpty()) {
|
||||
return EvictDataResult::CANT_EVICT;
|
||||
}
|
||||
|
||||
int64_t totalSize = GetSize();
|
||||
|
||||
int64_t toEvict = totalSize - aThreshold;
|
||||
if (toEvict <= 0 || mInitializedDecoders.IsEmpty()) {
|
||||
return false;
|
||||
if (toEvict <= 0) {
|
||||
return EvictDataResult::NO_DATA_EVICTED;
|
||||
}
|
||||
|
||||
// Get a list of initialized decoders.
|
||||
nsTArray<SourceBufferDecoder*> decoders;
|
||||
decoders.AppendElements(mInitializedDecoders);
|
||||
const TimeUnit evictThresholdTime{TimeUnit::FromSeconds(MSE_EVICT_THRESHOLD_TIME)};
|
||||
|
||||
// First try to evict data before the current play position, starting
|
||||
// with the oldest decoder.
|
||||
for (uint32_t i = 0; i < decoders.Length() && toEvict > 0; ++i) {
|
||||
media::TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
|
||||
MSE_DEBUG("Step1. decoder=%u/%u threshold=%u toEvict=%lld",
|
||||
i, decoders.Length(), aThreshold, toEvict);
|
||||
@ -331,9 +332,8 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
// To ensure we don't evict data past the current playback position
|
||||
// we apply a threshold of a few seconds back and evict data up to
|
||||
// that point.
|
||||
if (aPlaybackTime > MSE_EVICT_THRESHOLD_TIME) {
|
||||
media::TimeUnit time = media::TimeUnit::FromSeconds(aPlaybackTime) -
|
||||
media::TimeUnit::FromSeconds(MSE_EVICT_THRESHOLD_TIME);
|
||||
if (aPlaybackTime > evictThresholdTime) {
|
||||
TimeUnit time = aPlaybackTime - evictThresholdTime;
|
||||
bool isActive = decoders[i] == mCurrentDecoder ||
|
||||
mParentDecoder->IsActiveReader(decoders[i]->GetReader());
|
||||
if (!isActive && buffered.GetEnd() < time) {
|
||||
@ -341,16 +341,16 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
// It can be fully evicted.
|
||||
MSE_DEBUG("evicting all bufferedEnd=%f "
|
||||
"aPlaybackTime=%f time=%f, size=%lld",
|
||||
buffered.GetEnd().ToSeconds(), aPlaybackTime, time,
|
||||
decoders[i]->GetResource()->GetSize());
|
||||
buffered.GetEnd().ToSeconds(), aPlaybackTime.ToSeconds(),
|
||||
time, decoders[i]->GetResource()->GetSize());
|
||||
toEvict -= decoders[i]->GetResource()->EvictAll();
|
||||
} else {
|
||||
int64_t playbackOffset =
|
||||
decoders[i]->ConvertToByteOffset(time.ToSeconds());
|
||||
MSE_DEBUG("evicting some bufferedEnd=%f "
|
||||
"aPlaybackTime=%f time=%f, playbackOffset=%lld size=%lld",
|
||||
buffered.GetEnd().ToSeconds(), aPlaybackTime, time,
|
||||
playbackOffset, decoders[i]->GetResource()->GetSize());
|
||||
buffered.GetEnd().ToSeconds(), aPlaybackTime.ToSeconds(),
|
||||
time, playbackOffset, decoders[i]->GetResource()->GetSize());
|
||||
if (playbackOffset > 0) {
|
||||
ErrorResult rv;
|
||||
toEvict -= decoders[i]->GetResource()->EvictData(playbackOffset,
|
||||
@ -358,7 +358,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
return EvictDataResult::CANT_EVICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -376,7 +376,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
if (decoders[i] == mCurrentDecoder) {
|
||||
continue;
|
||||
}
|
||||
media::TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
|
||||
// Remove data from older decoders than the current one.
|
||||
MSE_DEBUG("evicting all "
|
||||
@ -406,7 +406,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
// Find the next decoder we're likely going to play with.
|
||||
nsRefPtr<SourceBufferDecoder> nextPlayingDecoder = nullptr;
|
||||
if (playingDecoder) {
|
||||
media::TimeIntervals buffered = playingDecoder->GetBuffered();
|
||||
TimeIntervals buffered = playingDecoder->GetBuffered();
|
||||
nextPlayingDecoder =
|
||||
mParentDecoder->SelectDecoder(buffered.GetEnd().ToMicroseconds() + 1,
|
||||
EOS_FUZZ_US,
|
||||
@ -423,7 +423,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
decoders[i] == mCurrentDecoder) {
|
||||
continue;
|
||||
}
|
||||
media::TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
|
||||
MSE_DEBUG("evicting all "
|
||||
"bufferedStart=%f bufferedEnd=%f aPlaybackTime=%f size=%lld",
|
||||
@ -438,12 +438,12 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
bool evicted = toEvict < (totalSize - aThreshold);
|
||||
if (evicted) {
|
||||
if (playingDecoder) {
|
||||
media::TimeIntervals ranges = playingDecoder->GetBuffered();
|
||||
*aBufferStartTime = std::max(0.0, ranges.GetStart().ToSeconds());
|
||||
TimeIntervals ranges = playingDecoder->GetBuffered();
|
||||
*aBufferStartTime = std::max(TimeUnit::FromSeconds(0), ranges.GetStart());
|
||||
} else {
|
||||
// We do not currently have data to play yet.
|
||||
// Avoid evicting anymore data to minimize rebuffering time.
|
||||
*aBufferStartTime = 0.0;
|
||||
*aBufferStartTime = TimeUnit::FromSeconds(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,7 +451,9 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
NotifyTimeRangesChanged();
|
||||
}
|
||||
|
||||
return evicted;
|
||||
return evicted ?
|
||||
EvictDataResult::DATA_EVICTED :
|
||||
(HasOnlyIncompleteMedia() ? EvictDataResult::CANT_EVICT : EvictDataResult::NO_DATA_EVICTED);
|
||||
}
|
||||
|
||||
void
|
||||
@ -461,7 +463,7 @@ TrackBuffer::RemoveEmptyDecoders(nsTArray<mozilla::SourceBufferDecoder*>& aDecod
|
||||
|
||||
// Remove decoders that have no data in them
|
||||
for (uint32_t i = 0; i < aDecoders.Length(); ++i) {
|
||||
media::TimeIntervals buffered = aDecoders[i]->GetBuffered();
|
||||
TimeIntervals buffered = aDecoders[i]->GetBuffered();
|
||||
MSE_DEBUG("maybe remove empty decoders=%d "
|
||||
"size=%lld start=%f end=%f",
|
||||
i, aDecoders[i]->GetResource()->GetSize(),
|
||||
@ -495,7 +497,7 @@ TrackBuffer::HasOnlyIncompleteMedia()
|
||||
if (!mCurrentDecoder) {
|
||||
return false;
|
||||
}
|
||||
media::TimeIntervals buffered = mCurrentDecoder->GetBuffered();
|
||||
TimeIntervals buffered = mCurrentDecoder->GetBuffered();
|
||||
MSE_DEBUG("mCurrentDecoder.size=%lld, start=%f end=%f",
|
||||
mCurrentDecoder->GetResource()->GetSize(),
|
||||
buffered.GetStart(), buffered.GetEnd());
|
||||
@ -503,12 +505,12 @@ TrackBuffer::HasOnlyIncompleteMedia()
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::EvictBefore(double aTime)
|
||||
TrackBuffer::EvictBefore(TimeUnit aTime)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
|
||||
int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime);
|
||||
int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime.ToSeconds());
|
||||
if (endOffset > 0) {
|
||||
MSE_DEBUG("decoder=%u offset=%lld",
|
||||
i, endOffset);
|
||||
@ -524,12 +526,12 @@ TrackBuffer::EvictBefore(double aTime)
|
||||
NotifyTimeRangesChanged();
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
TimeIntervals
|
||||
TrackBuffer::Buffered()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
media::TimeIntervals buffered;
|
||||
TimeIntervals buffered;
|
||||
|
||||
for (auto& decoder : mInitializedDecoders) {
|
||||
buffered += decoder->GetBuffered();
|
||||
@ -537,14 +539,14 @@ TrackBuffer::Buffered()
|
||||
// mParser may not be initialized yet, and will only be so if we have a
|
||||
// buffered range.
|
||||
if (buffered.Length()) {
|
||||
buffered.SetFuzz(media::TimeUnit::FromMicroseconds(mParser->GetRoundingError()));
|
||||
buffered.SetFuzz(TimeUnit::FromMicroseconds(mParser->GetRoundingError()));
|
||||
}
|
||||
|
||||
return buffered;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceBufferDecoder>
|
||||
TrackBuffer::NewDecoder(int64_t aTimestampOffset)
|
||||
TrackBuffer::NewDecoder(TimeUnit aTimestampOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mParentDecoder);
|
||||
@ -552,7 +554,7 @@ TrackBuffer::NewDecoder(int64_t aTimestampOffset)
|
||||
DiscardCurrentDecoder();
|
||||
|
||||
nsRefPtr<SourceBufferDecoder> decoder =
|
||||
mParentDecoder->CreateSubDecoder(mType, aTimestampOffset - mAdjustedTimestamp);
|
||||
mParentDecoder->CreateSubDecoder(mType, (aTimestampOffset - mAdjustedTimestamp).ToMicroseconds());
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -820,7 +822,7 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
|
||||
MSE_DEBUG("Reader %p activated",
|
||||
aDecoder->GetReader());
|
||||
mInitializationPromise.ResolveIfExists(aDecoder->GetRealMediaDuration() > 0, __func__);
|
||||
mInitializationPromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -914,10 +916,10 @@ bool
|
||||
TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
media::TimeUnit time{media::TimeUnit::FromMicroseconds(aTime)};
|
||||
TimeUnit time{TimeUnit::FromMicroseconds(aTime)};
|
||||
for (auto& decoder : mInitializedDecoders) {
|
||||
media::TimeIntervals r = decoder->GetBuffered();
|
||||
r.SetFuzz(media::TimeUnit::FromMicroseconds(aTolerance));
|
||||
TimeIntervals r = decoder->GetBuffered();
|
||||
r.SetFuzz(TimeUnit::FromMicroseconds(aTolerance));
|
||||
if (r.Contains(time)) {
|
||||
return true;
|
||||
}
|
||||
@ -1073,15 +1075,14 @@ TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::RangeRemoval(media::TimeUnit aStart,
|
||||
media::TimeUnit aEnd)
|
||||
TrackBuffer::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
media::TimeIntervals buffered = Buffered();
|
||||
media::TimeUnit bufferedStart = buffered.GetStart();
|
||||
media::TimeUnit bufferedEnd = buffered.GetEnd();
|
||||
TimeIntervals buffered = Buffered();
|
||||
TimeUnit bufferedStart = buffered.GetStart();
|
||||
TimeUnit bufferedEnd = buffered.GetEnd();
|
||||
|
||||
if (!buffered.Length() || aStart > bufferedEnd || aEnd < bufferedStart) {
|
||||
// Nothing to remove.
|
||||
@ -1101,7 +1102,7 @@ TrackBuffer::RangeRemoval(media::TimeUnit aStart,
|
||||
if (aStart <= bufferedStart && aEnd < bufferedEnd) {
|
||||
// Evict data from beginning.
|
||||
for (size_t i = 0; i < decoders.Length(); ++i) {
|
||||
media::TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
TimeIntervals buffered = decoders[i]->GetBuffered();
|
||||
if (buffered.GetEnd() < aEnd) {
|
||||
// Can be fully removed.
|
||||
MSE_DEBUG("remove all bufferedEnd=%f size=%lld",
|
||||
@ -1144,11 +1145,11 @@ TrackBuffer::RangeRemoval(media::TimeUnit aStart,
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::AdjustDecodersTimestampOffset(int32_t aOffset)
|
||||
TrackBuffer::AdjustDecodersTimestampOffset(TimeUnit aOffset)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); i++) {
|
||||
mDecoders[i]->SetTimestampOffset(mDecoders[i]->GetTimestampOffset() + aOffset);
|
||||
mDecoders[i]->SetTimestampOffset(mDecoders[i]->GetTimestampOffset() + aOffset.ToMicroseconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,8 @@ class ContainerParser;
|
||||
class MediaSourceDecoder;
|
||||
class MediaLargeByteBuffer;
|
||||
|
||||
class TrackBuffer final {
|
||||
class TrackBuffer final : public SourceBufferContentManager {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffer);
|
||||
|
||||
TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
|
||||
|
||||
nsRefPtr<ShutdownPromise> Shutdown();
|
||||
@ -35,24 +33,38 @@ public:
|
||||
// Append data to the current decoder. Also responsible for calling
|
||||
// NotifyDataArrived on the decoder to keep buffered range computation up
|
||||
// to date. Returns false if the append failed.
|
||||
nsRefPtr<TrackBufferAppendPromise> AppendData(MediaLargeByteBuffer* aData,
|
||||
int64_t aTimestampOffset /* microseconds */);
|
||||
nsRefPtr<AppendPromise> AppendData(MediaLargeByteBuffer* aData,
|
||||
TimeUnit aTimestampOffset /* microseconds */) override;
|
||||
|
||||
// Evicts data held in the current decoders SourceBufferResource from the
|
||||
// start of the buffer through to aPlaybackTime. aThreshold is used to
|
||||
// bound the data being evicted. It will not evict more than aThreshold
|
||||
// bytes. aBufferStartTime contains the new start time of the current
|
||||
// decoders buffered data after the eviction. Returns true if data was
|
||||
// evicted.
|
||||
bool EvictData(double aPlaybackTime, uint32_t aThreshold, double* aBufferStartTime);
|
||||
// decoders buffered data after the eviction.
|
||||
EvictDataResult EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) override;
|
||||
|
||||
// Evicts data held in all the decoders SourceBufferResource from the start
|
||||
// of the buffer through to aTime.
|
||||
void EvictBefore(double aTime);
|
||||
void EvictBefore(TimeUnit aTime) override;
|
||||
|
||||
bool RangeRemoval(TimeUnit aStart, TimeUnit aEnd) override;
|
||||
|
||||
void AbortAppendData() override;
|
||||
|
||||
int64_t GetSize() override;
|
||||
|
||||
void ResetParserState() override;
|
||||
|
||||
// Returns the union of the decoders buffered ranges in aRanges.
|
||||
// This may be called on any thread.
|
||||
media::TimeIntervals Buffered();
|
||||
media::TimeIntervals Buffered() override;
|
||||
|
||||
void Ended() override
|
||||
{
|
||||
EndCurrentDecoder();
|
||||
}
|
||||
|
||||
void Detach() override;
|
||||
|
||||
// Mark the current decoder's resource as ended, clear mCurrentDecoder and
|
||||
// reset mLast{Start,End}Timestamp. Main thread only.
|
||||
@ -60,8 +72,6 @@ public:
|
||||
// Mark the current decoder's resource as ended.
|
||||
void EndCurrentDecoder();
|
||||
|
||||
void Detach();
|
||||
|
||||
// Returns true if an init segment has been appended.
|
||||
bool HasInitSegment();
|
||||
|
||||
@ -77,30 +87,11 @@ public:
|
||||
|
||||
void BreakCycles();
|
||||
|
||||
// Run MSE Reset Parser State Algorithm.
|
||||
// 3.5.2 Reset Parser State
|
||||
// http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
|
||||
void ResetParserState();
|
||||
|
||||
// Returns a reference to mInitializedDecoders, used by MediaSourceReader
|
||||
// to select decoders.
|
||||
// TODO: Refactor to a cleaner interface between TrackBuffer and MediaSourceReader.
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& Decoders();
|
||||
|
||||
// Runs MSE range removal algorithm.
|
||||
// http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
|
||||
// Implementation is only partial, we can only trim a buffer.
|
||||
// Returns true if data was evicted.
|
||||
// Times are in microseconds.
|
||||
bool RangeRemoval(mozilla::media::TimeUnit aStart,
|
||||
mozilla::media::TimeUnit aEnd);
|
||||
|
||||
// Abort any pending appendBuffer by rejecting any pending promises.
|
||||
void AbortAppendData();
|
||||
|
||||
// Return the size used by all decoders managed by this TrackBuffer.
|
||||
int64_t GetSize();
|
||||
|
||||
// Return true if we have a partial media segment being appended that is
|
||||
// currently not playable.
|
||||
bool HasOnlyIncompleteMedia();
|
||||
@ -116,14 +107,14 @@ public:
|
||||
private:
|
||||
friend class DecodersToInitialize;
|
||||
friend class MetadataRecipient;
|
||||
~TrackBuffer();
|
||||
virtual ~TrackBuffer();
|
||||
|
||||
// Create a new decoder, set mCurrentDecoder to the new decoder and
|
||||
// returns it. The new decoder must be queued using QueueInitializeDecoder
|
||||
// for initialization.
|
||||
// The decoder is not considered initialized until it is added to
|
||||
// mInitializedDecoders.
|
||||
already_AddRefed<SourceBufferDecoder> NewDecoder(int64_t aTimestampOffset /* microseconds */);
|
||||
already_AddRefed<SourceBufferDecoder> NewDecoder(TimeUnit aTimestampOffset);
|
||||
|
||||
// Helper for AppendData, ensures NotifyDataArrived is called whenever
|
||||
// data is appended to the current decoder's SourceBufferResource.
|
||||
@ -201,11 +192,11 @@ private:
|
||||
// AppendData. Accessed on the main thread only.
|
||||
int64_t mLastStartTimestamp;
|
||||
Maybe<int64_t> mLastEndTimestamp;
|
||||
void AdjustDecodersTimestampOffset(int32_t aOffset);
|
||||
void AdjustDecodersTimestampOffset(TimeUnit aOffset);
|
||||
|
||||
// The timestamp offset used by our current decoder, in microseconds.
|
||||
int64_t mLastTimestampOffset;
|
||||
int64_t mAdjustedTimestamp;
|
||||
// The timestamp offset used by our current decoder.
|
||||
TimeUnit mLastTimestampOffset;
|
||||
TimeUnit mAdjustedTimestamp;
|
||||
|
||||
// True if at least one of our decoders has encrypted content.
|
||||
bool mIsWaitingOnCDM;
|
||||
@ -219,7 +210,7 @@ private:
|
||||
bool mDecoderPerSegment;
|
||||
bool mShutdown;
|
||||
|
||||
MediaPromiseHolder<TrackBufferAppendPromise> mInitializationPromise;
|
||||
MediaPromiseHolder<AppendPromise> mInitializationPromise;
|
||||
// Track our request for metadata from the reader.
|
||||
MediaPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ EXPORTS += [
|
||||
'AsyncEventRunner.h',
|
||||
'MediaSourceDecoder.h',
|
||||
'MediaSourceReader.h',
|
||||
'SourceBufferContentManager.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
@ -25,6 +26,7 @@ UNIFIED_SOURCES += [
|
||||
'MediaSourceUtils.cpp',
|
||||
'ResourceQueue.cpp',
|
||||
'SourceBuffer.cpp',
|
||||
'SourceBufferContentManager.cpp',
|
||||
'SourceBufferDecoder.cpp',
|
||||
'SourceBufferList.cpp',
|
||||
'SourceBufferResource.cpp',
|
||||
|
@ -135,11 +135,17 @@ function setupEnvironment() {
|
||||
['media.peerconnection.enabled', true],
|
||||
['media.peerconnection.identity.enabled', true],
|
||||
['media.peerconnection.identity.timeout', 12000],
|
||||
['media.peerconnection.ice.stun_client_maximum_transmits', 14],
|
||||
['media.peerconnection.ice.trickle_grace_period', 30000],
|
||||
['media.navigator.permission.disabled', true],
|
||||
['media.getusermedia.screensharing.enabled', true],
|
||||
['media.getusermedia.screensharing.allowed_domains', "mochi.test"]
|
||||
]
|
||||
}, setTestOptions);
|
||||
|
||||
// We don't care about waiting for this to complete, we just want to ensure
|
||||
// that we don't build up a huge backlog of GC work.
|
||||
SpecialPowers.exactGC(window);
|
||||
}
|
||||
|
||||
// This is called by steeplechase; which provides the test configuration options
|
||||
|
@ -1,7 +1,7 @@
|
||||
[DEFAULT]
|
||||
# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
|
||||
tags = msg webrtc
|
||||
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet')
|
||||
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
|
||||
support-files =
|
||||
head.js
|
||||
dataChannel.js
|
||||
@ -23,13 +23,11 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||
[test_dataChannel_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_dataChannel_basicDataOnly.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_dataChannel_basicVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_dataChannel_bug1013809.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
|
||||
[test_dataChannel_noOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_enumerateDevices.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_getUserMedia_basicAudio.html]
|
||||
@ -45,41 +43,29 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no
|
||||
[test_getUserMedia_basicVideoAudio.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange
|
||||
[test_getUserMedia_constraints.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_callbacks.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
|
||||
[test_getUserMedia_gumWithinGum.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_playAudioTwice.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_playVideoAudioTwice.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
|
||||
[test_getUserMedia_playVideoTwice.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
|
||||
[test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_peerIdentity.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing slow on b2g)
|
||||
[test_peerConnection_addIceCandidate.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_basicAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_basicAudioVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_basicAudioVideoNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_basicVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_basicScreenshare.html]
|
||||
@ -93,15 +79,12 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e1
|
||||
[test_peerConnection_basicH264Video.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_peerConnection_bug822674.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_bug825703.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_bug827843.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_bug834153.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_bug1013809.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_bug1042791.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_peerConnection_capturedVideo.html]
|
||||
@ -112,19 +95,16 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_close.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_noTrickleAnswer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_noTrickleOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_noTrickleOfferAnswer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_offerRequiresReceiveAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_offerRequiresReceiveVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
|
||||
@ -138,62 +118,55 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||
[test_peerConnection_syncSetDescription.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_setLocalAnswerInStable.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_setRemoteAnswerInStable.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_setRemoteOfferInHaveLocalOffer.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_throwInCallbacks.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_toJSON.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
|
||||
[test_peerConnection_twoAudioStreams.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_twoAudioTracksInOneStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_twoAudioVideoStreams.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_twoVideoStreams.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_twoVideoTracksInOneStream.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet') # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_addSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_answererAddSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeThenAddAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_addSecondVideoStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeVideoTrack.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeThenAddVideoTrack.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_replaceVideoThenRenegotiate.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_addSecondAudioStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeThenAddAudioTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_addSecondVideoStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeThenAddVideoTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_addDataChannel.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
|
||||
[test_peerConnection_addDataChannelNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
|
||||
[test_peerConnection_webAudio.html]
|
||||
tags = webaudio webrtc
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
|
@ -615,7 +615,7 @@ function DataChannelWrapper(dataChannel, peerConnectionWrapper) {
|
||||
is(this.readyState, "open", "data channel is 'open' after 'onopen'");
|
||||
resolve(this);
|
||||
};
|
||||
}), 60000, "channel didn't open in time");
|
||||
}), 180000, "channel didn't open in time");
|
||||
}
|
||||
|
||||
DataChannelWrapper.prototype = {
|
||||
|
@ -224,6 +224,18 @@ interface CanvasRenderingContext2D {
|
||||
void asyncDrawXULElement(XULElement elem, double x, double y, double w,
|
||||
double h, DOMString bgColor,
|
||||
optional unsigned long flags = 0);
|
||||
|
||||
/**
|
||||
* Render the root widget of a window into the canvas. Unlike drawWindow,
|
||||
* this uses the operating system to snapshot the widget on-screen, rather
|
||||
* than reading from our own compositor.
|
||||
*
|
||||
* Currently, this is only supported on Windows, and only on widgets that
|
||||
* use OMTC, and only from within the chrome process.
|
||||
*/
|
||||
[Throws, ChromeOnly]
|
||||
void drawWidgetAsOnScreen(Window window);
|
||||
|
||||
/**
|
||||
* This causes a context that is currently using a hardware-accelerated
|
||||
* backend to fallback to a software one. All state should be preserved.
|
||||
|
@ -2565,10 +2565,9 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
||||
{
|
||||
ScopedBindFramebuffer autoFB(this);
|
||||
|
||||
// Even though we're reading. We're doing it on
|
||||
// the producer side. So we call ProducerAcquire
|
||||
// instead of ConsumerAcquire.
|
||||
src->ProducerAcquire();
|
||||
// We're consuming from the producer side, so which do we use?
|
||||
// Really, we just want a read-only lock, so ConsumerAcquire is the best match.
|
||||
src->ProducerReadAcquire();
|
||||
|
||||
if (src->mAttachType == AttachmentType::Screen) {
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
||||
@ -2595,7 +2594,7 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
||||
|
||||
ReadPixelsIntoDataSurface(this, dest);
|
||||
|
||||
src->ProducerRelease();
|
||||
src->ProducerReadRelease();
|
||||
}
|
||||
|
||||
if (tempFB)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "../layers/ipc/ShadowLayers.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
@ -39,55 +40,43 @@ GLScreenBuffer::Create(GLContext* gl,
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
UniquePtr<SurfaceFactory> factory;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
/* On B2G, we want a Gralloc factory, and we want one right at the start */
|
||||
layers::ISurfaceAllocator* allocator = caps.surfaceAllocator;
|
||||
if (!factory &&
|
||||
allocator &&
|
||||
XRE_GetProcessType() != GeckoProcessType_Default)
|
||||
{
|
||||
layers::TextureFlags flags = layers::TextureFlags::DEALLOCATE_CLIENT |
|
||||
layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
if (!caps.premultAlpha) {
|
||||
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
if (!caps.premultAlpha) {
|
||||
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
factory = MakeUnique<SurfaceFactory_Gralloc>(gl, caps, flags,
|
||||
allocator);
|
||||
}
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
/* On OSX, we want an IOSurface factory, and we want one right at the start */
|
||||
if (!factory) {
|
||||
factory = SurfaceFactory_IOSurface::Create(gl, caps);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!factory) {
|
||||
factory = MakeUnique<SurfaceFactory_Basic>(gl, caps);
|
||||
}
|
||||
UniquePtr<SurfaceFactory> factory = MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
|
||||
|
||||
ret.reset( new GLScreenBuffer(gl, caps, Move(factory)) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
GLScreenBuffer::GLScreenBuffer(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
UniquePtr<SurfaceFactory> factory)
|
||||
: mGL(gl)
|
||||
, mCaps(caps)
|
||||
, mFactory(Move(factory))
|
||||
, mNeedsBlit(true)
|
||||
, mUserReadBufferMode(LOCAL_GL_BACK)
|
||||
, mUserDrawFB(0)
|
||||
, mUserReadFB(0)
|
||||
, mInternalDrawFB(0)
|
||||
, mInternalReadFB(0)
|
||||
#ifdef DEBUG
|
||||
, mInInternalMode_DrawFB(true)
|
||||
, mInInternalMode_ReadFB(true)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
GLScreenBuffer::~GLScreenBuffer()
|
||||
{
|
||||
mFactory = nullptr;
|
||||
mDraw = nullptr;
|
||||
mRead = nullptr;
|
||||
|
||||
// bug 914823: it is crucial to destroy the Factory _after_ we destroy
|
||||
// the SharedSurfaces around here! Reason: the shared surfaces will want
|
||||
// to ask the Allocator (e.g. the ClientLayerManager) to destroy their
|
||||
// buffers, but that Allocator may be kept alive by the Factory,
|
||||
// as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
|
||||
// to the Allocator!
|
||||
mFactory = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
|
||||
{
|
||||
@ -465,7 +454,7 @@ GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
|
||||
bool
|
||||
GLScreenBuffer::Swap(const gfx::IntSize& size)
|
||||
{
|
||||
RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
|
||||
RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
|
||||
if (!newBack)
|
||||
return false;
|
||||
|
||||
@ -522,7 +511,7 @@ GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
|
||||
bool
|
||||
GLScreenBuffer::Resize(const gfx::IntSize& size)
|
||||
{
|
||||
RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
|
||||
RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
|
||||
if (!newBack)
|
||||
return false;
|
||||
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include "SurfaceTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class SharedSurfaceTextureClient;
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
|
||||
class GLContext;
|
||||
@ -136,8 +140,8 @@ public:
|
||||
protected:
|
||||
UniquePtr<SurfaceFactory> mFactory;
|
||||
|
||||
RefPtr<ShSurfHandle> mBack;
|
||||
RefPtr<ShSurfHandle> mFront;
|
||||
RefPtr<layers::SharedSurfaceTextureClient> mBack;
|
||||
RefPtr<layers::SharedSurfaceTextureClient> mFront;
|
||||
|
||||
UniquePtr<DrawBuffer> mDraw;
|
||||
UniquePtr<ReadBuffer> mRead;
|
||||
@ -159,21 +163,7 @@ protected:
|
||||
|
||||
GLScreenBuffer(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
UniquePtr<SurfaceFactory> factory)
|
||||
: mGL(gl)
|
||||
, mCaps(caps)
|
||||
, mFactory(Move(factory))
|
||||
, mNeedsBlit(true)
|
||||
, mUserReadBufferMode(LOCAL_GL_BACK)
|
||||
, mUserDrawFB(0)
|
||||
, mUserReadFB(0)
|
||||
, mInternalDrawFB(0)
|
||||
, mInternalReadFB(0)
|
||||
#ifdef DEBUG
|
||||
, mInInternalMode_DrawFB(true)
|
||||
, mInInternalMode_ReadFB(true)
|
||||
#endif
|
||||
{}
|
||||
UniquePtr<SurfaceFactory> factory);
|
||||
|
||||
public:
|
||||
virtual ~GLScreenBuffer();
|
||||
@ -182,7 +172,7 @@ public:
|
||||
return mFactory.get();
|
||||
}
|
||||
|
||||
ShSurfHandle* Front() const {
|
||||
const RefPtr<layers::SharedSurfaceTextureClient>& Front() const {
|
||||
return mFront;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "SharedSurfaceGL.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
@ -32,12 +35,9 @@ SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
dest->mAttachType == AttachmentType::Screen)
|
||||
{
|
||||
// Here, we actually need to blit through a temp surface, so let's make one.
|
||||
UniquePtr<SharedSurface_GLTexture> tempSurf;
|
||||
tempSurf = SharedSurface_GLTexture::Create(gl,
|
||||
gl,
|
||||
factory->mFormats,
|
||||
src->mSize,
|
||||
factory->mCaps.alpha);
|
||||
UniquePtr<SharedSurface_Basic> tempSurf;
|
||||
tempSurf = SharedSurface_Basic::Create(gl, factory->mFormats, src->mSize,
|
||||
factory->mCaps.alpha);
|
||||
|
||||
ProdCopy(src, tempSurf.get(), factory);
|
||||
ProdCopy(tempSurf.get(), dest, factory);
|
||||
@ -203,20 +203,21 @@ SharedSurface::SharedSurface(SharedSurfaceType type,
|
||||
AttachmentType attachType,
|
||||
GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha)
|
||||
bool hasAlpha,
|
||||
bool canRecycle)
|
||||
: mType(type)
|
||||
, mAttachType(attachType)
|
||||
, mGL(gl)
|
||||
, mSize(size)
|
||||
, mHasAlpha(hasAlpha)
|
||||
, mCanRecycle(canRecycle)
|
||||
, mIsLocked(false)
|
||||
, mIsProducerAcquired(false)
|
||||
, mIsConsumerAcquired(false)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
void
|
||||
SharedSurface::LockProd()
|
||||
@ -262,8 +263,6 @@ SharedSurface::PollSync_ContentThread()
|
||||
return PollSync_ContentThread_Impl();
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceFactory
|
||||
|
||||
@ -301,12 +300,15 @@ ChooseBufferBits(const SurfaceCaps& caps,
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceFactory::SurfaceFactory(GLContext* gl,
|
||||
SharedSurfaceType type,
|
||||
const SurfaceCaps& caps)
|
||||
: mGL(gl)
|
||||
SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags)
|
||||
: mType(type)
|
||||
, mGL(gl)
|
||||
, mCaps(caps)
|
||||
, mType(type)
|
||||
, mAllocator(allocator)
|
||||
, mFlags(flags)
|
||||
, mFormats(gl->ChooseGLFormats(caps))
|
||||
{
|
||||
ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
|
||||
@ -314,51 +316,95 @@ SurfaceFactory::SurfaceFactory(GLContext* gl,
|
||||
|
||||
SurfaceFactory::~SurfaceFactory()
|
||||
{
|
||||
while (!mScraps.Empty()) {
|
||||
mScraps.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<SharedSurface>
|
||||
SurfaceFactory::NewSharedSurface(const gfx::IntSize& size)
|
||||
{
|
||||
// Attempt to reuse an old surface.
|
||||
while (!mScraps.Empty()) {
|
||||
UniquePtr<SharedSurface> cur = mScraps.Pop();
|
||||
|
||||
if (cur->mSize == size)
|
||||
return Move(cur);
|
||||
|
||||
// Let `cur` be destroyed as it falls out of scope, if it wasn't
|
||||
// moved.
|
||||
while (!mRecycleTotalPool.empty()) {
|
||||
StopRecycling(*mRecycleTotalPool.begin());
|
||||
}
|
||||
|
||||
return CreateShared(size);
|
||||
MOZ_RELEASE_ASSERT(mRecycleTotalPool.empty());
|
||||
|
||||
// If we mRecycleFreePool.clear() before StopRecycling(), we may try to recycle it,
|
||||
// fail, call StopRecycling(), then return here and call it again.
|
||||
mRecycleFreePool.clear();
|
||||
}
|
||||
|
||||
TemporaryRef<ShSurfHandle>
|
||||
SurfaceFactory::NewShSurfHandle(const gfx::IntSize& size)
|
||||
TemporaryRef<layers::SharedSurfaceTextureClient>
|
||||
SurfaceFactory::NewTexClient(const gfx::IntSize& size)
|
||||
{
|
||||
auto surf = NewSharedSurface(size);
|
||||
while (!mRecycleFreePool.empty()) {
|
||||
RefPtr<layers::SharedSurfaceTextureClient> cur = mRecycleFreePool.front();
|
||||
mRecycleFreePool.pop();
|
||||
|
||||
if (cur->Surf()->mSize == size) {
|
||||
return cur.forget();
|
||||
}
|
||||
|
||||
StopRecycling(cur);
|
||||
}
|
||||
|
||||
UniquePtr<SharedSurface> surf = Move(CreateShared(size));
|
||||
if (!surf)
|
||||
return nullptr;
|
||||
|
||||
// Before next use, wait until SharedSurface's buffer
|
||||
// is no longer being used.
|
||||
surf->WaitForBufferOwnership();
|
||||
RefPtr<layers::SharedSurfaceTextureClient> ret;
|
||||
ret = new layers::SharedSurfaceTextureClient(mAllocator, mFlags, Move(surf), this);
|
||||
|
||||
return MakeAndAddRef<ShSurfHandle>(this, Move(surf));
|
||||
StartRecycling(ret);
|
||||
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
// Auto-deletes surfs of the wrong type.
|
||||
void
|
||||
SurfaceFactory::Recycle(UniquePtr<SharedSurface> surf)
|
||||
SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc)
|
||||
{
|
||||
MOZ_ASSERT(surf);
|
||||
tc->SetRecycleCallback(&SurfaceFactory::RecycleCallback, static_cast<void*>(this));
|
||||
|
||||
if (surf->mType == mType) {
|
||||
mScraps.Push(Move(surf));
|
||||
bool didInsert = mRecycleTotalPool.insert(tc);
|
||||
MOZ_RELEASE_ASSERT(didInsert);
|
||||
mozilla::unused << didInsert;
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
|
||||
{
|
||||
// Must clear before releasing ref.
|
||||
tc->ClearRecycleCallback();
|
||||
|
||||
bool didErase = mRecycleTotalPool.erase(tc);
|
||||
MOZ_RELEASE_ASSERT(didErase);
|
||||
mozilla::unused << didErase;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<layers::SharedSurfaceTextureClient> tc;
|
||||
tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
|
||||
|
||||
SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
|
||||
|
||||
if (tc->mSurf->mCanRecycle) {
|
||||
if (factory->Recycle(tc))
|
||||
return;
|
||||
}
|
||||
|
||||
// Did not recover the tex client. End the (re)cycle!
|
||||
factory->StopRecycling(tc);
|
||||
}
|
||||
|
||||
bool
|
||||
SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient)
|
||||
{
|
||||
MOZ_ASSERT(texClient);
|
||||
|
||||
if (mRecycleFreePool.size() >= 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<layers::SharedSurfaceTextureClient> texClientRef = texClient;
|
||||
mRecycleFreePool.push(texClientRef);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define SHARED_SURFACE_H_
|
||||
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "GLContextTypes.h"
|
||||
@ -34,6 +35,15 @@ namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
class ISurfaceAllocator;
|
||||
class SharedSurfaceTextureClient;
|
||||
enum class TextureFlags : uint32_t;
|
||||
class SurfaceDescriptor;
|
||||
class TextureClient;
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
|
||||
class GLContext;
|
||||
@ -51,6 +61,7 @@ public:
|
||||
GLContext* const mGL;
|
||||
const gfx::IntSize mSize;
|
||||
const bool mHasAlpha;
|
||||
const bool mCanRecycle;
|
||||
protected:
|
||||
bool mIsLocked;
|
||||
bool mIsProducerAcquired;
|
||||
@ -61,7 +72,8 @@ protected:
|
||||
AttachmentType attachType,
|
||||
GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha);
|
||||
bool hasAlpha,
|
||||
bool canRecycle);
|
||||
|
||||
public:
|
||||
virtual ~SharedSurface() {
|
||||
@ -86,6 +98,8 @@ protected:
|
||||
virtual void ProducerReleaseImpl() {
|
||||
Fence();
|
||||
}
|
||||
virtual void ProducerReadAcquireImpl() {}
|
||||
virtual void ProducerReadReleaseImpl() {}
|
||||
virtual void ConsumerAcquireImpl() {
|
||||
WaitSync();
|
||||
}
|
||||
@ -102,6 +116,16 @@ public:
|
||||
ProducerReleaseImpl();
|
||||
mIsProducerAcquired = false;
|
||||
}
|
||||
void ProducerReadAcquire() {
|
||||
MOZ_ASSERT(!mIsProducerAcquired);
|
||||
ProducerReadAcquireImpl();
|
||||
mIsProducerAcquired = true;
|
||||
}
|
||||
void ProducerReadRelease() {
|
||||
MOZ_ASSERT(mIsProducerAcquired);
|
||||
ProducerReadReleaseImpl();
|
||||
mIsProducerAcquired = false;
|
||||
}
|
||||
void ConsumerAcquire() {
|
||||
MOZ_ASSERT(!mIsConsumerAcquired);
|
||||
ConsumerAcquireImpl();
|
||||
@ -173,36 +197,91 @@ public:
|
||||
virtual bool NeedsIndirectReads() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class UniquePtrQueue
|
||||
class RefSet
|
||||
{
|
||||
std::set<T*> mSet;
|
||||
|
||||
public:
|
||||
~RefSet() {
|
||||
clear();
|
||||
}
|
||||
|
||||
auto begin() -> decltype(mSet.begin()) {
|
||||
return mSet.begin();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (auto itr = mSet.begin(); itr != mSet.end(); ++itr) {
|
||||
(*itr)->Release();
|
||||
}
|
||||
mSet.clear();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return mSet.empty();
|
||||
}
|
||||
|
||||
bool insert(T* x) {
|
||||
if (mSet.insert(x).second) {
|
||||
x->AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool erase(T* x) {
|
||||
if (mSet.erase(x)) {
|
||||
x->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class RefQueue
|
||||
{
|
||||
std::queue<T*> mQueue;
|
||||
|
||||
public:
|
||||
~UniquePtrQueue() {
|
||||
MOZ_ASSERT(Empty());
|
||||
~RefQueue() {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
void clear() {
|
||||
while (!empty()) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return mQueue.empty();
|
||||
}
|
||||
|
||||
void Push(UniquePtr<T> up) {
|
||||
T* p = up.release();
|
||||
mQueue.push(p);
|
||||
size_t size() const {
|
||||
return mQueue.size();
|
||||
}
|
||||
|
||||
UniquePtr<T> Pop() {
|
||||
UniquePtr<T> ret;
|
||||
void push(T* x) {
|
||||
mQueue.push(x);
|
||||
x->AddRef();
|
||||
}
|
||||
|
||||
if (!mQueue.empty()) {
|
||||
ret.reset(mQueue.front());
|
||||
mQueue.pop();
|
||||
}
|
||||
T* front() const {
|
||||
return mQueue.front();
|
||||
}
|
||||
|
||||
return Move(ret);
|
||||
void pop() {
|
||||
T* x = mQueue.front();
|
||||
x->Release();
|
||||
mQueue.pop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -213,18 +292,21 @@ public:
|
||||
// with SupportsWeakPtr. (bug 1049278)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SurfaceFactory)
|
||||
|
||||
const SharedSurfaceType mType;
|
||||
GLContext* const mGL;
|
||||
const SurfaceCaps mCaps;
|
||||
const SharedSurfaceType mType;
|
||||
const RefPtr<layers::ISurfaceAllocator> mAllocator;
|
||||
const layers::TextureFlags mFlags;
|
||||
const GLFormats mFormats;
|
||||
|
||||
protected:
|
||||
SurfaceCaps mDrawCaps;
|
||||
SurfaceCaps mReadCaps;
|
||||
RefQueue<layers::SharedSurfaceTextureClient> mRecycleFreePool;
|
||||
RefSet<layers::SharedSurfaceTextureClient> mRecycleTotalPool;
|
||||
|
||||
SurfaceFactory(GLContext* gl,
|
||||
SharedSurfaceType type,
|
||||
const SurfaceCaps& caps);
|
||||
SurfaceFactory(SharedSurfaceType type, GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
public:
|
||||
virtual ~SurfaceFactory();
|
||||
@ -240,44 +322,19 @@ public:
|
||||
protected:
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) = 0;
|
||||
|
||||
UniquePtrQueue<SharedSurface> mScraps;
|
||||
void StartRecycling(layers::SharedSurfaceTextureClient* tc);
|
||||
void SetRecycleCallback(layers::SharedSurfaceTextureClient* tc);
|
||||
void StopRecycling(layers::SharedSurfaceTextureClient* tc);
|
||||
|
||||
public:
|
||||
UniquePtr<SharedSurface> NewSharedSurface(const gfx::IntSize& size);
|
||||
TemporaryRef<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
|
||||
//TemporaryRef<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
|
||||
TemporaryRef<layers::SharedSurfaceTextureClient> NewTexClient(const gfx::IntSize& size);
|
||||
|
||||
static void RecycleCallback(layers::TextureClient* tc, void* /*closure*/);
|
||||
|
||||
// Auto-deletes surfs of the wrong type.
|
||||
void Recycle(UniquePtr<SharedSurface> surf);
|
||||
};
|
||||
|
||||
class ShSurfHandle : public RefCounted<ShSurfHandle>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(ShSurfHandle)
|
||||
|
||||
private:
|
||||
const WeakPtr<SurfaceFactory> mFactory;
|
||||
UniquePtr<SharedSurface> mSurf;
|
||||
|
||||
public:
|
||||
ShSurfHandle(SurfaceFactory* factory, UniquePtr<SharedSurface> surf)
|
||||
: mFactory(factory)
|
||||
, mSurf(Move(surf))
|
||||
{
|
||||
MOZ_ASSERT(mFactory);
|
||||
MOZ_ASSERT(mSurf);
|
||||
}
|
||||
|
||||
~ShSurfHandle() {
|
||||
if (mFactory) {
|
||||
mFactory->Recycle(Move(mSurf));
|
||||
}
|
||||
}
|
||||
|
||||
SharedSurface* Surf() const {
|
||||
MOZ_ASSERT(mSurf.get());
|
||||
return mSurf.get();
|
||||
}
|
||||
bool Recycle(layers::SharedSurfaceTextureClient* texClient);
|
||||
};
|
||||
|
||||
class ScopedReadbackFB
|
||||
|
@ -4,11 +4,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SharedSurfaceANGLE.h"
|
||||
#include "GLContextEGL.h"
|
||||
#include "GLLibraryEGL.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "GLContextEGL.h"
|
||||
#include "GLLibraryEGL.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
@ -105,7 +106,8 @@ SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl,
|
||||
AttachmentType::Screen,
|
||||
gl,
|
||||
size,
|
||||
hasAlpha)
|
||||
hasAlpha,
|
||||
true)
|
||||
, mEGL(egl)
|
||||
, mContext(context)
|
||||
, mPBuffer(pbuffer)
|
||||
@ -182,6 +184,21 @@ SharedSurface_ANGLEShareHandle::ProducerReleaseImpl()
|
||||
Fence();
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl()
|
||||
{
|
||||
ProducerAcquireImpl();
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl()
|
||||
{
|
||||
if (mKeyedMutex) {
|
||||
mKeyedMutex->ReleaseSync(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurface_ANGLEShareHandle::ConsumerAcquireImpl()
|
||||
{
|
||||
@ -253,6 +270,16 @@ SharedSurface_ANGLEShareHandle::PollSync_ContentThread_Impl()
|
||||
return PollSync();
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
||||
{
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
*out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)mShareHandle, format,
|
||||
mSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Factory
|
||||
|
||||
@ -388,8 +415,9 @@ ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
|
||||
}
|
||||
|
||||
/*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
|
||||
SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
||||
const SurfaceCaps& caps)
|
||||
SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags)
|
||||
{
|
||||
GLLibraryEGL* egl = &sEGLLibrary;
|
||||
if (!egl)
|
||||
@ -401,7 +429,7 @@ SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
||||
|
||||
bool success;
|
||||
typedef SurfaceFactory_ANGLEShareHandle ptrT;
|
||||
UniquePtr<ptrT> ret( new ptrT(gl, egl, caps, &success) );
|
||||
UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, &success) );
|
||||
|
||||
if (!success)
|
||||
return nullptr;
|
||||
@ -410,10 +438,12 @@ SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
|
||||
}
|
||||
|
||||
SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
||||
GLLibraryEGL* egl,
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags,
|
||||
GLLibraryEGL* egl,
|
||||
bool* const out_success)
|
||||
: SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
|
||||
: SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator, flags)
|
||||
, mProdGL(gl)
|
||||
, mEGL(egl)
|
||||
{
|
||||
|
@ -38,7 +38,9 @@ protected:
|
||||
GLLibraryEGL* const mEGL;
|
||||
const EGLContext mContext;
|
||||
const EGLSurface mPBuffer;
|
||||
public:
|
||||
const HANDLE mShareHandle;
|
||||
protected:
|
||||
RefPtr<IDXGIKeyedMutex> mKeyedMutex;
|
||||
RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
|
||||
RefPtr<ID3D11Texture2D> mConsumerTexture;
|
||||
@ -66,6 +68,8 @@ public:
|
||||
virtual void Fence() override;
|
||||
virtual void ProducerAcquireImpl() override;
|
||||
virtual void ProducerReleaseImpl() override;
|
||||
virtual void ProducerReadAcquireImpl() override;
|
||||
virtual void ProducerReadReleaseImpl() override;
|
||||
virtual void ConsumerAcquireImpl() override;
|
||||
virtual void ConsumerReleaseImpl() override;
|
||||
virtual bool WaitSync() override;
|
||||
@ -75,14 +79,11 @@ public:
|
||||
virtual bool WaitSync_ContentThread_Impl() override;
|
||||
virtual bool PollSync_ContentThread_Impl() override;
|
||||
|
||||
// Implementation-specific functions below:
|
||||
HANDLE GetShareHandle() {
|
||||
return mShareHandle;
|
||||
}
|
||||
|
||||
const RefPtr<ID3D11Texture2D>& GetConsumerTexture() const {
|
||||
return mConsumerTexture;
|
||||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
};
|
||||
|
||||
|
||||
@ -98,12 +99,14 @@ protected:
|
||||
|
||||
public:
|
||||
static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl,
|
||||
const SurfaceCaps& caps);
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
protected:
|
||||
SurfaceFactory_ANGLEShareHandle(GLContext* gl,
|
||||
GLLibraryEGL* egl,
|
||||
const SurfaceCaps& caps,
|
||||
SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags, GLLibraryEGL* egl,
|
||||
bool* const out_success);
|
||||
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "GLContextEGL.h"
|
||||
#include "GLLibraryEGL.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "SharedSurface.h"
|
||||
#include "TextureGarbageBin.h"
|
||||
@ -72,7 +73,8 @@ SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
|
||||
AttachmentType::GLTexture,
|
||||
gl,
|
||||
size,
|
||||
hasAlpha)
|
||||
hasAlpha,
|
||||
false) // Can't recycle, as mSync changes never update TextureHost.
|
||||
, mMutex("SharedSurface_EGLImage mutex")
|
||||
, mEGL(egl)
|
||||
, mFormats(formats)
|
||||
@ -115,6 +117,7 @@ SharedSurface_EGLImage::Fence()
|
||||
mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
|
||||
{
|
||||
if (mSync) {
|
||||
MOZ_RELEASE_ASSERT(false, "Non-recycleable should not Fence twice.");
|
||||
MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
|
||||
mSync = 0;
|
||||
}
|
||||
@ -152,14 +155,7 @@ SharedSurface_EGLImage::WaitSync()
|
||||
0,
|
||||
LOCAL_EGL_FOREVER);
|
||||
|
||||
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
|
||||
mSync = 0;
|
||||
|
||||
return true;
|
||||
return status == LOCAL_EGL_CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -177,14 +173,8 @@ SharedSurface_EGLImage::PollSync()
|
||||
mSync,
|
||||
LOCAL_EGL_SYNC_STATUS_KHR,
|
||||
&status) );
|
||||
if (status != LOCAL_EGL_SIGNALED_KHR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE( mEGL->fDestroySync(mEGL->Display(), mSync) );
|
||||
mSync = 0;
|
||||
|
||||
return true;
|
||||
return status == LOCAL_EGL_SIGNALED_KHR;
|
||||
}
|
||||
|
||||
EGLDisplay
|
||||
@ -215,10 +205,20 @@ SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL, GLuint* out_te
|
||||
*out_target = LOCAL_GL_TEXTURE_EXTERNAL;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
||||
{
|
||||
*out_descriptor = layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
|
||||
mSize, mHasAlpha);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static*/ UniquePtr<SurfaceFactory_EGLImage>
|
||||
SurfaceFactory_EGLImage::Create(GLContext* prodGL,
|
||||
const SurfaceCaps& caps)
|
||||
SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags)
|
||||
{
|
||||
EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext();
|
||||
|
||||
@ -227,7 +227,7 @@ SurfaceFactory_EGLImage::Create(GLContext* prodGL,
|
||||
|
||||
GLLibraryEGL* egl = &sEGLLibrary;
|
||||
if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
|
||||
ret.reset( new ptrT(prodGL, context, caps) );
|
||||
ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
|
||||
}
|
||||
|
||||
return Move(ret);
|
||||
|
@ -77,6 +77,8 @@ public:
|
||||
// Implementation-specific functions below:
|
||||
// Returns texture and target
|
||||
void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target);
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
};
|
||||
|
||||
|
||||
@ -87,17 +89,20 @@ class SurfaceFactory_EGLImage
|
||||
public:
|
||||
// Fallible:
|
||||
static UniquePtr<SurfaceFactory_EGLImage> Create(GLContext* prodGL,
|
||||
const SurfaceCaps& caps);
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
protected:
|
||||
const EGLContext mContext;
|
||||
|
||||
SurfaceFactory_EGLImage(GLContext* prodGL,
|
||||
EGLContext context,
|
||||
const SurfaceCaps& caps)
|
||||
: SurfaceFactory(prodGL, SharedSurfaceType::EGLImageShare, caps)
|
||||
SurfaceFactory_EGLImage(GLContext* prodGL, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags,
|
||||
EGLContext context)
|
||||
: SurfaceFactory(SharedSurfaceType::EGLImageShare, prodGL, caps, allocator, flags)
|
||||
, mContext(context)
|
||||
{}
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
|
||||
|
@ -39,40 +39,37 @@ SharedSurface_Basic::Create(GLContext* gl,
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
SurfaceFormat format = SurfaceFormat::B8G8R8X8;
|
||||
switch (formats.color_texInternalFormat) {
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGB8:
|
||||
if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
|
||||
format = SurfaceFormat::R5G6B5;
|
||||
else
|
||||
format = SurfaceFormat::B8G8R8X8;
|
||||
break;
|
||||
case LOCAL_GL_RGBA:
|
||||
case LOCAL_GL_RGBA8:
|
||||
case LOCAL_GL_BGRA:
|
||||
case LOCAL_GL_BGRA8_EXT:
|
||||
format = SurfaceFormat::B8G8R8A8;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unhandled Tex format.");
|
||||
}
|
||||
bool ownsTex = true;
|
||||
ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, tex, ownsTex) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, format, tex) );
|
||||
|
||||
/*static*/ UniquePtr<SharedSurface_Basic>
|
||||
SharedSurface_Basic::Wrap(GLContext* gl,
|
||||
const IntSize& size,
|
||||
bool hasAlpha,
|
||||
GLuint tex)
|
||||
{
|
||||
bool ownsTex = false;
|
||||
UniquePtr<SharedSurface_Basic> ret( new SharedSurface_Basic(gl, size, hasAlpha, tex,
|
||||
ownsTex) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
|
||||
const IntSize& size,
|
||||
bool hasAlpha,
|
||||
SurfaceFormat format,
|
||||
GLuint tex)
|
||||
GLuint tex,
|
||||
bool ownsTex)
|
||||
: SharedSurface(SharedSurfaceType::Basic,
|
||||
AttachmentType::GLTexture,
|
||||
gl,
|
||||
size,
|
||||
hasAlpha)
|
||||
hasAlpha,
|
||||
true)
|
||||
, mTex(tex)
|
||||
, mOwnsTex(ownsTex)
|
||||
, mFB(0)
|
||||
{
|
||||
mGL->MakeCurrent();
|
||||
@ -97,150 +94,16 @@ SharedSurface_Basic::~SharedSurface_Basic()
|
||||
if (mFB)
|
||||
mGL->fDeleteFramebuffers(1, &mFB);
|
||||
|
||||
mGL->fDeleteTextures(1, &mTex);
|
||||
if (mOwnsTex)
|
||||
mGL->fDeleteTextures(1, &mTex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SharedSurface_GLTexture
|
||||
|
||||
/*static*/ UniquePtr<SharedSurface_GLTexture>
|
||||
SharedSurface_GLTexture::Create(GLContext* prodGL,
|
||||
GLContext* consGL,
|
||||
const GLFormats& formats,
|
||||
const IntSize& size,
|
||||
bool hasAlpha,
|
||||
GLuint texture)
|
||||
{
|
||||
MOZ_ASSERT(prodGL);
|
||||
MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
|
||||
|
||||
prodGL->MakeCurrent();
|
||||
|
||||
GLuint tex = texture;
|
||||
|
||||
bool ownsTex = false;
|
||||
|
||||
UniquePtr<SharedSurface_GLTexture> ret;
|
||||
|
||||
if (!tex) {
|
||||
GLContext::LocalErrorScope localError(*prodGL);
|
||||
|
||||
tex = CreateTextureForOffscreen(prodGL, formats, size);
|
||||
|
||||
GLenum err = localError.GetError();
|
||||
MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
|
||||
if (err) {
|
||||
prodGL->fDeleteTextures(1, &tex);
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
ownsTex = true;
|
||||
}
|
||||
|
||||
ret.reset( new SharedSurface_GLTexture(prodGL, consGL, size,
|
||||
hasAlpha, tex, ownsTex) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
SharedSurface_GLTexture::~SharedSurface_GLTexture()
|
||||
{
|
||||
if (!mGL->MakeCurrent())
|
||||
return;
|
||||
|
||||
if (mOwnsTex) {
|
||||
mGL->fDeleteTextures(1, &mTex);
|
||||
}
|
||||
|
||||
if (mSync) {
|
||||
mGL->fDeleteSync(mSync);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurface_GLTexture::Fence()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mGL->MakeCurrent();
|
||||
|
||||
if (mConsGL && mGL->IsExtensionSupported(GLContext::ARB_sync)) {
|
||||
if (mSync) {
|
||||
mGL->fDeleteSync(mSync);
|
||||
mSync = 0;
|
||||
}
|
||||
|
||||
mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
if (mSync) {
|
||||
mGL->fFlush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(!mSync);
|
||||
|
||||
mGL->fFinish();
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_GLTexture::WaitSync()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mSync) {
|
||||
// We either used glFinish, or we passed this fence already.
|
||||
// (PollSync/WaitSync returned true previously)
|
||||
return true;
|
||||
}
|
||||
|
||||
mConsGL->MakeCurrent();
|
||||
MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync));
|
||||
|
||||
mConsGL->fWaitSync(mSync,
|
||||
0,
|
||||
LOCAL_GL_TIMEOUT_IGNORED);
|
||||
mConsGL->fDeleteSync(mSync);
|
||||
mSync = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_GLTexture::PollSync()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mSync) {
|
||||
// We either used glFinish, or we passed this fence already.
|
||||
// (PollSync/WaitSync returned true previously)
|
||||
return true;
|
||||
}
|
||||
|
||||
mConsGL->MakeCurrent();
|
||||
MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync));
|
||||
|
||||
GLint status = 0;
|
||||
mConsGL->fGetSynciv(mSync,
|
||||
LOCAL_GL_SYNC_STATUS,
|
||||
1,
|
||||
nullptr,
|
||||
&status);
|
||||
if (status != LOCAL_GL_SIGNALED)
|
||||
return false;
|
||||
|
||||
mConsGL->fDeleteSync(mSync);
|
||||
mSync = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint
|
||||
SharedSurface_GLTexture::ConsTexture(GLContext* consGL)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(consGL);
|
||||
MOZ_ASSERT(mGL->SharesWith(consGL));
|
||||
MOZ_ASSERT_IF(mConsGL, consGL == mConsGL);
|
||||
|
||||
mConsGL = consGL;
|
||||
|
||||
return mTex;
|
||||
}
|
||||
SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
|
||||
const layers::TextureFlags& flags)
|
||||
: SurfaceFactory(SharedSurfaceType::Basic, gl, caps, nullptr, flags)
|
||||
{ }
|
||||
|
||||
} /* namespace gfx */
|
||||
} /* namespace mozilla */
|
||||
|
@ -38,6 +38,11 @@ public:
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha);
|
||||
|
||||
static UniquePtr<SharedSurface_Basic> Wrap(GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha,
|
||||
GLuint tex);
|
||||
|
||||
static SharedSurface_Basic* Cast(SharedSurface* surf) {
|
||||
MOZ_ASSERT(surf->mType == SharedSurfaceType::Basic);
|
||||
|
||||
@ -46,13 +51,14 @@ public:
|
||||
|
||||
protected:
|
||||
const GLuint mTex;
|
||||
const bool mOwnsTex;
|
||||
GLuint mFB;
|
||||
|
||||
SharedSurface_Basic(GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha,
|
||||
gfx::SurfaceFormat format,
|
||||
GLuint tex);
|
||||
GLuint tex,
|
||||
bool ownsTex);
|
||||
|
||||
public:
|
||||
virtual ~SharedSurface_Basic();
|
||||
@ -67,15 +73,19 @@ public:
|
||||
virtual GLuint ProdTexture() override {
|
||||
return mTex;
|
||||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override {
|
||||
MOZ_CRASH("don't do this");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class SurfaceFactory_Basic
|
||||
: public SurfaceFactory
|
||||
{
|
||||
public:
|
||||
SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps)
|
||||
: SurfaceFactory(gl, SharedSurfaceType::Basic, caps)
|
||||
{}
|
||||
SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
|
||||
bool hasAlpha = mReadCaps.alpha;
|
||||
@ -83,99 +93,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Using shared GL textures:
|
||||
class SharedSurface_GLTexture
|
||||
: public SharedSurface
|
||||
{
|
||||
public:
|
||||
static UniquePtr<SharedSurface_GLTexture> Create(GLContext* prodGL,
|
||||
GLContext* consGL,
|
||||
const GLFormats& formats,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha,
|
||||
GLuint texture = 0);
|
||||
|
||||
static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
|
||||
MOZ_ASSERT(surf->mType == SharedSurfaceType::GLTextureShare);
|
||||
|
||||
return (SharedSurface_GLTexture*)surf;
|
||||
}
|
||||
|
||||
protected:
|
||||
GLContext* mConsGL;
|
||||
const GLuint mTex;
|
||||
const bool mOwnsTex;
|
||||
GLsync mSync;
|
||||
mutable Mutex mMutex;
|
||||
|
||||
SharedSurface_GLTexture(GLContext* prodGL,
|
||||
GLContext* consGL,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha,
|
||||
GLuint tex,
|
||||
bool ownsTex)
|
||||
: SharedSurface(SharedSurfaceType::GLTextureShare,
|
||||
AttachmentType::GLTexture,
|
||||
prodGL,
|
||||
size,
|
||||
hasAlpha)
|
||||
, mConsGL(consGL)
|
||||
, mTex(tex)
|
||||
, mOwnsTex(ownsTex)
|
||||
, mSync(0)
|
||||
, mMutex("SharedSurface_GLTexture mutex")
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~SharedSurface_GLTexture();
|
||||
|
||||
virtual void LockProdImpl() override {}
|
||||
virtual void UnlockProdImpl() override {}
|
||||
|
||||
virtual void Fence() override;
|
||||
virtual bool WaitSync() override;
|
||||
virtual bool PollSync() override;
|
||||
|
||||
virtual GLuint ProdTexture() override {
|
||||
return mTex;
|
||||
}
|
||||
|
||||
// Custom:
|
||||
|
||||
GLuint ConsTexture(GLContext* consGL);
|
||||
|
||||
GLenum ConsTextureTarget() const {
|
||||
return ProdTextureTarget();
|
||||
}
|
||||
};
|
||||
|
||||
class SurfaceFactory_GLTexture
|
||||
: public SurfaceFactory
|
||||
{
|
||||
protected:
|
||||
GLContext* const mConsGL;
|
||||
|
||||
public:
|
||||
// If we don't know `consGL` at construction time, use `nullptr`, and call
|
||||
// `SetConsumerGL()` on each `SharedSurface_GLTexture` before calling its
|
||||
// `WaitSync()`.
|
||||
SurfaceFactory_GLTexture(GLContext* prodGL,
|
||||
GLContext* consGL,
|
||||
const SurfaceCaps& caps)
|
||||
: SurfaceFactory(prodGL, SharedSurfaceType::GLTextureShare, caps)
|
||||
, mConsGL(consGL)
|
||||
{
|
||||
MOZ_ASSERT(consGL != prodGL);
|
||||
}
|
||||
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
|
||||
bool hasAlpha = mReadCaps.alpha;
|
||||
return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace gfx */
|
||||
} /* namespace mozilla */
|
||||
|
||||
|
@ -35,13 +35,10 @@ namespace gl {
|
||||
using namespace mozilla::layers;
|
||||
using namespace android;
|
||||
|
||||
SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL,
|
||||
const SurfaceCaps& caps,
|
||||
layers::TextureFlags flags,
|
||||
layers::ISurfaceAllocator* allocator)
|
||||
: SurfaceFactory(prodGL, SharedSurfaceType::Gralloc, caps)
|
||||
, mFlags(flags)
|
||||
, mAllocator(allocator)
|
||||
SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags)
|
||||
: SurfaceFactory(SharedSurfaceType::Gralloc, prodGL, caps, allocator, flags)
|
||||
{
|
||||
MOZ_ASSERT(mAllocator);
|
||||
}
|
||||
@ -132,7 +129,8 @@ SharedSurface_Gralloc::SharedSurface_Gralloc(GLContext* prodGL,
|
||||
AttachmentType::GLTexture,
|
||||
prodGL,
|
||||
size,
|
||||
hasAlpha)
|
||||
hasAlpha,
|
||||
true)
|
||||
, mEGL(egl)
|
||||
, mSync(0)
|
||||
, mAllocator(allocator)
|
||||
@ -282,5 +280,12 @@ SharedSurface_Gralloc::WaitForBufferOwnership()
|
||||
mTextureClient->WaitForBufferOwnership();
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
||||
{
|
||||
mTextureClient->MarkShared();
|
||||
return mTextureClient->ToSurfaceDescriptor(*out_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
@ -73,20 +73,17 @@ public:
|
||||
layers::GrallocTextureClientOGL* GetTextureClient() {
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
};
|
||||
|
||||
class SurfaceFactory_Gralloc
|
||||
: public SurfaceFactory
|
||||
{
|
||||
protected:
|
||||
const layers::TextureFlags mFlags;
|
||||
RefPtr<layers::ISurfaceAllocator> mAllocator;
|
||||
|
||||
public:
|
||||
SurfaceFactory_Gralloc(GLContext* prodGL,
|
||||
const SurfaceCaps& caps,
|
||||
layers::TextureFlags flags,
|
||||
layers::ISurfaceAllocator* allocator);
|
||||
SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
|
||||
bool hasAlpha = mReadCaps.alpha;
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include "SharedSurfaceIO.h"
|
||||
|
||||
#include "GLContextCGL.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "ScopedGLHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -152,7 +153,8 @@ SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioS
|
||||
AttachmentType::GLTexture,
|
||||
gl,
|
||||
size,
|
||||
hasAlpha)
|
||||
hasAlpha,
|
||||
true)
|
||||
, mIOSurf(ioSurf)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
@ -170,18 +172,29 @@ SharedSurface_IOSurface::~SharedSurface_IOSurface()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
||||
{
|
||||
bool isOpaque = !mHasAlpha;
|
||||
*out_descriptor = layers::SurfaceDescriptorMacIOSurface(mIOSurf->GetIOSurfaceID(),
|
||||
mIOSurf->GetContentsScaleFactor(),
|
||||
isOpaque);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceFactory_IOSurface
|
||||
|
||||
/*static*/ UniquePtr<SurfaceFactory_IOSurface>
|
||||
SurfaceFactory_IOSurface::Create(GLContext* gl,
|
||||
const SurfaceCaps& caps)
|
||||
SurfaceFactory_IOSurface::Create(GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags)
|
||||
{
|
||||
gfx::IntSize maxDims(MacIOSurface::GetMaxWidth(),
|
||||
MacIOSurface::GetMaxHeight());
|
||||
|
||||
typedef SurfaceFactory_IOSurface ptrT;
|
||||
UniquePtr<ptrT> ret( new ptrT(gl, caps, maxDims) );
|
||||
UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,21 @@ namespace gl {
|
||||
|
||||
class SharedSurface_IOSurface : public SharedSurface
|
||||
{
|
||||
private:
|
||||
const RefPtr<MacIOSurface> mIOSurf;
|
||||
GLuint mProdTex;
|
||||
|
||||
public:
|
||||
static UniquePtr<SharedSurface_IOSurface> Create(const RefPtr<MacIOSurface>& ioSurf,
|
||||
GLContext* gl,
|
||||
bool hasAlpha);
|
||||
|
||||
private:
|
||||
SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
|
||||
GLContext* gl, const gfx::IntSize& size,
|
||||
bool hasAlpha);
|
||||
|
||||
public:
|
||||
~SharedSurface_IOSurface();
|
||||
|
||||
virtual void LockProdImpl() override { }
|
||||
@ -57,13 +67,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
|
||||
GLContext* gl, const gfx::IntSize& size,
|
||||
bool hasAlpha);
|
||||
|
||||
RefPtr<MacIOSurface> mIOSurf;
|
||||
GLuint mProdTex;
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
};
|
||||
|
||||
class SurfaceFactory_IOSurface : public SurfaceFactory
|
||||
@ -71,17 +75,19 @@ class SurfaceFactory_IOSurface : public SurfaceFactory
|
||||
public:
|
||||
// Infallible.
|
||||
static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
|
||||
const SurfaceCaps& caps);
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags);
|
||||
protected:
|
||||
const gfx::IntSize mMaxDims;
|
||||
|
||||
SurfaceFactory_IOSurface(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
SurfaceFactory_IOSurface(GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::ISurfaceAllocator>& allocator,
|
||||
const layers::TextureFlags& flags,
|
||||
const gfx::IntSize& maxDims)
|
||||
: SurfaceFactory(gl, SharedSurfaceType::IOSurface, caps)
|
||||
: SurfaceFactory(SharedSurfaceType::IOSurface, gl, caps, allocator, flags)
|
||||
, mMaxDims(maxDims)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
|
||||
};
|
||||
|
@ -70,7 +70,6 @@ enum class SharedSurfaceType : uint8_t {
|
||||
Unknown = 0,
|
||||
|
||||
Basic,
|
||||
GLTextureShare,
|
||||
EGLImageShare,
|
||||
EGLSurfaceANGLE,
|
||||
DXGLInterop,
|
||||
|
@ -13,16 +13,35 @@
|
||||
#include "base/task.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
#define ADDREF_MANUALLY(obj) (obj)->AddRefManually(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define RELEASE_MANUALLY(obj) (obj)->ReleaseManually(__FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<class U>
|
||||
class StaticRefPtr;
|
||||
|
||||
namespace gl {
|
||||
template<typename T>
|
||||
class RefSet;
|
||||
|
||||
template<typename T>
|
||||
class RefQueue;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class AtomicRefCountedWithFinalize
|
||||
{
|
||||
protected:
|
||||
protected:
|
||||
AtomicRefCountedWithFinalize()
|
||||
: mRecycleCallback(nullptr)
|
||||
, mRefCount(0)
|
||||
, mMessageLoopToPostDestructionTo(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mSpew(false)
|
||||
, mManualAddRefs(0)
|
||||
, mManualReleases(0)
|
||||
#endif
|
||||
{}
|
||||
|
||||
~AtomicRefCountedWithFinalize() {
|
||||
@ -41,12 +60,69 @@ class AtomicRefCountedWithFinalize
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
// Mark user classes that are considered flawless.
|
||||
template<typename U>
|
||||
friend class RefPtr;
|
||||
|
||||
template<class U>
|
||||
friend class ::mozilla::StaticRefPtr;
|
||||
|
||||
template<typename U>
|
||||
friend class TemporaryRef;
|
||||
|
||||
template<class U>
|
||||
friend class ::nsRefPtr;
|
||||
|
||||
template<class U>
|
||||
friend struct ::RunnableMethodTraits;
|
||||
|
||||
template<typename U>
|
||||
friend class ::mozilla::gl::RefSet;
|
||||
|
||||
template<typename U>
|
||||
friend class ::mozilla::gl::RefQueue;
|
||||
|
||||
//friend class mozilla::gl::SurfaceFactory;
|
||||
|
||||
void AddRefManually(const char* funcName, const char* fileName, uint32_t lineNum) {
|
||||
#ifdef DEBUG
|
||||
uint32_t count = ++mManualAddRefs;
|
||||
if (mSpew) {
|
||||
printf_stderr("AddRefManually() #%u in %s at %s:%u\n", count, funcName,
|
||||
fileName, lineNum);
|
||||
}
|
||||
#else
|
||||
(void)funcName;
|
||||
(void)fileName;
|
||||
(void)lineNum;
|
||||
#endif
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void ReleaseManually(const char* funcName, const char* fileName, uint32_t lineNum) {
|
||||
#ifdef DEBUG
|
||||
uint32_t count = ++mManualReleases;
|
||||
if (mSpew) {
|
||||
printf_stderr("ReleaseManually() #%u in %s at %s:%u\n", count, funcName,
|
||||
fileName, lineNum);
|
||||
}
|
||||
#else
|
||||
(void)funcName;
|
||||
(void)fileName;
|
||||
(void)lineNum;
|
||||
#endif
|
||||
Release();
|
||||
}
|
||||
|
||||
private:
|
||||
void AddRef() {
|
||||
MOZ_ASSERT(mRefCount >= 0, "AddRef() during/after Finalize()/dtor.");
|
||||
++mRefCount;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
MOZ_ASSERT(mRefCount > 0, "Release() during/after Finalize()/dtor.");
|
||||
// Read mRecycleCallback early so that it does not get set to
|
||||
// deleted memory, if the object is goes away. See bug 994903.
|
||||
// This saves us in the case where there is no callback, so that
|
||||
@ -70,6 +146,8 @@ class AtomicRefCountedWithFinalize
|
||||
mRecycleCallback = nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mManualAddRefs == mManualReleases);
|
||||
|
||||
T* derived = static_cast<T*>(this);
|
||||
derived->Finalize();
|
||||
if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
|
||||
@ -93,6 +171,7 @@ class AtomicRefCountedWithFinalize
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
typedef void (*RecycleCallback)(T* aObject, void* aClosure);
|
||||
/**
|
||||
* Set a callback responsible for recycling this object
|
||||
@ -126,8 +205,15 @@ private:
|
||||
void *mClosure;
|
||||
Atomic<int> mRefCount;
|
||||
MessageLoop *mMessageLoopToPostDestructionTo;
|
||||
#ifdef DEBUG
|
||||
public:
|
||||
bool mSpew;
|
||||
private:
|
||||
Atomic<uint32_t> mManualAddRefs;
|
||||
Atomic<uint32_t> mManualReleases;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -3,8 +3,9 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BasicLayersImpl.h" // for FillWithMask, etc
|
||||
#include "CopyableCanvasLayer.h"
|
||||
|
||||
#include "BasicLayersImpl.h" // for FillWithMask, etc
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "GLScreenBuffer.h" // for GLScreenBuffer
|
||||
#include "SharedSurface.h" // for SharedSurface
|
||||
@ -21,6 +22,7 @@
|
||||
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "gfxUtils.h"
|
||||
#include "client/TextureClientSharedSurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -56,11 +58,8 @@ CopyableCanvasLayer::Initialize(const Data& aData)
|
||||
|
||||
if (aData.mFrontbufferGLTex) {
|
||||
gfx::IntSize size(aData.mSize.width, aData.mSize.height);
|
||||
mGLFrontbuffer = SharedSurface_GLTexture::Create(aData.mGLContext,
|
||||
nullptr,
|
||||
aData.mGLContext->GetGLFormats(),
|
||||
size, aData.mHasAlpha,
|
||||
aData.mFrontbufferGLTex);
|
||||
mGLFrontbuffer = SharedSurface_Basic::Wrap(aData.mGLContext, size, aData.mHasAlpha,
|
||||
aData.mFrontbufferGLTex);
|
||||
}
|
||||
} else if (aData.mDrawTarget) {
|
||||
mDrawTarget = aData.mDrawTarget;
|
||||
@ -108,7 +107,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
||||
frontbuffer = mGLFrontbuffer.get();
|
||||
} else {
|
||||
GLScreenBuffer* screen = mGLContext->Screen();
|
||||
ShSurfHandle* front = screen->Front();
|
||||
const auto& front = screen->Front();
|
||||
if (front) {
|
||||
frontbuffer = front->Surf();
|
||||
}
|
||||
@ -137,7 +136,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
||||
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
|
||||
mGLContext->Readback(frontbuffer, data);
|
||||
if (needsPremult) {
|
||||
gfxUtils::PremultiplyDataSurface(data, data);
|
||||
gfxUtils::PremultiplyDataSurface(data, data);
|
||||
}
|
||||
aDestTarget->ReleaseBits(destData);
|
||||
return;
|
||||
|
@ -39,7 +39,7 @@ MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic(
|
||||
)
|
||||
: TextureHost(aFlags)
|
||||
{
|
||||
mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
|
||||
mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(),
|
||||
aDescriptor.scaleFactor(),
|
||||
!aDescriptor.isOpaque());
|
||||
}
|
||||
|
@ -22,9 +22,7 @@
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for printf_stderr, NS_ASSERTION
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "SharedSurfaceGralloc.h"
|
||||
#endif
|
||||
#include "TextureClientSharedSurface.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
@ -37,13 +35,6 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
|
||||
CompositableForwarder* aForwarder,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
NS_WARNING("Most platforms still need an optimized way to share GL cross process.");
|
||||
return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (aType) {
|
||||
case CanvasClientTypeShSurf:
|
||||
return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
|
||||
@ -149,28 +140,11 @@ CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
CanvasClientSharedSurface::CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
{ }
|
||||
|
||||
CanvasClientSharedSurface::~CanvasClientSharedSurface()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Accelerated backends
|
||||
|
||||
static TemporaryRef<TextureClient>
|
||||
TexClientFromShSurf(ISurfaceAllocator* aAllocator, SharedSurface* surf,
|
||||
TextureFlags flags)
|
||||
{
|
||||
switch (surf->mType) {
|
||||
case SharedSurfaceType::Basic:
|
||||
return nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
case SharedSurfaceType::Gralloc:
|
||||
return GrallocTextureClientOGL::FromSharedSurface(surf, flags);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return MakeAndAddRef<SharedSurfaceTextureClient>(aAllocator, flags, surf);
|
||||
}
|
||||
ClearSurfaces();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
@ -330,91 +304,92 @@ TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
static TemporaryRef<gl::ShSurfHandle>
|
||||
static TemporaryRef<SharedSurfaceTextureClient>
|
||||
CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory)
|
||||
{
|
||||
RefPtr<gl::ShSurfHandle> dest = factory->NewShSurfHandle(src->mSize);
|
||||
RefPtr<SharedSurfaceTextureClient> dest = factory->NewTexClient(src->mSize);
|
||||
if (!dest) {
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
SharedSurface::ProdCopy(src, dest->Surf(), factory);
|
||||
dest->Surf()->Fence();
|
||||
return dest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
if (mFront) {
|
||||
mPrevFront = mFront;
|
||||
mFront = nullptr;
|
||||
}
|
||||
|
||||
auto gl = aLayer->mGLContext;
|
||||
gl->MakeCurrent();
|
||||
|
||||
RefPtr<TextureClient> newFront;
|
||||
|
||||
if (aLayer->mGLFrontbuffer) {
|
||||
mFront = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
|
||||
if (mFront)
|
||||
mFront->Surf()->Fence();
|
||||
mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
|
||||
if (!mShSurfClient) {
|
||||
gfxCriticalError() << "Invalid canvas front buffer";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mFront = gl->Screen()->Front();
|
||||
}
|
||||
if (!mFront) {
|
||||
gfxCriticalError() << "Invalid canvas front buffer";
|
||||
return;
|
||||
mShSurfClient = gl->Screen()->Front();
|
||||
if (!mShSurfClient) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(mShSurfClient);
|
||||
|
||||
newFront = mShSurfClient;
|
||||
|
||||
SharedSurface* surf = mShSurfClient->Surf();
|
||||
|
||||
// Readback if needed.
|
||||
mReadbackClient = nullptr;
|
||||
|
||||
// Alright, now sort out the IPC goop.
|
||||
SharedSurface* surf = mFront->Surf();
|
||||
auto forwarder = GetForwarder();
|
||||
auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE;
|
||||
|
||||
// Get a TexClient from our surf.
|
||||
RefPtr<TextureClient> newTex = TexClientFromShSurf(GetForwarder(), surf, flags);
|
||||
if (!newTex) {
|
||||
bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
|
||||
if (needsReadback) {
|
||||
TextureFlags flags = aLayer->Flags() |
|
||||
TextureFlags::IMMUTABLE;
|
||||
|
||||
auto manager = aLayer->ClientManager();
|
||||
auto shadowForwarder = manager->AsShadowForwarder();
|
||||
auto layersBackend = shadowForwarder->GetCompositorBackendType();
|
||||
mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
|
||||
|
||||
newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend);
|
||||
newFront = mReadbackClient;
|
||||
} else {
|
||||
mReadbackClient = nullptr;
|
||||
}
|
||||
|
||||
if (!newTex) {
|
||||
MOZ_ASSERT(newFront);
|
||||
if (!newFront) {
|
||||
// May happen in a release build in case of memory pressure.
|
||||
gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. size: " << aSize;
|
||||
gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: " << aSize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( AddTextureClient(newTex) );
|
||||
|
||||
// Remove the old TexClient.
|
||||
if (mFrontTex) {
|
||||
// remove old buffer from CompositableHost
|
||||
RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
|
||||
// Hold TextureClient until transaction complete.
|
||||
tracker->SetTextureClient(mFrontTex);
|
||||
mFrontTex->SetRemoveFromCompositableTracker(tracker);
|
||||
// RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
|
||||
GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontTex);
|
||||
|
||||
mFrontTex = nullptr;
|
||||
if (mFront) {
|
||||
if (mFront->GetFlags() & TextureFlags::RECYCLE) {
|
||||
mFront->WaitForCompositorRecycle();
|
||||
}
|
||||
}
|
||||
|
||||
// Use the new TexClient.
|
||||
mFrontTex = newTex;
|
||||
mFront = newFront;
|
||||
|
||||
forwarder->UseTexture(this, mFrontTex);
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
|
||||
|
||||
forwarder->UseTexture(this, mFront);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::ClearSurfaces()
|
||||
{
|
||||
mFrontTex = nullptr;
|
||||
// It is important to destroy the SharedSurface *after* the TextureClient.
|
||||
mFront = nullptr;
|
||||
mPrevFront = nullptr;
|
||||
mShSurfClient = nullptr;
|
||||
mReadbackClient = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -18,18 +18,12 @@
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class SharedSurface;
|
||||
class ShSurfHandle;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ClientCanvasLayer;
|
||||
class CompositableForwarder;
|
||||
class SharedSurfaceTextureClient;
|
||||
|
||||
/**
|
||||
* Compositable client for 2d and webgl canvas.
|
||||
@ -114,10 +108,9 @@ private:
|
||||
class CanvasClientSharedSurface : public CanvasClient
|
||||
{
|
||||
private:
|
||||
RefPtr<gl::ShSurfHandle> mFront;
|
||||
RefPtr<gl::ShSurfHandle> mPrevFront;
|
||||
|
||||
RefPtr<TextureClient> mFrontTex;
|
||||
RefPtr<SharedSurfaceTextureClient> mShSurfClient;
|
||||
RefPtr<TextureClient> mReadbackClient;
|
||||
RefPtr<TextureClient> mFront;
|
||||
|
||||
void ClearSurfaces();
|
||||
|
||||
@ -125,10 +118,7 @@ public:
|
||||
CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags);
|
||||
|
||||
~CanvasClientSharedSurface()
|
||||
{
|
||||
ClearSurfaces();
|
||||
}
|
||||
~CanvasClientSharedSurface();
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override {
|
||||
return TextureInfo(CompositableType::IMAGE);
|
||||
|
@ -70,48 +70,40 @@ ClientCanvasLayer::Initialize(const Data& aData)
|
||||
}
|
||||
MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
|
||||
|
||||
auto forwarder = ClientManager()->AsShadowForwarder();
|
||||
|
||||
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
if (!aData.mIsGLAlphaPremult) {
|
||||
mFlags |= TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
UniquePtr<SurfaceFactory> factory;
|
||||
|
||||
if (!gfxPrefs::WebGLForceLayersReadback()) {
|
||||
switch (ClientManager()->AsShadowForwarder()->GetCompositorBackendType()) {
|
||||
switch (forwarder->GetCompositorBackendType()) {
|
||||
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
|
||||
#if defined(XP_MACOSX)
|
||||
factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
|
||||
#else
|
||||
if (mGLContext->GetContextType() == GLContextType::EGL) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
TextureFlags flags = TextureFlags::DEALLOCATE_CLIENT |
|
||||
TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
if (!aData.mIsGLAlphaPremult) {
|
||||
flags |= TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext,
|
||||
caps,
|
||||
flags,
|
||||
ClientManager()->AsShadowForwarder());
|
||||
#else
|
||||
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
bool isCrossProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
|
||||
if (!isCrossProcess) {
|
||||
// [Basic/OGL Layers, OMTC] WebGL layer init.
|
||||
factory = SurfaceFactory_EGLImage::Create(mGLContext, caps);
|
||||
} else {
|
||||
// we could do readback here maybe
|
||||
NS_NOTREACHED("isCrossProcess but not on native B2G!");
|
||||
factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder,
|
||||
mFlags);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// [Basic Layers, OMTC] WebGL layer init.
|
||||
// Well, this *should* work...
|
||||
#ifdef XP_MACOSX
|
||||
factory = SurfaceFactory_IOSurface::Create(mGLContext, caps);
|
||||
#else
|
||||
GLContext* nullConsGL = nullptr; // Bug 1050044.
|
||||
factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, nullConsGL, caps);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
|
||||
#ifdef XP_WIN
|
||||
if (mGLContext->IsANGLE() && DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
|
||||
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps);
|
||||
if (mGLContext->IsANGLE() &&
|
||||
DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device()))
|
||||
{
|
||||
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,
|
||||
mFlags);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -127,7 +119,7 @@ ClientCanvasLayer::Initialize(const Data& aData)
|
||||
mFactory = Move(factory);
|
||||
if (!mFactory) {
|
||||
// Absolutely must have a factory here, so create a basic one
|
||||
mFactory = MakeUnique<SurfaceFactory_Basic>(mGLContext, caps);
|
||||
mFactory = MakeUnique<SurfaceFactory_Basic>(mGLContext, caps, mFlags);
|
||||
}
|
||||
} else {
|
||||
if (factory)
|
||||
|
@ -6,7 +6,7 @@
|
||||
#ifndef GFX_CLIENTCANVASLAYER_H
|
||||
#define GFX_CLIENTCANVASLAYER_H
|
||||
|
||||
#include "mozilla/layers/CanvasClient.h" // for CanvasClient, etc
|
||||
#include "CanvasClient.h" // for CanvasClient, etc
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "CopyableCanvasLayer.h" // for CopyableCanvasLayer
|
||||
#include "Layers.h" // for CanvasLayer, etc
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class SharedSurface;
|
||||
class SurfaceFactory;
|
||||
}
|
||||
|
||||
@ -81,6 +80,9 @@ public:
|
||||
{
|
||||
return mCanvasClient;
|
||||
}
|
||||
|
||||
const TextureFlags& Flags() const { return mFlags; }
|
||||
|
||||
protected:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
@ -93,6 +95,8 @@ protected:
|
||||
|
||||
UniquePtr<gl::SurfaceFactory> mFactory;
|
||||
|
||||
TextureFlags mFlags;
|
||||
|
||||
friend class DeprecatedCanvasClient2D;
|
||||
friend class CanvasClient2D;
|
||||
friend class CanvasClientSharedSurface;
|
||||
|
@ -20,8 +20,6 @@
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
#include "mozilla/layers/PTextureChild.h"
|
||||
#include "SharedSurface.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "LayersLogging.h" // for AppendToString
|
||||
@ -113,7 +111,7 @@ public:
|
||||
|
||||
bool RecvCompositorRecycle() override
|
||||
{
|
||||
RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
|
||||
RECYCLE_LOG("[CLIENT] Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
|
||||
mWaitForRecycle = nullptr;
|
||||
return true;
|
||||
}
|
||||
@ -121,7 +119,7 @@ public:
|
||||
void WaitForCompositorRecycle()
|
||||
{
|
||||
mWaitForRecycle = mTextureClient;
|
||||
RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
|
||||
RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
|
||||
SendClientRecycle();
|
||||
}
|
||||
|
||||
@ -587,6 +585,10 @@ TextureClient::Finalize()
|
||||
// Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
|
||||
// when calling TextureChild::ActorDestroy()
|
||||
actor->mTextureClient = nullptr;
|
||||
|
||||
// `actor->mWaitForRecycle` may not be null, as we may be being called from setting
|
||||
// this RefPtr to null! Clearing it here will double-Release() it.
|
||||
|
||||
// this will call ForceRemove in the right thread, using a sync proxy if needed
|
||||
if (actor->GetForwarder()) {
|
||||
actor->GetForwarder()->RemoveTexture(this);
|
||||
@ -915,32 +917,6 @@ BufferTextureClient::GetLockedData() const
|
||||
return serializer.GetData();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SharedSurfaceTextureClient
|
||||
|
||||
SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
gl::SharedSurface* surf)
|
||||
: TextureClient(aAllocator, aFlags)
|
||||
, mIsLocked(false)
|
||||
, mSurf(surf)
|
||||
, mGL(mSurf->mGL)
|
||||
{
|
||||
AddFlags(TextureFlags::DEALLOCATE_CLIENT);
|
||||
}
|
||||
|
||||
SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
|
||||
{
|
||||
// the data is owned externally.
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = SharedSurfaceDescriptor((uintptr_t)mSurf);
|
||||
return true;
|
||||
}
|
||||
|
||||
TemporaryRef<SyncObject>
|
||||
SyncObject::CreateSyncObject(SyncHandle aHandle)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint8_t, uint64_t
|
||||
#include "GLContextTypes.h" // for GLContext (ptr only), etc
|
||||
#include "GLTextureImage.h" // for TextureImage
|
||||
#include "ImageTypes.h" // for StereoMode
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
@ -32,10 +31,6 @@
|
||||
class gfxImageSurface;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
class SharedSurface;
|
||||
}
|
||||
|
||||
// When defined, we track which pool the tile came from and test for
|
||||
// any inconsistencies. This can be defined in release build as well.
|
||||
@ -476,9 +471,13 @@ public:
|
||||
virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
|
||||
mReadbackSink = aReadbackSink;
|
||||
}
|
||||
|
||||
|
||||
virtual void SyncWithObject(SyncObject* aSyncObject) { }
|
||||
|
||||
void MarkShared() {
|
||||
mShared = true;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called once, just before the destructor.
|
||||
@ -690,66 +689,6 @@ protected:
|
||||
size_t mBufSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* A TextureClient implementation to share SharedSurfaces.
|
||||
*/
|
||||
class SharedSurfaceTextureClient : public TextureClient
|
||||
{
|
||||
public:
|
||||
SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags,
|
||||
gl::SharedSurface* surf);
|
||||
|
||||
protected:
|
||||
~SharedSurfaceTextureClient();
|
||||
|
||||
public:
|
||||
// Boilerplate start
|
||||
virtual bool IsAllocated() const override { return true; }
|
||||
|
||||
virtual bool Lock(OpenMode) override {
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
mIsLocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Unlock() override {
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
mIsLocked = false;
|
||||
}
|
||||
|
||||
virtual bool IsLocked() const override { return mIsLocked; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return false; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override {
|
||||
return gfx::SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return gfx::IntSize(); }
|
||||
|
||||
// This TextureClient should not be used in a context where we use CreateSimilar
|
||||
// (ex. component alpha) because the underlying texture data is always created by
|
||||
// an external producer.
|
||||
virtual TemporaryRef<TextureClient>
|
||||
CreateSimilar(TextureFlags, TextureAllocationFlags) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool AllocateForSurface(gfx::IntSize,
|
||||
TextureAllocationFlags) override {
|
||||
MOZ_CRASH("Should never hit this.");
|
||||
return false;
|
||||
}
|
||||
// Boilerplate end
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
protected:
|
||||
bool mIsLocked;
|
||||
gl::SharedSurface* const mSurf;
|
||||
RefPtr<gl::GLContext> mGL; // Just for reference holding.
|
||||
};
|
||||
|
||||
struct TextureClientAutoUnlock
|
||||
{
|
||||
TextureClient* mTexture;
|
||||
|
45
gfx/layers/client/TextureClientSharedSurface.cpp
Normal file
45
gfx/layers/client/TextureClientSharedSurface.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TextureClientSharedSurface.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "SharedSurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
UniquePtr<gl::SharedSurface> surf,
|
||||
gl::SurfaceFactory* factory)
|
||||
: TextureClient(aAllocator, aFlags | TextureFlags::RECYCLE)
|
||||
, mSurf(Move(surf))
|
||||
{ }
|
||||
|
||||
SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
|
||||
{
|
||||
// Free the ShSurf implicitly.
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
SharedSurfaceTextureClient::GetSize() const
|
||||
{
|
||||
return mSurf->mSize;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurfaceTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
return mSurf->ToSurfaceDescriptor(&aOutDescriptor);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
75
gfx/layers/client/TextureClientSharedSurface.h
Normal file
75
gfx/layers/client/TextureClientSharedSurface.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint8_t, uint64_t
|
||||
#include "GLContextTypes.h" // for GLContext (ptr only), etc
|
||||
#include "TextureClient.h"
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, RefCounted
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
class SharedSurface;
|
||||
class SurfaceFactory;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class SharedSurfaceTextureClient : public TextureClient
|
||||
{
|
||||
protected:
|
||||
const UniquePtr<gl::SharedSurface> mSurf;
|
||||
|
||||
friend class gl::SurfaceFactory;
|
||||
|
||||
SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags,
|
||||
UniquePtr<gl::SharedSurface> surf,
|
||||
gl::SurfaceFactory* factory);
|
||||
|
||||
~SharedSurfaceTextureClient();
|
||||
|
||||
public:
|
||||
virtual bool IsAllocated() const override { return true; }
|
||||
virtual bool Lock(OpenMode) override { return false; }
|
||||
virtual bool IsLocked() const override { return false; }
|
||||
virtual bool HasInternalBuffer() const override { return false; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override {
|
||||
return gfx::SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
|
||||
virtual TemporaryRef<TextureClient>
|
||||
CreateSimilar(TextureFlags, TextureAllocationFlags) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool AllocateForSurface(gfx::IntSize,
|
||||
TextureAllocationFlags) override {
|
||||
MOZ_CRASH("Should never hit this.");
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
gl::SharedSurface* Surf() const {
|
||||
return mSurf.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_GFX_TEXTURECLIENT_SHAREDSURFACE_H
|
@ -25,7 +25,6 @@ namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
FPSCounter::FPSCounter(const char* aName)
|
||||
: mWriteIndex(0)
|
||||
@ -396,7 +395,7 @@ static void DrawDigits(unsigned int aValue,
|
||||
Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
|
||||
Rect clipRect = Rect(0, 0, 300, 100);
|
||||
aCompositor->DrawQuad(drawRect, clipRect,
|
||||
aEffectChain, opacity, transform);
|
||||
aEffectChain, opacity, transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,7 @@ ImageHost::ImageHost(const TextureInfo& aTextureInfo)
|
||||
{}
|
||||
|
||||
ImageHost::~ImageHost()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void
|
||||
ImageHost::UseTextureHost(TextureHost* aTexture)
|
||||
|
@ -22,9 +22,6 @@
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include <limits>
|
||||
#include "SharedSurface.h"
|
||||
#include "SharedSurfaceEGL.h"
|
||||
#include "SharedSurfaceGL.h"
|
||||
#include "../opengl/CompositorOGL.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
@ -35,7 +32,6 @@
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "../opengl/GrallocTextureClient.h"
|
||||
#include "../opengl/GrallocTextureHost.h"
|
||||
#include "SharedSurfaceGralloc.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_X11
|
||||
@ -43,12 +39,10 @@
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "SharedSurfaceIO.h"
|
||||
#include "../opengl/MacIOSurfaceTextureHostOGL.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "SharedSurfaceANGLE.h"
|
||||
#include "mozilla/layers/TextureDIB.h"
|
||||
#endif
|
||||
|
||||
@ -96,6 +90,8 @@ public:
|
||||
RefPtr<TextureHost> mTextureHost;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// static
|
||||
PTextureParent*
|
||||
TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
|
||||
@ -217,9 +213,6 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
|
||||
case SurfaceDescriptor::TSurfaceTextureDescriptor:
|
||||
return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
|
||||
|
||||
case SurfaceDescriptor::TSharedSurfaceDescriptor:
|
||||
return MakeAndAddRef<SharedSurfaceTextureHost>(aFlags, aDesc.get_SharedSurfaceDescriptor());
|
||||
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
|
||||
if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL) {
|
||||
return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
|
||||
@ -875,153 +868,6 @@ TextureParent::RecvRecycleTexture(const TextureFlags& aTextureFlags)
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static RefPtr<TextureSource>
|
||||
SharedSurfaceToTexSource(gl::SharedSurface* abstractSurf, Compositor* compositor)
|
||||
{
|
||||
MOZ_ASSERT(abstractSurf);
|
||||
MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Basic);
|
||||
MOZ_ASSERT(abstractSurf->mType != gl::SharedSurfaceType::Gralloc);
|
||||
|
||||
if (!compositor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat format = abstractSurf->mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
|
||||
: gfx::SurfaceFormat::R8G8B8X8;
|
||||
|
||||
RefPtr<TextureSource> texSource;
|
||||
switch (abstractSurf->mType) {
|
||||
#ifdef XP_WIN
|
||||
case gl::SharedSurfaceType::EGLSurfaceANGLE: {
|
||||
auto surf = gl::SharedSurface_ANGLEShareHandle::Cast(abstractSurf);
|
||||
|
||||
MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_D3D11);
|
||||
CompositorD3D11* compositorD3D11 = static_cast<CompositorD3D11*>(compositor);
|
||||
RefPtr<ID3D11Texture2D> tex = surf->GetConsumerTexture();
|
||||
|
||||
if (!tex) {
|
||||
NS_WARNING("Failed to open shared resource.");
|
||||
break;
|
||||
}
|
||||
texSource = new DataTextureSourceD3D11(format, compositorD3D11, tex);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case gl::SharedSurfaceType::GLTextureShare: {
|
||||
auto surf = gl::SharedSurface_GLTexture::Cast(abstractSurf);
|
||||
|
||||
MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
|
||||
CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
|
||||
gl::GLContext* gl = compositorOGL->gl();
|
||||
|
||||
GLenum target = surf->ConsTextureTarget();
|
||||
GLuint tex = surf->ConsTexture(gl);
|
||||
texSource = new GLTextureSource(compositorOGL, tex, target,
|
||||
surf->mSize, format,
|
||||
true/*externally owned*/);
|
||||
break;
|
||||
}
|
||||
case gl::SharedSurfaceType::EGLImageShare: {
|
||||
auto surf = gl::SharedSurface_EGLImage::Cast(abstractSurf);
|
||||
|
||||
MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
|
||||
CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
|
||||
gl::GLContext* gl = compositorOGL->gl();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
GLenum target = 0;
|
||||
GLuint tex = 0;
|
||||
surf->AcquireConsumerTexture(gl, &tex, &target);
|
||||
|
||||
texSource = new GLTextureSource(compositorOGL, tex, target,
|
||||
surf->mSize, format,
|
||||
true/*externally owned*/);
|
||||
break;
|
||||
}
|
||||
#ifdef XP_MACOSX
|
||||
case gl::SharedSurfaceType::IOSurface: {
|
||||
auto surf = gl::SharedSurface_IOSurface::Cast(abstractSurf);
|
||||
MacIOSurface* ioSurf = surf->GetIOSurface();
|
||||
|
||||
MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_OPENGL);
|
||||
CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(compositor);
|
||||
|
||||
texSource = new MacIOSurfaceTextureSourceOGL(compositorOGL, ioSurf);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texSource.get(), "TextureSource creation failed.");
|
||||
return texSource;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// SharedSurfaceTextureHost
|
||||
|
||||
SharedSurfaceTextureHost::SharedSurfaceTextureHost(TextureFlags aFlags,
|
||||
const SharedSurfaceDescriptor& aDesc)
|
||||
: TextureHost(aFlags)
|
||||
, mIsLocked(false)
|
||||
, mSurf((gl::SharedSurface*)aDesc.surf())
|
||||
, mCompositor(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mSurf);
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
SharedSurfaceTextureHost::GetFormat() const
|
||||
{
|
||||
MOZ_ASSERT(mTexSource);
|
||||
return mTexSource->GetFormat();
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
SharedSurfaceTextureHost::GetSize() const
|
||||
{
|
||||
MOZ_ASSERT(mTexSource);
|
||||
return mTexSource->GetSize();
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurfaceTextureHost::EnsureTexSource()
|
||||
{
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
|
||||
if (mTexSource)
|
||||
return;
|
||||
|
||||
mTexSource = SharedSurfaceToTexSource(mSurf, mCompositor);
|
||||
MOZ_ASSERT(mTexSource);
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurfaceTextureHost::Lock()
|
||||
{
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
|
||||
mSurf->ConsumerAcquire();
|
||||
|
||||
mIsLocked = true;
|
||||
|
||||
EnsureTexSource();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SharedSurfaceTextureHost::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
mSurf->ConsumerRelease();
|
||||
mIsLocked = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace
|
||||
|
@ -31,9 +31,6 @@
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class SharedSurface;
|
||||
}
|
||||
namespace ipc {
|
||||
class Shmem;
|
||||
}
|
||||
@ -43,7 +40,6 @@ namespace layers {
|
||||
class Compositor;
|
||||
class CompositableParentManager;
|
||||
class SurfaceDescriptor;
|
||||
class SharedSurfaceDescriptor;
|
||||
class ISurfaceAllocator;
|
||||
class TextureHostOGL;
|
||||
class TextureSourceOGL;
|
||||
@ -681,64 +677,6 @@ protected:
|
||||
uint8_t* mBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* A TextureHost for SharedSurfaces
|
||||
*/
|
||||
class SharedSurfaceTextureHost : public TextureHost
|
||||
{
|
||||
public:
|
||||
SharedSurfaceTextureHost(TextureFlags aFlags,
|
||||
const SharedSurfaceDescriptor& aDesc);
|
||||
|
||||
virtual ~SharedSurfaceTextureHost() {
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
}
|
||||
|
||||
virtual void DeallocateDeviceData() override {};
|
||||
|
||||
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override {
|
||||
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
|
||||
}
|
||||
|
||||
virtual void SetCompositor(Compositor* aCompositor) override {
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
|
||||
if (aCompositor == mCompositor)
|
||||
return;
|
||||
|
||||
mTexSource = nullptr;
|
||||
mCompositor = aCompositor;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual bool Lock() override;
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override {
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
MOZ_ASSERT(mTexSource);
|
||||
aTexture = mTexSource;
|
||||
return !!aTexture;
|
||||
}
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
virtual const char* Name() override { return "SharedSurfaceTextureHost"; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void EnsureTexSource();
|
||||
|
||||
bool mIsLocked;
|
||||
gl::SharedSurface* const mSurf;
|
||||
RefPtr<Compositor> mCompositor;
|
||||
RefPtr<TextureSource> mTexSource;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoLockTextureHost
|
||||
{
|
||||
public:
|
||||
|
@ -802,6 +802,18 @@ CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorParent::RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot)
|
||||
{
|
||||
if (!mCompositor || !mCompositor->GetWidget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
|
||||
mCompositor->GetWidget()->CaptureWidgetOnScreen(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorParent::RecvFlushRendering()
|
||||
{
|
||||
@ -1688,6 +1700,8 @@ public:
|
||||
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
const gfx::IntRect& aRect) override
|
||||
{ return true; }
|
||||
virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override
|
||||
{ return true; }
|
||||
virtual bool RecvFlushRendering() override { return true; }
|
||||
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
|
||||
virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
|
||||
|
@ -240,6 +240,7 @@ public:
|
||||
virtual bool RecvAdoptChild(const uint64_t& child) override;
|
||||
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
const gfx::IntRect& aRect) override;
|
||||
virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override;
|
||||
virtual bool RecvFlushRendering() override;
|
||||
|
||||
virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override;
|
||||
|
@ -351,7 +351,7 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
|
||||
static void ReleaseTextureClientNow(TextureClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
aClient->Release();
|
||||
RELEASE_MANUALLY(aClient);
|
||||
}
|
||||
|
||||
// static
|
||||
@ -368,7 +368,7 @@ void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
|
||||
// has already shut down, along with the TextureChild, which means no
|
||||
// message will be sent and it is safe to run this code from any thread.
|
||||
MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
|
||||
aClient->Release();
|
||||
RELEASE_MANUALLY(aClient);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ bool ImageBridgeParent::RecvWillStop()
|
||||
static void
|
||||
ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent)
|
||||
{
|
||||
aImageBridgeParent->Release();
|
||||
RELEASE_MANUALLY(aImageBridgeParent);
|
||||
}
|
||||
|
||||
bool ImageBridgeParent::RecvStop()
|
||||
@ -218,7 +218,7 @@ bool ImageBridgeParent::RecvStop()
|
||||
// the handling of this sync message can't race with the destruction of
|
||||
// the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames"
|
||||
// assertion of MessageChannel.
|
||||
AddRef();
|
||||
ADDREF_MANUALLY(this);
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&ReleaseImageBridgeParent, this));
|
||||
|
@ -162,12 +162,12 @@ protected:
|
||||
void AddIPDLReference() {
|
||||
MOZ_ASSERT(mIPCOpen == false);
|
||||
mIPCOpen = true;
|
||||
AddRef();
|
||||
ADDREF_MANUALLY(this);
|
||||
}
|
||||
void ReleaseIPDLReference() {
|
||||
MOZ_ASSERT(mIPCOpen == true);
|
||||
mIPCOpen = false;
|
||||
Release();
|
||||
RELEASE_MANUALLY(this);
|
||||
}
|
||||
friend class CompositorParent;
|
||||
friend class CrossProcessCompositorParent;
|
||||
|
@ -65,7 +65,7 @@ struct SurfaceDescriptorDXGIYCbCr {
|
||||
};
|
||||
|
||||
struct SurfaceDescriptorMacIOSurface {
|
||||
uint32_t surface;
|
||||
uint32_t surfaceId;
|
||||
double scaleFactor;
|
||||
bool isOpaque;
|
||||
};
|
||||
@ -79,6 +79,7 @@ struct EGLImageDescriptor {
|
||||
uintptr_t image; // `EGLImage` is a `void*`.
|
||||
uintptr_t fence;
|
||||
IntSize size;
|
||||
bool hasAlpha;
|
||||
};
|
||||
|
||||
struct NewSurfaceDescriptorGralloc {
|
||||
@ -92,10 +93,6 @@ struct NewSurfaceDescriptorGralloc {
|
||||
bool isOpaque;
|
||||
};
|
||||
|
||||
struct SharedSurfaceDescriptor {
|
||||
uintptr_t surf;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for shmem-backed YCbCr and (flavors of) RGBA textures
|
||||
*/
|
||||
@ -107,7 +104,7 @@ struct SurfaceDescriptorShmem {
|
||||
/**
|
||||
* Used for "raw memory"-backed YCbCr and (flavors of) RGBA textures
|
||||
*/
|
||||
struct SurfaceDescriptorMemory {
|
||||
struct SurfaceDescriptorMemory {
|
||||
uintptr_t data;
|
||||
SurfaceFormat format;
|
||||
};
|
||||
@ -125,7 +122,6 @@ union SurfaceDescriptor {
|
||||
EGLImageDescriptor;
|
||||
SurfaceDescriptorMacIOSurface;
|
||||
NewSurfaceDescriptorGralloc;
|
||||
SharedSurfaceDescriptor;
|
||||
null_t;
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,14 @@ parent:
|
||||
// and so forth being interpolated. That's what we want to happen.
|
||||
sync MakeSnapshot(SurfaceDescriptor inSnapshot, IntRect dirtyRect);
|
||||
|
||||
// Same as Makesnapshot(), except the snapshot is read from the underlying
|
||||
// operating system desktop rather than the compositor's backbuffer. This
|
||||
// is intended for testing whether hardware acceleration works.
|
||||
//
|
||||
// This call is part of IPDL, even though it simply wraps an nsIWidget
|
||||
// call, to make sure it does not occur in the middle of a composite.
|
||||
sync MakeWidgetSnapshot(SurfaceDescriptor inSnapshot);
|
||||
|
||||
// Make sure any pending composites are started immediately and
|
||||
// block until they are completed.
|
||||
sync FlushRendering();
|
||||
|
@ -37,7 +37,10 @@ SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
|
||||
|
||||
if (mCompositable->GetAsyncID() != 0 &&
|
||||
!InImageBridgeChildThread()) {
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().take());
|
||||
ADDREF_MANUALLY(mTextureClient);
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
|
||||
mTextureClient = nullptr;
|
||||
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().take());
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,10 @@ SharedRGBImage::~SharedRGBImage()
|
||||
|
||||
if (mCompositable->GetAsyncID() != 0 &&
|
||||
!InImageBridgeChildThread()) {
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().take());
|
||||
ADDREF_MANUALLY(mTextureClient);
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
|
||||
mTextureClient = nullptr;
|
||||
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().take());
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ EXPORTS.mozilla.layers += [
|
||||
'client/TextureClient.h',
|
||||
'client/TextureClientPool.h',
|
||||
'client/TextureClientRecycleAllocator.h',
|
||||
'client/TextureClientSharedSurface.h',
|
||||
'client/TiledContentClient.h',
|
||||
'composite/AsyncCompositionManager.h',
|
||||
'composite/CanvasLayerComposite.h',
|
||||
@ -267,6 +268,7 @@ UNIFIED_SOURCES += [
|
||||
'client/TextureClient.cpp',
|
||||
'client/TextureClientPool.cpp',
|
||||
'client/TextureClientRecycleAllocator.cpp',
|
||||
'client/TextureClientSharedSurface.cpp',
|
||||
'client/TiledContentClient.cpp',
|
||||
'composite/AsyncCompositionManager.cpp',
|
||||
'composite/CanvasLayerComposite.cpp',
|
||||
|
@ -19,6 +19,10 @@ class MediaBuffer;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class SharedSurface;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
|
||||
const SurfaceDescriptorMacIOSurface& aDescriptor)
|
||||
: TextureHost(aFlags)
|
||||
{
|
||||
mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
|
||||
mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(),
|
||||
aDescriptor.scaleFactor(),
|
||||
!aDescriptor.isOpaque());
|
||||
}
|
||||
|
@ -46,7 +46,9 @@ EGLImageTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
MOZ_ASSERT(IsAllocated());
|
||||
|
||||
const EGLImageImage::Data* data = mImage->GetData();
|
||||
aOutDescriptor = EGLImageDescriptor((uintptr_t)data->mImage, (uintptr_t)data->mSync, mSize);
|
||||
const bool hasAlpha = true;
|
||||
aOutDescriptor = EGLImageDescriptor((uintptr_t)data->mImage, (uintptr_t)data->mSync,
|
||||
mSize, hasAlpha);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,6 @@
|
||||
#include "mozilla/gfx/2D.h" // for DataSourceSurface
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
# include "GrallocImages.h" // for GrallocImage
|
||||
# include "EGLImageHelpers.h"
|
||||
#endif
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/GrallocTextureHost.h"
|
||||
@ -26,11 +22,17 @@
|
||||
#include "AndroidSurfaceTexture.h"
|
||||
#include "GfxTexturesReporter.h" // for GfxTexturesReporter
|
||||
#include "GLBlitTextureImageHelper.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
# include "GrallocImages.h" // for GrallocImage
|
||||
# include "EGLImageHelpers.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "SharedSurfaceIO.h"
|
||||
#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
|
||||
#endif
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
|
||||
using namespace mozilla::gl;
|
||||
using namespace mozilla::gfx;
|
||||
@ -69,7 +71,8 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
|
||||
result = new EGLImageTextureHost(aFlags,
|
||||
(EGLImage)desc.image(),
|
||||
(EGLSync)desc.fence(),
|
||||
desc.size());
|
||||
desc.size(),
|
||||
desc.hasAlpha());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -494,6 +497,8 @@ EGLImageTextureSource::EGLImageTextureSource(CompositorOGL* aCompositor,
|
||||
, mWrapMode(aWrapMode)
|
||||
, mSize(aSize)
|
||||
{
|
||||
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -507,13 +512,12 @@ EGLImageTextureSource::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
|
||||
MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl()),
|
||||
"EGLImage not supported or disabled in runtime");
|
||||
|
||||
GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit);
|
||||
GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit);
|
||||
|
||||
gl()->fActiveTexture(aTextureUnit);
|
||||
gl()->fBindTexture(mTextureTarget, tex);
|
||||
|
||||
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D);
|
||||
gl()->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mImage);
|
||||
gl()->fEGLImageTargetTexture2D(mTextureTarget, mImage);
|
||||
|
||||
ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
|
||||
}
|
||||
@ -549,18 +553,18 @@ EGLImageTextureSource::GetTextureTransform()
|
||||
EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags,
|
||||
EGLImage aImage,
|
||||
EGLSync aSync,
|
||||
gfx::IntSize aSize)
|
||||
gfx::IntSize aSize,
|
||||
bool hasAlpha)
|
||||
: TextureHost(aFlags)
|
||||
, mImage(aImage)
|
||||
, mSync(aSync)
|
||||
, mSize(aSize)
|
||||
, mHasAlpha(hasAlpha)
|
||||
, mCompositor(nullptr)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
EGLImageTextureHost::~EGLImageTextureHost()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
gl::GLContext*
|
||||
EGLImageTextureHost::gl() const
|
||||
@ -575,14 +579,23 @@ EGLImageTextureHost::Lock()
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
|
||||
EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
|
||||
|
||||
if (mSync) {
|
||||
MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
|
||||
status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
|
||||
}
|
||||
|
||||
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
|
||||
MOZ_ASSERT(status != 0,
|
||||
"ClientWaitSync generated an error. Has mSync already been destroyed?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mTextureSource) {
|
||||
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
|
||||
GLenum target = LOCAL_GL_TEXTURE_2D;
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
|
||||
: gfx::SurfaceFormat::R8G8B8X8;
|
||||
GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
|
||||
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
|
||||
mTextureSource = new EGLImageTextureSource(mCompositor,
|
||||
mImage,
|
||||
|
@ -425,7 +425,8 @@ public:
|
||||
EGLImageTextureHost(TextureFlags aFlags,
|
||||
EGLImage aImage,
|
||||
EGLSync aSync,
|
||||
gfx::IntSize aSize);
|
||||
gfx::IntSize aSize,
|
||||
bool hasAlpha);
|
||||
|
||||
virtual ~EGLImageTextureHost();
|
||||
|
||||
@ -461,6 +462,7 @@ protected:
|
||||
const EGLImage mImage;
|
||||
const EGLSync mSync;
|
||||
const gfx::IntSize mSize;
|
||||
const bool mHasAlpha;
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
RefPtr<EGLImageTextureSource> mTextureSource;
|
||||
};
|
||||
|
@ -391,7 +391,7 @@ IsSafeImageTransformComponent(gfxFloat aValue)
|
||||
return aValue >= -32768 && aValue <= 32767;
|
||||
}
|
||||
|
||||
#if !defined(MOZ_GFX_OPTIMIZE_MOBILE) && !defined(MOZ_WIDGET_COCOA)
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
/**
|
||||
* This returns the fastest operator to use for solid surfaces which have no
|
||||
* alpha channel or their alpha channel is uniformly opaque.
|
||||
@ -457,7 +457,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
|
||||
nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(surface, size, gfxMatrix::Translation(-needed.TopLeft()));
|
||||
return drawable.forget();
|
||||
}
|
||||
#endif // !MOZ_GFX_OPTIMIZE_MOBILE && !MOZ_WIDGET_COCOA
|
||||
#endif // !MOZ_GFX_OPTIMIZE_MOBILE
|
||||
|
||||
// working around cairo/pixman bug (bug 364968)
|
||||
// Our device-space-to-image-space transform may not be acceptable to pixman.
|
||||
@ -652,7 +652,7 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
|
||||
// On Mobile, we don't ever want to do this; it has the potential for
|
||||
// allocating very large temporary surfaces, especially since we'll
|
||||
// do full-page snapshots often (see bug 749426).
|
||||
#if !defined(MOZ_GFX_OPTIMIZE_MOBILE) && !defined(MOZ_WIDGET_COCOA)
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
nsRefPtr<gfxDrawable> restrictedDrawable =
|
||||
CreateSamplingRestrictedDrawable(aDrawable, aContext,
|
||||
aRegion, aFormat);
|
||||
|
@ -701,11 +701,35 @@ js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
|
||||
return proto;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReportLastIndexNonwritable(JSContext* cx)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_READ_ONLY, "\"lastIndex\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetLastIndex(JSContext* cx, Handle<RegExpObject*> reobj, double lastIndex)
|
||||
{
|
||||
if (!reobj->lookup(cx, cx->names().lastIndex)->writable())
|
||||
return ReportLastIndexNonwritable(cx);
|
||||
|
||||
reobj->setLastIndex(lastIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES6 final draft 21.2.5.2.2. */
|
||||
RegExpRunStatus
|
||||
js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
|
||||
MatchPairs* matches, RegExpStaticsUpdate staticsUpdate)
|
||||
{
|
||||
/* Step 1 (b) was performed by CallNonGenericMethod. */
|
||||
/*
|
||||
* WARNING: Despite the presence of spec step comment numbers, this
|
||||
* algorithm isn't consistent with any ES6 version, draft or
|
||||
* otherwise. YOU HAVE BEEN WARNED.
|
||||
*/
|
||||
|
||||
/* Steps 1-2 performed by the caller. */
|
||||
Rooted<RegExpObject*> reobj(cx, ®exp->as<RegExpObject>());
|
||||
|
||||
RegExpGuard re(cx);
|
||||
@ -721,16 +745,15 @@ js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
|
||||
res = nullptr;
|
||||
}
|
||||
|
||||
/* Step 3. */
|
||||
RootedLinearString input(cx, string->ensureLinear(cx));
|
||||
if (!input)
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/* Step 4. */
|
||||
RootedValue lastIndex(cx, reobj->getLastIndex());
|
||||
/* Step 3. */
|
||||
size_t length = input->length();
|
||||
|
||||
/* Step 5. */
|
||||
/* Steps 4-5. */
|
||||
RootedValue lastIndex(cx, reobj->getLastIndex());
|
||||
int searchIndex;
|
||||
if (lastIndex.isInt32()) {
|
||||
/* Aggressively avoid doubles. */
|
||||
@ -740,9 +763,13 @@ js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
|
||||
if (!ToInteger(cx, lastIndex, &d))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/* Inlined steps 6, 7, 9a with doubles to detect failure case. */
|
||||
/* Inlined steps 6-10, 15.a with doubles to detect failure case. */
|
||||
if (reobj->needUpdateLastIndex() && (d < 0 || d > length)) {
|
||||
reobj->zeroLastIndex();
|
||||
/* Steps 15.a.i-ii. */
|
||||
if (!SetLastIndex(cx, reobj, 0))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/* Step 15.a.iii. */
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
}
|
||||
|
||||
@ -750,7 +777,7 @@ js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
|
||||
}
|
||||
|
||||
/*
|
||||
* Steps 6-7 (with sticky extension).
|
||||
* Steps 6-10.
|
||||
*
|
||||
* Also make sure that we have a MatchPairs for regexps which update their
|
||||
* last index, as we won't compute the last index otherwise.
|
||||
@ -763,22 +790,30 @@ js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
|
||||
matches = &alternateMatches.ref();
|
||||
}
|
||||
|
||||
/* Step 9a. */
|
||||
/* Step 15.a. */
|
||||
if (searchIndex < 0 || size_t(searchIndex) > length) {
|
||||
reobj->zeroLastIndex();
|
||||
/* Steps 15.a.i-ii. */
|
||||
if (!SetLastIndex(cx, reobj, 0))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/* Step 15.a.iii. */
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
}
|
||||
|
||||
/* Steps 8-21. */
|
||||
/* Step 14-29. */
|
||||
RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, searchIndex, matches);
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/* Steps 9a and 11 (with sticky extension). */
|
||||
if (status == RegExpRunStatus_Success_NotFound)
|
||||
reobj->zeroLastIndex();
|
||||
else if (reobj->needUpdateLastIndex())
|
||||
reobj->setLastIndex((*matches)[0].limit);
|
||||
if (status == RegExpRunStatus_Success_NotFound) {
|
||||
/* Steps 15.a.i-ii. */
|
||||
if (!SetLastIndex(cx, reobj, 0))
|
||||
return RegExpRunStatus_Error;
|
||||
} else if (reobj->needUpdateLastIndex()) {
|
||||
/* Steps 18.a-b. */
|
||||
if (!SetLastIndex(cx, reobj, (*matches)[0].limit))
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ var ignoreClasses = {
|
||||
"XPCOMFunctions" : true, // I'm a little unsure of this one
|
||||
"_MD_IOVector" : true,
|
||||
"malloc_table_t": true, // replace_malloc
|
||||
"malloc_hook_table_t": true, // replace_malloc
|
||||
};
|
||||
|
||||
// Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing
|
||||
|
@ -367,7 +367,8 @@ Statistics::formatCompactSummaryMessage() const
|
||||
"Max Pause: %.3fms; MMU 20ms: %.1f%%; MMU 50ms: %.1f%%; Total: %.3fms; ",
|
||||
t(longest), mmu20 * 100., mmu50 * 100., t(total));
|
||||
} else {
|
||||
JS_snprintf(buffer, sizeof(buffer), "Non-Incremental: %.3fms; ", t(total));
|
||||
JS_snprintf(buffer, sizeof(buffer), "Non-Incremental: %.3fms (%s); ",
|
||||
t(total), nonincrementalReason_);
|
||||
}
|
||||
if (!fragments.append(make_string_copy(buffer)))
|
||||
return UniqueChars(nullptr);
|
||||
|
27
js/src/tests/ecma_6/RegExp/lastIndex-nonwritable.js
Normal file
27
js/src/tests/ecma_6/RegExp/lastIndex-nonwritable.js
Normal file
@ -0,0 +1,27 @@
|
||||
var BUGNUMBER = 1168416;
|
||||
var summary = "Regexp.prototype.test/exec shouldn't change lastIndex if not writable.";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var regex = /0/g;
|
||||
Object.freeze(regex);
|
||||
var str = "abc000";
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.value, 0);
|
||||
|
||||
assertThrowsInstanceOf(() => regex.test(str), TypeError);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.value, 0);
|
||||
|
||||
assertThrowsInstanceOf(() => regex.exec(str), TypeError);
|
||||
|
||||
desc = Object.getOwnPropertyDescriptor(regex, "lastIndex");
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.value, 0);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -1560,9 +1560,8 @@ void XPCJSRuntime::DestroyJSContextStack()
|
||||
|
||||
void XPCJSRuntime::SystemIsBeingShutDown()
|
||||
{
|
||||
if (mDetachedWrappedNativeProtoMap)
|
||||
mDetachedWrappedNativeProtoMap->
|
||||
Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
|
||||
mDetachedWrappedNativeProtoMap->
|
||||
Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
|
||||
}
|
||||
|
||||
#define JS_OPTIONS_DOT_STR "javascript.options."
|
||||
@ -1644,51 +1643,33 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
JS_SetRuntimePrivate(Runtime(), nullptr);
|
||||
|
||||
// clean up and destroy maps...
|
||||
if (mWrappedJSMap) {
|
||||
mWrappedJSMap->ShutdownMarker();
|
||||
delete mWrappedJSMap;
|
||||
mWrappedJSMap = nullptr;
|
||||
}
|
||||
mWrappedJSMap->ShutdownMarker();
|
||||
delete mWrappedJSMap;
|
||||
mWrappedJSMap = nullptr;
|
||||
|
||||
if (mWrappedJSClassMap) {
|
||||
delete mWrappedJSClassMap;
|
||||
mWrappedJSClassMap = nullptr;
|
||||
}
|
||||
delete mWrappedJSClassMap;
|
||||
mWrappedJSClassMap = nullptr;
|
||||
|
||||
if (mIID2NativeInterfaceMap) {
|
||||
delete mIID2NativeInterfaceMap;
|
||||
mIID2NativeInterfaceMap = nullptr;
|
||||
}
|
||||
delete mIID2NativeInterfaceMap;
|
||||
mIID2NativeInterfaceMap = nullptr;
|
||||
|
||||
if (mClassInfo2NativeSetMap) {
|
||||
delete mClassInfo2NativeSetMap;
|
||||
mClassInfo2NativeSetMap = nullptr;
|
||||
}
|
||||
delete mClassInfo2NativeSetMap;
|
||||
mClassInfo2NativeSetMap = nullptr;
|
||||
|
||||
if (mNativeSetMap) {
|
||||
delete mNativeSetMap;
|
||||
mNativeSetMap = nullptr;
|
||||
}
|
||||
delete mNativeSetMap;
|
||||
mNativeSetMap = nullptr;
|
||||
|
||||
if (mThisTranslatorMap) {
|
||||
delete mThisTranslatorMap;
|
||||
mThisTranslatorMap = nullptr;
|
||||
}
|
||||
delete mThisTranslatorMap;
|
||||
mThisTranslatorMap = nullptr;
|
||||
|
||||
if (mNativeScriptableSharedMap) {
|
||||
delete mNativeScriptableSharedMap;
|
||||
mNativeScriptableSharedMap = nullptr;
|
||||
}
|
||||
delete mNativeScriptableSharedMap;
|
||||
mNativeScriptableSharedMap = nullptr;
|
||||
|
||||
if (mDyingWrappedNativeProtoMap) {
|
||||
delete mDyingWrappedNativeProtoMap;
|
||||
mDyingWrappedNativeProtoMap = nullptr;
|
||||
}
|
||||
delete mDyingWrappedNativeProtoMap;
|
||||
mDyingWrappedNativeProtoMap = nullptr;
|
||||
|
||||
if (mDetachedWrappedNativeProtoMap) {
|
||||
delete mDetachedWrappedNativeProtoMap;
|
||||
mDetachedWrappedNativeProtoMap = nullptr;
|
||||
}
|
||||
delete mDetachedWrappedNativeProtoMap;
|
||||
mDetachedWrappedNativeProtoMap = nullptr;
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
// Tell the profiler that the runtime is gone
|
||||
@ -3674,7 +3655,7 @@ XPCJSRuntime::DebugDump(int16_t depth)
|
||||
XPC_LOG_INDENT();
|
||||
XPC_LOG_ALWAYS(("mJSRuntime @ %x", Runtime()));
|
||||
|
||||
XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
|
||||
XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)",
|
||||
&mWrappedJSToReleaseArray,
|
||||
mWrappedJSToReleaseArray.Length()));
|
||||
|
||||
@ -3692,43 +3673,39 @@ XPCJSRuntime::DebugDump(int16_t depth)
|
||||
XPC_LOG_OUTDENT();
|
||||
}
|
||||
|
||||
XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)", \
|
||||
mWrappedJSClassMap, mWrappedJSClassMap ? \
|
||||
mWrappedJSClassMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",
|
||||
mWrappedJSClassMap, mWrappedJSClassMap->Count()));
|
||||
// iterate wrappersclasses...
|
||||
if (depth && mWrappedJSClassMap && mWrappedJSClassMap->Count()) {
|
||||
if (depth && mWrappedJSClassMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
}
|
||||
XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)", \
|
||||
mWrappedJSMap, mWrappedJSMap ? \
|
||||
mWrappedJSMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",
|
||||
mWrappedJSMap, mWrappedJSMap->Count()));
|
||||
// iterate wrappers...
|
||||
if (depth && mWrappedJSMap && mWrappedJSMap->Count()) {
|
||||
if (depth && mWrappedJSMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
mWrappedJSMap->Dump(depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
}
|
||||
|
||||
XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)", \
|
||||
mIID2NativeInterfaceMap, mIID2NativeInterfaceMap ? \
|
||||
mIID2NativeInterfaceMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)",
|
||||
mIID2NativeInterfaceMap,
|
||||
mIID2NativeInterfaceMap->Count()));
|
||||
|
||||
XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)", \
|
||||
mClassInfo2NativeSetMap, mClassInfo2NativeSetMap ? \
|
||||
mClassInfo2NativeSetMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)",
|
||||
mClassInfo2NativeSetMap,
|
||||
mClassInfo2NativeSetMap->Count()));
|
||||
|
||||
XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)", \
|
||||
mThisTranslatorMap, mThisTranslatorMap ? \
|
||||
mThisTranslatorMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)",
|
||||
mThisTranslatorMap, mThisTranslatorMap->Count()));
|
||||
|
||||
XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)", \
|
||||
mNativeSetMap, mNativeSetMap ? \
|
||||
mNativeSetMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",
|
||||
mNativeSetMap, mNativeSetMap->Count()));
|
||||
|
||||
// iterate sets...
|
||||
if (depth && mNativeSetMap && mNativeSetMap->Count()) {
|
||||
if (depth && mNativeSetMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
|
@ -173,8 +173,8 @@ Native2WrappedNativeMap::newMap(int length)
|
||||
}
|
||||
|
||||
Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
|
||||
: mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
|
||||
}
|
||||
|
||||
Native2WrappedNativeMap::~Native2WrappedNativeMap()
|
||||
@ -187,7 +187,7 @@ Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
|
||||
n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -213,16 +213,12 @@ const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps =
|
||||
IID2WrappedJSClassMap*
|
||||
IID2WrappedJSClassMap::newMap(int length)
|
||||
{
|
||||
IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new IID2WrappedJSClassMap(length);
|
||||
}
|
||||
|
||||
IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
|
||||
: mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
|
||||
}
|
||||
|
||||
IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
|
||||
@ -230,7 +226,6 @@ IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
|
||||
delete mTable;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
// implement IID2NativeInterfaceMap...
|
||||
|
||||
@ -246,16 +241,12 @@ const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
|
||||
IID2NativeInterfaceMap*
|
||||
IID2NativeInterfaceMap::newMap(int length)
|
||||
{
|
||||
IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new IID2NativeInterfaceMap(length);
|
||||
}
|
||||
|
||||
IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length)
|
||||
: mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
|
||||
}
|
||||
|
||||
IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
|
||||
@ -268,7 +259,7 @@ IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
|
||||
n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -287,16 +278,12 @@ IID2NativeInterfaceMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
|
||||
ClassInfo2NativeSetMap*
|
||||
ClassInfo2NativeSetMap::newMap(int length)
|
||||
{
|
||||
ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new ClassInfo2NativeSetMap(length);
|
||||
}
|
||||
|
||||
ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
|
||||
: mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
|
||||
}
|
||||
|
||||
ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
|
||||
@ -310,7 +297,7 @@ ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocS
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
// The second arg is nullptr because this is a "shallow" measurement of the map.
|
||||
n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf) : 0;
|
||||
n += PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -325,8 +312,8 @@ ClassInfo2WrappedNativeProtoMap::newMap(int length)
|
||||
}
|
||||
|
||||
ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
|
||||
: mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
|
||||
}
|
||||
|
||||
ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
|
||||
@ -339,7 +326,7 @@ ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallo
|
||||
{
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
|
||||
n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -437,16 +424,12 @@ const struct PLDHashTableOps NativeSetMap::Entry::sOps =
|
||||
NativeSetMap*
|
||||
NativeSetMap::newMap(int length)
|
||||
{
|
||||
NativeSetMap* map = new NativeSetMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new NativeSetMap(length);
|
||||
}
|
||||
|
||||
NativeSetMap::NativeSetMap(int length)
|
||||
: mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
|
||||
}
|
||||
|
||||
NativeSetMap::~NativeSetMap()
|
||||
@ -459,7 +442,7 @@ NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
|
||||
n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -500,16 +483,12 @@ const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps =
|
||||
IID2ThisTranslatorMap*
|
||||
IID2ThisTranslatorMap::newMap(int length)
|
||||
{
|
||||
IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new IID2ThisTranslatorMap(length);
|
||||
}
|
||||
|
||||
IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
|
||||
: mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
|
||||
}
|
||||
|
||||
IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
|
||||
@ -575,17 +554,12 @@ const struct PLDHashTableOps XPCNativeScriptableSharedMap::Entry::sOps =
|
||||
XPCNativeScriptableSharedMap*
|
||||
XPCNativeScriptableSharedMap::newMap(int length)
|
||||
{
|
||||
XPCNativeScriptableSharedMap* map =
|
||||
new XPCNativeScriptableSharedMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new XPCNativeScriptableSharedMap(length);
|
||||
}
|
||||
|
||||
XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length)
|
||||
: mTable(new PLDHashTable(&Entry::sOps, sizeof(Entry), length))
|
||||
{
|
||||
mTable = new PLDHashTable(&Entry::sOps, sizeof(Entry), length);
|
||||
}
|
||||
|
||||
XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
|
||||
@ -627,17 +601,13 @@ XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags,
|
||||
XPCWrappedNativeProtoMap*
|
||||
XPCWrappedNativeProtoMap::newMap(int length)
|
||||
{
|
||||
XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(length);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
return new XPCWrappedNativeProtoMap(length);
|
||||
}
|
||||
|
||||
XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length)
|
||||
: mTable(new PLDHashTable(PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
|
||||
length))
|
||||
{
|
||||
mTable = new PLDHashTable(PL_DHashGetStubOps(),
|
||||
sizeof(PLDHashEntryStub), length);
|
||||
}
|
||||
|
||||
XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
|
||||
|
@ -32,10 +32,13 @@ class JSObject2WrappedJSMap
|
||||
public:
|
||||
static JSObject2WrappedJSMap* newMap(int length) {
|
||||
JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap();
|
||||
if (map && map->mTable.init(length))
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
if (!map->mTable.init(length)) {
|
||||
// This is a decent estimate of the size of the hash table's
|
||||
// entry storage. The |2| is because on average the capacity is
|
||||
// twice the requested length.
|
||||
NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
inline nsXPCWrappedJS* Find(JSObject* Obj) {
|
||||
@ -599,10 +602,13 @@ class JSObject2JSObjectMap
|
||||
public:
|
||||
static JSObject2JSObjectMap* newMap(int length) {
|
||||
JSObject2JSObjectMap* map = new JSObject2JSObjectMap();
|
||||
if (map && map->mTable.init(length))
|
||||
return map;
|
||||
delete map;
|
||||
return nullptr;
|
||||
if (!map->mTable.init(length)) {
|
||||
// This is a decent estimate of the size of the hash table's
|
||||
// entry storage. The |2| is because on average the capacity is
|
||||
// twice the requested length.
|
||||
NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
inline JSObject* Find(JSObject* key) {
|
||||
|
@ -428,15 +428,11 @@ XPCWrappedNativeScope::~XPCWrappedNativeScope()
|
||||
|
||||
// We can do additional cleanup assertions here...
|
||||
|
||||
if (mWrappedNativeMap) {
|
||||
MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
|
||||
delete mWrappedNativeMap;
|
||||
}
|
||||
MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
|
||||
delete mWrappedNativeMap;
|
||||
|
||||
if (mWrappedNativeProtoMap) {
|
||||
MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
|
||||
delete mWrappedNativeProtoMap;
|
||||
}
|
||||
MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
|
||||
delete mWrappedNativeProtoMap;
|
||||
|
||||
// This should not be necessary, since the Components object should die
|
||||
// with the scope but just in case.
|
||||
@ -833,21 +829,20 @@ XPCWrappedNativeScope::DebugDump(int16_t depth)
|
||||
XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get()));
|
||||
XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get()));
|
||||
|
||||
XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)", \
|
||||
mWrappedNativeMap, \
|
||||
mWrappedNativeMap ? mWrappedNativeMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",
|
||||
mWrappedNativeMap, mWrappedNativeMap->Count()));
|
||||
// iterate contexts...
|
||||
if (depth && mWrappedNativeMap && mWrappedNativeMap->Count()) {
|
||||
if (depth && mWrappedNativeMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
}
|
||||
|
||||
XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)", \
|
||||
mWrappedNativeProtoMap, \
|
||||
mWrappedNativeProtoMap ? mWrappedNativeProtoMap->Count() : 0));
|
||||
XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)",
|
||||
mWrappedNativeProtoMap,
|
||||
mWrappedNativeProtoMap->Count()));
|
||||
// iterate contexts...
|
||||
if (depth && mWrappedNativeProtoMap && mWrappedNativeProtoMap->Count()) {
|
||||
if (depth && mWrappedNativeProtoMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
|
@ -87,7 +87,6 @@ WrapperFactory::CreateXrayWaiver(JSContext* cx, HandleObject obj)
|
||||
if (!scope->mWaiverWrapperMap) {
|
||||
scope->mWaiverWrapperMap =
|
||||
JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_LENGTH);
|
||||
MOZ_ASSERT(scope->mWaiverWrapperMap);
|
||||
}
|
||||
if (!scope->mWaiverWrapperMap->Add(cx, obj, waiver))
|
||||
return nullptr;
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a nsFrameList from the shell arena.
|
||||
* Infallibly allocate a nsFrameList from the shell arena.
|
||||
*/
|
||||
void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
|
||||
|
||||
|
@ -145,8 +145,6 @@ nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine)
|
||||
}
|
||||
}
|
||||
|
||||
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
||||
// to perform the allocation.
|
||||
void*
|
||||
nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
|
||||
{
|
||||
|
@ -206,8 +206,8 @@ private:
|
||||
nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock);
|
||||
~nsLineBox();
|
||||
|
||||
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
||||
// to perform the allocation.
|
||||
// Infallible overloaded new operator. Uses an arena (which comes from the
|
||||
// presShell) to perform the allocation.
|
||||
void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
|
||||
void operator delete(void* aPtr, size_t sz) = delete;
|
||||
|
||||
|
@ -116,7 +116,7 @@ random-if(OSX==1010) == background-size-monster-rem.html background-size-monster
|
||||
# the image aren't the issue, because they're being obscured to avoid sampling
|
||||
# algorithm dependencies (at least assuming the sampling algorithm in use
|
||||
# doesn't sample too far astray from the boundaries).
|
||||
fails-if(supportsRepeatResampling) == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
|
||||
fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
|
||||
|
||||
# -moz-default-background-color and -moz-default-color (bug 591341)
|
||||
== background-moz-default-background-color.html background-moz-default-background-color-ref.html
|
||||
|
@ -1014,7 +1014,7 @@ skip-if(B2G||Mulet) == 421234-1.html 421234-1-ref.html # Initial mulet triage: p
|
||||
== 421436-1b.html 421436-1-ref.html
|
||||
== 421632-1.html 421632-1-ref.html
|
||||
!= 421710-1.html about:blank
|
||||
skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 421885-1.xml 421885-1-ref.xml # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) fails-if(Android) == 421885-1.xml 421885-1-ref.xml # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
== 421955-1.html 421955-1-ref.html
|
||||
skip-if(B2G||Mulet) == 422249-1.html 422249-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
== 422394-1.html 422394-1-ref.html
|
||||
@ -1164,13 +1164,13 @@ random == 445004-1.html 445004-1-ref.html # bug 472268
|
||||
== 445142-1c.html 445142-1-ref.html
|
||||
== 445142-2a.html 445142-2-ref.html
|
||||
== 445142-2b.html 445142-2-ref.html
|
||||
fails-if(!supportsRepeatResampling) == 446100-1a.html about:blank
|
||||
skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1b.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1c.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fails-if(!supportsRepeatResampling) == 446100-1d.html about:blank
|
||||
== 446100-1a.html about:blank
|
||||
skip-if(B2G||Mulet) fails-if(Android) == 446100-1b.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) fails-if(Android) == 446100-1c.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
== 446100-1d.html about:blank
|
||||
== 446100-1e.html about:blank
|
||||
== 446100-1f.html about:blank
|
||||
skip-if(B2G||Mulet) fails-if(Android) fails-if(!supportsRepeatResampling) == 446100-1g.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) fails-if(Android) == 446100-1g.html about:blank # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
== 446100-1h.html about:blank
|
||||
skip-if(B2G||Mulet) == 447749-1.html 447749-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fuzzy(127,2) == 448193.html 448193-ref.html
|
||||
|
@ -18,7 +18,7 @@ fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint-
|
||||
== element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
|
||||
fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
|
||||
== element-paint-native-widget.html element-paint-native-widget-ref.html
|
||||
fails-if(!supportsRepeatResampling) == element-paint-subimage-sampling-restriction.html about:blank
|
||||
== element-paint-subimage-sampling-restriction.html about:blank
|
||||
== element-paint-clippath.html element-paint-clippath-ref.html
|
||||
== element-paint-sharpness-01a.html element-paint-sharpness-01b.html
|
||||
== element-paint-sharpness-01b.html element-paint-sharpness-01c.html
|
||||
|
@ -1394,7 +1394,6 @@ SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
|
||||
NS_NOTREACHED("SetFactor: inappropriate unit");
|
||||
}
|
||||
|
||||
// Overloaded new operator that allocates from a presShell arena.
|
||||
void*
|
||||
nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
|
||||
{
|
||||
@ -1554,20 +1553,11 @@ nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
|
||||
else {
|
||||
next = entry->mRuleNode = new (mPresContext)
|
||||
nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
|
||||
if (!next) {
|
||||
PL_DHashTableRawRemove(ChildrenHash(), entry);
|
||||
NS_WARNING("out of memory");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
} else if (!next) {
|
||||
// Create the new entry in our list.
|
||||
next = new (mPresContext)
|
||||
nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
|
||||
if (!next) {
|
||||
NS_WARNING("out of memory");
|
||||
return this;
|
||||
}
|
||||
next->mNextSibling = ChildrenList();
|
||||
SetChildrenList(next);
|
||||
}
|
||||
|
@ -394,7 +394,7 @@ private:
|
||||
uint32_t mRefCnt;
|
||||
|
||||
public:
|
||||
// Overloaded new operator that allocates from a presShell arena.
|
||||
// Infallible overloaded new operator that allocates from a presShell arena.
|
||||
void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
|
||||
void Destroy() { DestroyInternal(nullptr); }
|
||||
|
||||
@ -651,6 +651,7 @@ private:
|
||||
~nsRuleNode();
|
||||
|
||||
public:
|
||||
// This is infallible; it will never return nullptr.
|
||||
static nsRuleNode* CreateRootNode(nsPresContext* aPresContext);
|
||||
|
||||
static void EnsureBlockDisplay(uint8_t& display,
|
||||
|
@ -218,10 +218,7 @@ nsStyleSet::BeginReconstruct()
|
||||
NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
|
||||
|
||||
// Create a new rule tree root
|
||||
nsRuleNode* newTree =
|
||||
nsRuleNode::CreateRootNode(mRuleTree->PresContext());
|
||||
if (!newTree)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsRuleNode* newTree = nsRuleNode::CreateRootNode(mRuleTree->PresContext());
|
||||
|
||||
// Save the old rule tree so we can destroy it later
|
||||
if (!mOldRuleTrees.AppendElement(mRuleTree)) {
|
||||
|
@ -755,9 +755,6 @@ function BuildConditionSandbox(aURL) {
|
||||
dump("REFTEST INFO | " + JSON.stringify(CU.waiveXrays(sandbox)) + " \n");
|
||||
gDumpedConditionSandbox = true;
|
||||
}
|
||||
|
||||
// Graphics features
|
||||
sandbox.supportsRepeatResampling = !sandbox.cocoaWidget;
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "runnable_utils.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
|
||||
// nICEr includes
|
||||
extern "C" {
|
||||
@ -434,8 +436,29 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
|
||||
NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232);
|
||||
}
|
||||
|
||||
NR_reg_set_uint4((char *)"stun.client.maximum_transmits",7);
|
||||
NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD, 5000);
|
||||
int32_t stun_client_maximum_transmits = 7;
|
||||
int32_t ice_trickle_grace_period = 5000;
|
||||
#ifndef MOZILLA_XPCOMRT_API
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIPrefService> prefs =
|
||||
do_GetService("@mozilla.org/preferences-service;1", &res);
|
||||
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
||||
if (branch) {
|
||||
branch->GetIntPref(
|
||||
"media.peerconnection.ice.stun_client_maximum_transmits",
|
||||
&stun_client_maximum_transmits);
|
||||
branch->GetIntPref(
|
||||
"media.peerconnection.ice.trickle_grace_period",
|
||||
&ice_trickle_grace_period);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
NR_reg_set_uint4((char *)"stun.client.maximum_transmits",
|
||||
stun_client_maximum_transmits);
|
||||
NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
|
||||
ice_trickle_grace_period);
|
||||
|
||||
if (allow_loopback) {
|
||||
NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
|
||||
|
@ -35,6 +35,10 @@ typedef MALLOC_USABLE_SIZE_CONST_PTR void * usable_ptr_t;
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_DECL
|
||||
# ifndef MALLOC_DECL_VOID
|
||||
# define MALLOC_DECL_VOID(func, ...) MALLOC_DECL(func, void, __VA_ARGS__)
|
||||
# endif
|
||||
|
||||
# if MALLOC_FUNCS & MALLOC_FUNCS_INIT
|
||||
MALLOC_DECL(init, void, const malloc_table_t *)
|
||||
# endif
|
||||
@ -47,17 +51,19 @@ MALLOC_DECL(posix_memalign, int, void **, size_t, size_t)
|
||||
MALLOC_DECL(aligned_alloc, void *, size_t, size_t)
|
||||
MALLOC_DECL(calloc, void *, size_t, size_t)
|
||||
MALLOC_DECL(realloc, void *, void *, size_t)
|
||||
MALLOC_DECL(free, void, void *)
|
||||
MALLOC_DECL_VOID(free, void *)
|
||||
MALLOC_DECL(memalign, void *, size_t, size_t)
|
||||
MALLOC_DECL(valloc, void *, size_t)
|
||||
MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t)
|
||||
MALLOC_DECL(malloc_good_size, size_t, size_t)
|
||||
# endif
|
||||
# if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC
|
||||
MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t *)
|
||||
MALLOC_DECL(jemalloc_purge_freed_pages, void, void)
|
||||
MALLOC_DECL(jemalloc_free_dirty_pages, void, void)
|
||||
MALLOC_DECL_VOID(jemalloc_stats, jemalloc_stats_t *)
|
||||
MALLOC_DECL_VOID(jemalloc_purge_freed_pages, void)
|
||||
MALLOC_DECL_VOID(jemalloc_free_dirty_pages, void)
|
||||
# endif
|
||||
|
||||
# undef MALLOC_DECL_VOID
|
||||
#endif /* MALLOC_DECL */
|
||||
|
||||
#undef MALLOC_DECL
|
||||
|
@ -74,19 +74,6 @@
|
||||
|
||||
MOZ_BEGIN_EXTERN_C
|
||||
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
typedef return_type(name ## _impl_t)(__VA_ARGS__);
|
||||
|
||||
#include "malloc_decls.h"
|
||||
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
name ## _impl_t * name;
|
||||
|
||||
typedef struct {
|
||||
#include "malloc_decls.h"
|
||||
} malloc_table_t;
|
||||
|
||||
|
||||
/* MOZ_NO_REPLACE_FUNC_DECL and MOZ_REPLACE_WEAK are only defined in
|
||||
* replace_malloc.c. Normally including this header will add function
|
||||
* definitions. */
|
||||
|
@ -48,15 +48,59 @@
|
||||
|
||||
struct ReplaceMallocBridge;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
MOZ_BEGIN_EXTERN_C
|
||||
|
||||
#ifndef REPLACE_MALLOC_IMPL
|
||||
/* Returns the replace-malloc bridge if there is one to be returned. */
|
||||
extern "C" MFBT_API ReplaceMallocBridge* get_bridge();
|
||||
MFBT_API ReplaceMallocBridge* get_bridge();
|
||||
#endif
|
||||
|
||||
/* Table of malloc functions.
|
||||
* e.g. void* (*malloc)(size_t), etc.
|
||||
*/
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
typedef return_type(name ## _impl_t)(__VA_ARGS__);
|
||||
|
||||
#include "malloc_decls.h"
|
||||
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
name ## _impl_t * name;
|
||||
|
||||
typedef struct {
|
||||
#include "malloc_decls.h"
|
||||
} malloc_table_t;
|
||||
|
||||
|
||||
/* Table of malloc hook functions.
|
||||
* Those functions are called with the arguments and results of malloc
|
||||
* functions after they are called.
|
||||
* e.g. void* (*malloc_hook)(void*, size_t), etc.
|
||||
* They can either return the result they're given, or alter it before
|
||||
* returning it.
|
||||
* The hooks corresponding to functions, like free(void*), that return no
|
||||
* value, don't take an extra argument.
|
||||
* The table must at least contain a pointer for malloc_hook and free_hook
|
||||
* functions. They will be used as fallback if no pointer is given for
|
||||
* other allocation functions, like calloc_hook.
|
||||
*/
|
||||
#define MALLOC_DECL(name, return_type, ...) \
|
||||
return_type (*name ## _hook)(return_type, __VA_ARGS__);
|
||||
#define MALLOC_DECL_VOID(name, ...) \
|
||||
void (*name ## _hook)(__VA_ARGS__);
|
||||
|
||||
typedef struct {
|
||||
#include "malloc_decls.h"
|
||||
/* Like free_hook, but called before realloc_hook. free_hook is called
|
||||
* instead of not given. */
|
||||
void (*realloc_hook_before)(void* aPtr);
|
||||
} malloc_hook_table_t;
|
||||
|
||||
MOZ_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace mozilla {
|
||||
namespace dmd {
|
||||
struct DMDFuncs;
|
||||
@ -75,7 +119,7 @@ struct DebugFdRegistry
|
||||
|
||||
struct ReplaceMallocBridge
|
||||
{
|
||||
ReplaceMallocBridge() : mVersion(2) {}
|
||||
ReplaceMallocBridge() : mVersion(3) {}
|
||||
|
||||
/* This method was added in version 1 of the bridge. */
|
||||
virtual mozilla::dmd::DMDFuncs* GetDMDFuncs() { return nullptr; }
|
||||
@ -86,6 +130,23 @@ struct ReplaceMallocBridge
|
||||
* This method was added in version 2 of the bridge. */
|
||||
virtual void InitDebugFd(mozilla::DebugFdRegistry&) {}
|
||||
|
||||
/* Register a list of malloc functions and hook functions to the
|
||||
* replace-malloc library so that it can choose to dispatch to them
|
||||
* when needed. The details of what is dispatched when is left to the
|
||||
* replace-malloc library.
|
||||
* Passing a nullptr for either table will unregister a previously
|
||||
* registered table under the same name.
|
||||
* Returns nullptr if registration failed.
|
||||
* If registration succeeded, a table of "pure" malloc functions is
|
||||
* returned. Those "pure" malloc functions won't call hooks.
|
||||
* /!\ Do not rely on registration/unregistration to be instantaneous.
|
||||
* Functions from a previously registered table may still be called for
|
||||
* a brief time after RegisterHook returns.
|
||||
* This method was added in version 3 of the bridge. */
|
||||
virtual const malloc_table_t*
|
||||
RegisterHook(const char* aName, const malloc_table_t* aTable,
|
||||
const malloc_hook_table_t* aHookTable) { return nullptr; }
|
||||
|
||||
#ifndef REPLACE_MALLOC_IMPL
|
||||
/* Returns the replace-malloc bridge if its version is at least the
|
||||
* requested one. */
|
||||
@ -124,6 +185,15 @@ struct ReplaceMalloc
|
||||
singleton->InitDebugFd(aRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
static const malloc_table_t*
|
||||
RegisterHook(const char* aName, const malloc_table_t* aTable,
|
||||
const malloc_hook_table_t* aHookTable)
|
||||
{
|
||||
auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 3);
|
||||
return singleton ? singleton->RegisterHook(aName, aTable, aHookTable)
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -4,7 +4,10 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['logalloc']
|
||||
DIRS += [
|
||||
'logalloc',
|
||||
'replace',
|
||||
]
|
||||
|
||||
# Build jemalloc3 as a replace-malloc lib when building with mozjemalloc
|
||||
if not CONFIG['MOZ_JEMALLOC3']:
|
||||
|
255
memory/replace/replace/ReplaceMalloc.cpp
Normal file
255
memory/replace/replace/ReplaceMalloc.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "replace_malloc.h"
|
||||
#include <errno.h>
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
/* Replace-malloc library allowing different kinds of dispatch.
|
||||
* The long term goal is to allow multiple replace-malloc libraries
|
||||
* to be loaded and coexist properly.
|
||||
* This is however a limited version to fulfil more immediate needs.
|
||||
*/
|
||||
static const malloc_table_t* gFuncs = nullptr;
|
||||
/* This should normally be a mozilla::Atomic<const malloc_hook_table_t*>
|
||||
* but MSVC 2013's atomic type doesn't like it. */
|
||||
static mozilla::Atomic<malloc_hook_table_t*> gHookTable(nullptr);
|
||||
|
||||
class GenericReplaceMallocBridge : public ReplaceMallocBridge
|
||||
{
|
||||
virtual const malloc_table_t*
|
||||
RegisterHook(const char* aName, const malloc_table_t* aTable,
|
||||
const malloc_hook_table_t* aHookTable) override
|
||||
{
|
||||
// Can't register a hook before replace_init is called.
|
||||
if (!gFuncs) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Expect a name to be given.
|
||||
if (!aName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Giving a malloc_table_t is not supported yet.
|
||||
if (aTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aHookTable) {
|
||||
// Expect at least a malloc and a free hook.
|
||||
if (!aHookTable->malloc_hook || !aHookTable->free_hook) {
|
||||
return nullptr;
|
||||
}
|
||||
gHookTable = const_cast<malloc_hook_table_t*>(aHookTable);
|
||||
return gFuncs;
|
||||
}
|
||||
gHookTable = nullptr;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
replace_init(const malloc_table_t* aTable)
|
||||
{
|
||||
gFuncs = aTable;
|
||||
}
|
||||
|
||||
ReplaceMallocBridge*
|
||||
replace_get_bridge()
|
||||
{
|
||||
static GenericReplaceMallocBridge bridge;
|
||||
return &bridge;
|
||||
}
|
||||
|
||||
void*
|
||||
replace_malloc(size_t aSize)
|
||||
{
|
||||
void* ptr = gFuncs->malloc(aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
return hook_table->malloc_hook(ptr, aSize);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int
|
||||
replace_posix_memalign(void** aPtr, size_t aAlignment, size_t aSize)
|
||||
{
|
||||
int ret = gFuncs->posix_memalign(aPtr, aAlignment, aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->posix_memalign_hook) {
|
||||
return hook_table->posix_memalign_hook(ret, aPtr, aAlignment, aSize);
|
||||
}
|
||||
void* ptr = hook_table->malloc_hook(*aPtr, aSize);
|
||||
if (!ptr && *aPtr) {
|
||||
*aPtr = ptr;
|
||||
ret = ENOMEM;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void*
|
||||
replace_aligned_alloc(size_t aAlignment, size_t aSize)
|
||||
{
|
||||
void* ptr = gFuncs->aligned_alloc(aAlignment, aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->aligned_alloc_hook) {
|
||||
return hook_table->aligned_alloc_hook(ptr, aAlignment, aSize);
|
||||
}
|
||||
return hook_table->malloc_hook(ptr, aSize);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void*
|
||||
replace_calloc(size_t aNum, size_t aSize)
|
||||
{
|
||||
void* ptr = gFuncs->calloc(aNum, aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->calloc_hook) {
|
||||
return hook_table->calloc_hook(ptr, aNum, aSize);
|
||||
}
|
||||
mozilla::CheckedInt<size_t> size = mozilla::CheckedInt<size_t>(aNum) * aSize;
|
||||
if (size.isValid()) {
|
||||
return hook_table->malloc_hook(ptr, size.value());
|
||||
}
|
||||
/* If the multiplication above overflows, calloc will have failed, so ptr
|
||||
* is null. But the hook might still be interested in knowing about the
|
||||
* allocation attempt. The choice made is to indicate the overflow with
|
||||
* the biggest value of a size_t, which is not that bad an indicator:
|
||||
* there are only 5 prime factors to 2^32 - 1 and 7 prime factors to
|
||||
* 2^64 - 1 and none of them is going to come directly out of sizeof().
|
||||
* IOW, the likelyhood of aNum * aSize being exactly SIZE_MAX is low
|
||||
* enough, and SIZE_MAX still conveys that the attempted allocation was
|
||||
* too big anyways. */
|
||||
return hook_table->malloc_hook(ptr, SIZE_MAX);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void*
|
||||
replace_realloc(void* aPtr, size_t aSize)
|
||||
{
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->realloc_hook_before) {
|
||||
hook_table->realloc_hook_before(aPtr);
|
||||
} else {
|
||||
hook_table->free_hook(aPtr);
|
||||
}
|
||||
}
|
||||
void* new_ptr = gFuncs->realloc(aPtr, aSize);
|
||||
/* The hook table might have changed since before realloc was called,
|
||||
* either because of unregistration or registration of a new table.
|
||||
* We however go with consistency and use the same hook table as the
|
||||
* one that was used before the call to realloc. */
|
||||
if (hook_table) {
|
||||
if (hook_table->realloc_hook) {
|
||||
/* aPtr is likely invalid when reaching here, it is only given for
|
||||
* tracking purposes, and should not be dereferenced. */
|
||||
return hook_table->realloc_hook(new_ptr, aPtr, aSize);
|
||||
}
|
||||
return hook_table->malloc_hook(new_ptr, aSize);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
replace_free(void* aPtr)
|
||||
{
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
hook_table->free_hook(aPtr);
|
||||
}
|
||||
gFuncs->free(aPtr);
|
||||
}
|
||||
|
||||
void*
|
||||
replace_memalign(size_t aAlignment, size_t aSize)
|
||||
{
|
||||
void* ptr = gFuncs->memalign(aAlignment, aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->memalign_hook) {
|
||||
return hook_table->memalign_hook(ptr, aAlignment, aSize);
|
||||
}
|
||||
return hook_table->malloc_hook(ptr, aSize);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void*
|
||||
replace_valloc(size_t aSize)
|
||||
{
|
||||
void* ptr = gFuncs->valloc(aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table) {
|
||||
if (hook_table->valloc_hook) {
|
||||
return hook_table->valloc_hook(ptr, aSize);
|
||||
}
|
||||
return hook_table->malloc_hook(ptr, aSize);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t
|
||||
replace_malloc_usable_size(usable_ptr_t aPtr)
|
||||
{
|
||||
size_t ret = gFuncs->malloc_usable_size(aPtr);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table && hook_table->malloc_usable_size_hook) {
|
||||
return hook_table->malloc_usable_size_hook(ret, aPtr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
replace_malloc_good_size(size_t aSize)
|
||||
{
|
||||
size_t ret = gFuncs->malloc_good_size(aSize);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table && hook_table->malloc_good_size_hook) {
|
||||
return hook_table->malloc_good_size_hook(ret, aSize);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
replace_jemalloc_stats(jemalloc_stats_t* aStats)
|
||||
{
|
||||
gFuncs->jemalloc_stats(aStats);
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table && hook_table->jemalloc_stats_hook) {
|
||||
hook_table->jemalloc_stats_hook(aStats);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
replace_jemalloc_purge_freed_pages(void)
|
||||
{
|
||||
gFuncs->jemalloc_purge_freed_pages();
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table && hook_table->jemalloc_purge_freed_pages_hook) {
|
||||
hook_table->jemalloc_purge_freed_pages_hook();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
replace_jemalloc_free_dirty_pages(void)
|
||||
{
|
||||
gFuncs->jemalloc_free_dirty_pages();
|
||||
const malloc_hook_table_t* hook_table = gHookTable;
|
||||
if (hook_table && hook_table->jemalloc_free_dirty_pages_hook) {
|
||||
hook_table->jemalloc_free_dirty_pages_hook();
|
||||
}
|
||||
}
|
13
memory/replace/replace/moz.build
Normal file
13
memory/replace/replace/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
SharedLibrary('replace_malloc')
|
||||
|
||||
SOURCES += [
|
||||
'ReplaceMalloc.cpp',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
@ -523,8 +523,7 @@ Preferences::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = PREF_Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PREF_Init();
|
||||
|
||||
rv = pref_InitInitialObjects();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -644,8 +643,7 @@ Preferences::ResetPrefs()
|
||||
NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
|
||||
PREF_CleanupPrefs();
|
||||
|
||||
nsresult rv = PREF_Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PREF_Init();
|
||||
|
||||
return pref_InitInitialObjects();
|
||||
}
|
||||
|
@ -375,7 +375,8 @@ pref("media.peerconnection.ice.loopback", false); // Set only for testing in off
|
||||
pref("media.peerconnection.use_document_iceservers", true);
|
||||
pref("media.peerconnection.identity.enabled", true);
|
||||
pref("media.peerconnection.identity.timeout", 10000);
|
||||
pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
|
||||
pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
|
||||
pref("media.peerconnection.ice.trickle_grace_period", 5000);
|
||||
// These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
|
||||
// kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
|
||||
// setting (for Xxx = Ec, Agc, or Ns). Defaults are all set to kXxxDefault here.
|
||||
|
@ -147,7 +147,7 @@ static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, u
|
||||
|
||||
#define PREF_HASHTABLE_INITIAL_LENGTH 1024
|
||||
|
||||
nsresult PREF_Init()
|
||||
void PREF_Init()
|
||||
{
|
||||
if (!gHashTable) {
|
||||
gHashTable = new PLDHashTable(&pref_HashTableOps,
|
||||
@ -157,7 +157,6 @@ nsresult PREF_Init()
|
||||
PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
|
||||
PREFNAME_ARENA_SIZE);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Frees the callback list. */
|
||||
|
@ -42,7 +42,7 @@ struct PrefHashEntry : PLDHashEntryHdr
|
||||
// the preference hashtable.
|
||||
// </font>
|
||||
*/
|
||||
nsresult PREF_Init();
|
||||
void PREF_Init();
|
||||
|
||||
/*
|
||||
// Cleanup should be called at program exit to free the
|
||||
|
@ -130,10 +130,14 @@ function addCertFromFile(certdb, filename, trustString) {
|
||||
|
||||
function constructCertFromFile(filename) {
|
||||
let certFile = do_get_file(filename, false);
|
||||
let certDER = readFile(certFile);
|
||||
let certBytes = readFile(certFile);
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
return certdb.constructX509(certDER, certDER.length);
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
try {
|
||||
return certdb.constructX509(certBytes, certBytes.length);
|
||||
} catch (e) {}
|
||||
// It might be PEM instead of DER.
|
||||
return certdb.constructX509FromBase64(pemToBase64(certBytes));
|
||||
}
|
||||
|
||||
function setCertTrust(cert, trustString) {
|
||||
|
@ -5,7 +5,10 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += ['tlsserver']
|
||||
TEST_DIRS += ['test_intermediate_basic_usage_constraints']
|
||||
TEST_DIRS += [
|
||||
'test_cert_keyUsage',
|
||||
'test_intermediate_basic_usage_constraints',
|
||||
]
|
||||
|
||||
if not CONFIG['MOZ_NO_SMART_CARDS']:
|
||||
DIRS += ['pkcs11testmodule']
|
||||
|
61
security/manager/ssl/tests/unit/test_cert_keyUsage.js
Normal file
61
security/manager/ssl/tests/unit/test_cert_keyUsage.js
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
let caList = ["ca-no-keyUsage-extension", "ca-missing-keyCertSign",
|
||||
"ca-all-usages"];
|
||||
let eeList = ["ee-no-keyUsage-extension", "ee-keyCertSign-only",
|
||||
"ee-keyEncipherment-only", "ee-keyCertSign-and-keyEncipherment"];
|
||||
|
||||
let caUsage = "SSL CA";
|
||||
let allEEUsages = "Client,Server,Sign,Encrypt,Object Signer";
|
||||
let serverEEUsages = "Server,Encrypt";
|
||||
|
||||
let expectedUsagesMap = {
|
||||
"ca-no-keyUsage-extension": caUsage,
|
||||
"ca-missing-keyCertSign": "",
|
||||
"ca-all-usages": caUsage,
|
||||
|
||||
"ee-no-keyUsage-extension-ca-no-keyUsage-extension": allEEUsages,
|
||||
"ee-no-keyUsage-extension-ca-missing-keyCertSign": "",
|
||||
"ee-no-keyUsage-extension-ca-all-usages": allEEUsages,
|
||||
|
||||
"ee-keyCertSign-only-ca-no-keyUsage-extension": "",
|
||||
"ee-keyCertSign-only-ca-missing-keyCertSign": "",
|
||||
"ee-keyCertSign-only-ca-all-usages": "",
|
||||
|
||||
"ee-keyEncipherment-only-ca-no-keyUsage-extension": serverEEUsages,
|
||||
"ee-keyEncipherment-only-ca-missing-keyCertSign": "",
|
||||
"ee-keyEncipherment-only-ca-all-usages": serverEEUsages,
|
||||
|
||||
"ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension": serverEEUsages,
|
||||
"ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign": "",
|
||||
"ee-keyCertSign-and-keyEncipherment-ca-all-usages": serverEEUsages,
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
caList.forEach(function(ca) {
|
||||
addCertFromFile(certdb, "test_cert_keyUsage/" + ca + ".pem",
|
||||
"CTu,CTu,CTu");
|
||||
let caCert = certdb.findCertByNickname(null, ca);
|
||||
let usages = {};
|
||||
caCert.getUsagesString(true, {}, usages); // true indicates local-only
|
||||
equal(usages.value, expectedUsagesMap[ca],
|
||||
"Actual and expected CA usages should match");
|
||||
eeList.forEach(function(ee) {
|
||||
let eeFullName = ee + "-" + ca;
|
||||
let cert = constructCertFromFile(
|
||||
"test_cert_keyUsage/" + eeFullName + ".pem");
|
||||
cert.getUsagesString(true, {}, usages); // true indicates local-only
|
||||
equal(usages.value, expectedUsagesMap[eeFullName],
|
||||
"Actual and expected EE usages should match");
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
issuer:ca-all-usages
|
||||
subject:ca-all-usages
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user