import changes from `dev' branch of rmottola/Arctic-Fox:

- nsTArray*: fully sync with AF, and use ActualAlloc::Successful (adaf2f742)
- Bug 1182808 - Part 2: Remove AlignedFallibleTArray. r=padenot (e0f112fb4)
- Bug 1182808 - Part 3: Rename AlignedTArray_Impl to AlignedTArray and remove existing AlignedTArray. r=padenot (ff2beea1e)
- Bug 1148582 - Include the rounded clip of the async scrolled scroll frame in its mAncestorClip. (1633f8cb2)
- Bug 1148582 - Support multiple mask layers per layer in LayerManagerComposite. (d292070f8)
- Bug 1143575. #include nsDebug.h in YCbCrImageDataSerializer.cpp for NS_WARN_IF. r=nical (c9a7fe42c)
- Bug 1143575. Remove ImageClientBridge::Updated. r=nical (095f1f806)
- Bug 1143575. Pass a picture rect with OpUseOverlaySource and OpUseTexture, and eliminate OpUpdatePictureRect. r=nical (c134913c2)
- Bug 1143575. Extend IPDL OpUseTexture to support multiple timestamped images. r=nical (54d018cd1)
- Bug 1143575. Replace ImageClientSingle::UpdateImage's use of Image serial numbers with ImageContainer state generation counters, and switch it to use ImageContainer::GetCurrentImages. r=nical (e2e096ad2)
- Bug 1143575. ImageClient::UpdateImage should not return false when there's no image, because recreating the ImageClient won't help. r=nical (4be2ed5ed)
- Bug 1143575. Make ImageClientSingle handle multiple textures. r=nical (8889f2639)
- Bug 1143575. Store composition time in Compositor. r=nical (1501cc5d0)
- Bug 1143575. Implement ImageHost support for multiple timed images. r=nical (99a440556)
- Bug 1168456 - Remove NotifyWaitingForResourcesStatusChanged() call from MediaCodecReader r=bholley,bwu (efabdbeed)
- Bug 1163871: Use DebugOnly to suppress opt build warning in gonk nsAppShell.cpp. r=mwu (fc77b0322)
- Bug 1165161 - stop bootAnim with "browser-ui-startup-complete" event.  r=mwu (a2a9bbfdd)
- Bug 949036 - Make ID3v2 tag detection more careful - not every bit of data containing ID3 is a tag. r=eflores (ac590bbd1)
- bug 1137076 handle null mDecoder during Reader shutdown r=edwin (1507b0627)
- Bug 1150322 - Fix duration parsing in MediaOmxReader - r=sotaro (93577cfea)
- Bug 1112219 - Implement platform independent MediaResourceManager r=cpearce,bwu,nical (cc722ccf3)
- Bug 1091037 - Raise ImageBridge thread priority r=gsvelto,nical (d66ecdd06)
- Bug 1143575. Route ImageCompositeNotifications to ImageContainers. r=nical (fe5d3da61)
- bug 1184801 process AnalyserNode input only when required r=padenot (8079b66f5)
- Bug 1157768 - FFTBlock Changes for using libav fft; r=padenot (3238d710c)
- bug 914392 move mSharedBuffers ownership to engine r=padenot (4444d8352)
This commit is contained in:
2021-03-23 10:01:13 +08:00
parent fa6c289afc
commit c34e72358b
118 changed files with 3485 additions and 2387 deletions
+1
View File
@@ -47,6 +47,7 @@ class RenderFrameChild;
namespace layers {
class APZEventState;
class ImageCompositeNotification;
struct SetTargetAPZCCallback;
struct SetAllowedTouchBehaviorCallback;
}
+49 -14
View File
@@ -178,36 +178,67 @@ MP3Parser::GetSamplesPerFrame()
const char sID3Head[3] = { 'I', 'D', '3' };
const uint32_t ID3_HEADER_LENGTH = 10;
const uint32_t ID3_FOOTER_LENGTH = 10;
const uint8_t ID3_FOOTER_PRESENT = 0x10;
ID3Parser::ID3Parser()
: mCurrentChar(0)
, mVersion(0)
, mFlags(0)
, mHeaderLength(0)
{ }
void
ID3Parser::Reset()
{
mCurrentChar = mHeaderLength = 0;
mCurrentChar = mVersion = mFlags = mHeaderLength = 0;
}
bool
ID3Parser::ParseChar(char ch)
{
// First three bytes of an ID3v2 header must match the string "ID3".
if (mCurrentChar < sizeof(sID3Head) / sizeof(*sID3Head)
&& ch != sID3Head[mCurrentChar]) {
goto fail;
}
// The last four bytes of the header is a 28-bit unsigned integer with the
// high bit of each byte unset.
if (mCurrentChar >= 6 && mCurrentChar < ID3_HEADER_LENGTH) {
if (ch & 0x80) {
goto fail;
} else {
switch (mCurrentChar) {
// The first three bytes of an ID3v2 header must match the string "ID3".
case 0: case 1: case 2:
if (ch != sID3Head[mCurrentChar]) {
goto fail;
}
break;
// The fourth and fifth bytes give the version, between 2 and 4.
case 3:
if (ch < '\2' || ch > '\4') {
goto fail;
}
mVersion = uint8_t(ch);
break;
case 4:
if (ch != '\0') {
goto fail;
}
break;
// The sixth byte gives the flags; valid flags depend on the version.
case 5:
if ((ch & (0xff >> mVersion)) != '\0') {
goto fail;
}
mFlags = uint8_t(ch);
break;
// Bytes seven through ten give the sum of the byte length of the extended
// header, the padding and the frames after unsynchronisation.
// These bytes form a 28-bit integer, with the high bit of each byte unset.
case 6: case 7: case 8: case 9:
if (ch & 0x80) {
goto fail;
}
mHeaderLength <<= 7;
mHeaderLength |= ch;
}
if (mCurrentChar == 9) {
mHeaderLength += ID3_HEADER_LENGTH;
mHeaderLength += (mFlags & ID3_FOOTER_PRESENT) ? ID3_FOOTER_LENGTH : 0;
}
break;
default:
MOZ_CRASH("Header already fully parsed!");
}
mCurrentChar++;
@@ -215,6 +246,10 @@ ID3Parser::ParseChar(char ch)
return IsParsed();
fail:
if (mCurrentChar) {
Reset();
return ParseChar(ch);
}
Reset();
return false;
}
+2
View File
@@ -29,6 +29,8 @@ public:
private:
uint32_t mCurrentChar;
uint8_t mVersion;
uint8_t mFlags;
uint32_t mHeaderLength;
};
-3
View File
@@ -182,9 +182,6 @@ MediaDecoderReader::AsyncReadMetadata()
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
// PreReadMetadata causes us to try to allocate various hardware and OS
// resources, which may not be available at the moment.
PreReadMetadata();
if (IsWaitingMediaResources()) {
return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__);
}
+2 -5
View File
@@ -165,19 +165,16 @@ public:
virtual bool HasVideo() = 0;
// The default implementation of AsyncReadMetadata is implemented in terms of
// synchronous PreReadMetadata() / ReadMetadata() calls. Implementations may also
// synchronous ReadMetadata() calls. Implementations may also
// override AsyncReadMetadata to create a more proper async implementation.
virtual nsRefPtr<MetadataPromise> AsyncReadMetadata();
// A function that is called before ReadMetadata() call.
virtual void PreReadMetadata() {};
// Read header data for all bitstreams in the file. Fills aInfo with
// the data required to present the media, and optionally fills *aTags
// with tag metadata from the file.
// Returns NS_OK on success, or NS_ERROR_FAILURE on failure.
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) = 0;
MetadataTags** aTags) { MOZ_CRASH(); }
// Fills aInfo with the latest cached data required to present the media,
// ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
-7
View File
@@ -55,13 +55,6 @@ public:
}
virtual nsRefPtr<MetadataPromise> AsyncReadMetadata() override;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) override
{
// Unused as we provide AsyncReadMetadataAPI.
// However we must implement it as it's pure virtual.
return NS_OK;
}
virtual void ReadUpdatedMetadata(MediaInfo* aInfo) override;
+5 -1
View File
@@ -534,12 +534,16 @@ AppleMP3Reader::NotifyDataArrived(const char* aBuffer,
}
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
if (!mMP3FrameParser.IsMP3()) {
return;
}
uint64_t duration = mMP3FrameParser.GetDuration();
if (duration != mDuration) {
LOGD("Updating media duration to %lluus\n", duration);
mDuration = duration;
MOZ_ASSERT(mDecoder);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDuration = duration;
mDecoder->UpdateEstimatedMediaDuration(duration);
}
}
+7 -2
View File
@@ -404,15 +404,20 @@ void
DirectShowReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mMP3FrameParser.NeedsData()) {
return;
}
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
if (!mMP3FrameParser.IsMP3()) {
return;
}
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
int64_t duration = mMP3FrameParser.GetDuration();
if (duration != mDuration) {
mDuration = duration;
MOZ_ASSERT(mDecoder);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDuration = duration;
mDecoder->UpdateEstimatedMediaDuration(mDuration);
}
}
-1
View File
@@ -65,7 +65,6 @@ if CONFIG['MOZ_WEBRTC']:
if CONFIG['MOZ_OMX_DECODER']:
DIRS += ['omx']
DIRS += ['omx/mediaresourcemanager']
TEST_DIRS += [
'compiledtest',
+53 -23
View File
@@ -99,36 +99,40 @@ MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
, mPendingRequestMediaResource(false)
{
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
mResourceHandler = new MediaResourceHandler(this);
}
MediaCodecProxy::~MediaCodecProxy()
{
releaseCodec();
SetMediaCodecFree();
ReleaseMediaCodec();
}
bool
MediaCodecProxy::AskMediaCodecAndWait()
{
if (mResourceHandler == nullptr) {
if (mResourceClient || mCodec.get()) {
return false;
}
if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) {
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
mozilla::MediaSystemResourceType type =
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
if (allocateCodec()) {
return true;
}
} else {
}
if (!mResourceClient) {
return false;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = true;
// request video codec
mResourceClient->Acquire();
while (mPendingRequestMediaResource) {
mMediaCodecLock.Wait();
@@ -141,21 +145,30 @@ MediaCodecProxy::AskMediaCodecAndWait()
bool
MediaCodecProxy::AsyncAskMediaCodec()
{
if ((strncasecmp(mCodecMime.get(), "video/", 6) != 0) ||
(mResourceHandler == nullptr)) {
if (mResourceClient || mCodec.get()) {
return false;
}
if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) {
return false;
}
// request video codec
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
mozilla::MediaSystemResourceType type =
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
mResourceClient->Acquire();
return true;
}
void
MediaCodecProxy::SetMediaCodecFree()
MediaCodecProxy::ReleaseMediaCodec()
{
if (mResourceHandler == nullptr) {
releaseCodec();
if (!mResourceClient) {
return;
}
@@ -165,8 +178,10 @@ MediaCodecProxy::SetMediaCodecFree()
mon.NotifyAll();
}
mResourceHandler->cancelResource();
mResourceHandler = nullptr;
if (mResourceClient) {
mResourceClient->ReleaseResource();
mResourceClient = nullptr;
}
}
bool
@@ -477,15 +492,19 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
return OK;
}
// Called on a Binder thread
// Called on ImageBridge thread
void
MediaCodecProxy::resourceReserved()
MediaCodecProxy::ResourceReserved()
{
MCP_LOG("resourceReserved");
// Create MediaCodec
releaseCodec();
if (!allocateCodec()) {
SetMediaCodecFree();
ReleaseMediaCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecCanceled();
}
return;
}
@@ -501,6 +520,18 @@ MediaCodecProxy::resourceReserved()
}
}
// Called on ImageBridge thread
void
MediaCodecProxy::ResourceReserveFailed()
{
ReleaseMediaCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecCanceled();
}
}
bool MediaCodecProxy::Prepare()
{
@@ -624,8 +655,7 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
void MediaCodecProxy::ReleaseMediaResources()
{
releaseCodec();
SetMediaCodecFree()
ReleaseMediaCodec();
}
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
+11 -8
View File
@@ -11,8 +11,10 @@
#include <stagefright/MediaCodec.h>
#include <stagefright/MediaBuffer.h>
#include <utils/threads.h>
#include "MediaResourceHandler.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "mozilla/Monitor.h"
#include "nsRefPtr.h"
namespace android {
// This class is intended to be a proxy for MediaCodec with codec resource
@@ -21,7 +23,8 @@ namespace android {
// MediaCodecReader.cpp. Another useage is to use configure(), Prepare(),
// Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which
// doesn't need to handle the buffers for codec.
class MediaCodecProxy : public MediaResourceHandler::ResourceListener
class MediaCodecProxy : public RefBase
, public mozilla::MediaSystemResourceReservationListener
{
public:
/* Codec resource notification listener.
@@ -137,6 +140,7 @@ public:
// It asks for the OMX codec and blocked until the resource is grant to be
// allocated.
// Audio codec allocation should use this.
bool AskMediaCodecAndWait();
// It asks for the OMX codec asynchronously.
@@ -144,15 +148,14 @@ public:
bool AsyncAskMediaCodec();
// Free the OMX codec so others can allocate it.
void SetMediaCodecFree();
void ReleaseMediaCodec();
protected:
virtual ~MediaCodecProxy();
// MediaResourceHandler::EventListener::resourceReserved()
virtual void resourceReserved();
// MediaResourceHandler::EventListener::resourceCanceled()
virtual void resourceCanceled() {}
// MediaResourceReservationListener
void ResourceReserved() override;
void ResourceReserveFailed() override;
private:
// Forbidden
@@ -180,7 +183,7 @@ private:
wp<CodecResourceListener> mListener;
// Media Resource Management
sp<MediaResourceHandler> mResourceHandler;
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
// MediaCodec instance
mutable RWLock mCodecLock;
+72 -60
View File
@@ -269,7 +269,6 @@ MediaCodecReader::ProcessCachedDataTask::Run()
MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
: MediaOmxCommonReader(aDecoder)
, mExtractor(nullptr)
, mIsWaitingResources(false)
, mTextureClientIndexesLock("MediaCodecReader::mTextureClientIndexesLock")
, mColorConverterBufferSize(0)
, mParserMonitor("MediaCodecReader::mParserMonitor")
@@ -290,19 +289,6 @@ MediaCodecReader::Init(MediaDecoderReader* aCloneDonor)
return NS_OK;
}
bool
MediaCodecReader::IsWaitingMediaResources()
{
return mIsWaitingResources;
}
void
MediaCodecReader::UpdateIsWaitingMediaResources()
{
mIsWaitingResources = (mVideoTrack.mCodec != nullptr) &&
(!mVideoTrack.mCodec->allocated());
}
void
MediaCodecReader::ReleaseMediaResources()
{
@@ -648,58 +634,66 @@ MediaCodecReader::ParseDataSegment(const char* aBuffer,
return true;
}
void
MediaCodecReader::PreReadMetadata()
{
UpdateIsWaitingMediaResources();
}
nsresult
MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
nsRefPtr<MediaDecoderReader::MetadataPromise>
MediaCodecReader::AsyncReadMetadata()
{
MOZ_ASSERT(OnTaskQueue());
if (!ReallocateResources()) {
return NS_ERROR_FAILURE;
if (!ReallocateExtractorResources()) {
return MediaDecoderReader::MetadataPromise::CreateAndReject(
ReadMetadataFailureReason::METADATA_ERROR, __func__);
}
bool incrementalParserNeeded =
mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
if (incrementalParserNeeded && !TriggerIncrementalParser()) {
return NS_ERROR_FAILURE;
return MediaDecoderReader::MetadataPromise::CreateAndReject(
ReadMetadataFailureReason::METADATA_ERROR, __func__);
}
// Bug 1050667, both MediaDecoderStateMachine and MediaCodecReader
// relies on IsWaitingMediaResources() function. And the waiting state will be
// changed by binder thread, so we store the waiting state in a cache value to
// make them in the same waiting state.
UpdateIsWaitingMediaResources();
if (IsWaitingMediaResources()) {
return NS_OK;
}
nsRefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
nsRefPtr<MediaCodecReader> self = this;
mMediaResourceRequest.Begin(CreateMediaCodecs()
->RefableThen(GetTaskQueue(), __func__,
[self] (bool) -> void {
self->mMediaResourceRequest.Complete();
self->HandleResourceAllocated();
}, [self] (bool) -> void {
self->mMediaResourceRequest.Complete();
self->mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
}));
return p;
}
void
MediaCodecReader::HandleResourceAllocated()
{
// Configure video codec after the codecReserved.
if (mVideoTrack.mSource != nullptr) {
if (!ConfigureMediaCodec(mVideoTrack)) {
DestroyMediaCodec(mVideoTrack);
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
}
// TODO: start streaming
if (!UpdateDuration()) {
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
if (!UpdateAudioInfo()) {
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
if (!UpdateVideoInfo()) {
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
// Set the total duration (the max of the audio and video track).
@@ -727,14 +721,15 @@ MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
mozilla::TimeStamp::Now());
}
*aInfo = mInfo;
*aTags = nullptr;
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
metadata->mInfo = mInfo;
metadata->mTags = nullptr;
#ifdef MOZ_AUDIO_OFFLOAD
CheckAudioOffload();
#endif
return NS_OK;
mMetadataPromise.Resolve(metadata, __func__);
}
nsresult
@@ -1081,13 +1076,12 @@ MediaCodecReader::GetAudioOffloadTrack()
}
bool
MediaCodecReader::ReallocateResources()
MediaCodecReader::ReallocateExtractorResources()
{
if (CreateLooper() &&
CreateExtractor() &&
CreateMediaSources() &&
CreateTaskQueues() &&
CreateMediaCodecs()) {
CreateTaskQueues()) {
return true;
}
@@ -1098,6 +1092,10 @@ MediaCodecReader::ReallocateResources()
void
MediaCodecReader::ReleaseCriticalResources()
{
mMediaResourceRequest.DisconnectIfExists();
mMediaResourcePromise.RejectIfExists(true, __func__);
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
ResetDecode();
// Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline.
@@ -1293,21 +1291,35 @@ MediaCodecReader::CreateTaskQueues()
return true;
}
bool
nsRefPtr<MediaOmxCommonReader::MediaResourcePromise>
MediaCodecReader::CreateMediaCodecs()
{
if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) &&
CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) {
return true;
bool isWaiting = false;
nsRefPtr<MediaResourcePromise> p = mMediaResourcePromise.Ensure(__func__);
if (!CreateMediaCodec(mLooper, mAudioTrack, false, isWaiting, nullptr)) {
mMediaResourcePromise.Reject(true, __func__);
return p;
}
return false;
if (!CreateMediaCodec(mLooper, mVideoTrack, true, isWaiting, mVideoListener)) {
mMediaResourcePromise.Reject(true, __func__);
return p;
}
if (!isWaiting) {
// No MediaCodec allocation wait.
mMediaResourcePromise.Resolve(true, __func__);
}
return p;
}
bool
MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
Track& aTrack,
bool aAsync,
bool& aIsWaiting,
wp<MediaCodecProxy::CodecResourceListener> aListener)
{
if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) {
@@ -1352,10 +1364,14 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
DestroyMediaCodec(aTrack);
return false;
}
} else if (aAsync && !aTrack.mCodec->AsyncAskMediaCodec()) {
NS_WARNING("Couldn't request MediaCodec asynchronously");
DestroyMediaCodec(aTrack);
return false;
} else if (aAsync) {
if (aTrack.mCodec->AsyncAskMediaCodec()) {
aIsWaiting = true;
} else {
NS_WARNING("Couldn't request MediaCodec asynchronously");
DestroyMediaCodec(aTrack);
return false;
}
}
}
@@ -1921,18 +1937,14 @@ MediaCodecReader::ClearColorConverterBuffer()
void
MediaCodecReader::VideoCodecReserved()
{
mDecoder->NotifyWaitingForResourcesStatusChanged();
mMediaResourcePromise.ResolveIfExists(true, __func__);
}
// Called on Binder thread.
void
MediaCodecReader::VideoCodecCanceled()
{
if (mVideoTrack.mTaskQueue) {
RefPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources);
mVideoTrack.mTaskQueue->Dispatch(task.forget());
}
mMediaResourcePromise.RejectIfExists(true, __func__);
}
} // namespace mozilla
+12 -18
View File
@@ -52,6 +52,7 @@ class MediaCodecReader : public MediaOmxCommonReader
{
typedef mozilla::layers::TextureClient TextureClient;
typedef mozilla::layers::FenceHandle FenceHandle;
typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
public:
MediaCodecReader(AbstractMediaDecoder* aDecoder);
@@ -61,9 +62,6 @@ public:
// on failure.
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
// True if this reader is waiting media resource allocation
virtual bool IsWaitingMediaResources();
// True when this reader need to become dormant state
virtual bool IsDormantNeeded() { return true;}
@@ -94,13 +92,7 @@ public:
virtual bool HasAudio();
virtual bool HasVideo();
virtual void PreReadMetadata() override;
// Read header data for all bitstreams in the file. Fills aInfo with
// the data required to present the media, and optionally fills *aTags
// with tag metadata from the file.
// Returns NS_OK on success, or NS_ERROR_FAILURE on failure.
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
// Moves the decode head to aTime microseconds. aStartTime and aEndTime
// denote the start and end times of the media in usecs, and aCurrentTime
@@ -184,16 +176,17 @@ protected:
virtual bool CreateExtractor();
// Check the underlying HW resource is available and store the result in
// mIsWaitingResources.
void UpdateIsWaitingMediaResources();
virtual void HandleResourceAllocated();
android::sp<android::MediaExtractor> mExtractor;
// A cache value updated by UpdateIsWaitingMediaResources(), makes the
// "waiting resources state" is synchronous to StateMachine.
bool mIsWaitingResources;
MediaPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
// XXX Remove after bug 1168008 land.
MediaPromiseConsumerHolder<MediaResourcePromise> mMediaResourceRequest;
MediaPromiseHolder<MediaResourcePromise> mMediaResourcePromise;
private:
// An intermediary class that can be managed by android::sp<T>.
// Redirect codecReserved() and codecCanceled() to MediaCodecReader.
class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
@@ -336,7 +329,7 @@ private:
MediaCodecReader() = delete;
const MediaCodecReader& operator=(const MediaCodecReader& rhs) = delete;
bool ReallocateResources();
bool ReallocateExtractorResources();
void ReleaseCriticalResources();
void ReleaseResources();
@@ -348,10 +341,11 @@ private:
bool CreateMediaSources();
void DestroyMediaSources();
bool CreateMediaCodecs();
nsRefPtr<MediaResourcePromise> CreateMediaCodecs();
static bool CreateMediaCodec(android::sp<android::ALooper>& aLooper,
Track& aTrack,
bool aAsync,
bool& aIsWaiting,
android::wp<android::MediaCodecProxy::CodecResourceListener> aListener);
static bool ConfigureMediaCodec(Track& aTrack);
void DestroyMediaCodecs();
+2
View File
@@ -24,6 +24,8 @@ class AbstractMediaDecoder;
class MediaOmxCommonReader : public MediaDecoderReader
{
public:
typedef MediaPromise<bool /* aIgnored */, bool /* aIgnored */, /* IsExclusive = */ true> MediaResourcePromise;
MediaOmxCommonReader(AbstractMediaDecoder* aDecoder);
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
+74 -69
View File
@@ -124,26 +124,17 @@ private:
uint64_t mFullLength;
};
void MediaOmxReader::CancelProcessCachedData()
{
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mIsShutdown = true;
}
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
: MediaOmxCommonReader(aDecoder)
, mMutex("MediaOmxReader.Data")
, mShutdownMutex("MediaOmxReader.Shutdown")
, mHasVideo(false)
, mHasAudio(false)
, mVideoSeekTimeUs(-1)
, mAudioSeekTimeUs(-1)
, mLastParserDuration(-1)
, mSkipCount(0)
, mUseParserDuration(false)
, mIsShutdown(false)
, mMP3FrameParser(-1)
, mIsWaitingResources(false)
{
if (!gMediaDecoderLog) {
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
@@ -161,6 +152,16 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
return NS_OK;
}
already_AddRefed<AbstractMediaDecoder>
MediaOmxReader::SafeGetDecoder() {
nsRefPtr<AbstractMediaDecoder> decoder;
MutexAutoLock lock(mShutdownMutex);
if (!mIsShutdown) {
decoder = mDecoder;
}
return decoder.forget();
}
void MediaOmxReader::ReleaseDecoder()
{
if (mOmxDecoder.get()) {
@@ -172,9 +173,10 @@ void MediaOmxReader::ReleaseDecoder()
nsRefPtr<ShutdownPromise>
MediaOmxReader::Shutdown()
{
nsCOMPtr<nsIRunnable> cancelEvent =
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
NS_DispatchToMainThread(cancelEvent);
{
MutexAutoLock lock(mShutdownMutex);
mIsShutdown = true;
}
nsRefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
@@ -185,22 +187,11 @@ MediaOmxReader::Shutdown()
return p;
}
bool MediaOmxReader::IsWaitingMediaResources()
{
return mIsWaitingResources;
}
void MediaOmxReader::UpdateIsWaitingMediaResources()
{
if (mOmxDecoder.get()) {
mIsWaitingResources = mOmxDecoder->IsWaitingMediaResources();
} else {
mIsWaitingResources = false;
}
}
void MediaOmxReader::ReleaseMediaResources()
{
mMediaResourceRequest.DisconnectIfExists();
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
ResetDecode();
// Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline.
@@ -235,23 +226,17 @@ nsresult MediaOmxReader::InitOmxDecoder()
return NS_OK;
}
void MediaOmxReader::PreReadMetadata()
{
UpdateIsWaitingMediaResources();
}
nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
nsRefPtr<MediaDecoderReader::MetadataPromise>
MediaOmxReader::AsyncReadMetadata()
{
MOZ_ASSERT(OnTaskQueue());
EnsureActive();
*aTags = nullptr;
// Initialize the internal OMX Decoder.
nsresult rv = InitOmxDecoder();
if (NS_FAILED(rv)) {
return rv;
return MediaDecoderReader::MetadataPromise::CreateAndReject(
ReadMetadataFailureReason::METADATA_ERROR, __func__);
}
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
@@ -263,32 +248,44 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
ProcessCachedData(0, true);
}
if (!mOmxDecoder->AllocateMediaResources()) {
return NS_ERROR_FAILURE;
}
// Bug 1050667, both MediaDecoderStateMachine and MediaOmxReader
// relies on IsWaitingMediaResources() function. And the waiting state will be
// changed by binder thread, so we store the waiting state in a cache value to
// make them in consistent state.
UpdateIsWaitingMediaResources();
if (IsWaitingMediaResources()) {
return NS_OK;
}
nsRefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
nsRefPtr<MediaOmxReader> self = this;
mMediaResourceRequest.Begin(mOmxDecoder->AllocateMediaResources()
->RefableThen(GetTaskQueue(), __func__,
[self] (bool) -> void {
self->mMediaResourceRequest.Complete();
self->HandleResourceAllocated();
}, [self] (bool) -> void {
self->mMediaResourceRequest.Complete();
self->mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
}));
return p;
}
void MediaOmxReader::HandleResourceAllocated()
{
EnsureActive();
// After resources are available, set the metadata.
if (!mOmxDecoder->EnsureMetadata()) {
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
if (isMP3 && mMP3FrameParser.IsMP3()) {
int64_t duration = mMP3FrameParser.GetDuration();
// The MP3FrameParser may reported a duration;
// return -1 if no frame has been parsed.
if (duration >= 0) {
mUseParserDuration = true;
mLastParserDuration = duration;
mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(mLastParserDuration));
}
// Check if the MP3 frame parser found a duration.
mLastParserDuration = mMP3FrameParser.GetDuration();
}
if (mLastParserDuration >= 0) {
// Prefer the parser duration if we have it.
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->SetMediaDuration(mLastParserDuration);
} else {
// MP3 parser failed to find a duration.
// Set the total duration (the max of the audio and video track).
int64_t durationUs;
mOmxDecoder->GetDuration(&durationUs);
@@ -308,7 +305,8 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
nsIntSize displaySize(displayWidth, displayHeight);
nsIntSize frameSize(width, height);
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
return NS_ERROR_FAILURE;
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
return;
}
// Video track's frame sizes will not overflow. Activate the video track.
@@ -332,13 +330,15 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
mInfo.mAudio.mRate = sampleRate;
}
*aInfo = mInfo;
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
metadata->mInfo = mInfo;
metadata->mTags = nullptr;
#ifdef MOZ_AUDIO_OFFLOAD
CheckAudioOffload();
#endif
return NS_OK;
mMetadataPromise.Resolve(metadata, __func__);
}
bool
@@ -472,23 +472,27 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
{
MOZ_ASSERT(NS_IsMainThread());
if (IsShutdown()) {
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
if (!decoder) { // reader has shut down
return;
}
if (HasVideo()) {
return;
}
if (!mMP3FrameParser.NeedsData()) {
return;
}
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
if (!mMP3FrameParser.IsMP3()) {
return;
}
int64_t duration = mMP3FrameParser.GetDuration();
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (duration != mLastParserDuration && mUseParserDuration) {
if (duration != mLastParserDuration) {
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
mLastParserDuration = duration;
mDecoder->UpdateEstimatedMediaDuration(mLastParserDuration);
decoder->UpdateEstimatedMediaDuration(mLastParserDuration);
}
}
@@ -574,7 +578,8 @@ void MediaOmxReader::EnsureActive() {
int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
{
// Could run on decoder thread or IO thread.
if (IsShutdown()) {
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
if (!decoder) { // reader has shut down
return -1;
}
// We read data in chunks of 32 KiB. We can reduce this
@@ -585,8 +590,8 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
MOZ_ASSERT(mDecoder->GetResource());
int64_t resourceLength = mDecoder->GetResource()->GetCachedDataEnd(0);
MOZ_ASSERT(decoder->GetResource());
int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0);
NS_ENSURE_TRUE(resourceLength >= 0, -1);
if (aOffset >= resourceLength) {
@@ -597,7 +602,7 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
nsAutoArrayPtr<char> buffer(new char[bufferLength]);
nsresult rv = mDecoder->GetResource()->ReadFromCache(buffer.get(),
nsresult rv = decoder->GetResource()->ReadFromCache(buffer.get(),
aOffset, bufferLength);
NS_ENSURE_SUCCESS(rv, -1);
+17 -20
View File
@@ -12,6 +12,7 @@
#include "nsMimeTypes.h"
#include "MP3FrameParser.h"
#include "nsRect.h"
#include <ui/GraphicBuffer.h>
#include <stagefright/MediaSource.h>
@@ -26,8 +27,11 @@ class AbstractMediaDecoder;
class MediaOmxReader : public MediaOmxCommonReader
{
// This flag protect the mIsShutdown variable, that may access by decoder / main / IO thread.
Mutex mMutex;
typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
// This mutex is held when accessing the mIsShutdown variable, which is
// modified on the decode task queue and read on main and IO threads.
Mutex mShutdownMutex;
nsCString mType;
bool mHasVideo;
bool mHasAudio;
@@ -37,17 +41,16 @@ class MediaOmxReader : public MediaOmxCommonReader
int64_t mAudioSeekTimeUs;
int64_t mLastParserDuration;
int32_t mSkipCount;
bool mUseParserDuration;
// If mIsShutdown is false, and mShutdownMutex is held, then
// AbstractMediaDecoder::mDecoder will be non-null.
bool mIsShutdown;
MediaPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
MediaPromiseConsumerHolder<MediaResourcePromise> mMediaResourceRequest;
protected:
android::sp<android::OmxDecoder> mOmxDecoder;
android::sp<android::MediaExtractor> mExtractor;
MP3FrameParser mMP3FrameParser;
// A cache value updated by UpdateIsWaitingMediaResources(), makes the
// "waiting resources state" is synchronous to StateMachine.
bool mIsWaitingResources;
// Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
// on decode thread. It create and initialize the OMX decoder including
// setting up custom extractor. The extractor provide the essential
@@ -58,10 +61,7 @@ protected:
// to activate the decoder automatically.
virtual void EnsureActive();
// Check the underlying HW resources are available and store the result in
// mIsWaitingResources. The result might be changed by binder thread,
// Can only called by ReadMetadata.
void UpdateIsWaitingMediaResources();
virtual void HandleResourceAllocated();
public:
MediaOmxReader(AbstractMediaDecoder* aDecoder);
@@ -85,15 +85,11 @@ public:
return mHasVideo;
}
// Return mIsWaitingResources.
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() { return true;}
virtual void ReleaseMediaResources();
virtual void PreReadMetadata() override;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
virtual nsRefPtr<SeekPromise>
Seek(int64_t aTime, int64_t aEndTime) override;
@@ -104,7 +100,7 @@ public:
virtual nsRefPtr<ShutdownPromise> Shutdown() override;
bool IsShutdown() {
MutexAutoLock lock(mMutex);
MutexAutoLock lock(mShutdownMutex);
return mIsShutdown;
}
@@ -112,9 +108,10 @@ public:
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
void CancelProcessCachedData();
android::sp<android::MediaSource> GetAudioOffloadTrack();
private:
already_AddRefed<AbstractMediaDecoder> SafeGetDecoder();
};
} // namespace mozilla
+51 -55
View File
@@ -16,8 +16,6 @@
#include "nsDebug.h"
#include "IMediaResourceManagerService.h"
#include "OMXCodecProxy.h"
namespace android {
@@ -60,13 +58,13 @@ OMXCodecProxy::OMXCodecProxy(
mFlags(flags),
mNativeWindow(nativeWindow),
mSource(source),
mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
mState(ResourceState::START)
{
}
OMXCodecProxy::~OMXCodecProxy()
{
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
if (mOMXCodec.get()) {
wp<MediaSource> tmp = mOMXCodec;
@@ -79,8 +77,9 @@ OMXCodecProxy::~OMXCodecProxy()
// Complete all pending Binder ipc transactions
IPCThreadState::self()->flushCommands();
if (mManagerService.get() && mClient.get()) {
mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
if (mResourceClient) {
mResourceClient->ReleaseResource();
mResourceClient = nullptr;
}
mSource.clear();
@@ -88,25 +87,25 @@ OMXCodecProxy::~OMXCodecProxy()
mComponentName = nullptr;
}
MediaResourceManagerClient::State OMXCodecProxy::getState()
void OMXCodecProxy::setListener(const wp<CodecResourceListener>& listener)
{
Mutex::Autolock autoLock(mLock);
return mState;
mListener = listener;
}
void OMXCodecProxy::setEventListener(const wp<OMXCodecProxy::EventListener>& listener)
void OMXCodecProxy::notifyResourceReserved()
{
Mutex::Autolock autoLock(mLock);
mEventListener = listener;
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecReserved();
}
}
void OMXCodecProxy::notifyStatusChangedLocked()
void OMXCodecProxy::notifyResourceCanceled()
{
if (mEventListener != nullptr) {
sp<EventListener> listener = mEventListener.promote();
if (listener != nullptr) {
listener->statusChanged();
}
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecCanceled();
}
}
@@ -114,45 +113,32 @@ void OMXCodecProxy::requestResource()
{
Mutex::Autolock autoLock(mLock);
if (mClient.get()) {
if (mResourceClient) {
return;
}
sp<MediaResourceManagerClient::EventListener> listener = this;
mClient = new MediaResourceManagerClient(listener);
mState = ResourceState::WAITING;
mManagerService = mClient->getMediaResourceManagerService();
if (!mManagerService.get()) {
mClient = nullptr;
return;
}
mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
mResourceClient->Acquire();
}
bool OMXCodecProxy::IsWaitingResources()
{
Mutex::Autolock autoLock(mLock);
return mState == MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE;
}
// called on Binder ipc thread
void OMXCodecProxy::statusChanged(int event)
// Called on ImageBridge thread
void
OMXCodecProxy::ResourceReserved()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) {
return;
}
mState = (MediaResourceManagerClient::State) event;
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::WAITING) {
return;
}
const char *mime;
if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) {
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
notifyStatusChangedLocked();
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
@@ -160,8 +146,8 @@ void OMXCodecProxy::statusChanged(int event)
sp<MediaSource> codec;
mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow);
if (mOMXCodec == nullptr) {
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
notifyStatusChangedLocked();
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
// Check if this video is sized such that we're comfortable
@@ -181,27 +167,37 @@ void OMXCodecProxy::statusChanged(int event)
printf_stderr("Failed to get video size, or it was too large for HW decoder (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
width, height, maxWidth, maxHeight);
mOMXCodec.clear();
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
notifyStatusChangedLocked();
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
if (mOMXCodec->start() != OK) {
NS_WARNING("Couldn't start OMX video source");
mOMXCodec.clear();
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
notifyStatusChangedLocked();
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
}
notifyStatusChangedLocked();
mState = ResourceState::ACQUIRED;
notifyResourceReserved();
}
// Called on ImageBridge thread
void
OMXCodecProxy::ResourceReserveFailed()
{
Mutex::Autolock autoLock(mLock);
mState = ResourceState::NOT_ACQUIRED;
}
status_t OMXCodecProxy::start(MetaData *params)
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@@ -212,7 +208,7 @@ status_t OMXCodecProxy::stop()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@@ -223,7 +219,7 @@ sp<MetaData> OMXCodecProxy::getFormat()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
sp<MetaData> meta = new MetaData;
return meta;
}
@@ -235,7 +231,7 @@ status_t OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options)
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@@ -246,7 +242,7 @@ status_t OMXCodecProxy::pause()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
+38 -15
View File
@@ -13,18 +13,39 @@
#include <stagefright/MediaSource.h>
#include <utils/threads.h>
#include "MediaResourceManagerClient.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "nsRefPtr.h"
namespace android {
struct MetaData;
class OMXCodecProxy : public MediaSource,
public MediaResourceManagerClient::EventListener
class OMXCodecProxy : public MediaSource
, public mozilla::MediaSystemResourceReservationListener
{
public:
struct EventListener : public virtual RefBase {
virtual void statusChanged() = 0;
/* Codec resource notification listener.
* All functions are called on the Binder thread.
*/
struct CodecResourceListener : public virtual RefBase {
/* The codec resource is reserved and can be granted.
* The client can allocate the requested resource.
*/
virtual void codecReserved() = 0;
/* The codec resource is not reserved any more.
* The client should release the resource as soon as possible if the
* resource is still being held.
*/
virtual void codecCanceled() = 0;
};
// Enumeration for the valid resource allcoation states
enum class ResourceState : int8_t {
START,
WAITING,
ACQUIRED,
NOT_ACQUIRED,
END
};
static sp<OMXCodecProxy> Create(
@@ -35,15 +56,13 @@ public:
uint32_t flags = 0,
const sp<ANativeWindow> &nativeWindow = nullptr);
MediaResourceManagerClient::State getState();
void setEventListener(const wp<EventListener>& listener);
void setListener(const wp<CodecResourceListener>& listener);
void requestResource();
bool IsWaitingResources();
// MediaResourceManagerClient::EventListener
virtual void statusChanged(int event);
// MediaSystemResourceReservationListener
void ResourceReserved() override;
void ResourceReserveFailed() override;
// MediaSource
virtual status_t start(MetaData *params = nullptr);
@@ -68,6 +87,9 @@ protected:
virtual ~OMXCodecProxy();
void notifyResourceReserved();
void notifyResourceCanceled();
void notifyStatusChangedLocked();
private:
@@ -87,11 +109,12 @@ private:
sp<MediaSource> mSource;
sp<MediaSource> mOMXCodec;
sp<MediaResourceManagerClient> mClient;
MediaResourceManagerClient::State mState;
sp<IMediaResourceManagerService> mManagerService;
wp<OMXCodecProxy::EventListener> mEventListener;
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
ResourceState mState;
// Codec Resource Notification Listener
wp<CodecResourceListener> mListener;
};
} // namespace android
+8 -14
View File
@@ -17,7 +17,7 @@
#include "AudioChannelFormat.h"
#include "GrallocImages.h"
#include <mozilla/Monitor.h>
#include "mozilla/Monitor.h"
#include "mozilla/layers/GrallocTextureClient.h"
using namespace mozilla;
@@ -45,27 +45,21 @@ enum BufferState
bool
OMXCodecReservation::ReserveOMXCodec()
{
if (!mManagerService.get()) {
sp<MediaResourceManagerClient::EventListener> listener = this;
mClient = new MediaResourceManagerClient(listener);
mManagerService = mClient->getMediaResourceManagerService();
if (!mManagerService.get()) {
mClient = nullptr;
return true; // not really in use, but not usable
}
if (mClient) {
// Already tried reservation.
return false;
}
return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
mClient = new mozilla::MediaSystemResourceClient(mType);
return mClient->AcquireSyncNoWait(); // don't wait if resrouce is not available
}
void
OMXCodecReservation::ReleaseOMXCodec()
{
if (!mManagerService.get() || !mClient.get()) {
if (!mClient) {
return;
}
mManagerService->cancelClient(mClient, mType);
mClient->ReleaseResource();
}
OMXAudioEncoder*
+7 -12
View File
@@ -15,22 +15,21 @@
#include "AudioSegment.h"
#include "GonkNativeWindow.h"
#include "GonkNativeWindowClient.h"
#include "IMediaResourceManagerService.h"
#include "MediaResourceManagerClient.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "nsRefPtr.h"
#include <speex/speex_resampler.h>
namespace android {
// Wrapper class for managing HW codec reservations
class OMXCodecReservation : public MediaResourceManagerClient::EventListener
class OMXCodecReservation : public RefBase
{
public:
OMXCodecReservation(bool aEncoder)
{
mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
IMediaResourceManagerService::HW_VIDEO_DECODER;
mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
}
virtual ~OMXCodecReservation()
@@ -44,14 +43,10 @@ public:
/** Release the Encode or Decode resource for this instance */
virtual void ReleaseOMXCodec();
// MediaResourceManagerClient::EventListener
virtual void statusChanged(int event) {}
private:
IMediaResourceManagerService::ResourceType mType;
mozilla::MediaSystemResourceType mType;
sp<MediaResourceManagerClient> mClient;
sp<IMediaResourceManagerService> mManagerService;
nsRefPtr<mozilla::MediaSystemResourceClient> mClient;
};
+26 -30
View File
@@ -91,12 +91,13 @@ OmxDecoder::~OmxDecoder()
mLooper->stop();
}
void OmxDecoder::statusChanged()
void OmxDecoder::codecReserved()
{
sp<AMessage> notify =
new AMessage(kNotifyStatusChanged, mReflector->id());
// post AMessage to OmxDecoder via ALooper.
notify->post();
mMediaResourcePromise.ResolveIfExists(true, __func__);
}
void OmxDecoder::codecCanceled()
{
mMediaResourcePromise.RejectIfExists(true, __func__);
}
static sp<IOMX> sOMX = nullptr;
@@ -213,14 +214,6 @@ bool OmxDecoder::EnsureMetadata() {
return true;
}
bool OmxDecoder::IsWaitingMediaResources()
{
if (mVideoSource.get()) {
return mVideoSource->IsWaitingResources();
}
return false;
}
static bool isInEmulator()
{
char propQemu[PROPERTY_VALUE_MAX];
@@ -228,8 +221,10 @@ static bool isInEmulator()
return !strncmp(propQemu, "1", 1);
}
bool OmxDecoder::AllocateMediaResources()
nsRefPtr<mozilla::MediaOmxCommonReader::MediaResourcePromise> OmxDecoder::AllocateMediaResources()
{
nsRefPtr<MediaResourcePromise> p = mMediaResourcePromise.Ensure(__func__);
if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
// OMXClient::connect() always returns OK and abort's fatally if
// it can't connect.
@@ -280,10 +275,11 @@ bool OmxDecoder::AllocateMediaResources()
mNativeWindowClient);
if (mVideoSource == nullptr) {
NS_WARNING("Couldn't create OMX video source");
return false;
mMediaResourcePromise.Reject(true, __func__);
return p;
} else {
sp<OMXCodecProxy::EventListener> listener = this;
mVideoSource->setEventListener(listener);
sp<OMXCodecProxy::CodecResourceListener> listener = this;
mVideoSource->setListener(listener);
mVideoSource->requestResource();
}
}
@@ -299,7 +295,8 @@ bool OmxDecoder::AllocateMediaResources()
const char *audioMime = nullptr;
sp<MetaData> meta = mAudioTrack->getFormat();
if (!meta->findCString(kKeyMIMEType, &audioMime)) {
return false;
mMediaResourcePromise.Reject(true, __func__);
return p;
}
if (!strcasecmp(audioMime, "audio/raw")) {
mAudioSource = mAudioTrack;
@@ -325,20 +322,28 @@ bool OmxDecoder::AllocateMediaResources()
flags);
if (mAudioSource == nullptr) {
NS_WARNING("Couldn't create OMX audio source");
return false;
mMediaResourcePromise.Reject(true, __func__);
return p;
}
}
if (mAudioSource->start() != OK) {
NS_WARNING("Couldn't start OMX audio source");
mAudioSource.clear();
return false;
mMediaResourcePromise.Reject(true, __func__);
return p;
}
}
return true;
if (!mVideoSource.get()) {
// No resource allocation wait.
mMediaResourcePromise.Resolve(true, __func__);
}
return p;
}
void OmxDecoder::ReleaseMediaResources() {
mMediaResourcePromise.RejectIfExists(true, __func__);
ReleaseVideoBuffer();
ReleaseAudioBuffer();
@@ -821,15 +826,6 @@ void OmxDecoder::onMessageReceived(const sp<AMessage> &msg)
}
break;
}
case kNotifyStatusChanged:
{
// Our decode may have acquired the hardware resource that it needs
// to start. Notify the state machine to resume loading metadata.
mDecoder->NotifyWaitingForResourcesStatusChanged();
break;
}
default:
TRESPASS();
break;
+9 -9
View File
@@ -10,6 +10,7 @@
#include "mozilla/layers/FenceUtils.h"
#include "MP3FrameParser.h"
#include "MPAPI.h"
#include "MediaOmxCommonReader.h"
#include "MediaResource.h"
#include "AbstractMediaDecoder.h"
#include "OMXCodecProxy.h"
@@ -20,7 +21,7 @@ class OmxDecoder;
namespace android {
class OmxDecoder : public OMXCodecProxy::EventListener {
class OmxDecoder : public OMXCodecProxy::CodecResourceListener {
typedef MPAPI::AudioFrame AudioFrame;
typedef MPAPI::VideoFrame VideoFrame;
typedef mozilla::MP3FrameParser MP3FrameParser;
@@ -28,6 +29,7 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
typedef mozilla::layers::FenceHandle FenceHandle;
typedef mozilla::layers::TextureClient TextureClient;
typedef mozilla::MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
enum {
kPreferSoftwareCodecs = 1,
@@ -37,7 +39,6 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
enum {
kNotifyPostReleaseVideoBuffer = 'noti',
kNotifyStatusChanged = 'stat'
};
AbstractMediaDecoder *mDecoder;
@@ -120,6 +121,8 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
// 'true' if a read from the audio stream was done while reading the metadata
bool mAudioMetadataRead;
mozilla::MediaPromiseHolder<MediaResourcePromise> mMediaResourcePromise;
void ReleaseVideoBuffer();
void ReleaseAudioBuffer();
// Call with mSeekLock held.
@@ -141,8 +144,9 @@ public:
OmxDecoder(MediaResource *aResource, AbstractMediaDecoder *aDecoder);
~OmxDecoder();
// MediaResourceManagerClient::EventListener
virtual void statusChanged();
// OMXCodecProxy::CodecResourceListener
virtual void codecReserved();
virtual void codecCanceled();
// The MediaExtractor provides essential information for creating OMXCodec
// instance. Such as video/audio codec, we can retrieve them through the
@@ -158,11 +162,7 @@ public:
// mDurationUs and video/audio metadata.
bool EnsureMetadata();
// Only called by MediaOmxDecoder, do not call this function arbitrarily.
// See bug 1050667.
bool IsWaitingMediaResources();
bool AllocateMediaResources();
nsRefPtr<MediaResourcePromise> AllocateMediaResources();
void ReleaseMediaResources();
bool SetVideoFormat();
bool SetAudioFormat();
+16 -8
View File
@@ -88,20 +88,28 @@ RtspMediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
}
nsresult
RtspMediaCodecReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
nsRefPtr<MediaDecoderReader::MetadataPromise>
RtspMediaCodecReader::AsyncReadMetadata()
{
mRtspResource->DisablePlayoutDelay();
EnsureActive();
nsresult rv = MediaCodecReader::ReadMetadata(aInfo, aTags);
nsRefPtr<MediaDecoderReader::MetadataPromise> p =
MediaCodecReader::AsyncReadMetadata();
// Send a PAUSE to the RTSP server because the underlying media resource is
// not ready.
SetIdle();
if (rv == NS_OK && !IsWaitingMediaResources()) {
mRtspResource->EnablePlayoutDelay();
}
return p;
}
return rv;
void
RtspMediaCodecReader::HandleResourceAllocated()
{
EnsureActive();
MediaCodecReader::HandleResourceAllocated();
mRtspResource->EnablePlayoutDelay();;
}
} // namespace mozilla
+4 -2
View File
@@ -58,8 +58,10 @@ public:
// Disptach a DecodeAudioDataTask to decode audio data.
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) override;
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata()
override;
virtual void HandleResourceAllocated() override;
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
+16 -11
View File
@@ -81,22 +81,27 @@ void RtspOmxReader::EnsureActive() {
MediaOmxReader::EnsureActive();
}
nsresult RtspOmxReader::ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
nsRefPtr<MediaDecoderReader::MetadataPromise>
RtspOmxReader::AsyncReadMetadata()
{
// Send a PLAY command to the RTSP server before reading metadata.
// Because we might need some decoded samples to ensure we have configuration.
mRtspResource->DisablePlayoutDelay();
EnsureActive();
nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
if (rv == NS_OK && !IsWaitingMediaResources()) {
mRtspResource->EnablePlayoutDelay();
} else if (IsWaitingMediaResources()) {
// Send a PAUSE to the RTSP server because the underlying media resource is
// not ready.
SetIdle();
}
return rv;
nsRefPtr<MediaDecoderReader::MetadataPromise> p =
MediaOmxReader::AsyncReadMetadata();
// Send a PAUSE to the RTSP server because the underlying media resource is
// not ready.
SetIdle();
return p;
}
void RtspOmxReader::HandleResourceAllocated()
{
MediaOmxReader::HandleResourceAllocated();
mRtspResource->EnablePlayoutDelay();
}
} // namespace mozilla
+4 -2
View File
@@ -64,8 +64,10 @@ public:
virtual void SetIdle() override;
virtual nsresult ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
final override;
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata()
override;
virtual void HandleResourceAllocated() override;
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
@@ -1,62 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerClient"
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include "IMediaResourceManagerClient.h"
namespace android {
enum {
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION
};
class BpMediaResourceManagerClient : public BpInterface<IMediaResourceManagerClient>
{
public:
BpMediaResourceManagerClient(const sp<IBinder>& impl)
: BpInterface<IMediaResourceManagerClient>(impl)
{
}
void statusChanged(int event)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerClient::getInterfaceDescriptor());
data.writeInt32(event);
remote()->transact(STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
};
IMPLEMENT_META_INTERFACE(MediaResourceManagerClient, "android.media.IMediaResourceManagerClient");
// ----------------------------------------------------------------------
status_t BnMediaResourceManagerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case STATUS_CHANGED: {
CHECK_INTERFACE(IMediaResourceManagerClient, data, reply);
int event = data.readInt32();
statusChanged(event);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
}; // namespace android
@@ -1,43 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
#define ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
#include <utils/RefBase.h>
#include <binder/IInterface.h>
namespace android {
// ----------------------------------------------------------------------------
class IMediaResourceManagerClient : public IInterface
{
public:
DECLARE_META_INTERFACE(MediaResourceManagerClient);
// Notifies a change of media resource request status.
virtual void statusChanged(int event) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaResourceManagerClient : public BnInterface<IMediaResourceManagerClient>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
@@ -1,118 +0,0 @@
/*
** Copyright 2010, The Android Open Source Project
** Copyright 2013, Mozilla Foundation
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerDeathNotifier"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "IMediaResourceManagerDeathNotifier.h"
#define DN_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define DN_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define DN_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define DN_LOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
namespace android {
// client singleton for binder interface to services
Mutex IMediaResourceManagerDeathNotifier::sServiceLock;
sp<IMediaResourceManagerService> IMediaResourceManagerDeathNotifier::sMediaResourceManagerService;
sp<IMediaResourceManagerDeathNotifier::DeathNotifier> IMediaResourceManagerDeathNotifier::sDeathNotifier;
SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeathNotifier::sObitRecipients;
// establish binder interface to MediaResourceManagerService
/*static*/const sp<IMediaResourceManagerService>&
IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
{
DN_LOGV("getMediaResourceManagerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaResourceManagerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.resource_manager"));
if (binder != 0) {
break;
}
DN_LOGW("Media resource manager service not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaResourceManagerService = interface_cast<IMediaResourceManagerService>(binder);
}
DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
return sMediaResourceManagerService;
}
/*static*/ void
IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.add(recipient);
}
/*static*/ void
IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.remove(recipient);
}
void
IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
{
DN_LOGW("media resource manager service died");
// Need to do this with the lock held
SortedVector< wp<IMediaResourceManagerDeathNotifier> > list;
{
Mutex::Autolock _l(sServiceLock);
sMediaResourceManagerService.clear();
list = sObitRecipients;
}
// Notify application when media server dies.
// Don't hold the static lock during callback in case app
// makes a call that needs the lock.
size_t count = list.size();
for (size_t iter = 0; iter < count; ++iter) {
sp<IMediaResourceManagerDeathNotifier> notifier = list[iter].promote();
if (notifier != 0) {
notifier->died();
}
}
}
IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier()
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.clear();
if (sMediaResourceManagerService != 0) {
sMediaResourceManagerService->asBinder()->unlinkToDeath(this);
}
}
}; // namespace android
@@ -1,67 +0,0 @@
/*
** Copyright 2010, The Android Open Source Project
** Copyright 2013, Mozilla Foundation
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
#define ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
#include <utils/threads.h>
#include <utils/SortedVector.h>
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Handle MediaResourceManagerService's death notification.
* Made from android's IMediaDeathNotifier class.
*/
class IMediaResourceManagerDeathNotifier: virtual public RefBase
{
public:
IMediaResourceManagerDeathNotifier() { addObitRecipient(this); }
virtual ~IMediaResourceManagerDeathNotifier() { removeObitRecipient(this); }
virtual void died() = 0;
static const sp<IMediaResourceManagerService>& getMediaResourceManagerService();
private:
IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &);
IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &);
static void addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
static void removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
class DeathNotifier: public IBinder::DeathRecipient
{
public:
DeathNotifier() {}
virtual ~DeathNotifier();
virtual void binderDied(const wp<IBinder>& who);
};
friend class DeathNotifier;
static Mutex sServiceLock;
static sp<IMediaResourceManagerService> sMediaResourceManagerService;
static sp<DeathNotifier> sDeathNotifier;
static SortedVector< wp<IMediaResourceManagerDeathNotifier> > sObitRecipients;
};
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
@@ -1,92 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerService"
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Function ID used between BpMediaResourceManagerService and
* BnMediaResourceManagerService by using Binder ipc.
*/
enum {
REQUEST_MEDIA_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
DEREGISTER_CLIENT
};
class BpMediaResourceManagerService : public BpInterface<IMediaResourceManagerService>
{
public:
BpMediaResourceManagerService(const sp<IBinder>& impl)
: BpInterface<IMediaResourceManagerService>(impl)
{
}
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(resourceType);
data.writeInt32(willWait ? 1 : 0);
remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
return reply.readInt32();
}
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(resourceType);
remote()->transact(DEREGISTER_CLIENT, data, &reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService");
// ----------------------------------------------------------------------
status_t BnMediaResourceManagerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_MEDIA_RESOURCE: {
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
int resourceType = data.readInt32();
bool willWait = (data.readInt32() == 1);
status_t result = requestMediaResource(client, resourceType, willWait);
reply->writeInt32(result);
return NO_ERROR;
} break;
case DEREGISTER_CLIENT: {
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
int resourceType = data.readInt32();
status_t result = cancelClient(client, resourceType);
reply->writeInt32(result);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
}; // namespace android
@@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
#define ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include "IMediaResourceManagerClient.h"
namespace android {
// ----------------------------------------------------------------------------
class IMediaResourceManagerService : public IInterface
{
public:
DECLARE_META_INTERFACE(MediaResourceManagerService);
// Enumeration for the resource types
enum ResourceType {
HW_VIDEO_DECODER = 0,
HW_AUDIO_DECODER, // Not supported currently.
HW_VIDEO_ENCODER,
HW_AUDIO_ENCODER, // Not supported currently.
HW_CAMERA, // Not supported currently.
NUM_OF_RESOURCE_TYPES,
INVALID_RESOURCE_TYPE = -1
};
enum ErrorCode {
RESOURCE_NOT_AVAILABLE = -EAGAIN
};
// Request a media resource for IMediaResourceManagerClient.
// client is the binder that service will notify (through
// IMediaResourceManagerClient::statusChanged()) when request status changed.
// resourceType is type of resource that client would like to request.
// willWait indicates that, when the resource is not currently available
// (i.e., already in use by another client), if the client wants to wait. If
// true, client will be put into a (FIFO) waiting list and be notified when
// resource is available.
// For unsupported types, this function returns BAD_TYPE. For supported
// types, it always returns OK when willWait is true; otherwise it will
// return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
// resouce is in use.
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
// Client must call this function after it's done with the media resource requested.
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
@@ -1,95 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MediaResourceHandler.h"
namespace android {
MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
: mListener(aListener)
, mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
, mWaitingResource(false)
{
}
MediaResourceHandler::~MediaResourceHandler()
{
cancelResource();
}
bool
MediaResourceHandler::IsWaitingResource()
{
Mutex::Autolock al(mLock);
return mWaitingResource;
}
bool
MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
{
Mutex::Autolock al(mLock);
if (mClient != nullptr && mService != nullptr) {
return false;
}
sp<MediaResourceManagerClient> client = new MediaResourceManagerClient(this);
sp<IMediaResourceManagerService> service = client->getMediaResourceManagerService();
if (service == nullptr) {
return false;
}
if (service->requestMediaResource(client, (int)aType, true) != OK) {
return false;
}
mClient = client;
mService = service;
mType = aType;
mWaitingResource = true;
return true;
}
void
MediaResourceHandler::cancelResource()
{
Mutex::Autolock al(mLock);
if (mClient != nullptr && mService != nullptr) {
mService->cancelClient(mClient, (int)mType);
}
mWaitingResource = false;
mClient = nullptr;
mService = nullptr;
}
// Called on a Binder thread
void
MediaResourceHandler::statusChanged(int aEvent)
{
sp<ResourceListener> listener;
Mutex::Autolock autoLock(mLock);
listener = mListener.promote();
if (listener == nullptr) {
return;
}
mWaitingResource = false;
MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
if (state == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
listener->resourceReserved();
} else {
listener->resourceCanceled();
}
}
} // namespace android
@@ -1,71 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 MEDIA_RESOURCE_HANDLER_H
#define MEDIA_RESOURCE_HANDLER_H
#include <utils/threads.h>
#include <mozilla/Attributes.h>
#include "MediaResourceManagerClient.h"
namespace android {
class MediaResourceHandler : public MediaResourceManagerClient::EventListener
{
public:
/* Resource notification listener.
* All functions are called on the Binder thread.
*/
struct ResourceListener : public virtual RefBase {
/* The resource is reserved and can be granted.
* The client can allocate the requested resource.
*/
virtual void resourceReserved() = 0;
/* The resource is not reserved any more.
* The client should release the resource as soon as possible if the
* resource is still being held.
*/
virtual void resourceCanceled() = 0;
};
MediaResourceHandler(const wp<ResourceListener> &aListener);
virtual ~MediaResourceHandler();
// Request Resource
bool requestResource(IMediaResourceManagerService::ResourceType aType);
// Cancel Resource
void cancelResource();
bool IsWaitingResource();
protected:
// MediaResourceManagerClient::EventListener::statusChanged()
virtual void statusChanged(int event);
private:
// Forbidden
MediaResourceHandler() = delete;
MediaResourceHandler(const MediaResourceHandler &) = delete;
const MediaResourceHandler &operator=(const MediaResourceHandler &) = delete;
// Resource Notification Listener
wp<ResourceListener> mListener;
// Resource Management
Mutex mLock;
sp<IMediaResourceManagerClient> mClient;
sp<IMediaResourceManagerService> mService;
IMediaResourceManagerService::ResourceType mType;
bool mWaitingResource;
};
} // namespace android
#endif // MEDIA_RESOURCE_HANDLER_H
@@ -1,40 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourceManagerClient"
#include <utils/Log.h>
#include "MediaResourceManagerClient.h"
namespace android {
MediaResourceManagerClient::MediaResourceManagerClient(const wp<EventListener>& listener)
: mEventListener(listener)
{
}
void MediaResourceManagerClient::statusChanged(int event)
{
if (mEventListener != NULL) {
sp<EventListener> listener = mEventListener.promote();
if (listener != NULL) {
listener->statusChanged(event);
}
}
}
void MediaResourceManagerClient::died()
{
sp<EventListener> listener = mEventListener.promote();
if (listener != NULL) {
listener->statusChanged(CLIENT_STATE_SHUTDOWN);
}
}
}; // namespace android
@@ -1,45 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_MEDIARESOURCEMANAGERCLIENT_H
#define ANDROID_MEDIARESOURCEMANAGERCLIENT_H
#include "IMediaResourceManagerClient.h"
#include "IMediaResourceManagerDeathNotifier.h"
namespace android {
class MediaResourceManagerClient: public BnMediaResourceManagerClient,
public virtual IMediaResourceManagerDeathNotifier
{
public:
// Enumeration for the valid decoding states
enum State {
CLIENT_STATE_WAIT_FOR_RESOURCE,
CLIENT_STATE_RESOURCE_ASSIGNED,
CLIENT_STATE_SHUTDOWN
};
struct EventListener : public virtual RefBase {
// Notifies a change of media resource request status.
virtual void statusChanged(int event) = 0;
};
MediaResourceManagerClient(const wp<EventListener>& listener);
// DeathRecipient
void died();
// IMediaResourceManagerClient
virtual void statusChanged(int event);
private:
wp<EventListener> mEventListener;
};
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
@@ -1,371 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourceManagerService"
#include <mozilla/Assertions.h>
#include <binder/IServiceManager.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Log.h>
#include "MediaResourceManagerClient.h"
#include "MediaResourceManagerService.h"
namespace android {
const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
/* static */
void MediaResourceManagerService::instantiate() {
defaultServiceManager()->addService(
String16("media.resource_manager"),
new MediaResourceManagerService());
}
MediaResourceManagerService::MediaResourceManagerService()
{
mLooper = new ALooper;
mLooper->setName("MediaResourceManagerService");
mReflector = new AHandlerReflector<MediaResourceManagerService>(this);
// Register AMessage handler to ALooper.
mLooper->registerHandler(mReflector);
// Start ALooper thread.
mLooper->start();
}
MediaResourceManagerService::~MediaResourceManagerService()
{
// Unregister AMessage handler from ALooper.
mLooper->unregisterHandler(mReflector->id());
// Stop ALooper thread.
mLooper->stop();
}
void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
{
if (who != NULL) {
Mutex::Autolock autoLock(mLock);
sp<IBinder> binder = who.promote();
if (binder != NULL) {
mResources.forgetClient(binder);
}
}
}
status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
int resourceType, bool willWait)
{
ResourceType type = static_cast<ResourceType>(resourceType);
// Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
switch (type) {
case HW_VIDEO_DECODER:
case HW_VIDEO_ENCODER:
break;
default:
// Type not supported.
return BAD_TYPE;
}
Mutex::Autolock autoLock(mLock);
// Must know if it will be granted or not - if there are enough unfufilled requests to
// use up the resource, fail. Otherwise we know that enqueuing under lock will succeed.
if (!willWait &&
(mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
NAME_NOT_FOUND)) {
return RESOURCE_NOT_AVAILABLE;
}
// We could early-return here without enqueuing IF we can do the rest of
// the allocation safely here. However, enqueuing ensures there's only
// one copy of that code, and that any callbacks are made from the same
// context.
sp<IBinder> binder = client->asBinder();
mResources.enqueueRequest(binder, type);
binder->linkToDeath(this);
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
notify->setInt32(kMsgKeyResourceType, resourceType);
// Post AMessage to MediaResourceManagerService via ALooper.
notify->post();
return OK;
}
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
int resourceType)
{
Mutex::Autolock autoLock(mLock);
sp<IBinder> binder = client->asBinder();
cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
notify->setInt32(kMsgKeyResourceType, resourceType);
// Next!
// Note: since we held the lock while releasing and then posting, if there is
// a queue, no willWait==false entries can jump into the queue thinking they'll
// get the resource.
notify->post();
return NO_ERROR;
}
// Extract resource type from message.
static int32_t getResourceType(const sp<AMessage>& message)
{
int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
}
// Called on ALooper thread.
void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
{
Mutex::Autolock autoLock(mLock);
ResourceType type = static_cast<ResourceType>(getResourceType(msg));
// Note: a message is sent both for "I added an entry to the queue"
// (which may succeed, typically if the queue is empty), and for "I gave
// up the resource", in which case it's "give to the next waiting client,
// or no one".
// Exit if no resource is available, but leave the client in the waiting
// list.
int found = mResources.findAvailableResource(type);
if (found == NAME_NOT_FOUND) {
return;
}
// Exit if no request.
if (!mResources.hasRequest(type)) {
return;
}
sp<IBinder> req = mResources.nextRequest(type);
mResources.aquireResource(req, type, found);
// Notify resource assignment to the client.
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
mResources.dequeueRequest(type);
}
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
ResourceType resourceType)
{
mResources.forgetClient(binder, resourceType);
binder->unlinkToDeath(this);
}
MediaResourceManagerService::ResourceTable::ResourceTable()
{
// Populate types of resources.
for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
Resources& resources = mMap.editValueAt(index);
int available;
switch (type) {
case HW_VIDEO_DECODER:
available = VIDEO_DECODER_COUNT;
break;
case HW_VIDEO_ENCODER:
available = VIDEO_ENCODER_COUNT;
break;
default:
available = 0;
break;
}
resources.mSlots.insertAt(0, available);
}
}
MediaResourceManagerService::ResourceTable::~ResourceTable() {
// Remove resouces.
mMap.clear();
}
bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
{
return mMap.indexOfKey(type) != NAME_NOT_FOUND;
}
ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
size_t numberNeeded)
{
MOZ_ASSERT(numberNeeded > 0);
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
const Slots& slots = mMap.valueAt(found).mSlots;
found = NAME_NOT_FOUND;
for (size_t i = 0; i < slots.size(); i++) {
if (slots[i].mClient != nullptr) {
// Already in use.
continue;
}
if (--numberNeeded == 0) {
found = i;
break;
}
}
return found;
}
bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
ResourceType type,
size_t index)
{
ResourceSlot* slot = resourceOfTypeAt(type, index);
return slot && slot->mClient == client;
}
status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
ResourceType type,
size_t index)
{
ResourceSlot* slot = resourceOfTypeAt(type, index);
// Resouce should not be in use.
MOZ_ASSERT(slot && slot->mClient == nullptr);
if (!slot) {
return NAME_NOT_FOUND;
} else if (slot->mClient != nullptr) {
// Resource already in use by other client.
return PERMISSION_DENIED;
}
slot->mClient = client;
return OK;
}
MediaResourceManagerService::ResourceSlot*
MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
size_t index)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
Slots& slots = mMap.editValueAt(found).mSlots;
MOZ_ASSERT(index < slots.size());
if (index >= slots.size()) {
// Index out of range.
return nullptr;
}
return &(slots.editItemAt(index));
}
bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return !queue.empty();
}
uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return 0;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return queue.size();
}
sp<IBinder> MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return *(queue.begin());
}
status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
mMap.editValueAt(found).mRequestQueue.push_back(client);
return OK;
}
status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
queue.erase(queue.begin());
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
{
// Traverse all resources.
for (size_t i = 0; i < mMap.size(); i++) {
forgetClient(client, mMap.keyAt(i));
}
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
{
MOZ_ASSERT(supportsType(type));
Resources& resources = mMap.editValueFor(type);
// Remove pending requests for given client.
Fifo& queue = resources.mRequestQueue;
Fifo::iterator it(queue.begin());
while (it != queue.end()) {
if ((*it).get() == client.get()) {
queue.erase(it);
break;
}
it++;
}
// Revoke ownership for given client.
Slots& slots = resources.mSlots;
for (size_t i = 0; i < slots.size(); i++) {
ResourceSlot& slot = slots.editItemAt(i);
if (client.get() == slot.mClient.get()) {
slot.mClient = nullptr;
}
}
return OK;
}
}; // namespace android
@@ -1,135 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_MEDIARESOURCEMANAGERSERVICE_H
#define ANDROID_MEDIARESOURCEMANAGERSERVICE_H
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include "IMediaResourceManagerClient.h"
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Manage permissions of using media resources(hw decoder, hw encoder, camera)
* XXX Current implementation supports only one hw video codec.
* Need to extend to support multiple instance and other resources.
*/
class MediaResourceManagerService: public BnMediaResourceManagerService,
public IBinder::DeathRecipient
{
public:
// The maximum number of hardware resoureces available.
enum
{
VIDEO_DECODER_COUNT = 1,
VIDEO_ENCODER_COUNT = 1
};
enum
{
kNotifyRequest = 'noti',
};
static const char* kMsgKeyResourceType;
// Instantiate MediaResourceManagerService and register to service manager.
// If service manager is not present, wait until service manager becomes present.
static void instantiate();
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
// derived from IMediaResourceManagerService
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
int resourceType, bool willWait);
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
int resourceType);
// Receive a message from AHandlerReflector.
// Called on ALooper thread.
void onMessageReceived(const sp<AMessage> &msg);
protected:
MediaResourceManagerService();
virtual ~MediaResourceManagerService();
private:
// Represent a media resouce.
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
struct ResourceSlot
{
sp<IBinder> mClient;
};
typedef Vector<ResourceSlot> Slots;
typedef List<sp<IBinder> > Fifo;
struct Resources
{
// Queue of media resource requests. Hold IMediaResourceManagerClient that
// requesting a media resource as IBinder.
Fifo mRequestQueue;
// All resources that can be requested. Hold |ResourceSlot|s that track
// their usage.
Slots mSlots;
};
typedef KeyedVector<ResourceType, Resources> ResourcesMap;
// Manages requests from clients and availability of resources.
class ResourceTable
{
ResourceTable();
~ResourceTable();
// Resource operations.
bool supportsType(ResourceType type);
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
// Request operations.
bool hasRequest(ResourceType type);
uint32_t countRequests(ResourceType type);
sp<IBinder> nextRequest(ResourceType type);
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
status_t dequeueRequest(ResourceType type);
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
status_t forgetClient(const sp<IBinder>& client);
friend class MediaResourceManagerService;
// A map for all types of supported resources.
ResourcesMap mMap;
};
void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
// ALooper is a message loop used in stagefright.
// It creates a thread for messages and handles messages in the thread.
// ALooper is a clone of Looper in android Java.
// http://developer.android.com/reference/android/os/Looper.html
sp<ALooper> mLooper;
// deliver a message to a wrapped object(OmxDecoder).
// AHandlerReflector is similar to Handler in android Java.
// http://developer.android.com/reference/android/os/Handler.html
sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
// The lock protects manager operations called from multiple threads.
Mutex mLock;
// Keeps all the records.
ResourceTable mResources;
};
}; // namespace android
#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H
@@ -1,47 +0,0 @@
# -*- 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/.
EXPORTS += [
'IMediaResourceManagerClient.h',
'IMediaResourceManagerDeathNotifier.h',
'IMediaResourceManagerService.h',
'MediaResourceHandler.h',
'MediaResourceManagerClient.h',
'MediaResourceManagerService.h',
]
SOURCES += [
'IMediaResourceManagerClient.cpp',
'IMediaResourceManagerDeathNotifier.cpp',
'IMediaResourceManagerService.cpp',
'MediaResourceHandler.cpp',
'MediaResourceManagerClient.cpp',
'MediaResourceManagerService.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
# Suppress some GCC/clang warnings being treated as errors:
# - about multi-character constants which are used in codec-related code
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
CXXFLAGS += [
'-Wno-error=multichar'
]
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'frameworks/base/include',
'frameworks/base/include/binder',
'frameworks/base/include/utils',
'frameworks/base/include/media/',
'frameworks/base/include/media/stagefright/openmax',
'frameworks/base/media/libstagefright/include',
]
]
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True
-1
View File
@@ -94,7 +94,6 @@ LOCAL_INCLUDES += [
'/dom/base',
'/dom/html',
'/ipc/chromium/src',
'mediaresourcemanager',
]
CXXFLAGS += [
-1
View File
@@ -18,7 +18,6 @@ UNIFIED_SOURCES += [
]
LOCAL_INCLUDES += [
'/dom/media/omx/',
'/dom/media/omx/mediaresourcemanager',
]
include('/ipc/chromium/chromium-config.mozbuild')
@@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "mozilla/Monitor.h"
#include "mozilla/ReentrantMonitor.h"
#include "MediaSystemResourceClient.h"
namespace mozilla {
Atomic<uint32_t> MediaSystemResourceClient::sSerialCounter(0);
MediaSystemResourceClient::MediaSystemResourceClient(MediaSystemResourceType aReourceType)
: mResourceType(aReourceType)
, mId(++sSerialCounter)
, mListener(nullptr)
, mResourceState(RESOURCE_STATE_START)
, mIsSync(false)
, mAcquireSyncWaitMonitor(nullptr)
, mAcquireSyncWaitDone(nullptr)
{
mManager = MediaSystemResourceManager::Get();
if (mManager) {
mManager->Register(this);
}
}
MediaSystemResourceClient::~MediaSystemResourceClient()
{
ReleaseResource();
if (mManager) {
mManager->Unregister(this);
}
}
bool
MediaSystemResourceClient::SetListener(MediaSystemResourceReservationListener* aListener)
{
if (!mManager) {
return false;
}
return mManager->SetListener(this, aListener);
}
void
MediaSystemResourceClient::Acquire()
{
if (!mManager) {
return;
}
mManager->Acquire(this);
}
bool
MediaSystemResourceClient::AcquireSyncNoWait()
{
if (!mManager) {
return false;
}
return mManager->AcquireSyncNoWait(this);
}
void
MediaSystemResourceClient::ReleaseResource()
{
if (!mManager) {
return;
}
mManager->ReleaseResource(this);
}
} // namespace mozilla
@@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceClient_h_)
#define MediaSystemResourceClient_h_
#include "MediaSystemResourceManager.h"
#include "MediaSystemResourceTypes.h"
#include "mozilla/Atomics.h"
#include "mozilla/media/MediaSystemResourceTypes.h"
#include "mozilla/Monitor.h"
#include "mozilla/nsRefPtr.h"
namespace mozilla {
class MediaSystemResourceManager;
/**
* This is a base class for listener callbacks.
* This callback is invoked when the media system resource reservation state
* is changed.
*/
class MediaSystemResourceReservationListener {
public:
virtual void ResourceReserved() = 0;
virtual void ResourceReserveFailed() = 0;
};
/**
* MediaSystemResourceClient is used to reserve a media system resource
* like hw decoder. When system has a limitation of a media resource,
* use this class to mediate use rights of the resource.
*/
class MediaSystemResourceClient
{
public:
// Enumeration for the valid decoding states
enum ResourceState {
RESOURCE_STATE_START,
RESOURCE_STATE_WAITING,
RESOURCE_STATE_ACQUIRED,
RESOURCE_STATE_NOT_ACQUIRED,
RESOURCE_STATE_END
};
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceClient)
explicit MediaSystemResourceClient(MediaSystemResourceType aReourceType);
bool SetListener(MediaSystemResourceReservationListener* aListener);
// Try to acquire media resource asynchronously.
// If the resource is used by others, wait until acquired.
void Acquire();
// Try to acquire media resource synchronously. If the resource is not immediately
// available, fail to acquire it.
// return false if resource is not acquired.
// return true if resource is acquired.
//
// This function should not be called on ImageBridge thread.
// It should be used only for compatibility with legacy code.
bool AcquireSyncNoWait();
void ReleaseResource();
private:
~MediaSystemResourceClient();
nsRefPtr<MediaSystemResourceManager> mManager;
const MediaSystemResourceType mResourceType;
const uint32_t mId;
// Modified only by MediaSystemResourceManager.
// Accessed and modified with MediaSystemResourceManager::mReentrantMonitor held.
MediaSystemResourceReservationListener* mListener;
ResourceState mResourceState;
bool mIsSync;
ReentrantMonitor* mAcquireSyncWaitMonitor;
bool* mAcquireSyncWaitDone;
static mozilla::Atomic<uint32_t> sSerialCounter;
friend class MediaSystemResourceManager;
};
} // namespace mozilla
#endif
@@ -0,0 +1,425 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "gfxPrefs.h"
#include "MediaSystemResourceManagerChild.h"
#include "MediaTaskQueue.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "MediaSystemResourceManager.h"
namespace mozilla {
using namespace mozilla::ipc;
using namespace mozilla::layers;
/* static */ StaticRefPtr<MediaSystemResourceManager> MediaSystemResourceManager::sSingleton;
/* static */ MediaSystemResourceManager*
MediaSystemResourceManager::Get()
{
if (sSingleton) {
return sSingleton;
}
MediaSystemResourceManager::Init();
return sSingleton;
}
/* static */ void
MediaSystemResourceManager::Shutdown()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (sSingleton) {
sSingleton->CloseIPC();
sSingleton = nullptr;
}
}
/* static */ bool
MediaSystemResourceManager::IsMediaSystemResourceManagerEnabled()
{
#ifdef MOZ_WIDGET_GONK
return true;
#else
// XXX MediaSystemResourceManager is enabled only when ImageBridge is enabled.
// MediaSystemResourceManager uses ImageBridge's thread.
if (gfxPrefs::AsyncVideoOOPEnabled() &&
gfxPrefs::AsyncVideoEnabled()) {
return true;
} else {
return false;
}
#endif
}
class RunnableCallTask : public Task
{
public:
explicit RunnableCallTask(nsIRunnable* aRunnable)
: mRunnable(aRunnable) {}
void Run() override
{
mRunnable->Run();
}
protected:
nsCOMPtr<nsIRunnable> mRunnable;
};
/* static */ void
MediaSystemResourceManager::Init()
{
MOZ_ASSERT(IsMediaSystemResourceManagerEnabled());
if (!ImageBridgeChild::IsCreated()) {
NS_WARNING("ImageBridge does not exist");
return;
}
if (InImageBridgeChildThread()) {
if (!sSingleton) {
#ifdef DEBUG
static int timesCreated = 0;
timesCreated++;
MOZ_ASSERT(timesCreated == 1);
#endif
sSingleton = new MediaSystemResourceManager();
}
return;
}
ReentrantMonitor barrier("MediaSystemResourceManager::Init");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction([&]() {
if (!sSingleton) {
sSingleton = new MediaSystemResourceManager();
}
ReentrantMonitorAutoEnter autoMon(barrier);
done = true;
barrier.NotifyAll();
});
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE, new RunnableCallTask(runnable));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
}
MediaSystemResourceManager::MediaSystemResourceManager()
: mReentrantMonitor("MediaSystemResourceManager.mReentrantMonitor")
, mShutDown(false)
, mChild(nullptr)
{
MOZ_ASSERT(InImageBridgeChildThread());
OpenIPC();
}
MediaSystemResourceManager::~MediaSystemResourceManager()
{
MOZ_ASSERT(IsIpcClosed());
}
void
MediaSystemResourceManager::OpenIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
MOZ_ASSERT(!mChild);
media::PMediaSystemResourceManagerChild* child =
ImageBridgeChild::GetSingleton()->SendPMediaSystemResourceManagerConstructor();
mChild = static_cast<media::MediaSystemResourceManagerChild*>(child);
mChild->SetManager(this);
}
void
MediaSystemResourceManager::CloseIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (!mChild) {
return;
}
mChild->Destroy();
mChild = nullptr;
mShutDown = true;
}
void
MediaSystemResourceManager::OnIpcClosed()
{
mChild = nullptr;
}
bool
MediaSystemResourceManager::IsIpcClosed()
{
return mChild ? true : false;
}
void
MediaSystemResourceManager::Register(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(!mResourceClients.Get(aClient->mId));
mResourceClients.Put(aClient->mId, aClient);
}
void
MediaSystemResourceManager::Unregister(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(mResourceClients.Get(aClient->mId));
MOZ_ASSERT(mResourceClients.Get(aClient->mId) == aClient);
mResourceClients.Remove(aClient->mId);
}
bool
MediaSystemResourceManager::SetListener(MediaSystemResourceClient* aClient,
MediaSystemResourceReservationListener* aListener)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
if (!client) {
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
return false;
}
aClient->mListener = aListener;
return true;
}
void
MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = false; // async request
if (!client) {
HandleAcquireResult(aClient->mId, false);
return;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
}
bool
MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitor barrier("MediaSystemResourceManager::AcquireSyncNoWait");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = true; // sync request
if (InImageBridgeChildThread()) {
HandleAcquireResult(aClient->mId, false);
return false;
}
if (!aClient ||
!client ||
client != aClient) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// Hold barrier Monitor until acquire task end.
aClient->mAcquireSyncWaitMonitor = &barrier;
aClient->mAcquireSyncWaitDone = &done;
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
}
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED) {
return false;
}
return true;
}
}
void
MediaSystemResourceManager::DoAcquire(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
HandleAcquireResult(aId, false);
return;
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
MOZ_ASSERT(client);
if (!client ||
client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
HandleAcquireResult(aId, false);
return;
}
MOZ_ASSERT(aId == client->mId);
bool willWait = !client->mAcquireSyncWaitMonitor ? true : false;
mChild->SendAcquire(client->mId,
client->mResourceType,
willWait);
}
}
void
MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
if (!client ||
client != aClient ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_START ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_END) {
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoRelease,
aClient->mId));
}
}
void
MediaSystemResourceManager::DoRelease(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
return;
}
mChild->SendRelease(aId);
}
void
MediaSystemResourceManager::RecvResponse(uint32_t aId, bool aSuccess)
{
HandleAcquireResult(aId, aSuccess);
}
void
MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess)
{
if (!InImageBridgeChildThread()) {
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::HandleAcquireResult,
aId,
aSuccess));
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
if (!client) {
// Client was already unregistered.
return;
}
if (client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
return;
}
// Update state
if (aSuccess) {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED;
} else {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_NOT_ACQUIRED;
}
if (client->mIsSync) {
if (client->mAcquireSyncWaitMonitor) {
// Notify AcquireSync() complete
MOZ_ASSERT(client->mAcquireSyncWaitDone);
ReentrantMonitorAutoEnter autoMon(*client->mAcquireSyncWaitMonitor);
*client->mAcquireSyncWaitDone = true;
client->mAcquireSyncWaitMonitor->NotifyAll();
client->mAcquireSyncWaitMonitor = nullptr;
client->mAcquireSyncWaitDone = nullptr;
}
} else {
// Notify Acquire() result
if (client->mListener) {
if (aSuccess) {
client->mListener->ResourceReserved();
} else {
client->mListener->ResourceReserveFailed();
}
}
}
}
} // namespace mozilla
@@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceManager_h_)
#define MediaSystemResourceManager_h_
#include <queue>
#include "MediaSystemResourceTypes.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StaticPtr.h"
#include "nsAutoPtr.h"
#include "nsDataHashtable.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace media {
class MediaSystemResourceManagerChild;
}
class MediaSystemResourceClient;
class MediaSystemResourceReservationListener;
class MediaTaskQueue;
class ReentrantMonitor;
/**
* Manage media system resource allocation requests within a process.
*/
class MediaSystemResourceManager
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceManager)
static MediaSystemResourceManager* Get();
static void Init();
static void Shutdown();
void OnIpcClosed();
void Register(MediaSystemResourceClient* aClient);
void Unregister(MediaSystemResourceClient* aClient);
bool SetListener(MediaSystemResourceClient* aClient,
MediaSystemResourceReservationListener* aListener);
void Acquire(MediaSystemResourceClient* aClient);
bool AcquireSyncNoWait(MediaSystemResourceClient* aClient);
void ReleaseResource(MediaSystemResourceClient* aClient);
void RecvResponse(uint32_t aId, bool aSuccess);
private:
MediaSystemResourceManager();
virtual ~MediaSystemResourceManager();
static bool IsMediaSystemResourceManagerEnabled();
void OpenIPC();
void CloseIPC();
bool IsIpcClosed();
void DoAcquire(uint32_t aId);
void DoRelease(uint32_t aId);
void HandleAcquireResult(uint32_t aId, bool aSuccess);
ReentrantMonitor mReentrantMonitor;
bool mShutDown;
media::MediaSystemResourceManagerChild* mChild;
nsDataHashtable<nsUint32HashKey, MediaSystemResourceClient*> mResourceClients;
static StaticRefPtr<MediaSystemResourceManager> sSingleton;
};
} // namespace mozilla
#endif
@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 2; 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 "MediaSystemResourceManager.h"
#include "MediaSystemResourceManagerChild.h"
namespace mozilla {
namespace media {
MediaSystemResourceManagerChild::MediaSystemResourceManagerChild()
: mDestroyed(false)
{
}
MediaSystemResourceManagerChild::~MediaSystemResourceManagerChild()
{
}
bool
MediaSystemResourceManagerChild::RecvResponse(const uint32_t& aId,
const bool& aSuccess)
{
if (mManager) {
mManager->RecvResponse(aId, aSuccess);
}
return true;
}
void
MediaSystemResourceManagerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
{
MOZ_ASSERT(!mDestroyed);
if (mManager) {
mManager->OnIpcClosed();
}
mDestroyed = true;
}
void
MediaSystemResourceManagerChild::Destroy()
{
if (mDestroyed) {
return;
}
SendRemoveResourceManager();
// WARNING: |this| is dead, hands off
}
} // namespace media
} // namespace mozilla
@@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#if !defined(MediaSystemResourceManagerChild_h_)
#define MediaSystemResourceManagerChild_h_
#include "mozilla/media/PMediaSystemResourceManagerChild.h"
#include "nsISupportsImpl.h"
namespace mozilla {
class MediaSystemResourceManager;
namespace ipc {
class BackgroundChildImpl;
}
namespace media {
/**
* Handle MediaSystemResourceManager's IPC
*/
class MediaSystemResourceManagerChild final : public PMediaSystemResourceManagerChild
{
public:
struct ResourceListener {
/* The resource is reserved and can be granted.
* The client can allocate the requested resource.
*/
virtual void resourceReserved() = 0;
/* The resource is not reserved any more.
* The client should release the resource as soon as possible if the
* resource is still being held.
*/
virtual void resourceCanceled() = 0;
};
MediaSystemResourceManagerChild();
virtual ~MediaSystemResourceManagerChild();
void Destroy();
void SetManager(MediaSystemResourceManager* aManager)
{
mManager = aManager;
}
protected:
bool RecvResponse(const uint32_t& aId,
const bool& aSuccess) override;
private:
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
bool mDestroyed;
MediaSystemResourceManager* mManager;
friend class mozilla::ipc::BackgroundChildImpl;
};
} // namespatce media
} // namespatce mozilla
#endif
@@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 2; 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 "mozilla/unused.h"
#include "MediaSystemResourceManagerParent.h"
namespace mozilla {
namespace media {
using namespace ipc;
MediaSystemResourceManagerParent::MediaSystemResourceManagerParent()
: mDestroyed(false)
{
mMediaSystemResourceService = MediaSystemResourceService::Get();
}
MediaSystemResourceManagerParent::~MediaSystemResourceManagerParent()
{
MOZ_ASSERT(mDestroyed);
}
bool
MediaSystemResourceManagerParent::RecvAcquire(const uint32_t& aId,
const MediaSystemResourceType& aResourceType,
const bool& aWillWait)
{
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
MOZ_ASSERT(!request);
if (request) {
// Send fail response
mozilla::unused << SendResponse(aId, false /* fail */);
return true;
}
request = new MediaSystemResourceRequest(aId, aResourceType);
mResourceRequests.Put(aId, request);
mMediaSystemResourceService->Acquire(this, aId, aResourceType, aWillWait);
return true;
}
bool
MediaSystemResourceManagerParent::RecvRelease(const uint32_t& aId)
{
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
if (!request) {
return true;
}
mMediaSystemResourceService->ReleaseResource(this, aId, request->mResourceType);
mResourceRequests.Remove(aId);
return true;
}
bool
MediaSystemResourceManagerParent::RecvRemoveResourceManager()
{
return PMediaSystemResourceManagerParent::Send__delete__(this);
}
void
MediaSystemResourceManagerParent::ActorDestroy(ActorDestroyReason aReason)
{
MOZ_ASSERT(!mDestroyed);
// Release all resource requests of the MediaSystemResourceManagerParent.
// Clears all remaining pointers to this object.
mMediaSystemResourceService->ReleaseResource(this);
mDestroyed = true;
}
} // namespace media
} // namespace mozilla
@@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#if !defined(MediaSystemResourceManagerParent_h_)
#define MediaSystemResourceManagerParent_h_
#include "MediaSystemResourceManager.h"
#include "MediaSystemResourceService.h"
#include "MediaSystemResourceTypes.h"
#include "mozilla/media/PMediaSystemResourceManagerParent.h"
namespace mozilla {
namespace media {
/**
* Handle MediaSystemResourceManager's IPC
*/
class MediaSystemResourceManagerParent final : public PMediaSystemResourceManagerParent
{
public:
MediaSystemResourceManagerParent();
virtual ~MediaSystemResourceManagerParent();
protected:
bool RecvAcquire(const uint32_t& aId,
const MediaSystemResourceType& aResourceType,
const bool& aWillWait) override;
bool RecvRelease(const uint32_t& aId) override;
bool RecvRemoveResourceManager() override;
private:
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
struct MediaSystemResourceRequest {
MediaSystemResourceRequest()
: mId(-1), mResourceType(MediaSystemResourceType::INVALID_RESOURCE) {}
MediaSystemResourceRequest(uint32_t aId, MediaSystemResourceType aResourceType)
: mId(aId), mResourceType(aResourceType) {}
int32_t mId;
MediaSystemResourceType mResourceType;
};
bool mDestroyed;
nsRefPtr<MediaSystemResourceService> mMediaSystemResourceService;
nsClassHashtable<nsUint32HashKey, MediaSystemResourceRequest> mResourceRequests;
};
} // namespatce media
} // namespatce mozilla
#endif
@@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceMessageUtils_h_)
#define MediaSystemResourceMessageUtils_h_
#include "ipc/IPCMessageUtils.h"
#include "MediaSystemResourceTypes.h"
namespace IPC {
template <>
struct ParamTraits<mozilla::MediaSystemResourceType>
: public ContiguousEnumSerializer<
mozilla::MediaSystemResourceType,
mozilla::MediaSystemResourceType::VIDEO_DECODER,
mozilla::MediaSystemResourceType::INVALID_RESOURCE>
{};
} // namespace IPC
#endif
@@ -0,0 +1,273 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MediaSystemResourceManagerParent.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/unused.h"
#include "MediaSystemResourceService.h"
using namespace mozilla::layers;
namespace mozilla {
/* static */ StaticRefPtr<MediaSystemResourceService> MediaSystemResourceService::sSingleton;
/* static */ MediaSystemResourceService*
MediaSystemResourceService::Get()
{
if (sSingleton) {
return sSingleton;
}
Init();
return sSingleton;
}
/* static */ void
MediaSystemResourceService::Init()
{
if (!sSingleton) {
sSingleton = new MediaSystemResourceService();
}
}
/* static */ void
MediaSystemResourceService::Shutdown()
{
if (sSingleton) {
sSingleton->Destroy();
sSingleton = nullptr;
}
}
MediaSystemResourceService::MediaSystemResourceService()
: mDestroyed(false)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
#ifdef MOZ_WIDGET_GONK
// The maximum number of hardware resoureces available.
// XXX need to hange to a dynamic way.
enum
{
VIDEO_DECODER_COUNT = 1,
VIDEO_ENCODER_COUNT = 1
};
MediaSystemResource* resource;
resource = new MediaSystemResource(VIDEO_DECODER_COUNT);
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_DECODER), resource);
resource = new MediaSystemResource(VIDEO_ENCODER_COUNT);
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_ENCODER), resource);
#endif
}
MediaSystemResourceService::~MediaSystemResourceService()
{
}
void
MediaSystemResourceService::Destroy()
{
mDestroyed = true;
}
void
MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType,
bool aWillWait)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
// Send fail response
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
return;
}
// Try to acquire a resource
if (resource->mAcquiredRequests.size() < resource->mResourceCount) {
// Resource is available
resource->mAcquiredRequests.push_back(
MediaSystemResourceRequest(aParent, aId));
// Send success response
mozilla::unused << aParent->SendResponse(aId, true /* success */);
return;
} else if (!aWillWait) {
// Resource is not available and do not wait.
// Send fail response
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
return;
}
// Wait until acquire.
resource->mWaitingRequests.push_back(
MediaSystemResourceRequest(aParent, aId));
}
void
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
RemoveRequest(aParent, aId, aResourceType);
UpdateRequests(aResourceType);
}
struct ReleaseResourceData
{
MediaSystemResourceService* mSelf;
media::MediaSystemResourceManagerParent* mParent;
};
/*static*/PLDHashOperator
MediaSystemResourceService::ReleaseResourceForKey(const uint32_t& aKey,
nsAutoPtr<MediaSystemResource>& aData,
void* aClosure)
{
ReleaseResourceData* closure = static_cast<ReleaseResourceData*>(aClosure);
closure->mSelf->RemoveRequests(closure->mParent, static_cast<MediaSystemResourceType>(aKey));
closure->mSelf->UpdateRequests(static_cast<MediaSystemResourceType>(aKey));
return PLDHashOperator::PL_DHASH_NEXT;
}
void
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent)
{
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
ReleaseResourceData data = { this, aParent };
mResources.Enumerate(ReleaseResourceForKey, &data);
}
void
MediaSystemResourceService::RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(aParent);
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource) {
return;
}
std::deque<MediaSystemResourceRequest>::iterator it;
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
for (it = acquiredRequests.begin(); it != acquiredRequests.end(); it++) {
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
acquiredRequests.erase(it);
return;
}
}
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
for (it = waitingRequests.begin(); it != waitingRequests.end(); it++) {
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
waitingRequests.erase(it);
return;
}
}
}
void
MediaSystemResourceService::RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(aParent);
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
std::deque<MediaSystemResourceRequest>::iterator it;
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
for (it = acquiredRequests.begin(); it != acquiredRequests.end();) {
if ((*it).mParent == aParent) {
it = acquiredRequests.erase(it);
} else {
it++;
}
}
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
for (it = waitingRequests.begin(); it != waitingRequests.end();) {
if ((*it).mParent == aParent) {
it = waitingRequests.erase(it);
return;
} else {
it++;
}
}
}
void
MediaSystemResourceService::UpdateRequests(MediaSystemResourceType aResourceType)
{
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
while ((acquiredRequests.size() < resource->mResourceCount) &&
(waitingRequests.size() > 0)) {
MediaSystemResourceRequest& request = waitingRequests.front();
MOZ_ASSERT(request.mParent);
// Send response
mozilla::unused << request.mParent->SendResponse(request.mId, true /* success */);
// Move request to mAcquiredRequests
acquiredRequests.push_back(waitingRequests.front());
waitingRequests.pop_front();
}
}
} // namespace mozilla
@@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceService_h_)
#define MediaSystemResourceService_h_
#include <deque>
#include "MediaSystemResourceTypes.h"
#include "mozilla/StaticPtr.h"
#include "nsClassHashtable.h"
namespace mozilla {
namespace media {
class MediaSystemResourceManagerParent;
}
/**
* Manage media system resource allocation requests within system.
*/
class MediaSystemResourceService
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceService)
static MediaSystemResourceService* Get();
static void Init();
static void Shutdown();
void Acquire(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType,
bool aWillWait);
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType);
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent);
private:
MediaSystemResourceService();
~MediaSystemResourceService();
struct MediaSystemResourceRequest {
MediaSystemResourceRequest()
: mParent(nullptr), mId(-1) {}
MediaSystemResourceRequest(media::MediaSystemResourceManagerParent* aParent, uint32_t aId)
: mParent(aParent), mId(aId) {}
media::MediaSystemResourceManagerParent* mParent;
uint32_t mId;
};
struct MediaSystemResource {
MediaSystemResource()
: mResourceCount(0) {}
explicit MediaSystemResource(uint32_t aResourceCount)
: mResourceCount(aResourceCount) {}
std::deque<MediaSystemResourceRequest> mWaitingRequests;
std::deque<MediaSystemResourceRequest> mAcquiredRequests;
uint32_t mResourceCount;
};
void Destroy();
void RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType);
void RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
MediaSystemResourceType aResourceType);
void UpdateRequests(MediaSystemResourceType aResourceType);
static PLDHashOperator ReleaseResourceForKey(const uint32_t& aKey,
nsAutoPtr<MediaSystemResource>& aData,
void* aClosure);
bool mDestroyed;
nsClassHashtable<nsUint32HashKey, MediaSystemResource> mResources;
static StaticRefPtr<MediaSystemResourceService> sSingleton;
};
} // namespace mozilla
#endif
@@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceTypes_h_)
#define MediaSystemResourceTypes_h_
namespace mozilla {
enum class MediaSystemResourceType : uint32_t {
VIDEO_DECODER = 0,
AUDIO_DECODER, // Not supported currently.
VIDEO_ENCODER,
AUDIO_ENCODER, // Not supported currently.
CAMERA, // Not supported currently.
INVALID_RESOURCE,
};
} // namespace mozilla
#endif
@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 2; 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 protocol PImageBridge;
include "mozilla/media/MediaSystemResourceMessageUtils.h";
using mozilla::MediaSystemResourceType from "mozilla/media/MediaSystemResourceTypes.h";
namespace mozilla {
namespace media {
/*
* The PMediaSystemResourceManager is a sub-protocol in PImageBridge
*/
sync protocol PMediaSystemResourceManager
{
manager PImageBridge;
child:
async Response(uint32_t aId, bool aSuccess);
async __delete__();
parent:
async Acquire(uint32_t aId, MediaSystemResourceType aResourceType, bool aWillWait);
async Release(uint32_t aId);
/**
* Asynchronously tell the parent side to remove the PMediaSystemResourceManager.
*/
async RemoveResourceManager();
};
} // namespace media
} // namespace mozilla
+16 -3
View File
@@ -38,15 +38,28 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
]
EXPORTS.mozilla.media += ['MediaChild.h',
'MediaParent.h',
'MediaUtils.h'
'MediaParent.h',
'MediaSystemResourceClient.h',
'MediaSystemResourceManager.h',
'MediaSystemResourceManagerChild.h',
'MediaSystemResourceManagerParent.h',
'MediaSystemResourceMessageUtils.h',
'MediaSystemResourceService.h',
'MediaSystemResourceTypes.h',
'MediaUtils.h'
]
UNIFIED_SOURCES += ['MediaChild.cpp',
'MediaParent.cpp',
'MediaUtils.cpp'
'MediaSystemResourceClient.cpp',
'MediaSystemResourceManager.cpp',
'MediaSystemResourceManagerChild.cpp',
'MediaSystemResourceManagerParent.cpp',
'MediaSystemResourceService.cpp',
'MediaUtils.cpp',
]
IPDL_SOURCES += [
'PMedia.ipdl',
'PMediaSystemResourceManager.ipdl',
]
# /dom/base needed for nsGlobalWindow.h in MediaChild.cpp
LOCAL_INCLUDES += [
+7 -37
View File
@@ -14,18 +14,18 @@
* E: element type, must be a POD type.
* N: N bytes alignment for the first element, defaults to 32
*/
template <typename E, int N, typename Alloc>
class AlignedTArray_Impl : public nsTArray_Impl<E, Alloc>
template <typename E, int N = 32>
class AlignedTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
{
static_assert((N & (N-1)) == 0, "N must be power of 2");
typedef nsTArray_Impl<E, Alloc> base_type;
typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
public:
typedef E elem_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::index_type index_type;
AlignedTArray_Impl() {}
explicit AlignedTArray_Impl(size_type capacity) : base_type(capacity+sExtra) {}
AlignedTArray() {}
explicit AlignedTArray(size_type capacity) : base_type(capacity + sExtra) {}
elem_type* Elements() { return getAligned(base_type::Elements()); }
const elem_type* Elements() const { return getAligned(base_type::Elements()); }
elem_type& operator[](index_type i) { return Elements()[i];}
@@ -47,8 +47,8 @@ public:
}
private:
AlignedTArray_Impl(const AlignedTArray_Impl& other) = delete;
void operator=(const AlignedTArray_Impl& other) = delete;
AlignedTArray(const AlignedTArray& other) = delete;
void operator=(const AlignedTArray& other) = delete;
static const size_type sPadding = N <= MOZ_ALIGNOF(E) ? 0 : N - MOZ_ALIGNOF(E);
static const size_type sExtra = (sPadding + sizeof(E) - 1) / sizeof(E);
@@ -60,34 +60,4 @@ private:
}
};
template <typename E, int N=32>
class AlignedTArray : public AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator>
{
public:
typedef AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator> base_type;
typedef AlignedTArray<E, N> self_type;
typedef typename base_type::size_type size_type;
AlignedTArray() {}
explicit AlignedTArray(size_type capacity) : base_type(capacity) {}
private:
AlignedTArray(const AlignedTArray& other) = delete;
void operator=(const AlignedTArray& other) = delete;
};
template <typename E, int N=32>
class AlignedFallibleTArray : public AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator>
{
public:
typedef AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator> base_type;
typedef AlignedFallibleTArray<E, N> self_type;
typedef typename base_type::size_type size_type;
AlignedFallibleTArray() {}
explicit AlignedFallibleTArray(size_type capacity) : base_type(capacity) {}
private:
AlignedFallibleTArray(const AlignedFallibleTArray& other) = delete;
void operator=(const AlignedFallibleTArray& other) = delete;
};
#endif // AlignedTArray_h__
+86 -67
View File
@@ -12,6 +12,14 @@
#include "mozilla/PodOperations.h"
namespace mozilla {
static const uint32_t MAX_FFT_SIZE = 32768;
static const size_t CHUNK_COUNT = MAX_FFT_SIZE >> WEBAUDIO_BLOCK_SIZE_BITS;
static_assert(MAX_FFT_SIZE == CHUNK_COUNT * WEBAUDIO_BLOCK_SIZE,
"MAX_FFT_SIZE must be a multiple of WEBAUDIO_BLOCK_SIZE");
static_assert((CHUNK_COUNT & (CHUNK_COUNT - 1)) == 0,
"CHUNK_COUNT must be power of 2 for remainder behavior");
namespace dom {
NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode)
@@ -57,20 +65,7 @@ public:
{
*aOutput = aInput;
// If the input is silent, we sill need to send a silent buffer
if (aOutput->IsNull()) {
AllocateAudioBlock(1, aOutput);
float* samples =
static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
PodZero(samples, WEBAUDIO_BLOCK_SIZE);
}
uint32_t channelCount = aOutput->mChannelData.Length();
for (uint32_t channel = 0; channel < channelCount; ++channel) {
float* samples =
static_cast<float*>(const_cast<void*>(aOutput->mChannelData[channel]));
AudioBlockInPlaceScale(samples, aOutput->mVolume);
}
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, *aOutput);
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, aInput);
NS_DispatchToMainThread(transfer);
}
@@ -89,10 +84,15 @@ AnalyserNode::AnalyserNode(AudioContext* aContext)
, mMinDecibels(-100.)
, mMaxDecibels(-30.)
, mSmoothingTimeConstant(.8)
, mWriteIndex(0)
{
mStream = aContext->Graph()->CreateAudioNodeStream(new AnalyserNodeEngine(this),
MediaStreamGraph::INTERNAL_STREAM);
// Enough chunks must be recorded to handle the case of fftSize being
// increased to maximum immediately before getFloatTimeDomainData() is
// called, for example.
(void)mChunks.SetLength(CHUNK_COUNT, fallible);
AllocateBuffer();
}
@@ -101,7 +101,7 @@ AnalyserNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
amount += mAnalysisBlock.SizeOfExcludingThis(aMallocSizeOf);
amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
amount += mChunks.SizeOfExcludingThis(aMallocSizeOf);
amount += mOutputBuffer.SizeOfExcludingThis(aMallocSizeOf);
return amount;
}
@@ -123,7 +123,7 @@ AnalyserNode::SetFftSize(uint32_t aValue, ErrorResult& aRv)
{
// Disallow values that are not a power of 2 and outside the [32,32768] range
if (aValue < 32 ||
aValue > 32768 ||
aValue > MAX_FFT_SIZE ||
(aValue & (aValue - 1)) != 0) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
@@ -212,11 +212,9 @@ AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray)
aArray.ComputeLengthAndData();
float* buffer = aArray.Data();
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
size_t length = std::min(aArray.Length(), FftSize());
for (size_t i = 0; i < length; ++i) {
buffer[i] = mBuffer[(i + mWriteIndex) % mBuffer.Length()];;
}
GetTimeDomainData(buffer, length);
}
void
@@ -224,11 +222,18 @@ AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray)
{
aArray.ComputeLengthAndData();
unsigned char* buffer = aArray.Data();
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
size_t length = std::min(aArray.Length(), FftSize());
AlignedTArray<float> tmpBuffer;
if (!tmpBuffer.SetLength(length, fallible)) {
return;
}
GetTimeDomainData(tmpBuffer.Elements(), length);
unsigned char* buffer = aArray.Data();
for (size_t i = 0; i < length; ++i) {
const float value = mBuffer[(i + mWriteIndex) % mBuffer.Length()];
const float value = tmpBuffer[i];
// scale the value to the range of [0, UCHAR_MAX]
const float scaled = std::max(0.0f, std::min(float(UCHAR_MAX),
128.0f * (value + 1.0f)));
@@ -239,25 +244,19 @@ AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray)
bool
AnalyserNode::FFTAnalysis()
{
float* inputBuffer;
AlignedFallibleTArray<float> tmpBuffer;
if (mWriteIndex == 0) {
inputBuffer = mBuffer.Elements();
} else {
if (!tmpBuffer.SetLength(FftSize(), fallible)) {
return false;
}
inputBuffer = tmpBuffer.Elements();
memcpy(inputBuffer, mBuffer.Elements() + mWriteIndex, sizeof(float) * (FftSize() - mWriteIndex));
memcpy(inputBuffer + FftSize() - mWriteIndex, mBuffer.Elements(), sizeof(float) * mWriteIndex);
AlignedTArray<float> tmpBuffer;
size_t fftSize = FftSize();
if (!tmpBuffer.SetLength(fftSize, fallible)) {
return false;
}
ApplyBlackmanWindow(inputBuffer, FftSize());
float* inputBuffer = tmpBuffer.Elements();
GetTimeDomainData(inputBuffer, fftSize);
ApplyBlackmanWindow(inputBuffer, fftSize);
mAnalysisBlock.PerformFFT(inputBuffer);
// Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
const double magnitudeScale = 1.0 / FftSize();
const double magnitudeScale = 1.0 / fftSize;
for (uint32_t i = 0; i < mOutputBuffer.Length(); ++i) {
double scalarMagnitude = NS_hypot(mAnalysisBlock.RealData(i),
@@ -289,13 +288,7 @@ bool
AnalyserNode::AllocateBuffer()
{
bool result = true;
if (mBuffer.Length() != FftSize()) {
if (!mBuffer.SetLength(FftSize(), fallible)) {
return false;
}
memset(mBuffer.Elements(), 0, sizeof(float) * FftSize());
mWriteIndex = 0;
if (mOutputBuffer.Length() != FrequencyBinCount()) {
if (!mOutputBuffer.SetLength(FrequencyBinCount(), fallible)) {
return false;
}
@@ -307,31 +300,57 @@ AnalyserNode::AllocateBuffer()
void
AnalyserNode::AppendChunk(const AudioChunk& aChunk)
{
const uint32_t bufferSize = mBuffer.Length();
const uint32_t channelCount = aChunk.mChannelData.Length();
uint32_t chunkDuration = aChunk.mDuration;
MOZ_ASSERT((bufferSize & (bufferSize - 1)) == 0); // Must be a power of two!
MOZ_ASSERT(channelCount > 0);
MOZ_ASSERT(chunkDuration == WEBAUDIO_BLOCK_SIZE);
if (chunkDuration > bufferSize) {
// Copy a maximum bufferSize samples.
chunkDuration = bufferSize;
if (mChunks.Length() == 0) {
return;
}
PodCopy(mBuffer.Elements() + mWriteIndex, static_cast<const float*>(aChunk.mChannelData[0]), chunkDuration);
for (uint32_t i = 1; i < channelCount; ++i) {
AudioBlockAddChannelWithScale(static_cast<const float*>(aChunk.mChannelData[i]), 1.0f,
mBuffer.Elements() + mWriteIndex);
++mCurrentChunk;
mChunks[mCurrentChunk & (CHUNK_COUNT - 1)] = aChunk;
}
// Reads into aData the oldest aLength samples of the fftSize most recent
// samples.
void
AnalyserNode::GetTimeDomainData(float* aData, size_t aLength)
{
size_t fftSize = FftSize();
MOZ_ASSERT(aLength <= fftSize);
if (mChunks.Length() == 0) {
PodZero(aData, aLength);
return;
}
if (channelCount > 1) {
AudioBlockInPlaceScale(mBuffer.Elements() + mWriteIndex,
1.0f / aChunk.mChannelData.Length());
}
mWriteIndex += chunkDuration;
MOZ_ASSERT(mWriteIndex <= bufferSize);
if (mWriteIndex >= bufferSize) {
mWriteIndex = 0;
size_t readChunk =
mCurrentChunk - ((fftSize - 1) >> WEBAUDIO_BLOCK_SIZE_BITS);
size_t readIndex = (0 - fftSize) & (WEBAUDIO_BLOCK_SIZE - 1);
MOZ_ASSERT(readIndex == 0 || readIndex + fftSize == WEBAUDIO_BLOCK_SIZE);
for (size_t writeIndex = 0; writeIndex < aLength; ) {
const AudioChunk& chunk = mChunks[readChunk & (CHUNK_COUNT - 1)];
const size_t channelCount = chunk.mChannelData.Length();
size_t copyLength =
std::min<size_t>(aLength - writeIndex, WEBAUDIO_BLOCK_SIZE);
float* dataOut = &aData[writeIndex];
if (channelCount == 0) {
PodZero(dataOut, copyLength);
} else {
float scale = chunk.mVolume / channelCount;
{ // channel 0
auto channelData =
static_cast<const float*>(chunk.mChannelData[0]) + readIndex;
AudioBufferCopyWithScale(channelData, scale, dataOut, copyLength);
}
for (uint32_t i = 1; i < channelCount; ++i) {
auto channelData =
static_cast<const float*>(chunk.mChannelData[i]) + readIndex;
AudioBufferAddWithScale(channelData, scale, dataOut, copyLength);
}
}
readChunk++;
writeIndex += copyLength;
}
}
+4 -3
View File
@@ -71,15 +71,16 @@ private:
bool AllocateBuffer();
bool FFTAnalysis();
void ApplyBlackmanWindow(float* aBuffer, uint32_t aSize);
void GetTimeDomainData(float* aData, size_t aLength);
private:
FFTBlock mAnalysisBlock;
nsTArray<AudioChunk> mChunks;
double mMinDecibels;
double mMaxDecibels;
double mSmoothingTimeConstant;
uint32_t mWriteIndex;
AlignedFallibleTArray<float> mBuffer;
AlignedFallibleTArray<float> mOutputBuffer;
size_t mCurrentChunk = 0;
AlignedTArray<float> mOutputBuffer;
};
} // namespace dom
+12 -1
View File
@@ -478,11 +478,17 @@ public:
ScreenRotation GetScreenRotation() const {
return mScreenRotation;
}
void SetScreenRotation(ScreenRotation aRotation) {
mScreenRotation = aRotation;
}
TimeStamp GetCompositionTime() const {
return mCompositionTime;
}
void SetCompositionTime(TimeStamp aTimeStamp) {
mCompositionTime = aTimeStamp;
}
protected:
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
const gfx::Rect& aVisibleRect,
@@ -497,6 +503,11 @@ protected:
*/
static void SetBackend(LayersBackend backend);
/**
* Render time for the current composition.
*/
TimeStamp mCompositionTime;
uint32_t mCompositorID;
DiagnosticTypes mDiagnosticTypes;
PCompositorParent* mParent;
+72 -9
View File
@@ -14,6 +14,7 @@
#include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
#include "mozilla/layers/PImageContainerChild.h"
#include "mozilla/layers/ImageClient.h" // for ImageClient
#include "nsISupportsUtils.h" // for NS_IF_ADDREF
#include "YCbCrUtils.h" // for YCbCr conversions
@@ -49,6 +50,8 @@ using namespace mozilla::gfx;
Atomic<int32_t> Image::sSerialCounter(0);
Atomic<uint32_t> ImageContainer::sGenerationCounter(0);
already_AddRefed<Image>
ImageFactory::CreateImage(ImageFormat aFormat,
const gfx::IntSize &,
@@ -139,26 +142,55 @@ BufferRecycleBin::GetBuffer(uint32_t aSize)
return result;
}
ImageContainer::ImageContainer(ImageContainer::Mode flag)
/**
* The child side of PImageContainer. It's best to avoid ImageContainer filling
* this role since IPDL objects should be associated with a single thread and
* ImageContainer definitely isn't. This object belongs to (and is always
* destroyed on) the ImageBridge thread, except when we need to destroy it
* during shutdown.
* An ImageContainer owns one of these; we have a weak reference to our
* ImageContainer.
*/
class ImageContainerChild : public PImageContainerChild {
public:
explicit ImageContainerChild(ImageContainer* aImageContainer)
: mLock("ImageContainerChild"), mImageContainer(aImageContainer) {}
void ForgetImageContainer()
{
MutexAutoLock lock(mLock);
mImageContainer = nullptr;
}
// This protects mImageContainer. This is always taken before the
// mImageContainer's monitor (when both need to be held).
Mutex mLock;
ImageContainer* mImageContainer;
};
ImageContainer::ImageContainer(Mode flag)
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
mGenerationCounter(++sGenerationCounter),
mPaintCount(0),
mPreviousImagePainted(false),
mImageFactory(new ImageFactory()),
mRecycleBin(new BufferRecycleBin()),
mImageClient(nullptr)
mImageClient(nullptr),
mIPDLChild(nullptr)
{
if (ImageBridgeChild::IsCreated()) {
// the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount
// of this class must be done on the ImageBridge thread.
switch(flag) {
switch (flag) {
case SYNCHRONOUS:
break;
case ASYNCHRONOUS:
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE).take();
mIPDLChild = new ImageContainerChild(this);
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE, this).take();
MOZ_ASSERT(mImageClient);
break;
case ASYNCHRONOUS_OVERLAY:
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY).take();
mIPDLChild = new ImageContainerChild(this);
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY, this).take();
MOZ_ASSERT(mImageClient);
break;
default:
@@ -171,7 +203,8 @@ ImageContainer::ImageContainer(ImageContainer::Mode flag)
ImageContainer::~ImageContainer()
{
if (IsAsync()) {
ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
mIPDLChild->ForgetImageContainer();
ImageBridgeChild::DispatchReleaseImageClient(mImageClient, mIPDLChild);
}
}
@@ -186,7 +219,8 @@ ImageContainer::CreateImage(ImageFormat aFormat)
// If this ImageContainer is async but the image type mismatch, fix it here
if (ImageBridgeChild::IsCreated()) {
ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY).take();
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(
CompositableType::IMAGE_OVERLAY, this).take();
}
}
}
@@ -205,6 +239,9 @@ ImageContainer::SetCurrentImageInternal(Image *aImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mActiveImage != aImage) {
mGenerationCounter = ++sGenerationCounter;
}
mActiveImage = aImage;
CurrentImageChanged();
}
@@ -285,12 +322,19 @@ ImageContainer::HasCurrentImage()
}
void
ImageContainer::GetCurrentImages(nsTArray<OwningImage>* aImages)
ImageContainer::GetCurrentImages(nsTArray<OwningImage>* aImages,
uint32_t* aGenerationCounter)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mActiveImage) {
aImages->AppendElement()->mImage = mActiveImage;
OwningImage* img = aImages->AppendElement();
img->mImage = mActiveImage;
img->mFrameID = mGenerationCounter;
img->mProducerID = 0;
}
if (aGenerationCounter) {
*aGenerationCounter = mGenerationCounter;
}
}
@@ -554,5 +598,24 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
return textureClient;
}
PImageContainerChild*
ImageContainer::GetPImageContainerChild()
{
return mIPDLChild;
}
/* static */ void
ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification)
{
ImageContainerChild* child =
static_cast<ImageContainerChild*>(aNotification.imageContainerChild());
if (child) {
MutexAutoLock lock(child->mLock);
if (child->mImageContainer) {
child->mImageContainer->NotifyCompositeInternal(aNotification);
}
}
}
} // namespace layers
} // namespace mozilla
+31 -4
View File
@@ -98,6 +98,9 @@ namespace mozilla {
namespace layers {
class ImageClient;
class ImageCompositeNotification;
class ImageContainerChild;
class PImageContainerChild;
class SharedPlanarYCbCrImage;
class TextureClient;
class CompositableClient;
@@ -180,8 +183,9 @@ protected:
void* mImplData;
int32_t mSerial;
ImageFormat mFormat;
static mozilla::Atomic<int32_t> sSerialCounter;
bool mSent;
static mozilla::Atomic<int32_t> sSerialCounter;
};
/**
@@ -284,6 +288,10 @@ public:
explicit ImageContainer(ImageContainer::Mode flag = SYNCHRONOUS);
typedef int32_t FrameID;
typedef int32_t ProducerID;
/**
* Create an Image in one of the given formats.
* Picks the "best" format from the list and creates an Image of that
@@ -375,17 +383,22 @@ public:
struct OwningImage {
nsRefPtr<Image> mImage;
TimeStamp mTimeStamp;
FrameID mFrameID;
ProducerID mProducerID;
};
/**
* Copy the current Image list to aImages.
* This has to add references since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference. This lock strictly guarantees the underlying image remains
* valid, it does not mean the current image cannot change.
* a reference.
* Can be called on any thread.
* May return an empty list to indicate there is no current image.
* If aGenerationCounter is non-null, sets *aGenerationCounter to a value
* that's unique for this ImageContainer state.
*/
void GetCurrentImages(nsTArray<OwningImage>* aImages);
void GetCurrentImages(nsTArray<OwningImage>* aImages,
uint32_t* aGenerationCounter = nullptr);
/**
* Returns the size of the image in pixels.
@@ -458,6 +471,10 @@ public:
}
}
PImageContainerChild* GetPImageContainerChild();
static void NotifyComposite(const ImageCompositeNotification& aNotification);
private:
typedef mozilla::ReentrantMonitor ReentrantMonitor;
@@ -485,7 +502,11 @@ private:
mPaintTime = TimeStamp();
}
void NotifyCompositeInternal(const ImageCompositeNotification& aNotification) {}
nsRefPtr<Image> mActiveImage;
// Updates every time mActiveImage changes
uint32_t mGenerationCounter;
// Number of contained images that have been painted at least once. It's up
// to the ImageContainer implementation to ensure accesses to this are
@@ -516,6 +537,12 @@ private:
// frames to the compositor through transactions in the main thread rather than
// asynchronusly using the ImageBridge IPDL protocol.
ImageClient* mImageClient;
// Object must be released on the ImageBridge thread. Field is immutable
// after creation of the ImageContainer.
ImageContainerChild* mIPDLChild;
static mozilla::Atomic<uint32_t> sGenerationCounter;
};
class AutoLockImage
+1
View File
@@ -12,6 +12,7 @@
#include "mozilla/mozalloc.h" // for operator delete
#include "nsDebug.h" // for NS_WARN_IF
#include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc
#include "nsDebug.h"
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
+10 -2
View File
@@ -103,7 +103,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
}
if (updated) {
GetForwarder()->UseTexture(this, mBuffer);
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mBuffer;
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize());
GetForwarder()->UseTextures(this, textures);
mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
}
}
@@ -380,7 +384,11 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
// Add the new TexClient.
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
forwarder->UseTexture(this, mFront);
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mFront;
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
forwarder->UseTextures(this, textures);
}
void
+1 -1
View File
@@ -20,6 +20,7 @@
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/ShadowLayerChild.h"
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
#include "mozilla/layers/PersistentBufferProvider.h"
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
@@ -610,7 +611,6 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
break;
}
default:
NS_RUNTIMEABORT("not reached");
}
+1 -1
View File
@@ -205,7 +205,7 @@ public:
virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) override;
virtual void RunOverfillCallback(const uint32_t aOverfill) override;
virtual void DidComposite(uint64_t aTransactionId);
void DidComposite(uint64_t aTransactionId);
virtual bool SupportsMixBlendModes(EnumSet<gfx::CompositionOp>& aMixBlendModes) override
{
+2 -2
View File
@@ -157,12 +157,12 @@ CompositableClient::GetIPDLActor() const
}
bool
CompositableClient::Connect()
CompositableClient::Connect(ImageContainer* aImageContainer)
{
if (!GetForwarder() || GetIPDLActor()) {
return false;
}
GetForwarder()->Connect(this);
GetForwarder()->Connect(this, aImageContainer);
return true;
}
+2 -1
View File
@@ -25,6 +25,7 @@ namespace layers {
class CompositableClient;
class BufferTextureClient;
class ImageBridgeChild;
class ImageContainer;
class CompositableForwarder;
class CompositableChild;
class PCompositableChild;
@@ -146,7 +147,7 @@ public:
/**
* Establishes the connection with compositor side through IPDL
*/
virtual bool Connect();
virtual bool Connect(ImageContainer* aImageContainer = nullptr);
void Destroy();
+6 -1
View File
@@ -396,7 +396,12 @@ ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
mForwarder->UseComponentAlphaTextures(this, mTextureClient,
mTextureClientOnWhite);
} else {
mForwarder->UseTexture(this, mTextureClient);
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mTextureClient;
IntSize size = mTextureClient->GetSize();
t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
GetForwarder()->UseTextures(this, textures);
}
mForwarder->UpdateTextureRegion(this,
ThebesBufferData(BufferRect(),
+141 -123
View File
@@ -113,129 +113,159 @@ void
ImageClientSingle::FlushAllImages(bool aExceptFront,
AsyncTransactionWaiter* aAsyncTransactionWaiter)
{
if (!aExceptFront && mFrontBuffer) {
RemoveTextureWithWaiter(mFrontBuffer, aAsyncTransactionWaiter);
mFrontBuffer = nullptr;
if (!aExceptFront) {
for (auto& b : mBuffers) {
RemoveTextureWithWaiter(b.mTextureClient, aAsyncTransactionWaiter);
}
mBuffers.Clear();
}
}
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
AutoLockImage autoLock(aContainer);
nsAutoTArray<ImageContainer::OwningImage,4> images;
uint32_t generationCounter;
aContainer->GetCurrentImages(&images, &generationCounter);
Image *image = autoLock.GetImage();
if (!image) {
return false;
}
// Don't try to update to an invalid image. We return true because the caller
// would attempt to recreate the ImageClient otherwise, and that isn't going
// to help.
if (!image->IsValid()) {
if (mLastUpdateGenerationCounter == generationCounter) {
return true;
}
mLastUpdateGenerationCounter = generationCounter;
if (mLastPaintedImageSerial == image->GetSerial()) {
return true;
}
RefPtr<TextureClient> texture = image->GetTextureClient(this);
AutoRemoveTexture autoRemoveTexture(this);
if (texture != mFrontBuffer) {
autoRemoveTexture.mTexture = mFrontBuffer;
mFrontBuffer = nullptr;
}
if (!texture) {
// Slow path, we should not be hitting it very often and if we do it means
// we are using an Image class that is not backed by textureClient and we
// should fix it.
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
const PlanarYCbCrData* data = ycbcr->GetData();
if (!data) {
return false;
}
texture = TextureClient::CreateForYCbCr(GetForwarder(),
data->mYSize, data->mCbCrSize, data->mStereoMode,
TextureFlags::DEFAULT | mTextureFlags
);
if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return false;
}
bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
MOZ_ASSERT(status);
texture->Unlock();
if (!status) {
return false;
}
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
image->GetFormat() == ImageFormat::EGLIMAGE) {
gfx::IntSize size = image->GetSize();
if (image->GetFormat() == ImageFormat::EGLIMAGE) {
EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
texture = new EGLImageTextureClient(GetForwarder(),
mTextureFlags,
typedImage,
size);
#ifdef MOZ_WIDGET_ANDROID
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
const SurfaceTextureImage::Data* data = typedImage->GetData();
texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
data->mSurfTex, size,
data->mOriginPos);
#endif
} else {
MOZ_ASSERT(false, "Bad ImageFormat.");
}
} else {
RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
MOZ_ASSERT(surface);
texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
gfx::BackendType::NONE, mTextureFlags);
if (!texture) {
return false;
}
MOZ_ASSERT(texture->CanExposeDrawTarget());
if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return false;
}
{
// We must not keep a reference to the DrawTarget after it has been unlocked.
DrawTarget* dt = texture->BorrowDrawTarget();
if (!dt) {
gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
return false;
}
MOZ_ASSERT(surface.get());
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
}
texture->Unlock();
for (int32_t i = images.Length() - 1; i >= 0; --i) {
if (!images[i].mImage->IsValid()) {
// Don't try to update to an invalid image.
images.RemoveElementAt(i);
}
}
if (!texture || !AddTextureClient(texture)) {
return false;
if (images.IsEmpty()) {
// We return true because the caller would attempt to recreate the
// ImageClient otherwise, and that isn't going to help.
return true;
}
mFrontBuffer = texture;
GetForwarder()->UseTexture(this, texture);
nsTArray<Buffer> newBuffers;
nsAutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
UpdatePictureRect(image->GetPictureRect());
for (auto& img : images) {
Image* image = img.mImage;
RefPtr<TextureClient> texture = image->GetTextureClient(this);
mLastPaintedImageSerial = image->GetSerial();
aContainer->NotifyPaintedImage(image);
for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
if (mBuffers[i].mImageSerial == image->GetSerial()) {
if (texture) {
MOZ_ASSERT(texture == mBuffers[i].mTextureClient);
} else {
texture = mBuffers[i].mTextureClient;
}
// Remove this element from mBuffers so mBuffers only contains
// images that aren't present in 'images'
mBuffers.RemoveElementAt(i);
}
}
texture->SyncWithObject(GetForwarder()->GetSyncObject());
if (!texture) {
// Slow path, we should not be hitting it very often and if we do it means
// we are using an Image class that is not backed by textureClient and we
// should fix it.
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
const PlanarYCbCrData* data = ycbcr->GetData();
if (!data) {
return false;
}
texture = TextureClient::CreateForYCbCr(GetForwarder(),
data->mYSize, data->mCbCrSize, data->mStereoMode,
TextureFlags::DEFAULT | mTextureFlags
);
if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return false;
}
bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
MOZ_ASSERT(status);
texture->Unlock();
if (!status) {
return false;
}
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
image->GetFormat() == ImageFormat::EGLIMAGE) {
gfx::IntSize size = image->GetSize();
if (image->GetFormat() == ImageFormat::EGLIMAGE) {
EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
texture = new EGLImageTextureClient(GetForwarder(),
mTextureFlags,
typedImage,
size);
#ifdef MOZ_WIDGET_ANDROID
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
const SurfaceTextureImage::Data* data = typedImage->GetData();
texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
data->mSurfTex, size,
data->mOriginPos);
#endif
} else {
MOZ_ASSERT(false, "Bad ImageFormat.");
}
} else {
RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
MOZ_ASSERT(surface);
texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
gfx::BackendType::NONE, mTextureFlags);
if (!texture) {
return false;
}
MOZ_ASSERT(texture->CanExposeDrawTarget());
if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return false;
}
{
// We must not keep a reference to the DrawTarget after it has been unlocked.
DrawTarget* dt = texture->BorrowDrawTarget();
if (!dt) {
gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
return false;
}
MOZ_ASSERT(surface.get());
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
}
texture->Unlock();
}
}
if (!texture || !AddTextureClient(texture)) {
return false;
}
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = texture;
t->mTimeStamp = img.mTimeStamp;
t->mPictureRect = image->GetPictureRect();
t->mFrameID = img.mFrameID;
t->mProducerID = img.mProducerID;
Buffer* newBuf = newBuffers.AppendElement();
newBuf->mImageSerial = image->GetSerial();
newBuf->mTextureClient = texture;
aContainer->NotifyPaintedImage(image);
texture->SyncWithObject(GetForwarder()->GetSyncObject());
}
GetForwarder()->UseTextures(this, textures);
for (auto& b : mBuffers) {
RemoveTexture(b.mTextureClient);
}
mBuffers.SwapElements(newBuffers);
return true;
}
@@ -250,7 +280,7 @@ ImageClientSingle::AddTextureClient(TextureClient* aTexture)
void
ImageClientSingle::OnDetach()
{
mFrontBuffer = nullptr;
mBuffers.Clear();
}
ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
@@ -258,20 +288,9 @@ ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
: CompositableClient(aFwd, aFlags)
, mLayer(nullptr)
, mType(aType)
, mLastPaintedImageSerial(0)
, mLastUpdateGenerationCounter(0)
{}
void
ImageClient::UpdatePictureRect(IntRect aRect)
{
if (mPictureRect == aRect) {
return;
}
mPictureRect = aRect;
MOZ_ASSERT(mForwarder);
GetForwarder()->UpdatePictureRect(this, aRect);
}
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
TextureFlags aFlags)
: ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
@@ -292,7 +311,6 @@ ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
AutoLockImage autoLock(aContainer);
aContainer->NotifyPaintedImage(autoLock.GetImage());
Updated();
return true;
}
@@ -334,9 +352,10 @@ ImageClientOverlay::UpdateImage(ImageContainer* aContainer, uint32_t aContentFla
return false;
}
if (mLastPaintedImageSerial == image->GetSerial()) {
if (mLastUpdateGenerationCounter == (uint32_t)image->GetSerial()) {
return true;
}
mLastUpdateGenerationCounter = (uint32_t)image->GetSerial();
AutoRemoveTexture autoRemoveTexture(this);
if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) {
@@ -347,9 +366,8 @@ ImageClientOverlay::UpdateImage(ImageContainer* aContainer, uint32_t aContentFla
OverlaySource source;
source.handle() = OverlayHandle(overlayId);
source.size() = size;
GetForwarder()->UseOverlaySource(this, source);
GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect());
}
UpdatePictureRect(image->GetPictureRect());
return true;
}
+7 -11
View File
@@ -56,12 +56,6 @@ public:
*/
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) = 0;
/**
* The picture rect is the area of the texture which makes up the image. That
* is, the area that should be composited. In texture space.
*/
virtual void UpdatePictureRect(gfx::IntRect aPictureRect);
virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) = 0;
void SetLayer(ClientLayer* aLayer) { mLayer = aLayer; }
@@ -85,8 +79,7 @@ protected:
ClientLayer* mLayer;
CompositableType mType;
int32_t mLastPaintedImageSerial;
gfx::IntRect mPictureRect;
uint32_t mLastUpdateGenerationCounter;
};
/**
@@ -113,7 +106,11 @@ public:
AsyncTransactionWaiter* aAsyncTransactionWaiter) override;
protected:
RefPtr<TextureClient> mFrontBuffer;
struct Buffer {
RefPtr<TextureClient> mTextureClient;
int32_t mImageSerial;
};
nsTArray<Buffer> mBuffers;
};
/**
@@ -128,8 +125,7 @@ public:
TextureFlags aFlags);
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override;
virtual bool Connect() override { return false; }
virtual void Updated() {}
virtual bool Connect(ImageContainer* aImageContainer) override { return false; }
virtual TextureInfo GetTextureInfo() const override
{
+8 -10
View File
@@ -95,17 +95,15 @@ CanvasLayerComposite::RenderLayer(const IntRect& aClipRect)
}
#endif
EffectChain effectChain(this);
AddBlendModeEffect(effectChain);
RenderWithAllMasks(this, mCompositor, aClipRect,
[&](EffectChain& effectChain, const Rect& clipRect) {
mCompositableHost->Composite(this, effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
GetEffectFilter(),
clipRect);
});
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
mCompositableHost->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
GetEffectFilter(),
clipRect);
mCompositableHost->BumpFlashCounter();
}
+9 -20
View File
@@ -21,28 +21,17 @@ namespace layers {
void
ColorLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
{
EffectChain effects(this);
GenEffectChain(effects);
gfx::IntRect boundRect = GetBounds();
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(),
effects);
gfx::Rect rect(boundRect.x, boundRect.y,
boundRect.width, boundRect.height);
gfx::Rect clipRect(aClipRect.x, aClipRect.y,
aClipRect.width, aClipRect.height);
float opacity = GetEffectiveOpacity();
AddBlendModeEffect(effects);
gfx::Rect rect(GetBounds());
const gfx::Matrix4x4& transform = GetEffectiveTransform();
mCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
RenderWithAllMasks(this, mCompositor, aClipRect,
[&](EffectChain& effectChain, const Rect& clipRect) {
GenEffectChain(effectChain);
mCompositor->DrawQuad(rect, clipRect, effectChain, GetEffectiveOpacity(), transform);
});
mCompositor->DrawDiagnostics(DiagnosticFlags::COLOR,
rect, clipRect,
rect, Rect(aClipRect),
transform);
}
+18 -9
View File
@@ -11,6 +11,7 @@
#include "gfxUtils.h"
#include "ImageHost.h" // for ImageHostBuffered, etc
#include "TiledContentHost.h" // for TiledContentHost
#include "mozilla/layers/ImageContainerParent.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
#include "mozilla/nsRefPtr.h" // for nsRefPtr
@@ -20,6 +21,9 @@
#include "mozilla/layers/PCompositableParent.h"
namespace mozilla {
using namespace gfx;
namespace layers {
class Compositor;
@@ -30,14 +34,15 @@ class Compositor;
*
* CompositableParent is owned by the IPDL system. It's deletion is triggered
* by either the CompositableChild's deletion, or by the IPDL communication
* goind down.
* going down.
*/
class CompositableParent : public PCompositableParent
{
public:
CompositableParent(CompositableParentManager* aMgr,
const TextureInfo& aTextureInfo,
uint64_t aID = 0)
uint64_t aID = 0,
PImageContainerParent* aImageContainer = nullptr)
{
MOZ_COUNT_CTOR(CompositableParent);
mHost = CompositableHost::Create(aTextureInfo);
@@ -45,6 +50,10 @@ public:
if (aID) {
CompositableMap::Set(aID, this);
}
if (aImageContainer) {
mHost->SetImageContainer(
static_cast<ImageContainerParent*>(aImageContainer));
}
}
~CompositableParent()
@@ -84,9 +93,10 @@ CompositableHost::~CompositableHost()
PCompositableParent*
CompositableHost::CreateIPDLActor(CompositableParentManager* aMgr,
const TextureInfo& aTextureInfo,
uint64_t aID)
uint64_t aID,
PImageContainerParent* aImageContainer)
{
return new CompositableParent(aMgr, aTextureInfo, aID);
return new CompositableParent(aMgr, aTextureInfo, aID, aImageContainer);
}
bool
@@ -104,13 +114,12 @@ CompositableHost::FromIPDLActor(PCompositableParent* aActor)
}
void
CompositableHost::UseTextureHost(TextureHost* aTexture)
CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
{
if (!aTexture) {
return;
}
if (GetCompositor()) {
aTexture->SetCompositor(GetCompositor());
for (auto& texture : aTextures) {
texture.mTexture->SetCompositor(GetCompositor());
}
}
}
+24 -17
View File
@@ -37,7 +37,9 @@ class DataSourceSurface;
namespace layers {
class Layer;
class LayerComposite;
class Compositor;
class ImageContainerParent;
class ThebesBufferData;
class TiledContentHost;
class CompositableParentManager;
@@ -75,7 +77,8 @@ public:
virtual void SetCompositor(Compositor* aCompositor);
// composite the contents of this buffer host to the compositor's surface
virtual void Composite(EffectChain& aEffectChain,
virtual void Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
@@ -98,16 +101,15 @@ public:
/**
* Returns the front buffer.
* *aPictureRect (if non-null, and the returned TextureHost is non-null)
* is set to the picture rect.
*/
virtual TextureHost* GetAsTextureHost() { return nullptr; }
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) {
return nullptr;
}
virtual LayerRenderState GetRenderState() = 0;
virtual void SetPictureRect(const gfx::IntRect& aPictureRect)
{
MOZ_ASSERT(false, "Should have been overridden");
}
virtual gfx::IntSize GetImageSize() const
{
MOZ_ASSERT(false, "Should have been overridden");
@@ -132,6 +134,8 @@ public:
Layer* GetLayer() const { return mLayer; }
void SetLayer(Layer* aLayer) { mLayer = aLayer; }
virtual void SetImageContainer(ImageContainerParent* aImageContainer) {}
virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
typedef uint32_t AttachFlags;
@@ -151,12 +155,6 @@ public:
SetLayer(aLayer);
mAttached = true;
mKeepAttached = aFlags & KEEP_ATTACHED;
// If we already have a textureHost before, use that in this moment.
RefPtr<TextureHost> frontBuffer = GetAsTextureHost();
if (frontBuffer) {
UseTextureHost(frontBuffer);
}
}
// Detach this compositable host from its layer.
// If we are used for async video, then it is not safe to blindly detach since
@@ -187,10 +185,18 @@ public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0;
virtual void UseTextureHost(TextureHost* aTexture);
struct TimedTexture {
RefPtr<TextureHost> mTexture;
TimeStamp mTimeStamp;
gfx::IntRect mPictureRect;
int32_t mFrameID;
int32_t mProducerID;
};
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures);
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
TextureHost* aTextureOnWhite);
virtual void UseOverlaySource(OverlaySource aOverlay) { }
virtual void UseOverlaySource(OverlaySource aOverlay,
const gfx::IntRect& aPictureRect) { }
virtual void RemoveTextureHost(TextureHost* aTexture);
@@ -203,7 +209,8 @@ public:
static PCompositableParent*
CreateIPDLActor(CompositableParentManager* mgr,
const TextureInfo& textureInfo,
uint64_t asyncID);
uint64_t asyncID,
PImageContainerParent* aImageContainer = nullptr);
static bool DestroyIPDLActor(PCompositableParent* actor);
@@ -271,7 +278,7 @@ private:
* is async, we store references to the async compositables in a CompositableMap
* that is accessed only on the compositor thread. During a layer transaction we
* send the message OpAttachAsyncCompositable(ID, PLayer), and on the compositor
* side we lookup the ID in the map and attach the correspondig compositable to
* side we lookup the ID in the map and attach the corresponding compositable to
* the layer.
*
* CompositableMap must be global because the image bridge doesn't have any
@@ -490,34 +490,25 @@ ContainerRender(ContainerT* aContainer,
return;
}
float opacity = aContainer->GetEffectiveOpacity();
gfx::IntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
gfx::Rect visibleRect(aContainer->GetEffectiveVisibleRegion().GetBounds());
nsRefPtr<Compositor> compositor = aManager->GetCompositor();
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
if (surf) {
WriteSnapshotToDumpFile(aContainer, surf);
}
}
#endif
EffectChain effectChain(aContainer);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
effectChain,
!aContainer->GetTransform().CanDraw2D());
if (autoMaskEffect.Failed()) {
NS_WARNING("Failed to apply a mask effect.");
return;
}
aContainer->AddBlendModeEffect(effectChain);
effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
aContainer->GetEffectiveTransform());
nsRefPtr<ContainerT> container = aContainer;
RenderWithAllMasks(aContainer, compositor, aClipRect,
[&, surface, compositor, container](EffectChain& effectChain, const Rect& clipRect) {
effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
compositor->DrawQuad(visibleRect, clipRect, effectChain,
container->GetEffectiveOpacity(),
container->GetEffectiveTransform());
});
} else {
RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
}
+10 -4
View File
@@ -35,7 +35,8 @@ ContentHostBase::~ContentHostBase()
}
void
ContentHostTexture::Composite(EffectChain& aEffectChain,
ContentHostTexture::Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const Filter& aFilter,
@@ -218,10 +219,15 @@ ContentHostTexture::Composite(EffectChain& aEffectChain,
}
void
ContentHostTexture::UseTextureHost(TextureHost* aTexture)
ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
{
ContentHostBase::UseTextureHost(aTexture);
mTextureHost = aTexture;
ContentHostBase::UseTextureHost(aTextures);
MOZ_ASSERT(aTextures.Length() == 1);
const TimedTexture& t = aTextures[0];
MOZ_ASSERT(t.mPictureRect.IsEqualInterior(
nsIntRect(nsIntPoint(0, 0), nsIntSize(t.mTexture->GetSize()))),
"Only default picture rect supported");
mTextureHost = t.mTexture;
mTextureHostOnWhite = nullptr;
mTextureSourceOnWhite = nullptr;
if (mTextureHost) {
+3 -2
View File
@@ -114,7 +114,8 @@ public:
, mLocked(false)
{ }
virtual void Composite(EffectChain& aEffectChain,
virtual void Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
@@ -131,7 +132,7 @@ public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
virtual void UseTextureHost(TextureHost* aTexture) override;
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
TextureHost* aTextureOnWhite) override;
+229 -107
View File
@@ -4,11 +4,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ImageHost.h"
#include "LayersLogging.h" // for AppendToString
#include "composite/CompositableHost.h" // for CompositableHost, etc
#include "ipc/IPCMessageUtils.h" // for null_t
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
#include "mozilla/layers/ImageContainerParent.h"
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
#include "nsAString.h"
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
#include "nsPrintfCString.h" // for nsPrintfCString
@@ -29,43 +32,155 @@ class ISurfaceAllocator;
ImageHost::ImageHost(const TextureInfo& aTextureInfo)
: CompositableHost(aTextureInfo)
, mHasPictureRect(false)
, mImageContainer(nullptr)
, mLastFrameID(-1)
, mLastProducerID(-1)
, mLocked(false)
{}
ImageHost::~ImageHost()
{}
{
SetImageContainer(nullptr);
}
void
ImageHost::UseTextureHost(TextureHost* aTexture)
ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
{
CompositableHost::UseTextureHost(aTexture);
mFrontBuffer = aTexture;
if (mFrontBuffer) {
mFrontBuffer->Updated();
mFrontBuffer->PrepareTextureSource(mTextureSource);
MOZ_ASSERT(!mLocked);
CompositableHost::UseTextureHost(aTextures);
MOZ_ASSERT(aTextures.Length() >= 1);
nsTArray<TimedImage> newImages;
// Remove all mImages without an mTextureSource to recycle.
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (!mImages[i].mTextureSource) {
mImages.RemoveElementAt(i);
}
}
// Create new TimedImage entries and recycle any mTextureSources that match
// our mFrontBuffers.
for (uint32_t i = 0; i < aTextures.Length(); ++i) {
const TimedTexture& t = aTextures[i];
MOZ_ASSERT(t.mTexture);
if (i + 1 < aTextures.Length() &&
t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
// Ignore frames before a frame that we already composited. We don't
// ever want to display these frames. This could be important if
// the frame producer adjusts timestamps (e.g. to track the audio clock)
// and the new frame times are earlier.
continue;
}
TimedImage& img = *newImages.AppendElement();
img.mFrontBuffer = t.mTexture;
for (uint32_t i = 0; i < mImages.Length(); ++i) {
if (mImages[i].mFrontBuffer == img.mFrontBuffer) {
img.mTextureSource = mImages[i].mTextureSource;
mImages.RemoveElementAt(i);
break;
}
}
img.mTimeStamp = t.mTimeStamp;
img.mPictureRect = t.mPictureRect;
img.mFrameID = t.mFrameID;
img.mProducerID = t.mProducerID;
}
// Recycle any leftover mTextureSources and call PrepareTextureSource on all
// images.
for (auto& img : newImages) {
if (!img.mTextureSource && !mImages.IsEmpty()) {
img.mTextureSource = mImages.LastElement().mTextureSource;
mImages.RemoveElementAt(mImages.Length() - 1);
}
img.mFrontBuffer->Updated();
img.mFrontBuffer->PrepareTextureSource(img.mTextureSource);
}
mImages.SwapElements(newImages);
}
void
ImageHost::RemoveTextureHost(TextureHost* aTexture)
{
MOZ_ASSERT(!mLocked);
CompositableHost::RemoveTextureHost(aTexture);
if (aTexture && mFrontBuffer == aTexture) {
mFrontBuffer->UnbindTextureSource();
mTextureSource = nullptr;
mFrontBuffer = nullptr;
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (mImages[i].mFrontBuffer == aTexture) {
aTexture->UnbindTextureSource();
mImages.RemoveElementAt(i);
}
}
}
TextureHost*
ImageHost::GetAsTextureHost()
int ImageHost::ChooseImageIndex() const
{
return mFrontBuffer;
if (!mCompositor || mImages.IsEmpty()) {
return -1;
}
TimeStamp now = mCompositor->GetCompositionTime();
if (now.IsNull()) {
// Not in a composition, so just return the last image we composited
// (if it's one of the current images).
for (uint32_t i = 0; i < mImages.Length(); ++i) {
if (mImages[i].mFrameID == mLastFrameID &&
mImages[i].mProducerID == mLastProducerID) {
return i;
}
}
return -1;
}
uint32_t result = 0;
while (result + 1 < mImages.Length() &&
mImages[result + 1].mTimeStamp <= now) {
++result;
}
return result;
}
const ImageHost::TimedImage* ImageHost::ChooseImage() const
{
int index = ChooseImageIndex();
return index >= 0 ? &mImages[index] : nullptr;
}
ImageHost::TimedImage* ImageHost::ChooseImage()
{
int index = ChooseImageIndex();
return index >= 0 ? &mImages[index] : nullptr;
}
TextureHost*
ImageHost::GetAsTextureHost(IntRect* aPictureRect)
{
TimedImage* img = ChooseImage();
if (aPictureRect && img) {
*aPictureRect = img->mPictureRect;
}
return img ? img->mFrontBuffer.get() : nullptr;
}
void ImageHost::Attach(Layer* aLayer,
Compositor* aCompositor,
AttachFlags aFlags)
{
CompositableHost::Attach(aLayer, aCompositor, aFlags);
for (auto& img : mImages) {
if (GetCompositor()) {
img.mFrontBuffer->SetCompositor(GetCompositor());
}
img.mFrontBuffer->Updated();
img.mFrontBuffer->PrepareTextureSource(img.mTextureSource);
}
}
void
ImageHost::Composite(EffectChain& aEffectChain,
ImageHost::Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
@@ -78,12 +193,13 @@ ImageHost::Composite(EffectChain& aEffectChain,
// set the new compositor yet.
return;
}
if (!mFrontBuffer) {
TimedImage* img = ChooseImage();
if (!img) {
return;
}
// Make sure the front buffer has a compositor
mFrontBuffer->SetCompositor(GetCompositor());
img->mFrontBuffer->SetCompositor(GetCompositor());
AutoLockCompositableHost autoLock(this);
if (autoLock.Failed()) {
@@ -91,36 +207,40 @@ ImageHost::Composite(EffectChain& aEffectChain,
return;
}
if (!mFrontBuffer->BindTextureSource(mTextureSource)) {
if (!img->mFrontBuffer->BindTextureSource(img->mTextureSource)) {
return;
}
if (!mTextureSource) {
if (!img->mTextureSource) {
// BindTextureSource above should have returned false!
MOZ_ASSERT(false);
return;
}
bool isAlphaPremultiplied = !(mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
mTextureSource.get(),
aFilter,
isAlphaPremultiplied,
GetRenderState());
bool isAlphaPremultiplied =
!(img->mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
RefPtr<TexturedEffect> effect =
CreateTexturedEffect(img->mFrontBuffer->GetFormat(),
img->mTextureSource.get(), aFilter, isAlphaPremultiplied,
GetRenderState());
if (!effect) {
return;
}
if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
if (mImageContainer) {
aLayer->GetLayerManager()->
AppendImageCompositeNotification(ImageCompositeNotification(
mImageContainer, nullptr,
img->mTimeStamp, GetCompositor()->GetCompositionTime(),
img->mFrameID, img->mProducerID));
}
mLastFrameID = img->mFrameID;
mLastProducerID = img->mProducerID;
}
aEffectChain.mPrimaryEffect = effect;
IntSize textureSize = mTextureSource->GetSize();
gfx::Rect gfxPictureRect
= mHasPictureRect ? gfx::Rect(0, 0, mPictureRect.width, mPictureRect.height)
: gfx::Rect(0, 0, textureSize.width, textureSize.height);
gfx::Rect pictureRect(0, 0,
mPictureRect.width,
mPictureRect.height);
BigImageIterator* it = mTextureSource->AsBigImageIterator();
gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
BigImageIterator* it = img->mTextureSource->AsBigImageIterator();
if (it) {
// This iteration does not work if we have multiple texture sources here
@@ -136,23 +256,19 @@ ImageHost::Composite(EffectChain& aEffectChain,
// the corresponding source tiles from all planes, with appropriate
// per-plane per-tile texture coords.
// DrawQuad currently assumes that all planes use the same texture coords.
MOZ_ASSERT(it->GetTileCount() == 1 || !mTextureSource->GetNextSibling(),
MOZ_ASSERT(it->GetTileCount() == 1 || !img->mTextureSource->GetNextSibling(),
"Can't handle multi-plane BigImages");
it->BeginBigImageIteration();
do {
IntRect tileRect = it->GetTileRect();
gfx::Rect rect(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
if (mHasPictureRect) {
rect = rect.Intersect(pictureRect);
effect->mTextureCoords = Rect(Float(rect.x - tileRect.x)/ tileRect.width,
Float(rect.y - tileRect.y) / tileRect.height,
Float(rect.width) / tileRect.width,
Float(rect.height) / tileRect.height);
} else {
effect->mTextureCoords = Rect(0, 0, 1, 1);
}
if (mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
rect = rect.Intersect(pictureRect);
effect->mTextureCoords = Rect(Float(rect.x - tileRect.x) / tileRect.width,
Float(rect.y - tileRect.y) / tileRect.height,
Float(rect.width) / tileRect.width,
Float(rect.height) / tileRect.height);
if (img->mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
effect->mTextureCoords.height = -effect->mTextureCoords.height;
}
@@ -163,32 +279,24 @@ ImageHost::Composite(EffectChain& aEffectChain,
} while (it->NextTile());
it->EndBigImageIteration();
// layer border
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE,
gfxPictureRect, aClipRect,
aTransform, mFlashCounter);
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE, pictureRect,
aClipRect, aTransform, mFlashCounter);
} else {
IntSize textureSize = mTextureSource->GetSize();
gfx::Rect rect;
if (mHasPictureRect) {
effect->mTextureCoords = Rect(Float(mPictureRect.x) / textureSize.width,
Float(mPictureRect.y) / textureSize.height,
Float(mPictureRect.width) / textureSize.width,
Float(mPictureRect.height) / textureSize.height);
rect = pictureRect;
} else {
effect->mTextureCoords = Rect(0, 0, 1, 1);
rect = gfx::Rect(0, 0, textureSize.width, textureSize.height);
}
IntSize textureSize = img->mTextureSource->GetSize();
effect->mTextureCoords = Rect(Float(img->mPictureRect.x) / textureSize.width,
Float(img->mPictureRect.y) / textureSize.height,
Float(img->mPictureRect.width) / textureSize.width,
Float(img->mPictureRect.height) / textureSize.height);
if (mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
if (img->mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
effect->mTextureCoords.height = -effect->mTextureCoords.height;
}
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
GetCompositor()->DrawQuad(pictureRect, aClipRect, aEffectChain,
aOpacity, aTransform);
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE,
rect, aClipRect,
pictureRect, aClipRect,
aTransform, mFlashCounter);
}
}
@@ -196,8 +304,10 @@ ImageHost::Composite(EffectChain& aEffectChain,
void
ImageHost::SetCompositor(Compositor* aCompositor)
{
if (mFrontBuffer && mCompositor != aCompositor) {
mFrontBuffer->SetCompositor(aCompositor);
if (mCompositor != aCompositor) {
for (auto& img : mImages) {
img.mFrontBuffer->SetCompositor(aCompositor);
}
}
CompositableHost::SetCompositor(aCompositor);
}
@@ -208,13 +318,12 @@ ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
aStream << aPrefix;
aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
AppendToString(aStream, mPictureRect, " [picture-rect=", "]");
if (mFrontBuffer) {
nsAutoCString pfx(aPrefix);
pfx += " ";
nsAutoCString pfx(aPrefix);
pfx += " ";
for (auto& img : mImages) {
aStream << "\n";
mFrontBuffer->PrintInfo(aStream, pfx.get());
img.mFrontBuffer->PrintInfo(aStream, pfx.get());
AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
}
}
@@ -223,11 +332,11 @@ ImageHost::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml)
{
if (mFrontBuffer) {
for (auto& img : mImages) {
aStream << aPrefix;
aStream << (aDumpHtml ? "<ul><li>TextureHost: "
: "TextureHost: ");
DumpTextureHost(aStream, mFrontBuffer);
DumpTextureHost(aStream, img.mFrontBuffer);
aStream << (aDumpHtml ? " </li></ul> " : " ");
}
}
@@ -235,8 +344,9 @@ ImageHost::Dump(std::stringstream& aStream,
LayerRenderState
ImageHost::GetRenderState()
{
if (mFrontBuffer) {
return mFrontBuffer->GetRenderState();
TimedImage* img = ChooseImage();
if (img) {
return img->mFrontBuffer->GetRenderState();
}
return LayerRenderState();
}
@@ -244,17 +354,22 @@ ImageHost::GetRenderState()
already_AddRefed<gfx::DataSourceSurface>
ImageHost::GetAsSurface()
{
return mFrontBuffer->GetAsSurface();
TimedImage* img = ChooseImage();
if (img) {
return img->mFrontBuffer->GetAsSurface();
}
return nullptr;
}
bool
ImageHost::Lock()
{
MOZ_ASSERT(!mLocked);
if (!mFrontBuffer) {
TimedImage* img = ChooseImage();
if (!img) {
return false;
}
if (!mFrontBuffer->Lock()) {
if (!img->mFrontBuffer->Lock()) {
return false;
}
mLocked = true;
@@ -265,8 +380,9 @@ void
ImageHost::Unlock()
{
MOZ_ASSERT(mLocked);
if (mFrontBuffer) {
mFrontBuffer->Unlock();
TimedImage* img = ChooseImage();
if (img) {
img->mFrontBuffer->Unlock();
}
mLocked = false;
}
@@ -274,38 +390,50 @@ ImageHost::Unlock()
IntSize
ImageHost::GetImageSize() const
{
if (mHasPictureRect) {
return IntSize(mPictureRect.width, mPictureRect.height);
const TimedImage* img = ChooseImage();
if (img) {
return IntSize(img->mPictureRect.width, img->mPictureRect.height);
}
if (mFrontBuffer) {
return mFrontBuffer->GetSize();
}
return IntSize();
}
already_AddRefed<TexturedEffect>
ImageHost::GenEffect(const gfx::Filter& aFilter)
{
if (!mFrontBuffer->BindTextureSource(mTextureSource)) {
TimedImage* img = ChooseImage();
if (!img) {
return nullptr;
}
if (!img->mFrontBuffer->BindTextureSource(img->mTextureSource)) {
return nullptr;
}
bool isAlphaPremultiplied = true;
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
if (img->mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED) {
isAlphaPremultiplied = false;
}
return CreateTexturedEffect(mFrontBuffer->GetFormat(),
mTextureSource,
return CreateTexturedEffect(img->mFrontBuffer->GetFormat(),
img->mTextureSource,
aFilter,
isAlphaPremultiplied,
GetRenderState());
}
void
ImageHost::SetImageContainer(ImageContainerParent* aImageContainer)
{
if (mImageContainer) {
mImageContainer->mImageHosts.RemoveElement(this);
}
mImageContainer = aImageContainer;
if (mImageContainer) {
mImageContainer->mImageHosts.AppendElement(this);
}
}
#ifdef MOZ_WIDGET_GONK
ImageHostOverlay::ImageHostOverlay(const TextureInfo& aTextureInfo)
: CompositableHost(aTextureInfo)
, mHasPictureRect(false)
{
}
@@ -314,7 +442,8 @@ ImageHostOverlay::~ImageHostOverlay()
}
void
ImageHostOverlay::Composite(EffectChain& aEffectChain,
ImageHostOverlay::Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
@@ -334,13 +463,8 @@ ImageHostOverlay::Composite(EffectChain& aEffectChain,
gfx::Rect rect;
gfx::Rect clipRect(aClipRect.x, aClipRect.y,
aClipRect.width, aClipRect.height);
if (mHasPictureRect) {
rect.SetRect(mPictureRect.x, mPictureRect.y,
mPictureRect.width, mPictureRect.height);
} else {
rect.SetRect(0, 0,
mOverlay.size().width, mOverlay.size().height);
}
rect.SetRect(mPictureRect.x, mPictureRect.y,
mPictureRect.width, mPictureRect.height);
mCompositor->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
mCompositor->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,
@@ -358,19 +482,17 @@ ImageHostOverlay::GetRenderState()
}
void
ImageHostOverlay::UseOverlaySource(OverlaySource aOverlay)
ImageHostOverlay::UseOverlaySource(OverlaySource aOverlay,
const nsIntRect& aPictureRect)
{
mOverlay = aOverlay;
mPictureRect = aPictureRect;
}
IntSize
ImageHostOverlay::GetImageSize() const
{
if (mHasPictureRect) {
return IntSize(mPictureRect.width, mPictureRect.height);
}
return IntSize();
return IntSize(mPictureRect.width, mPictureRect.height);
}
void
+37 -20
View File
@@ -32,6 +32,7 @@ namespace layers {
class Compositor;
struct EffectChain;
class ImageContainerParent;
/**
* ImageHost. Works with ImageClientSingle and ImageClientBuffered
@@ -44,26 +45,27 @@ public:
virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
virtual void Composite(EffectChain& aEffectChain,
virtual void Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual void UseTextureHost(TextureHost* aTexture) override;
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
virtual void RemoveTextureHost(TextureHost* aTexture) override;
virtual TextureHost* GetAsTextureHost() override;
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
virtual void Attach(Layer* aLayer,
Compositor* aCompositor,
AttachFlags aFlags = NO_FLAGS) override;
virtual void SetCompositor(Compositor* aCompositor) override;
virtual void SetPictureRect(const gfx::IntRect& aPictureRect) override
{
mPictureRect = aPictureRect;
mHasPictureRect = true;
}
virtual void SetImageContainer(ImageContainerParent* aImageContainer) override;
gfx::IntSize GetImageSize() const override;
@@ -84,11 +86,30 @@ public:
virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::Filter& aFilter) override;
protected:
struct TimedImage {
CompositableTextureHostRef mFrontBuffer;
CompositableTextureSourceRef mTextureSource;
TimeStamp mTimeStamp;
gfx::IntRect mPictureRect;
int32_t mFrameID;
int32_t mProducerID;
};
/**
* ChooseImage is guaranteed to return the same TimedImage every time it's
* called during the same composition --- it depends only on mImages and
* mCompositor->GetCompositionTime().
*/
const TimedImage* ChooseImage() const;
TimedImage* ChooseImage();
int ChooseImageIndex() const;
nsTArray<TimedImage> mImages;
// Weak reference, will be null if mImageContainer has been destroyed.
ImageContainerParent* mImageContainer;
int32_t mLastFrameID;
int32_t mLastProducerID;
CompositableTextureHostRef mFrontBuffer;
CompositableTextureSourceRef mTextureSource;
gfx::IntRect mPictureRect;
bool mHasPictureRect;
bool mLocked;
};
@@ -104,24 +125,20 @@ public:
virtual CompositableType GetType() { return mTextureInfo.mCompositableType; }
virtual void Composite(EffectChain& aEffectChain,
virtual void Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual LayerRenderState GetRenderState() override;
virtual void UseOverlaySource(OverlaySource aOverlay) override;
virtual void UseOverlaySource(OverlaySource aOverlay,
const gfx::IntRect& aPictureRect) override;
virtual gfx::IntSize GetImageSize() const override;
virtual void SetPictureRect(const nsIntRect& aPictureRect) override
{
mPictureRect = aPictureRect;
mHasPictureRect = true;
}
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
protected:
gfx::IntRect mPictureRect;
bool mHasPictureRect;
OverlaySource mOverlay;
};
+9 -11
View File
@@ -95,17 +95,15 @@ ImageLayerComposite::RenderLayer(const IntRect& aClipRect)
mCompositor->MakeCurrent();
EffectChain effectChain(this);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
AddBlendModeEffect(effectChain);
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
mImageHost->SetCompositor(mCompositor);
mImageHost->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransformForBuffer(),
GetEffectFilter(),
clipRect);
RenderWithAllMasks(this, mCompositor, aClipRect,
[&](EffectChain& effectChain, const Rect& clipRect) {
mImageHost->SetCompositor(mCompositor);
mImageHost->Composite(this, effectChain,
GetEffectiveOpacity(),
GetEffectiveTransformForBuffer(),
GetEffectFilter(),
clipRect);
});
mImageHost->BumpFlashCounter();
}
+5 -17
View File
@@ -247,27 +247,11 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque
}
}
bool
LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags)
{
NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
if (!mRoot) {
mInTransaction = false;
mIsCompositorReady = false;
return false;
}
EndTransaction(nullptr, nullptr);
return true;
}
void
LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
EndTransactionFlags aFlags)
{
NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here");
NS_ASSERTION(!(aFlags & END_NO_COMPOSITE),
"Shouldn't get END_NO_COMPOSITE here");
mInTransaction = false;
@@ -299,6 +283,10 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
}
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
MOZ_ASSERT(!aTimeStamp.IsNull());
// Set composition timestamp here because we need it in
// ComputeEffectiveTransforms (so the correct video frame size is picked)
mCompositor->SetCompositionTime(aTimeStamp);
// The results of our drawing always go directly into a pixel buffer,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
+160 -3
View File
@@ -18,6 +18,8 @@
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h" // for SurfaceFormat
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/Effects.h" // for EffectChain
#include "mozilla/layers/LayersMessages.h"
#include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h"
@@ -109,12 +111,22 @@ public:
{
MOZ_CRASH("Use BeginTransactionWithDrawTarget");
}
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget, const gfx::IntRect& aRect);
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
const gfx::IntRect& aRect);
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override
{
MOZ_CRASH("Use EndTransaction(aTimeStamp)");
return false;
}
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) override;
EndTransactionFlags aFlags = END_DEFAULT) override
{
MOZ_CRASH("Use EndTransaction(aTimeStamp)");
}
void EndTransaction(const TimeStamp& aTimeStamp,
EndTransactionFlags aFlags = END_DEFAULT);
virtual void SetRoot(Layer* aLayer) override { mRoot = aLayer; }
@@ -251,6 +263,15 @@ public:
bool AsyncPanZoomEnabled() const override;
void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification)
{
mImageCompositeNotifications.AppendElement(aNotification);
}
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification>* aNotifications)
{
aNotifications->MoveElementsFrom(mImageCompositeNotifications);
}
private:
/** Region we're clipping our current drawing to. */
nsIntRegion mClippingRegion;
@@ -297,6 +318,8 @@ private:
RefPtr<Compositor> mCompositor;
UniquePtr<LayerProperties> mClonedLayerTreeProperties;
nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
/**
* Context target, nullptr when drawing directly to our swap chain.
*/
@@ -358,6 +381,8 @@ public:
virtual void SetLayerManager(LayerManagerComposite* aManager);
LayerManagerComposite* GetLayerManager() const { return mCompositeManager; }
/**
* Perform a first pass over the layer tree to render all of the intermediate
* surfaces that we can. This allows us to avoid framebuffer switches in the
@@ -455,6 +480,138 @@ protected:
gfx::IntRect mClearRect;
};
// Render aLayer using aCompositor and apply all mask layers of aLayer: The
// layer's own mask layer (aLayer->GetMaskLayer()), and any ancestor mask
// layers.
// If more than one mask layer needs to be applied, we use intermediate surfaces
// (CompositingRenderTargets) for rendering, applying one mask layer at a time.
// Callers need to provide a callback function aRenderCallback that does the
// actual rendering of the source. It needs to have the following form:
// void (EffectChain& effectChain, const Rect& clipRect)
// aRenderCallback is called exactly once, inside this function, unless aLayer's
// visible region is completely clipped out (in that case, aRenderCallback won't
// be called at all).
// This function calls aLayer->AsLayerComposite()->AddBlendModeEffect for the
// final rendering pass.
//
// (This function should really live in LayerManagerComposite.cpp, but we
// need to use templates for passing lambdas until bug 1164522 is resolved.)
template<typename RenderCallbackType>
void
RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
const gfx::IntRect& aClipRect,
RenderCallbackType aRenderCallback)
{
Layer* firstMask = nullptr;
size_t maskLayerCount = 0;
size_t nextAncestorMaskLayer = 0;
size_t ancestorMaskLayerCount = aLayer->GetAncestorMaskLayerCount();
if (Layer* ownMask = aLayer->GetMaskLayer()) {
firstMask = ownMask;
maskLayerCount = ancestorMaskLayerCount + 1;
nextAncestorMaskLayer = 0;
} else if (ancestorMaskLayerCount > 0) {
firstMask = aLayer->GetAncestorMaskLayerAt(0);
maskLayerCount = ancestorMaskLayerCount;
nextAncestorMaskLayer = 1;
} else {
// no mask layers at all
}
bool firstMaskIs3D = false;
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
firstMaskIs3D = !container->GetTransform().CanDraw2D();
}
if (maskLayerCount <= 1) {
// This is the common case. Render in one pass and return.
EffectChain effectChain(aLayer);
LayerManagerComposite::AutoAddMaskEffect
autoMaskEffect(firstMask, effectChain, firstMaskIs3D);
aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain);
aRenderCallback(effectChain, gfx::Rect(aClipRect));
return;
}
// We have multiple mask layers.
// We split our list of mask layers into three parts:
// (1) The first mask
// (2) The list of intermediate masks (every mask except first and last)
// (3) The final mask.
// Part (2) can be empty.
// For parts (1) and (2) we need to allocate intermediate surfaces to render
// into. The final mask gets rendered into the original render target.
// Calculate the size of the intermediate surfaces.
gfx::Rect visibleRect(aLayer->GetEffectiveVisibleRegion().GetBounds());
gfx::Matrix4x4 transform = aLayer->GetEffectiveTransform();
// TODO: Use RenderTargetIntRect and TransformTo<...> here
gfx::IntRect surfaceRect =
RoundedOut(transform.TransformBounds(visibleRect)).Intersect(aClipRect);
if (surfaceRect.IsEmpty()) {
return;
}
RefPtr<CompositingRenderTarget> originalTarget =
aCompositor->GetCurrentRenderTarget();
RefPtr<CompositingRenderTarget> firstTarget =
aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
if (!firstTarget) {
return;
}
// Render the source while applying the first mask.
aCompositor->SetRenderTarget(firstTarget);
{
EffectChain firstEffectChain(aLayer);
LayerManagerComposite::AutoAddMaskEffect
firstMaskEffect(firstMask, firstEffectChain, firstMaskIs3D);
aRenderCallback(firstEffectChain, gfx::Rect(aClipRect - surfaceRect.TopLeft()));
// firstTarget now contains the transformed source with the first mask and
// opacity already applied.
}
// Apply the intermediate masks.
gfx::Rect intermediateClip(surfaceRect - surfaceRect.TopLeft());
RefPtr<CompositingRenderTarget> previousTarget = firstTarget;
for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) {
Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i);
RefPtr<CompositingRenderTarget> intermediateTarget =
aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
if (!intermediateTarget) {
break;
}
aCompositor->SetRenderTarget(intermediateTarget);
EffectChain intermediateEffectChain(aLayer);
LayerManagerComposite::AutoAddMaskEffect
intermediateMaskEffect(intermediateMask, intermediateEffectChain);
if (intermediateMaskEffect.Failed()) {
continue;
}
intermediateEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
aCompositor->DrawQuad(gfx::Rect(surfaceRect), intermediateClip,
intermediateEffectChain, 1.0, gfx::Matrix4x4());
previousTarget = intermediateTarget;
}
aCompositor->SetRenderTarget(originalTarget);
// Apply the final mask, rendering into originalTarget.
EffectChain finalEffectChain(aLayer);
finalEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
Layer* finalMask = aLayer->GetAncestorMaskLayerAt(ancestorMaskLayerCount - 1);
// The blend mode needs to be applied in this final step, because this is
// where we're blending with the actual background (which is in originalTarget).
aLayer->AsLayerComposite()->AddBlendModeEffect(finalEffectChain);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(finalMask, finalEffectChain);
if (!autoMaskEffect.Failed()) {
aCompositor->DrawQuad(gfx::Rect(surfaceRect), gfx::Rect(aClipRect),
finalEffectChain, 1.0, gfx::Matrix4x4());
}
}
} // namespace layers
} // namespace mozilla
+15 -13
View File
@@ -106,12 +106,13 @@ PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
PROFILER_LABEL("PaintedLayerComposite", "RenderLayer",
js::ProfileEntry::Category::GRAPHICS);
MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
Compositor* compositor = mCompositeManager->GetCompositor();
MOZ_ASSERT(mBuffer->GetCompositor() == compositor &&
mBuffer->GetLayer() == this,
"buffer is corrupted");
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
@@ -122,21 +123,22 @@ PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
}
#endif
EffectChain effectChain(this);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
AddBlendModeEffect(effectChain);
mBuffer->SetPaintWillResample(MayResample());
RenderWithAllMasks(this, compositor, aClipRect,
[&](EffectChain& effectChain, const Rect& clipRect) {
mBuffer->SetPaintWillResample(MayResample());
mBuffer->Composite(this, effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
GetEffectFilter(),
clipRect,
&visibleRegion);
});
mBuffer->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
GetEffectFilter(),
clipRect,
&visibleRegion);
mBuffer->BumpFlashCounter();
mCompositeManager->GetCompositor()->MakeCurrent();
compositor->MakeCurrent();
}
CompositableHost*
+2 -1
View File
@@ -350,7 +350,8 @@ TiledLayerBufferComposite::Clear()
}
void
TiledContentHost::Composite(EffectChain& aEffectChain,
TiledContentHost::Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
+7 -6
View File
@@ -235,12 +235,13 @@ public:
bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor);
void Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual void Composite(LayerComposite* aLayer,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
+18 -11
View File
@@ -22,6 +22,7 @@ namespace layers {
class CompositableClient;
class AsyncTransactionTracker;
class ImageContainer;
struct TextureFactoryIdentifier;
class SurfaceDescriptor;
class SurfaceDescriptorTiles;
@@ -50,7 +51,8 @@ public:
* Setup the IPDL actor for aCompositable to be part of layers
* transactions.
*/
virtual void Connect(CompositableClient* aCompositable) = 0;
virtual void Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer = nullptr) = 0;
/**
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
@@ -72,15 +74,10 @@ public:
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) = 0;
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/
virtual void UpdatePictureRect(CompositableClient* aCompositable,
const gfx::IntRect& aRect) = 0;
#ifdef MOZ_WIDGET_GONK
virtual void UseOverlaySource(CompositableClient* aCompositabl,
const OverlaySource& aOverlay) = 0;
const OverlaySource& aOverlay,
const gfx::IntRect& aPictureRect) = 0;
#endif
/**
@@ -133,12 +130,22 @@ public:
mTexturesToRemove.Clear();
}
struct TimedTextureClient {
TimedTextureClient()
: mTextureClient(nullptr), mFrameID(0), mProducerID(0) {}
TextureClient* mTextureClient;
TimeStamp mTimeStamp;
nsIntRect mPictureRect;
int32_t mFrameID;
int32_t mProducerID;
};
/**
* Tell the CompositableHost on the compositor side what texture to use for
* Tell the CompositableHost on the compositor side what textures to use for
* the next composition.
*/
virtual void UseTexture(CompositableClient* aCompositable,
TextureClient* aClient) = 0;
virtual void UseTextures(CompositableClient* aCompositable,
const nsTArray<TimedTextureClient>& aTextures) = 0;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) = 0;
@@ -68,6 +68,15 @@ bool ScheduleComposition(const T& op)
return true;
}
#if defined(DEBUG) || defined(MOZ_WIDGET_GONK)
static bool ValidatePictureRect(const mozilla::gfx::IntSize& aSize,
const nsIntRect& aPictureRect)
{
return nsIntRect(0, 0, aSize.width, aSize.height).Contains(aPictureRect) &&
!aPictureRect.IsEmpty();
}
#endif
bool
CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation& aEdit,
EditReplyVector& replyv)
@@ -102,13 +111,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
RenderTraceInvalidateEnd(thebes, "FF00FF");
break;
}
case CompositableOperation::TOpUpdatePictureRect: {
const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect();
CompositableHost* compositable = AsCompositable(op);
MOZ_ASSERT(compositable);
compositable->SetPictureRect(op.picture());
break;
}
case CompositableOperation::TOpUseTiledLayerBuffer: {
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
@@ -169,18 +171,28 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
case CompositableOperation::TOpUseTexture: {
const OpUseTexture& op = aEdit.get_OpUseTexture();
CompositableHost* compositable = AsCompositable(op);
RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
MOZ_ASSERT(tex.get());
compositable->UseTextureHost(tex);
nsAutoTArray<CompositableHost::TimedTexture,4> textures;
for (auto& timedTexture : op.textures()) {
CompositableHost::TimedTexture* t = textures.AppendElement();
t->mTexture =
TextureHost::AsTextureHost(timedTexture.textureParent());
MOZ_ASSERT(t->mTexture);
t->mTimeStamp = timedTexture.timeStamp();
t->mPictureRect = timedTexture.picture();
t->mFrameID = timedTexture.frameID();
t->mProducerID = timedTexture.producerID();
MOZ_ASSERT(ValidatePictureRect(t->mTexture->GetSize(), t->mPictureRect));
MaybeFence maybeFence = op.fence();
if (maybeFence.type() == MaybeFence::TFenceHandle) {
FenceHandle fence = maybeFence.get_FenceHandle();
if (fence.IsValid() && tex) {
tex->SetAcquireFenceHandle(fence);
MaybeFence maybeFence = timedTexture.fence();
if (maybeFence.type() == MaybeFence::TFenceHandle) {
FenceHandle fence = maybeFence.get_FenceHandle();
if (fence.IsValid()) {
t->mTexture->SetAcquireFenceHandle(fence);
}
}
}
compositable->UseTextureHost(textures);
if (IsAsync() && compositable->GetLayer()) {
ScheduleComposition(op);
@@ -209,7 +221,10 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
const OpUseOverlaySource& op = aEdit.get_OpUseOverlaySource();
CompositableHost* compositable = AsCompositable(op);
MOZ_ASSERT(compositable->GetType() == CompositableType::IMAGE_OVERLAY, "Invalid operation!");
compositable->UseOverlaySource(op.overlay());
if (!ValidatePictureRect(op.overlay().size(), op.picture())) {
return false;
}
compositable->UseOverlaySource(op.overlay(), op.picture());
break;
}
#endif
+12 -1
View File
@@ -38,10 +38,12 @@
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/FrameUniformityData.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Telemetry.h"
#ifdef MOZ_WIDGET_GTK
@@ -592,6 +594,7 @@ void CompositorParent::ShutDown()
MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
ReleaseImageBridgeParentSingleton();
MediaSystemResourceService::Shutdown();
sCompositorThreadHolder = nullptr;
@@ -1169,7 +1172,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
}
#endif
mLayerManager->SetDebugOverlayWantsNextFrame(false);
mLayerManager->EndEmptyTransaction();
mLayerManager->EndTransaction(time);
if (!aTarget) {
DidComposite();
@@ -1198,6 +1201,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
// Special full-tilt composite mode for performance testing
ScheduleComposition();
}
mCompositor->SetCompositionTime(TimeStamp());
mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start);
profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
@@ -1824,6 +1828,13 @@ CompositorParent::DidComposite()
unused << SendDidComposite(0, mPendingTransaction);
mPendingTransaction = 0;
}
if (mLayerManager) {
nsTArray<ImageCompositeNotification> notifications;
mLayerManager->ExtractImageCompositeNotifications(&notifications);
if (!notifications.IsEmpty()) {
unused << ImageBridgeParent::NotifyImageComposites(notifications);
}
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
+133 -43
View File
@@ -21,12 +21,15 @@
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
#include "mozilla/layers/ImageClient.h" // for ImageClient
#include "mozilla/layers/LayersMessages.h" // for CompositableOperation
#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
#include "mozilla/layers/PImageContainerChild.h"
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/mozalloc.h" // for operator new, etc
#include "nsAutoPtr.h" // for nsRefPtr
@@ -49,6 +52,7 @@ using base::Thread;
using base::ProcessId;
using namespace mozilla::ipc;
using namespace mozilla::gfx;
using namespace mozilla::media;
typedef std::vector<CompositableOperation> OpVector;
@@ -104,18 +108,25 @@ struct AutoEndTransaction {
};
void
ImageBridgeChild::UseTexture(CompositableClient* aCompositable,
TextureClient* aTexture)
ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
const nsTArray<TimedTextureClient>& aTextures)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture->GetIPDLActor());
FenceHandle fence = aTexture->GetAcquireFenceHandle();
nsAutoTArray<TimedTexture,4> textures;
for (auto& t : aTextures) {
MOZ_ASSERT(t.mTextureClient);
MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
FenceHandle fence = t.mTextureClient->GetAcquireFenceHandle();
textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
t.mTimeStamp, t.mPictureRect,
t.mFrameID, t.mProducerID));
}
mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor(),
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t())));
textures));
}
void
@@ -138,22 +149,15 @@ ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
#ifdef MOZ_WIDGET_GONK
void
ImageBridgeChild::UseOverlaySource(CompositableClient* aCompositable,
const OverlaySource& aOverlay)
const OverlaySource& aOverlay,
const nsIntRect& aPictureRect)
{
MOZ_ASSERT(aCompositable);
mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(), aOverlay));
mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(),
aOverlay, aPictureRect));
}
#endif
void
ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable,
const gfx::IntRect& aRect)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
}
// Singleton
static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
@@ -171,6 +175,9 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
MOZ_ASSERT(InImageBridgeChildThread(),
"Should be in ImageBridgeChild thread.");
MediaSystemResourceManager::Shutdown();
if (sImageBridgeChildSingleton) {
// Force all managed protocols to shut themselves down cleanly
InfallibleTArray<PCompositableChild*> compositables;
@@ -181,13 +188,17 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
InfallibleTArray<PTextureChild*> textures;
sImageBridgeChildSingleton->ManagedPTextureChild(textures);
for (int i = textures.Length() - 1; i >= 0; --i) {
TextureClient::AsTextureClient(textures[i])->ForceRemove();
TextureClient* client = TextureClient::AsTextureClient(textures[i]);
if (client) {
client->ForceRemove();
}
}
sImageBridgeChildSingleton->SendWillStop();
sImageBridgeChildSingleton->MarkShutDown();
// From now on, no message can be sent through the image bridge from the
// client side except the final Stop message.
}
*aDone = true;
aBarrier->NotifyAll();
}
@@ -210,10 +221,12 @@ static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone)
static void CreateImageClientSync(RefPtr<ImageClient>* result,
ReentrantMonitor* barrier,
CompositableType aType,
ImageContainer* aImageContainer,
bool *aDone)
{
ReentrantMonitorAutoEnter autoMon(*barrier);
*result = sImageBridgeChildSingleton->CreateImageClientNow(aType);
*result = sImageBridgeChildSingleton->CreateImageClientNow(
aType, aImageContainer);
*aDone = true;
barrier->NotifyAll();
}
@@ -250,19 +263,22 @@ ImageBridgeChild::MarkShutDown()
}
void
ImageBridgeChild::Connect(CompositableClient* aCompositable)
ImageBridgeChild::Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(!mShuttingDown);
uint64_t id = 0;
PCompositableChild* child =
SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id);
SendPCompositableConstructor(aCompositable->GetTextureInfo(),
aImageContainer->GetPImageContainerChild(), &id);
MOZ_ASSERT(child);
aCompositable->InitIPDLActor(child, id);
}
PCompositableChild*
ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID)
ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
PImageContainerChild* aChild, uint64_t* aID)
{
MOZ_ASSERT(!mShuttingDown);
return CompositableClient::CreateIPDLActor();
@@ -319,33 +335,43 @@ ConnectImageBridgeInChildProcess(Transport* aTransport,
#endif
}
static void ReleaseImageClientNow(ImageClient* aClient)
static void ReleaseImageClientNow(ImageClient* aClient,
PImageContainerChild* aChild)
{
MOZ_ASSERT(InImageBridgeChildThread());
aClient->Release();
if (aClient) {
aClient->Release();
}
if (aChild) {
aChild->SendAsyncDelete();
}
}
// static
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient,
PImageContainerChild* aChild)
{
if (!aClient) {
if (!aClient && !aChild) {
return;
}
if (!IsCreated()) {
// CompositableClient::Release should normally happen in the ImageBridgeChild
// thread because it usually generate some IPDL messages.
// However, if we take this branch it means that the ImageBridgeChild
// has already shut down, along with the CompositableChild, 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();
if (aClient) {
// CompositableClient::Release should normally happen in the ImageBridgeChild
// thread because it usually generate some IPDL messages.
// However, if we take this branch it means that the ImageBridgeChild
// has already shut down, along with the CompositableChild, 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();
}
delete aChild;
return;
}
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&ReleaseImageClientNow, aClient));
NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild));
}
static void ReleaseTextureClientNow(TextureClient* aClient)
@@ -383,7 +409,6 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
MOZ_ASSERT(aContainer);
sImageBridgeChildSingleton->BeginTransaction();
aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
aClient->OnTransaction();
sImageBridgeChildSingleton->EndTransaction();
}
@@ -416,7 +441,6 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
aContainer->ClearCurrentImage();
}
aClient->FlushAllImages(aExceptFront, aWaiter);
aClient->OnTransaction();
sImageBridgeChildSingleton->EndTransaction();
// This decrement is balanced by the increment in FlushAllImages.
// If any AsyncTransactionTrackers were created by FlushAllImages and attached
@@ -517,6 +541,19 @@ ImageBridgeChild::EndTransaction()
SendPendingAsyncMessges();
}
void
ImageBridgeChild::SendImageBridgeThreadId()
{
#ifdef MOZ_WIDGET_GONK
SendImageBridgeThreadId(gettid());
#endif
}
static void CallSendImageBridgeThreadId(ImageBridgeChild* aImageBridgeChild)
{
MOZ_ASSERT(InImageBridgeChildThread());
aImageBridgeChild->SendImageBridgeThreadId();
}
PImageBridgeChild*
ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
@@ -536,6 +573,10 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
FROM_HERE,
NewRunnableFunction(ConnectImageBridgeInChildProcess,
aTransport, aOtherPid));
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(CallSendImageBridgeThreadId,
sImageBridgeChildSingleton.get()));
return sImageBridgeChildSingleton;
}
@@ -589,6 +630,10 @@ bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
sImageBridgeParentSingleton = new ImageBridgeParent(
CompositorParent::CompositorLoop(), nullptr, base::GetCurrentProcId());
sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(CallSendImageBridgeThreadId,
sImageBridgeChildSingleton.get()));
return true;
} else {
return false;
@@ -621,18 +666,20 @@ ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier&
}
already_AddRefed<ImageClient>
ImageBridgeChild::CreateImageClient(CompositableType aType)
ImageBridgeChild::CreateImageClient(CompositableType aType,
ImageContainer* aImageContainer)
{
if (InImageBridgeChildThread()) {
return CreateImageClientNow(aType);
return CreateImageClientNow(aType, aImageContainer);
}
ReentrantMonitor barrier("CreateImageClient Lock");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
RefPtr<ImageClient> result = nullptr;
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync,
&result, &barrier, aType, &done));
GetMessageLoop()->PostTask(FROM_HERE,
NewRunnableFunction(&CreateImageClientSync, &result, &barrier, aType,
aImageContainer, &done));
// should stop the thread until the ImageClient has been created on
// the other thread
while (!done) {
@@ -642,14 +689,18 @@ ImageBridgeChild::CreateImageClient(CompositableType aType)
}
already_AddRefed<ImageClient>
ImageBridgeChild::CreateImageClientNow(CompositableType aType)
ImageBridgeChild::CreateImageClientNow(CompositableType aType,
ImageContainer* aImageContainer)
{
MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
if (aImageContainer) {
SendPImageContainerConstructor(aImageContainer->GetPImageContainerChild());
}
RefPtr<ImageClient> client
= ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
MOZ_ASSERT(client, "failed to create ImageClient");
if (client) {
client->Connect();
client->Connect(aImageContainer);
}
return client.forget();
}
@@ -791,6 +842,36 @@ ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
return TextureClient::DestroyIPDLActor(actor);
}
PMediaSystemResourceManagerChild*
ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
{
MOZ_ASSERT(!mShuttingDown);
return new mozilla::media::MediaSystemResourceManagerChild();
}
bool
ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
return true;
}
PImageContainerChild*
ImageBridgeChild::AllocPImageContainerChild()
{
// we always use the "power-user" ctor
NS_RUNTIMEABORT("not reached");
return nullptr;
}
bool
ImageBridgeChild::DeallocPImageContainerChild(PImageContainerChild* actor)
{
delete actor;
return true;
}
bool
ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
{
@@ -833,6 +914,15 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageDat
return true;
}
bool
ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
{
for (auto& n : aNotifications) {
ImageContainer::NotifyComposite(n);
}
return true;
}
PTextureChild*
ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
TextureFlags aFlags)
+31 -16
View File
@@ -152,6 +152,9 @@ public:
*/
void ConnectAsync(ImageBridgeParent* aParent);
using PImageBridgeChild::SendImageBridgeThreadId;
void SendImageBridgeThreadId();
static void IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier);
void BeginTransaction();
@@ -171,7 +174,8 @@ public:
*/
virtual MessageLoop * GetMessageLoop() const override;
PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) override;
PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo,
PImageContainerChild* aChild, uint64_t* aID) override;
bool DeallocPCompositableChild(PCompositableChild* aActor) override;
/**
@@ -186,13 +190,29 @@ public:
virtual bool
DeallocPTextureChild(PTextureChild* actor) override;
PMediaSystemResourceManagerChild*
AllocPMediaSystemResourceManagerChild() override;
bool
DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) override;
virtual PImageContainerChild*
AllocPImageContainerChild() override;
virtual bool
DeallocPImageContainerChild(PImageContainerChild* actor) override;
virtual bool
RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
already_AddRefed<ImageClient> CreateImageClient(CompositableType aType);
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType);
virtual bool
RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications) override;
static void DispatchReleaseImageClient(ImageClient* aClient);
already_AddRefed<ImageClient> CreateImageClient(CompositableType aType,
ImageContainer* aImageContainer);
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType,
ImageContainer* aImageContainer);
static void DispatchReleaseImageClient(ImageClient* aClient,
PImageContainerChild* aChild = nullptr);
static void DispatchReleaseTextureClient(TextureClient* aClient);
static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
@@ -203,21 +223,23 @@ public:
// CompositableForwarder
virtual void Connect(CompositableClient* aCompositable) override;
virtual void Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer) override;
virtual bool IsImageBridgeChild() const override { return true; }
/**
* See CompositableForwarder::UseTexture
* See CompositableForwarder::UseTextures
*/
virtual void UseTexture(CompositableClient* aCompositable,
TextureClient* aClient) override;
virtual void UseTextures(CompositableClient* aCompositable,
const nsTArray<TimedTextureClient>& aTextures) override;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) override;
#ifdef MOZ_WIDGET_GONK
virtual void UseOverlaySource(CompositableClient* aCompositable,
const OverlaySource& aOverlay) override;
const OverlaySource& aOverlay,
const nsIntRect& aPictureRect) override;
#endif
virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
@@ -235,13 +257,6 @@ public:
NS_RUNTIMEABORT("should not be called");
}
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/
virtual void UpdatePictureRect(CompositableClient* aCompositable,
const gfx::IntRect& aRect) override;
virtual void UpdateTextureRegion(CompositableClient* aCompositable,
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) override {
+95 -1
View File
@@ -12,9 +12,12 @@
#include "base/task.h" // for CancelableTask, DeleteTask, etc
#include "base/tracked.h" // for FROM_HERE
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/Hal.h" // for hal::SetCurrentThreadPriority()
#include "mozilla/HalTypes.h" // for hal::THREAD_PRIORITY_COMPOSITOR
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
#include "mozilla/layers/CompositableTransactionParent.h"
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
#include "mozilla/layers/LayerManagerComposite.h"
@@ -40,6 +43,7 @@ namespace layers {
using namespace mozilla::ipc;
using namespace mozilla::gfx;
using namespace mozilla::media;
std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
@@ -53,6 +57,7 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
ProcessId aChildProcessId)
: mMessageLoop(aLoop)
, mTransport(aTransport)
, mSetChildThreadPriority(false)
, mCompositorThreadHolder(GetCompositorThreadHolder())
{
MOZ_ASSERT(NS_IsMainThread());
@@ -78,6 +83,12 @@ ImageBridgeParent::~ImageBridgeParent()
new DeleteTask<Transport>(mTransport));
}
nsTArray<PImageContainerParent*> parents;
ManagedPImageContainerParent(parents);
for (PImageContainerParent* p : parents) {
delete p;
}
sImageBridges.erase(OtherPid());
}
@@ -95,6 +106,20 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
}
bool
ImageBridgeParent::RecvImageBridgeThreadId(const PlatformThreadId& aThreadId)
{
MOZ_ASSERT(!mSetChildThreadPriority);
if (mSetChildThreadPriority) {
return false;
}
mSetChildThreadPriority = true;
#ifdef MOZ_WIDGET_GONK
hal::SetThreadPriority(aThreadId, hal::THREAD_PRIORITY_COMPOSITOR);
#endif
return true;
}
class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
{
public:
@@ -217,11 +242,12 @@ static uint64_t GenImageContainerID() {
PCompositableParent*
ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo,
PImageContainerParent* aImageContainer,
uint64_t* aID)
{
uint64_t id = GenImageContainerID();
*aID = id;
return CompositableHost::CreateIPDLActor(this, aInfo, id);
return CompositableHost::CreateIPDLActor(this, aInfo, id, aImageContainer);
}
bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
@@ -242,6 +268,33 @@ ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
return TextureHost::DestroyIPDLActor(actor);
}
PMediaSystemResourceManagerParent*
ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
{
return new mozilla::media::MediaSystemResourceManagerParent();
}
bool
ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
return true;
}
PImageContainerParent*
ImageBridgeParent::AllocPImageContainerParent()
{
return new ImageContainerParent();
}
bool
ImageBridgeParent::DeallocPImageContainerParent(PImageContainerParent* actor)
{
delete actor;
return true;
}
void
ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
{
@@ -254,6 +307,47 @@ ImageBridgeParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData
return true;
}
class ProcessIdComparator
{
public:
bool Equals(const ImageCompositeNotification& aA,
const ImageCompositeNotification& aB) const
{
return aA.imageContainerParent()->OtherPid() == aB.imageContainerParent()->OtherPid();
}
bool LessThan(const ImageCompositeNotification& aA,
const ImageCompositeNotification& aB) const
{
return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid();
}
};
/* static */ bool
ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications)
{
// Group the notifications by destination process ID and then send the
// notifications in one message per group.
aNotifications.Sort(ProcessIdComparator());
uint32_t i = 0;
bool ok = true;
while (i < aNotifications.Length()) {
nsAutoTArray<ImageCompositeNotification,1> notifications;
notifications.AppendElement(aNotifications[i]);
uint32_t end = i + 1;
ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
while (end < aNotifications.Length() &&
aNotifications[end].imageContainerParent()->OtherPid() == pid) {
notifications.AppendElement(aNotifications[end]);
++end;
}
if (!GetInstance(pid)->SendDidComposite(notifications)) {
ok = false;
}
i = end;
}
return ok;
}
MessageLoop * ImageBridgeParent::GetMessageLoop() const {
return mMessageLoop;
}
+12 -1
View File
@@ -9,6 +9,7 @@
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint64_t
#include "CompositableTransactionParent.h"
#include "ImageContainerParent.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
#include "mozilla/Attributes.h" // for override
#include "mozilla/ipc/ProtocolUtils.h"
@@ -67,12 +68,14 @@ public:
}
// PImageBridge
virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
virtual bool RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) override;
virtual bool RecvUpdateNoSwap(EditArray&& aEdits) override;
virtual bool IsAsync() const override { return true; }
PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
PImageContainerParent* aImageContainer,
uint64_t*) override;
bool DeallocPCompositableParent(PCompositableParent* aActor) override;
@@ -80,6 +83,11 @@ public:
const TextureFlags& aFlags) override;
virtual bool DeallocPTextureParent(PTextureParent* actor) override;
PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
virtual PImageContainerParent* AllocPImageContainerParent() override;
virtual bool DeallocPImageContainerParent(PImageContainerParent* actor) override;
virtual bool
RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages) override;
@@ -135,6 +143,8 @@ public:
static ImageBridgeParent* GetInstance(ProcessId aId);
static bool NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications);
// Overriden from IToplevelProtocol
IToplevelProtocol*
CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
@@ -143,13 +153,14 @@ public:
private:
void DeferredDestroy();
MessageLoop* mMessageLoop;
Transport* mTransport;
// This keeps us alive until ActorDestroy(), at which point we do a
// deferred destruction of ourselves.
nsRefPtr<ImageBridgeParent> mSelfRef;
bool mSetChildThreadPriority;
/**
* Map of all living ImageBridgeParent instances
*/
+37
View File
@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ImageContainerParent.h"
#include "nsThreadUtils.h"
#include "mozilla/layers/ImageHost.h"
namespace mozilla {
namespace layers {
ImageContainerParent::~ImageContainerParent()
{
while (!mImageHosts.IsEmpty()) {
mImageHosts[mImageHosts.Length() - 1]->SetImageContainer(nullptr);
}
}
static void SendDeleteAndIgnoreResult(ImageContainerParent* self)
{
unused << PImageContainerParent::Send__delete__(self);
}
bool ImageContainerParent::RecvAsyncDelete()
{
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(&SendDeleteAndIgnoreResult, this));
return true;
}
}
}
+38
View File
@@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_ImageContainerParent_h
#define mozilla_layers_ImageContainerParent_h
#include "mozilla/Attributes.h" // for override
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/PImageContainerParent.h"
#include "nsAutoPtr.h" // for nsRefPtr
namespace mozilla {
namespace layers {
class ImageHost;
class ImageContainerParent : public PImageContainerParent
{
public:
ImageContainerParent() {}
~ImageContainerParent();
virtual bool RecvAsyncDelete() override;
nsAutoTArray<ImageHost*,1> mImageHosts;
private:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
} // namespace layers
} // namespace mozilla
#endif // ifndef mozilla_layers_ImageContainerParent_h
+1
View File
@@ -9,6 +9,7 @@
#include "mozilla/layers/CompositableClient.h" // for CompositableChild
#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
#include "mozilla/layers/PImageContainerChild.h"
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsDebug.h" // for NS_RUNTIMEABORT, etc
+1 -2
View File
@@ -583,7 +583,6 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
if (!Attach(cast(op.layerParent()), host, true)) {
return false;
}
host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
break;
}
@@ -598,7 +597,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
{
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
layer_manager()->EndTransaction(nullptr, nullptr, LayerManager::END_NO_IMMEDIATE_REDRAW);
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
}
if (reply) {
+33 -12
View File
@@ -9,6 +9,7 @@ include LayersSurfaces;
include protocol PCompositable;
include protocol PCompositor;
include protocol PLayer;
include protocol PImageContainer;
include protocol PRenderFrame;
include protocol PTexture;
@@ -53,7 +54,7 @@ struct TargetConfig {
};
// Create a shadow layer for |layer|
struct OpCreatePaintedLayer { PLayer layer; };
struct OpCreatePaintedLayer { PLayer layer; };
struct OpCreateContainerLayer { PLayer layer; };
struct OpCreateImageLayer { PLayer layer; };
struct OpCreateColorLayer { PLayer layer; };
@@ -348,6 +349,7 @@ struct OpUseTiledLayerBuffer {
struct OpUseOverlaySource {
PCompositable compositable;
OverlaySource overlay;
IntRect picture;
};
struct OpPaintTextureRegion {
@@ -356,11 +358,6 @@ struct OpPaintTextureRegion {
nsIntRegion updatedRegion;
};
struct OpUpdatePictureRect {
PCompositable compositable;
IntRect picture;
};
/**
* Tells the CompositableHost to remove the corresponding TextureHost
*/
@@ -386,14 +383,28 @@ union MaybeFence {
null_t;
};
struct TimedTexture {
PTexture texture;
MaybeFence fence;
TimeStamp timeStamp;
IntRect picture;
int32_t frameID;
int32_t producerID;
};
/**
* Tells the compositor-side which texture to use (for example, as front buffer
* if there is several textures for double buffering)
* Tells the compositor-side which textures to use (for example, as front buffer
* if there are several textures for double buffering).
* This provides a list of textures with timestamps, ordered by timestamp.
* The newest texture whose timestamp is <= the current time is rendered
* (where null is considered less than every other timestamp). If there is no
* such texture, the first texture is rendered.
* The first timestamp value can be null, but the others must not be.
* The list must not be empty.
*/
struct OpUseTexture {
PCompositable compositable;
PTexture texture;
MaybeFence fence;
TimedTexture[] textures;
};
struct OpUseComponentAlphaTextures {
@@ -419,8 +430,6 @@ struct OpDeliverFenceToTracker {
};
union CompositableOperation {
OpUpdatePictureRect;
OpPaintTextureRegion;
OpUseTiledLayerBuffer;
@@ -466,6 +475,18 @@ struct OpContentBufferSwap {
nsIntRegion frontUpdatedRegion;
};
/**
* An ImageCompositeNotification is sent the first time a particular
* image is composited by an ImageHost.
*/
struct ImageCompositeNotification {
PImageContainer imageContainer;
TimeStamp imageTimeStamp;
TimeStamp firstCompositeTimeStamp;
int32_t frameID;
int32_t producerID;
};
// Unit of a "changeset reply". This is a weird abstraction, probably
// only to be used for buffer swapping.
union EditReply {
+3
View File
@@ -7,6 +7,7 @@
include LayersSurfaces;
include LayersMessages;
include protocol PLayer;
include protocol PLayerTransaction;
include "mozilla/GfxMessageUtils.h";
include "nsRegion.h";
@@ -42,6 +43,8 @@ child:
// The compositor completed a layers transaction. id is the layers id
// of the child layer tree that was composited (or 0 when notifying
// the root layer tree).
// transactionId is the id of the transaction before this composite, or 0
// if there was no transaction since the last composite.
async DidComposite(uint64_t id, uint64_t transactionId);
// The parent sends the child the requested fill ratio numbers.
+13 -1
View File
@@ -6,15 +6,19 @@
include LayersSurfaces;
include LayersMessages;
include protocol PCompositable;
include protocol PImageContainer;
include protocol PLayer;
include protocol PTexture;
include ProtocolTypes;
include protocol PMediaSystemResourceManager;
include "mozilla/GfxMessageUtils.h";
using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
using PlatformThreadId from "base/platform_thread.h";
namespace mozilla {
namespace layers {
@@ -27,11 +31,16 @@ sync protocol PImageBridge
{
manages PCompositable;
manages PTexture;
manages PMediaSystemResourceManager;
manages PImageContainer;
child:
async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
async DidComposite(ImageCompositeNotification[] aNotifications);
parent:
async ImageBridgeThreadId(PlatformThreadId aTreahdId);
sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
async UpdateNoSwap(CompositableOperation[] ops);
@@ -48,8 +57,11 @@ parent:
// Second step
sync Stop();
sync PCompositable(TextureInfo aInfo) returns (uint64_t id);
sync PCompositable(TextureInfo aInfo,
PImageContainer aImageContainer) returns (uint64_t id);
async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
async PMediaSystemResourceManager();
async PImageContainer();
async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
};
+33
View File
@@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PImageBridge;
namespace mozilla {
namespace layers {
/**
* PImageContainer represents an ImageContainer.
*/
async protocol PImageContainer {
manager PImageBridge;
parent:
/**
* The child effectively owns the parent. When the child should be
* destroyed, it sends an AsyncDelete to the parent but does not die
* because we could still have messages in flight from the compositor
* mentioning the child. The parent handles AsyncDelete by destroying
* itself and sending __delete__ to the child to clean it up.
*/
async AsyncDelete();
child:
async __delete__();
};
} // layers
} // mozilla

Some files were not shown because too many files have changed in this diff Show More