diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index c103088abf..6b51f15940 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -47,6 +47,7 @@ class RenderFrameChild; namespace layers { class APZEventState; +class ImageCompositeNotification; struct SetTargetAPZCCallback; struct SetAllowedTouchBehaviorCallback; } diff --git a/dom/media/MP3FrameParser.cpp b/dom/media/MP3FrameParser.cpp index a77d3ebe17..0ce4fae0d8 100644 --- a/dom/media/MP3FrameParser.cpp +++ b/dom/media/MP3FrameParser.cpp @@ -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; } diff --git a/dom/media/MP3FrameParser.h b/dom/media/MP3FrameParser.h index fc24fa5ee3..5c36f16270 100644 --- a/dom/media/MP3FrameParser.h +++ b/dom/media/MP3FrameParser.h @@ -29,6 +29,8 @@ public: private: uint32_t mCurrentChar; + uint8_t mVersion; + uint8_t mFlags; uint32_t mHeaderLength; }; diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index 7563912f72..acb01e650b 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -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__); } diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index 6db7fa3b07..8b373c30df 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -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 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. diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index d8d98c44eb..d3b46a3076 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -55,13 +55,6 @@ public: } virtual nsRefPtr 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; diff --git a/dom/media/apple/AppleMP3Reader.cpp b/dom/media/apple/AppleMP3Reader.cpp index a351c044e5..ebab09cdc9 100644 --- a/dom/media/apple/AppleMP3Reader.cpp +++ b/dom/media/apple/AppleMP3Reader.cpp @@ -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); } } diff --git a/dom/media/directshow/DirectShowReader.cpp b/dom/media/directshow/DirectShowReader.cpp index 41b056d502..fdef04b8bd 100644 --- a/dom/media/directshow/DirectShowReader.cpp +++ b/dom/media/directshow/DirectShowReader.cpp @@ -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); } } diff --git a/dom/media/moz.build b/dom/media/moz.build index 69371c9d01..e07e4c2b90 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -65,7 +65,6 @@ if CONFIG['MOZ_WEBRTC']: if CONFIG['MOZ_OMX_DECODER']: DIRS += ['omx'] - DIRS += ['omx/mediaresourcemanager'] TEST_DIRS += [ 'compiledtest', diff --git a/dom/media/omx/MediaCodecProxy.cpp b/dom/media/omx/MediaCodecProxy.cpp index d98b81faba..5e53c258a9 100644 --- a/dom/media/omx/MediaCodecProxy.cpp +++ b/dom/media/omx/MediaCodecProxy.cpp @@ -99,36 +99,40 @@ MediaCodecProxy::MediaCodecProxy(sp 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 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 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) { diff --git a/dom/media/omx/MediaCodecProxy.h b/dom/media/omx/MediaCodecProxy.h index a17190fd2c..4bede31ae0 100644 --- a/dom/media/omx/MediaCodecProxy.h +++ b/dom/media/omx/MediaCodecProxy.h @@ -11,8 +11,10 @@ #include #include #include -#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 mListener; // Media Resource Management - sp mResourceHandler; + nsRefPtr mResourceClient; // MediaCodec instance mutable RWLock mCodecLock; diff --git a/dom/media/omx/MediaCodecReader.cpp b/dom/media/omx/MediaCodecReader.cpp index 177b3c656e..376ec243d0 100644 --- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -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 +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 p = mMetadataPromise.Ensure(__func__); + nsRefPtr 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 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 MediaCodecReader::CreateMediaCodecs() { - if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) && - CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) { - return true; + bool isWaiting = false; + nsRefPtr 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, Track& aTrack, bool aAsync, + bool& aIsWaiting, wp aListener) { if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) { @@ -1352,10 +1364,14 @@ MediaCodecReader::CreateMediaCodec(sp& 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 task = - NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources); - mVideoTrack.mTaskQueue->Dispatch(task.forget()); - } + mMediaResourcePromise.RejectIfExists(true, __func__); } } // namespace mozilla diff --git a/dom/media/omx/MediaCodecReader.h b/dom/media/omx/MediaCodecReader.h index 85f328b5e8..1e543e969c 100644 --- a/dom/media/omx/MediaCodecReader.h +++ b/dom/media/omx/MediaCodecReader.h @@ -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 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 mExtractor; - // A cache value updated by UpdateIsWaitingMediaResources(), makes the - // "waiting resources state" is synchronous to StateMachine. - bool mIsWaitingResources; + + MediaPromiseHolder mMetadataPromise; + // XXX Remove after bug 1168008 land. + MediaPromiseConsumerHolder mMediaResourceRequest; + MediaPromiseHolder mMediaResourcePromise; private: + // An intermediary class that can be managed by android::sp. // 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 CreateMediaCodecs(); static bool CreateMediaCodec(android::sp& aLooper, Track& aTrack, bool aAsync, + bool& aIsWaiting, android::wp aListener); static bool ConfigureMediaCodec(Track& aTrack); void DestroyMediaCodecs(); diff --git a/dom/media/omx/MediaOmxCommonReader.h b/dom/media/omx/MediaOmxCommonReader.h index 8f5984955b..1ff1554b6c 100644 --- a/dom/media/omx/MediaOmxCommonReader.h +++ b/dom/media/omx/MediaOmxCommonReader.h @@ -24,6 +24,8 @@ class AbstractMediaDecoder; class MediaOmxCommonReader : public MediaDecoderReader { public: + typedef MediaPromise MediaResourcePromise; + MediaOmxCommonReader(AbstractMediaDecoder* aDecoder); void SetAudioChannel(dom::AudioChannel aAudioChannel) { diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 77b8a27261..72f28a50fc 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -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 +MediaOmxReader::SafeGetDecoder() { + nsRefPtr 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 MediaOmxReader::Shutdown() { - nsCOMPtr cancelEvent = - NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData); - NS_DispatchToMainThread(cancelEvent); + { + MutexAutoLock lock(mShutdownMutex); + mIsShutdown = true; + } nsRefPtr 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 +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 p = mMetadataPromise.Ensure(__func__); + + nsRefPtr 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 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 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 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 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); diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h index f2914527f0..d9cbd906e2 100644 --- a/dom/media/omx/MediaOmxReader.h +++ b/dom/media/omx/MediaOmxReader.h @@ -12,6 +12,7 @@ #include "nsMimeTypes.h" #include "MP3FrameParser.h" #include "nsRect.h" + #include #include @@ -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 mMetadataPromise; + MediaPromiseConsumerHolder mMediaResourceRequest; protected: android::sp mOmxDecoder; android::sp 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 AsyncReadMetadata() override; + virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; @@ -104,7 +100,7 @@ public: virtual nsRefPtr 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 GetAudioOffloadTrack(); + +private: + already_AddRefed SafeGetDecoder(); }; } // namespace mozilla diff --git a/dom/media/omx/OMXCodecProxy.cpp b/dom/media/omx/OMXCodecProxy.cpp index 7b8e6968b5..dd250a89ae 100644 --- a/dom/media/omx/OMXCodecProxy.cpp +++ b/dom/media/omx/OMXCodecProxy.cpp @@ -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 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& listener) { Mutex::Autolock autoLock(mLock); - return mState; + mListener = listener; } -void OMXCodecProxy::setEventListener(const wp& listener) +void OMXCodecProxy::notifyResourceReserved() { - Mutex::Autolock autoLock(mLock); - mEventListener = listener; + sp listener = mListener.promote(); + if (listener != nullptr) { + listener->codecReserved(); + } } -void OMXCodecProxy::notifyStatusChangedLocked() +void OMXCodecProxy::notifyResourceCanceled() { - if (mEventListener != nullptr) { - sp listener = mEventListener.promote(); - if (listener != nullptr) { - listener->statusChanged(); - } + sp 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 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 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 ( but )", 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 OMXCodecProxy::getFormat() { Mutex::Autolock autoLock(mLock); - if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) { + if (mState != ResourceState::ACQUIRED) { sp 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); diff --git a/dom/media/omx/OMXCodecProxy.h b/dom/media/omx/OMXCodecProxy.h index 7c9e61efb9..3c3ef77043 100644 --- a/dom/media/omx/OMXCodecProxy.h +++ b/dom/media/omx/OMXCodecProxy.h @@ -13,18 +13,39 @@ #include #include -#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 Create( @@ -35,15 +56,13 @@ public: uint32_t flags = 0, const sp &nativeWindow = nullptr); - MediaResourceManagerClient::State getState(); - - void setEventListener(const wp& listener); + void setListener(const wp& 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 mSource; sp mOMXCodec; - sp mClient; - MediaResourceManagerClient::State mState; - sp mManagerService; - wp mEventListener; + nsRefPtr mResourceClient; + ResourceState mState; + + // Codec Resource Notification Listener + wp mListener; }; } // namespace android diff --git a/dom/media/omx/OMXCodecWrapper.cpp b/dom/media/omx/OMXCodecWrapper.cpp index d872ac425a..c19025b7a5 100644 --- a/dom/media/omx/OMXCodecWrapper.cpp +++ b/dom/media/omx/OMXCodecWrapper.cpp @@ -17,7 +17,7 @@ #include "AudioChannelFormat.h" #include "GrallocImages.h" -#include +#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 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* diff --git a/dom/media/omx/OMXCodecWrapper.h b/dom/media/omx/OMXCodecWrapper.h index 72e35e7208..4e087c20bc 100644 --- a/dom/media/omx/OMXCodecWrapper.h +++ b/dom/media/omx/OMXCodecWrapper.h @@ -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 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 mClient; - sp mManagerService; + nsRefPtr mClient; }; diff --git a/dom/media/omx/OmxDecoder.cpp b/dom/media/omx/OmxDecoder.cpp index b22647ee56..ec71232c3a 100644 --- a/dom/media/omx/OmxDecoder.cpp +++ b/dom/media/omx/OmxDecoder.cpp @@ -91,12 +91,13 @@ OmxDecoder::~OmxDecoder() mLooper->stop(); } -void OmxDecoder::statusChanged() +void OmxDecoder::codecReserved() { - sp 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 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 OmxDecoder::AllocateMediaResources() { + nsRefPtr 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 listener = this; - mVideoSource->setEventListener(listener); + sp listener = this; + mVideoSource->setListener(listener); mVideoSource->requestResource(); } } @@ -299,7 +295,8 @@ bool OmxDecoder::AllocateMediaResources() const char *audioMime = nullptr; sp 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 &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; diff --git a/dom/media/omx/OmxDecoder.h b/dom/media/omx/OmxDecoder.h index 6dfa647262..83cac84d31 100644 --- a/dom/media/omx/OmxDecoder.h +++ b/dom/media/omx/OmxDecoder.h @@ -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 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 AllocateMediaResources(); void ReleaseMediaResources(); bool SetVideoFormat(); bool SetAudioFormat(); diff --git a/dom/media/omx/RtspMediaCodecReader.cpp b/dom/media/omx/RtspMediaCodecReader.cpp index 4dbc3c3d19..35dd4844fe 100644 --- a/dom/media/omx/RtspMediaCodecReader.cpp +++ b/dom/media/omx/RtspMediaCodecReader.cpp @@ -88,20 +88,28 @@ RtspMediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe, return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe, aTimeThreshold); } -nsresult -RtspMediaCodecReader::ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) +nsRefPtr +RtspMediaCodecReader::AsyncReadMetadata() { mRtspResource->DisablePlayoutDelay(); EnsureActive(); - nsresult rv = MediaCodecReader::ReadMetadata(aInfo, aTags); + + nsRefPtr 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 diff --git a/dom/media/omx/RtspMediaCodecReader.h b/dom/media/omx/RtspMediaCodecReader.h index e5ac6eaed3..3bbf3ca162 100644 --- a/dom/media/omx/RtspMediaCodecReader.h +++ b/dom/media/omx/RtspMediaCodecReader.h @@ -58,8 +58,10 @@ public: // Disptach a DecodeAudioDataTask to decode audio data. virtual nsRefPtr RequestAudioData() override; - virtual nsresult ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) override; + virtual nsRefPtr AsyncReadMetadata() + override; + + virtual void HandleResourceAllocated() override; private: // A pointer to RtspMediaResource for calling the Rtsp specific function. diff --git a/dom/media/omx/RtspOmxReader.cpp b/dom/media/omx/RtspOmxReader.cpp index 2c21d10bc3..a2cf4e1570 100644 --- a/dom/media/omx/RtspOmxReader.cpp +++ b/dom/media/omx/RtspOmxReader.cpp @@ -81,22 +81,27 @@ void RtspOmxReader::EnsureActive() { MediaOmxReader::EnsureActive(); } -nsresult RtspOmxReader::ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags) +nsRefPtr +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 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 diff --git a/dom/media/omx/RtspOmxReader.h b/dom/media/omx/RtspOmxReader.h index 8c31b51ea8..97e6bb77af 100644 --- a/dom/media/omx/RtspOmxReader.h +++ b/dom/media/omx/RtspOmxReader.h @@ -64,8 +64,10 @@ public: virtual void SetIdle() override; - virtual nsresult ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags) - final override; + virtual nsRefPtr AsyncReadMetadata() + override; + + virtual void HandleResourceAllocated() override; private: // A pointer to RtspMediaResource for calling the Rtsp specific function. diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp deleted file mode 100644 index ae5dc2983a..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp +++ /dev/null @@ -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 - -#include -#include - -#include - -#include "IMediaResourceManagerClient.h" - -namespace android { - -enum { - STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION -}; - -class BpMediaResourceManagerClient : public BpInterface -{ -public: - BpMediaResourceManagerClient(const sp& impl) - : BpInterface(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 diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h deleted file mode 100644 index fdb0e5cc20..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h +++ /dev/null @@ -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 -#include - -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 -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp deleted file mode 100644 index 9781891214..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp +++ /dev/null @@ -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 - -#include -#include - -#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 IMediaResourceManagerDeathNotifier::sMediaResourceManagerService; -sp IMediaResourceManagerDeathNotifier::sDeathNotifier; -SortedVector< wp > IMediaResourceManagerDeathNotifier::sObitRecipients; - -// establish binder interface to MediaResourceManagerService -/*static*/const sp& -IMediaResourceManagerDeathNotifier::getMediaResourceManagerService() -{ - DN_LOGV("getMediaResourceManagerService"); - Mutex::Autolock _l(sServiceLock); - if (sMediaResourceManagerService.get() == 0) { - sp sm = defaultServiceManager(); - sp 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(binder); - } - DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?"); - return sMediaResourceManagerService; -} - -/*static*/ void -IMediaResourceManagerDeathNotifier::addObitRecipient(const wp& recipient) -{ - Mutex::Autolock _l(sServiceLock); - sObitRecipients.add(recipient); -} - -/*static*/ void -IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp& recipient) -{ - Mutex::Autolock _l(sServiceLock); - sObitRecipients.remove(recipient); -} - -void -IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp& who) -{ - DN_LOGW("media resource manager service died"); - // Need to do this with the lock held - SortedVector< wp > 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 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 diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h deleted file mode 100644 index e61377d7fb..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h +++ /dev/null @@ -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 -#include - -#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& getMediaResourceManagerService(); - -private: - IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &); - IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &); - - static void addObitRecipient(const wp& recipient); - static void removeObitRecipient(const wp& recipient); - - class DeathNotifier: public IBinder::DeathRecipient - { - public: - DeathNotifier() {} - virtual ~DeathNotifier(); - - virtual void binderDied(const wp& who); - }; - - friend class DeathNotifier; - - static Mutex sServiceLock; - static sp sMediaResourceManagerService; - static sp sDeathNotifier; - static SortedVector< wp > sObitRecipients; -}; - -}; // namespace android - -#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp deleted file mode 100644 index 371a6c6c6d..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp +++ /dev/null @@ -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 -#include - -#include -#include - -#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 -{ -public: - BpMediaResourceManagerService(const sp& impl) - : BpInterface(impl) - { - } - - virtual status_t requestMediaResource(const sp& 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& 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 client = interface_cast(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 client = interface_cast(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 diff --git a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.h b/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.h deleted file mode 100644 index 3bd8d1bbf5..0000000000 --- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.h +++ /dev/null @@ -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 -#include - -#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& 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& client, int resourceType) = 0; -}; - - -// ---------------------------------------------------------------------------- - -class BnMediaResourceManagerService : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp b/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp deleted file mode 100644 index 17371a1be9..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp +++ /dev/null @@ -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 &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 client = new MediaResourceManagerClient(this); - sp 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 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 diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h b/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h deleted file mode 100644 index f5994b5787..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h +++ /dev/null @@ -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 - -#include - -#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 &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 mListener; - - // Resource Management - Mutex mLock; - sp mClient; - sp mService; - IMediaResourceManagerService::ResourceType mType; - - bool mWaitingResource; -}; - -} // namespace android - -#endif // MEDIA_RESOURCE_HANDLER_H diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp b/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp deleted file mode 100644 index d39816c695..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp +++ /dev/null @@ -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 - -#include "MediaResourceManagerClient.h" - -namespace android { - -MediaResourceManagerClient::MediaResourceManagerClient(const wp& listener) - : mEventListener(listener) -{ -} - -void MediaResourceManagerClient::statusChanged(int event) -{ - if (mEventListener != NULL) { - sp listener = mEventListener.promote(); - if (listener != NULL) { - listener->statusChanged(event); - } - } -} - -void MediaResourceManagerClient::died() -{ - sp listener = mEventListener.promote(); - if (listener != NULL) { - listener->statusChanged(CLIENT_STATE_SHUTDOWN); - } -} - -}; // namespace android - diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.h b/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.h deleted file mode 100644 index 790d1ffe41..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.h +++ /dev/null @@ -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& listener); - - // DeathRecipient - void died(); - - // IMediaResourceManagerClient - virtual void statusChanged(int event); - -private: - wp mEventListener; -}; - -}; // namespace android - -#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp b/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp deleted file mode 100644 index e75ad5719b..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp +++ /dev/null @@ -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 - -#include -#include -#include - -#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(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& who) -{ - if (who != NULL) { - Mutex::Autolock autoLock(mLock); - sp binder = who.promote(); - if (binder != NULL) { - mResources.forgetClient(binder); - } - } -} - -status_t MediaResourceManagerService::requestMediaResource(const sp& client, - int resourceType, bool willWait) -{ - ResourceType type = static_cast(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 binder = client->asBinder(); - mResources.enqueueRequest(binder, type); - binder->linkToDeath(this); - - sp 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& client, - int resourceType) -{ - Mutex::Autolock autoLock(mLock); - - sp binder = client->asBinder(); - cancelClientLocked(binder, static_cast(resourceType)); - - sp 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& 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 &msg) -{ - Mutex::Autolock autoLock(mLock); - ResourceType type = static_cast(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 req = mResources.nextRequest(type); - mResources.aquireResource(req, type, found); - // Notify resource assignment to the client. - sp client = interface_cast(req); - client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED); - mResources.dequeueRequest(type); -} - -void MediaResourceManagerService::cancelClientLocked(const sp& 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(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& client, - ResourceType type, - size_t index) -{ - ResourceSlot* slot = resourceOfTypeAt(type, index); - return slot && slot->mClient == client; -} - -status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp& 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 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& 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& 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& 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 diff --git a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h b/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h deleted file mode 100644 index ade3f20f61..0000000000 --- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - -#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& who); - - // derived from IMediaResourceManagerService - virtual status_t requestMediaResource(const sp& client, - int resourceType, bool willWait); - virtual status_t cancelClient(const sp& client, - int resourceType); - - // Receive a message from AHandlerReflector. - // Called on ALooper thread. - void onMessageReceived(const sp &msg); - -protected: - MediaResourceManagerService(); - virtual ~MediaResourceManagerService(); - -private: - // Represent a media resouce. - // Hold a IMediaResourceManagerClient that got a media resource as IBinder. - struct ResourceSlot - { - sp mClient; - }; - typedef Vector Slots; - - typedef List > 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 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& client, ResourceType type, size_t index); - status_t aquireResource(const sp& 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 nextRequest(ResourceType type); - status_t enqueueRequest(const sp& client, ResourceType type); - status_t dequeueRequest(ResourceType type); - status_t forgetClient(const sp& client, ResourceType type); - status_t forgetClient(const sp& client); - - friend class MediaResourceManagerService; - - // A map for all types of supported resources. - ResourcesMap mMap; - }; - - void cancelClientLocked(const sp& 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 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 > mReflector; - - // The lock protects manager operations called from multiple threads. - Mutex mLock; - - // Keeps all the records. - ResourceTable mResources; -}; - -}; // namespace android - -#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H diff --git a/dom/media/omx/mediaresourcemanager/moz.build b/dom/media/omx/mediaresourcemanager/moz.build deleted file mode 100644 index 053be16319..0000000000 --- a/dom/media/omx/mediaresourcemanager/moz.build +++ /dev/null @@ -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 diff --git a/dom/media/omx/moz.build b/dom/media/omx/moz.build index 7615d3b5d0..6c11921387 100644 --- a/dom/media/omx/moz.build +++ b/dom/media/omx/moz.build @@ -94,7 +94,6 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/html', '/ipc/chromium/src', - 'mediaresourcemanager', ] CXXFLAGS += [ diff --git a/dom/media/platforms/gonk/moz.build b/dom/media/platforms/gonk/moz.build index 0cc28ed509..86c35da783 100644 --- a/dom/media/platforms/gonk/moz.build +++ b/dom/media/platforms/gonk/moz.build @@ -18,7 +18,6 @@ UNIFIED_SOURCES += [ ] LOCAL_INCLUDES += [ '/dom/media/omx/', - '/dom/media/omx/mediaresourcemanager', ] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/media/systemservices/MediaSystemResourceClient.cpp b/dom/media/systemservices/MediaSystemResourceClient.cpp new file mode 100644 index 0000000000..e1ad38aefe --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceClient.cpp @@ -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 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 diff --git a/dom/media/systemservices/MediaSystemResourceClient.h b/dom/media/systemservices/MediaSystemResourceClient.h new file mode 100644 index 0000000000..73d6e93157 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceClient.h @@ -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 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 sSerialCounter; + + friend class MediaSystemResourceManager; +}; + +} // namespace mozilla + +#endif diff --git a/dom/media/systemservices/MediaSystemResourceManager.cpp b/dom/media/systemservices/MediaSystemResourceManager.cpp new file mode 100644 index 0000000000..5493eb2c12 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManager.cpp @@ -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::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 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 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(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 diff --git a/dom/media/systemservices/MediaSystemResourceManager.h b/dom/media/systemservices/MediaSystemResourceManager.h new file mode 100644 index 0000000000..fb48b64f9d --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManager.h @@ -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 + +#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 mResourceClients; + + static StaticRefPtr sSingleton; +}; + +} // namespace mozilla + +#endif diff --git a/dom/media/systemservices/MediaSystemResourceManagerChild.cpp b/dom/media/systemservices/MediaSystemResourceManagerChild.cpp new file mode 100644 index 0000000000..2844738217 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManagerChild.cpp @@ -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 diff --git a/dom/media/systemservices/MediaSystemResourceManagerChild.h b/dom/media/systemservices/MediaSystemResourceManagerChild.h new file mode 100644 index 0000000000..57c451b936 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManagerChild.h @@ -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 diff --git a/dom/media/systemservices/MediaSystemResourceManagerParent.cpp b/dom/media/systemservices/MediaSystemResourceManagerParent.cpp new file mode 100644 index 0000000000..0029874373 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManagerParent.cpp @@ -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 diff --git a/dom/media/systemservices/MediaSystemResourceManagerParent.h b/dom/media/systemservices/MediaSystemResourceManagerParent.h new file mode 100644 index 0000000000..7ccf557b15 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceManagerParent.h @@ -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 mMediaSystemResourceService; + + nsClassHashtable mResourceRequests; +}; + +} // namespatce media +} // namespatce mozilla + +#endif diff --git a/dom/media/systemservices/MediaSystemResourceMessageUtils.h b/dom/media/systemservices/MediaSystemResourceMessageUtils.h new file mode 100644 index 0000000000..851fbb2532 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceMessageUtils.h @@ -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 + : public ContiguousEnumSerializer< + mozilla::MediaSystemResourceType, + mozilla::MediaSystemResourceType::VIDEO_DECODER, + mozilla::MediaSystemResourceType::INVALID_RESOURCE> +{}; + +} // namespace IPC + +#endif diff --git a/dom/media/systemservices/MediaSystemResourceService.cpp b/dom/media/systemservices/MediaSystemResourceService.cpp new file mode 100644 index 0000000000..d29b561150 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceService.cpp @@ -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::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(MediaSystemResourceType::VIDEO_DECODER), resource); + + resource = new MediaSystemResource(VIDEO_ENCODER_COUNT); + mResources.Put(static_cast(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(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(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& aData, + void* aClosure) +{ + ReleaseResourceData* closure = static_cast(aClosure); + + closure->mSelf->RemoveRequests(closure->mParent, static_cast(aKey)); + closure->mSelf->UpdateRequests(static_cast(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(aResourceType)); + if (!resource) { + return; + } + + std::deque::iterator it; + std::deque& acquiredRequests = + resource->mAcquiredRequests; + for (it = acquiredRequests.begin(); it != acquiredRequests.end(); it++) { + if (((*it).mParent == aParent) && ((*it).mId == aId)) { + acquiredRequests.erase(it); + return; + } + } + + std::deque& 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(aResourceType)); + + if (!resource || + resource->mResourceCount == 0) { + // Resource does not exit + return; + } + + std::deque::iterator it; + std::deque& acquiredRequests = + resource->mAcquiredRequests; + for (it = acquiredRequests.begin(); it != acquiredRequests.end();) { + if ((*it).mParent == aParent) { + it = acquiredRequests.erase(it); + } else { + it++; + } + } + + std::deque& 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(aResourceType)); + + if (!resource || + resource->mResourceCount == 0) { + // Resource does not exit + return; + } + + std::deque& acquiredRequests = + resource->mAcquiredRequests; + std::deque& 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 diff --git a/dom/media/systemservices/MediaSystemResourceService.h b/dom/media/systemservices/MediaSystemResourceService.h new file mode 100644 index 0000000000..a0d0967e7a --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceService.h @@ -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 + +#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 mWaitingRequests; + std::deque 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& aData, + void* aClosure); + + bool mDestroyed; + + nsClassHashtable mResources; + + static StaticRefPtr sSingleton; +}; + +} // namespace mozilla + +#endif diff --git a/dom/media/systemservices/MediaSystemResourceTypes.h b/dom/media/systemservices/MediaSystemResourceTypes.h new file mode 100644 index 0000000000..3257d89d29 --- /dev/null +++ b/dom/media/systemservices/MediaSystemResourceTypes.h @@ -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 diff --git a/dom/media/systemservices/PMediaSystemResourceManager.ipdl b/dom/media/systemservices/PMediaSystemResourceManager.ipdl new file mode 100644 index 0000000000..8ba5467656 --- /dev/null +++ b/dom/media/systemservices/PMediaSystemResourceManager.ipdl @@ -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 + diff --git a/dom/media/systemservices/moz.build b/dom/media/systemservices/moz.build index d8bcb24e43..8b9892cca6 100644 --- a/dom/media/systemservices/moz.build +++ b/dom/media/systemservices/moz.build @@ -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 += [ diff --git a/dom/media/webaudio/AlignedTArray.h b/dom/media/webaudio/AlignedTArray.h index f5a4ec6c3c..7631f11d22 100644 --- a/dom/media/webaudio/AlignedTArray.h +++ b/dom/media/webaudio/AlignedTArray.h @@ -14,18 +14,18 @@ * E: element type, must be a POD type. * N: N bytes alignment for the first element, defaults to 32 */ -template -class AlignedTArray_Impl : public nsTArray_Impl +template +class AlignedTArray : public nsTArray_Impl { static_assert((N & (N-1)) == 0, "N must be power of 2"); - typedef nsTArray_Impl base_type; + typedef nsTArray_Impl 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 -class AlignedTArray : public AlignedTArray_Impl -{ -public: - typedef AlignedTArray_Impl base_type; - typedef AlignedTArray 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 -class AlignedFallibleTArray : public AlignedTArray_Impl -{ -public: - typedef AlignedTArray_Impl base_type; - typedef AlignedFallibleTArray 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__ diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp index 18f90c91c0..8c3642c97c 100644 --- a/dom/media/webaudio/AnalyserNode.cpp +++ b/dom/media/webaudio/AnalyserNode.cpp @@ -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(const_cast(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(const_cast(aOutput->mChannelData[channel])); - AudioBlockInPlaceScale(samples, aOutput->mVolume); - } - nsRefPtr transfer = new TransferBuffer(aStream, *aOutput); + nsRefPtr 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 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 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 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(aChunk.mChannelData[0]), chunkDuration); - for (uint32_t i = 1; i < channelCount; ++i) { - AudioBlockAddChannelWithScale(static_cast(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(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(chunk.mChannelData[0]) + readIndex; + AudioBufferCopyWithScale(channelData, scale, dataOut, copyLength); + } + for (uint32_t i = 1; i < channelCount; ++i) { + auto channelData = + static_cast(chunk.mChannelData[i]) + readIndex; + AudioBufferAddWithScale(channelData, scale, dataOut, copyLength); + } + } + + readChunk++; + writeIndex += copyLength; } } diff --git a/dom/media/webaudio/AnalyserNode.h b/dom/media/webaudio/AnalyserNode.h index ac0da1701d..7fca5df6fe 100644 --- a/dom/media/webaudio/AnalyserNode.h +++ b/dom/media/webaudio/AnalyserNode.h @@ -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 mChunks; double mMinDecibels; double mMaxDecibels; double mSmoothingTimeConstant; - uint32_t mWriteIndex; - AlignedFallibleTArray mBuffer; - AlignedFallibleTArray mOutputBuffer; + size_t mCurrentChunk = 0; + AlignedTArray mOutputBuffer; }; } // namespace dom diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 3d0de9ac9c..a1bacd11a0 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -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; diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index df32c53e6e..782cf0422e 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -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 Image::sSerialCounter(0); +Atomic ImageContainer::sGenerationCounter(0); + already_AddRefed 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* aImages) +ImageContainer::GetCurrentImages(nsTArray* 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(aNotification.imageContainerChild()); + if (child) { + MutexAutoLock lock(child->mLock); + if (child->mImageContainer) { + child->mImageContainer->NotifyCompositeInternal(aNotification); + } + } +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index f4abbcf403..7dd89414e5 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -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 sSerialCounter; bool mSent; + + static mozilla::Atomic 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 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* aImages); + void GetCurrentImages(nsTArray* 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 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 sGenerationCounter; }; class AutoLockImage diff --git a/gfx/layers/YCbCrImageDataSerializer.cpp b/gfx/layers/YCbCrImageDataSerializer.cpp index c357e48cb1..1ba185159c 100644 --- a/gfx/layers/YCbCrImageDataSerializer.cpp +++ b/gfx/layers/YCbCrImageDataSerializer.cpp @@ -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) diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 2721696107..dbeeabfe95 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -103,7 +103,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) } if (updated) { - GetForwarder()->UseTexture(this, mBuffer); + nsAutoTArray 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 textures; + CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); + t->mTextureClient = mFront; + t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize()); + forwarder->UseTextures(this, textures); } void diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index ad380fe61f..5626de0d9e 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -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"); } diff --git a/gfx/layers/client/ClientLayerManager.h b/gfx/layers/client/ClientLayerManager.h index 239cc8f5f3..51d364d141 100644 --- a/gfx/layers/client/ClientLayerManager.h +++ b/gfx/layers/client/ClientLayerManager.h @@ -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& aMixBlendModes) override { diff --git a/gfx/layers/client/CompositableClient.cpp b/gfx/layers/client/CompositableClient.cpp index d6ea0fa202..2ebe6b1718 100644 --- a/gfx/layers/client/CompositableClient.cpp +++ b/gfx/layers/client/CompositableClient.cpp @@ -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; } diff --git a/gfx/layers/client/CompositableClient.h b/gfx/layers/client/CompositableClient.h index 1411985bfd..1a06327225 100644 --- a/gfx/layers/client/CompositableClient.h +++ b/gfx/layers/client/CompositableClient.h @@ -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(); diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 32985fb963..dd1ea80b65 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -396,7 +396,12 @@ ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw, mForwarder->UseComponentAlphaTextures(this, mTextureClient, mTextureClientOnWhite); } else { - mForwarder->UseTexture(this, mTextureClient); + nsAutoTArray 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(), diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index 2da29a38bc..134324936e 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -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 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 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(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(image); - texture = new EGLImageTextureClient(GetForwarder(), - mTextureFlags, - typedImage, - size); -#ifdef MOZ_WIDGET_ANDROID - } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { - SurfaceTextureImage* typedImage = static_cast(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 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 newBuffers; + nsAutoTArray textures; - UpdatePictureRect(image->GetPictureRect()); + for (auto& img : images) { + Image* image = img.mImage; + RefPtr 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(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(image); + texture = new EGLImageTextureClient(GetForwarder(), + mTextureFlags, + typedImage, + size); +#ifdef MOZ_WIDGET_ANDROID + } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { + SurfaceTextureImage* typedImage = static_cast(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 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(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; } diff --git a/gfx/layers/client/ImageClient.h b/gfx/layers/client/ImageClient.h index c3b7c97abf..6d5890192a 100644 --- a/gfx/layers/client/ImageClient.h +++ b/gfx/layers/client/ImageClient.h @@ -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 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 mFrontBuffer; + struct Buffer { + RefPtr mTextureClient; + int32_t mImageSerial; + }; + nsTArray 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 { diff --git a/gfx/layers/composite/CanvasLayerComposite.cpp b/gfx/layers/composite/CanvasLayerComposite.cpp index 009fa35132..ae9e988347 100644 --- a/gfx/layers/composite/CanvasLayerComposite.cpp +++ b/gfx/layers/composite/CanvasLayerComposite.cpp @@ -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(); } diff --git a/gfx/layers/composite/ColorLayerComposite.cpp b/gfx/layers/composite/ColorLayerComposite.cpp index 824803f3ba..dda537dbef 100644 --- a/gfx/layers/composite/ColorLayerComposite.cpp +++ b/gfx/layers/composite/ColorLayerComposite.cpp @@ -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); } diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 48d2a72fb2..3e77cfed4c 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -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(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& aTextures) { - if (!aTexture) { - return; - } if (GetCompositor()) { - aTexture->SetCompositor(GetCompositor()); + for (auto& texture : aTextures) { + texture.mTexture->SetCompositor(GetCompositor()); + } } } diff --git a/gfx/layers/composite/CompositableHost.h b/gfx/layers/composite/CompositableHost.h index f1f6fab0ec..7a66bd1873 100644 --- a/gfx/layers/composite/CompositableHost.h +++ b/gfx/layers/composite/CompositableHost.h @@ -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 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 mTexture; + TimeStamp mTimeStamp; + gfx::IntRect mPictureRect; + int32_t mFrameID; + int32_t mProducerID; + }; + virtual void UseTextureHost(const nsTArray& 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 diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 9f3c048db9..46ce1825a1 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -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 = aManager->GetCompositor(); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { - RefPtr surf = surface->Dump(aManager->GetCompositor()); + RefPtr 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 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)); } diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 0af885441f..68b2bb2962 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -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& 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) { diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 9ef34efa34..544236fb48 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -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& aTextures) override; virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack, TextureHost* aTextureOnWhite) override; diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp index 43d75c87c6..590187d1ca 100644 --- a/gfx/layers/composite/ImageHost.cpp +++ b/gfx/layers/composite/ImageHost.cpp @@ -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& 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 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 effect = CreateTexturedEffect(mFrontBuffer->GetFormat(), - mTextureSource.get(), - aFilter, - isAlphaPremultiplied, - GetRenderState()); + bool isAlphaPremultiplied = + !(img->mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED); + RefPtr 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 ? "
  • TextureHost: " : "TextureHost: "); - DumpTextureHost(aStream, mFrontBuffer); + DumpTextureHost(aStream, img.mFrontBuffer); aStream << (aDumpHtml ? "
" : " "); } } @@ -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 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 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 diff --git a/gfx/layers/composite/ImageHost.h b/gfx/layers/composite/ImageHost.h index 04100e7ae8..5c2c9465b2 100644 --- a/gfx/layers/composite/ImageHost.h +++ b/gfx/layers/composite/ImageHost.h @@ -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& 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 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 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; }; diff --git a/gfx/layers/composite/ImageLayerComposite.cpp b/gfx/layers/composite/ImageLayerComposite.cpp index 40fcf2e840..9d04f879fa 100644 --- a/gfx/layers/composite/ImageLayerComposite.cpp +++ b/gfx/layers/composite/ImageLayerComposite.cpp @@ -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(); } diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 0b2148c218..5e17010a22 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -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()); diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index 80988891e5..062d5afae8 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -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* aNotifications) + { + aNotifications->MoveElementsFrom(mImageCompositeNotifications); + } + private: /** Region we're clipping our current drawing to. */ nsIntRegion mClippingRegion; @@ -297,6 +318,8 @@ private: RefPtr mCompositor; UniquePtr mClonedLayerTreeProperties; + nsTArray 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 +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 originalTarget = + aCompositor->GetCurrentRenderTarget(); + + RefPtr 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 previousTarget = firstTarget; + for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) { + Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i); + RefPtr 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 diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index a096e71076..79cd7368fa 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -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* diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 1d395c0003..4b04338afb 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -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, diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index beb155ecd4..028c054c82 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -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; } diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index c57cda1891..11755b7000 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -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& aTextures) = 0; virtual void UseComponentAlphaTextures(CompositableClient* aCompositable, TextureClient* aClientOnBlack, TextureClient* aClientOnWhite) = 0; diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp index 574fff41d9..42013810b7 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -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 tex = TextureHost::AsTextureHost(op.textureParent()); - MOZ_ASSERT(tex.get()); - compositable->UseTextureHost(tex); + nsAutoTArray 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 diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 9f45e59673..9cb7eca268 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -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 notifications; + mLayerManager->ExtractImageCompositeNotifications(¬ifications); + if (!notifications.IsEmpty()) { + unused << ImageBridgeParent::NotifyImageComposites(notifications); + } + } MonitorAutoLock lock(*sIndirectLayerTreesLock); for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin(); diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 8b0b8b6b9e..d72ba0958e 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -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 OpVector; @@ -104,18 +108,25 @@ struct AutoEndTransaction { }; void -ImageBridgeChild::UseTexture(CompositableClient* aCompositable, - TextureClient* aTexture) +ImageBridgeChild::UseTextures(CompositableClient* aCompositable, + const nsTArray& aTextures) { MOZ_ASSERT(aCompositable); - MOZ_ASSERT(aTexture); MOZ_ASSERT(aCompositable->GetIPDLActor()); - MOZ_ASSERT(aTexture->GetIPDLActor()); - FenceHandle fence = aTexture->GetAcquireFenceHandle(); + nsAutoTArray 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 sImageBridgeChildSingleton; static StaticRefPtr 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 compositables; @@ -181,13 +188,17 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) InfallibleTArray 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* 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 -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 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 -ImageBridgeChild::CreateImageClientNow(CompositableType aType) +ImageBridgeChild::CreateImageClientNow(CompositableType aType, + ImageContainer* aImageContainer) { MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); + if (aImageContainer) { + SendPImageContainerConstructor(aImageContainer->GetPImageContainerChild()); + } RefPtr 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(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&& aMessages) { @@ -833,6 +914,15 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray&& aNotifications) +{ + for (auto& n : aNotifications) { + ImageContainer::NotifyComposite(n); + } + return true; +} + PTextureChild* ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, TextureFlags aFlags) diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 82f1531583..2fabdeec74 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -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&& aMessages) override; - already_AddRefed CreateImageClient(CompositableType aType); - already_AddRefed CreateImageClientNow(CompositableType aType); + virtual bool + RecvDidComposite(InfallibleTArray&& aNotifications) override; - static void DispatchReleaseImageClient(ImageClient* aClient); + already_AddRefed CreateImageClient(CompositableType aType, + ImageContainer* aImageContainer); + already_AddRefed 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& 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 { diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index e885577962..1f5f41c51e 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -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 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(mTransport)); } + nsTArray 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(aActor); + return true; +} + +PImageContainerParent* +ImageBridgeParent::AllocPImageContainerParent() +{ + return new ImageContainerParent(); +} + +bool +ImageBridgeParent::DeallocPImageContainerParent(PImageContainerParent* actor) +{ + delete actor; + return true; +} + void ImageBridgeParent::SendAsyncMessage(const InfallibleTArray& aMessage) { @@ -254,6 +307,47 @@ ImageBridgeParent::RecvChildAsyncMessages(InfallibleTArrayOtherPid() == aB.imageContainerParent()->OtherPid(); + } + bool LessThan(const ImageCompositeNotification& aA, + const ImageCompositeNotification& aB) const + { + return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid(); + } +}; + +/* static */ bool +ImageBridgeParent::NotifyImageComposites(nsTArray& 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 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; } diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index 78658d984e..bf9c9e4ebf 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -9,6 +9,7 @@ #include // for size_t #include // 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&& aMessages) override; @@ -135,6 +143,8 @@ public: static ImageBridgeParent* GetInstance(ProcessId aId); + static bool NotifyImageComposites(nsTArray& aNotifications); + // Overriden from IToplevelProtocol IToplevelProtocol* CloneToplevel(const InfallibleTArray& 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 mSelfRef; + bool mSetChildThreadPriority; + /** * Map of all living ImageBridgeParent instances */ diff --git a/gfx/layers/ipc/ImageContainerParent.cpp b/gfx/layers/ipc/ImageContainerParent.cpp new file mode 100644 index 0000000000..e343962831 --- /dev/null +++ b/gfx/layers/ipc/ImageContainerParent.cpp @@ -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; +} + +} +} diff --git a/gfx/layers/ipc/ImageContainerParent.h b/gfx/layers/ipc/ImageContainerParent.h new file mode 100644 index 0000000000..6f1e10edcc --- /dev/null +++ b/gfx/layers/ipc/ImageContainerParent.h @@ -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 mImageHosts; + +private: + virtual void ActorDestroy(ActorDestroyReason why) override {} +}; + +} // namespace layers +} // namespace mozilla + +#endif // ifndef mozilla_layers_ImageContainerParent_h diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp index 53d97d2bfb..50ff57a187 100644 --- a/gfx/layers/ipc/LayerTransactionChild.cpp +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -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 diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 967e61b5d2..e77f6fb8f4 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -583,7 +583,6 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray&& cset, if (!Attach(cast(op.layerParent()), host, true)) { return false; } - host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID()); break; } @@ -598,7 +597,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray&& 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) { diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 92260bcbd0..1987dd4a5f 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -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 { diff --git a/gfx/layers/ipc/PCompositor.ipdl b/gfx/layers/ipc/PCompositor.ipdl index ab0361beaa..eb01970da1 100644 --- a/gfx/layers/ipc/PCompositor.ipdl +++ b/gfx/layers/ipc/PCompositor.ipdl @@ -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. diff --git a/gfx/layers/ipc/PImageBridge.ipdl b/gfx/layers/ipc/PImageBridge.ipdl index 6975459283..99a4a70440 100644 --- a/gfx/layers/ipc/PImageBridge.ipdl +++ b/gfx/layers/ipc/PImageBridge.ipdl @@ -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); }; diff --git a/gfx/layers/ipc/PImageContainer.ipdl b/gfx/layers/ipc/PImageContainer.ipdl new file mode 100644 index 0000000000..7ae567a883 --- /dev/null +++ b/gfx/layers/ipc/PImageContainer.ipdl @@ -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 diff --git a/gfx/layers/ipc/ShadowLayerParent.cpp b/gfx/layers/ipc/ShadowLayerParent.cpp index f5d9f08d73..e0898715d4 100644 --- a/gfx/layers/ipc/ShadowLayerParent.cpp +++ b/gfx/layers/ipc/ShadowLayerParent.cpp @@ -25,12 +25,25 @@ ShadowLayerParent::ShadowLayerParent() : mLayer(nullptr) ShadowLayerParent::~ShadowLayerParent() { + Disconnect(); +} + +void +ShadowLayerParent::Disconnect() +{ + if (mLayer) { + mLayer->Disconnect(); + mLayer = nullptr; + } } void ShadowLayerParent::Bind(Layer* layer) { - mLayer = layer; + if (mLayer != layer) { + Disconnect(); + mLayer = layer; + } } void @@ -40,9 +53,7 @@ ShadowLayerParent::Destroy() // created, but just before the transaction in which Bind() would // have been called. In that case, we'll ignore shadow-layers // transactions from there on and never get a layer here. - if (mLayer) { - mLayer->Disconnect(); - } + Disconnect(); } ContainerLayerComposite* @@ -103,15 +114,11 @@ ShadowLayerParent::ActorDestroy(ActorDestroyReason why) case Deletion: // See comment near Destroy() above. - if (mLayer) { - mLayer->Disconnect(); - } + Disconnect(); break; case AbnormalShutdown: - if (mLayer) { - mLayer->Disconnect(); - } + Disconnect(); break; case NormalShutdown: diff --git a/gfx/layers/ipc/ShadowLayerParent.h b/gfx/layers/ipc/ShadowLayerParent.h index 01d24df730..30c7f9eb1a 100644 --- a/gfx/layers/ipc/ShadowLayerParent.h +++ b/gfx/layers/ipc/ShadowLayerParent.h @@ -48,6 +48,8 @@ public: private: virtual void ActorDestroy(ActorDestroyReason why) override; + void Disconnect(); + nsRefPtr mLayer; }; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index c4c0646dd3..81fca29b6b 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -39,8 +39,9 @@ class Shmem; namespace layers { -using namespace mozilla::ipc; +using namespace mozilla::gfx; using namespace mozilla::gl; +using namespace mozilla::ipc; class ClientTiledLayerBuffer; @@ -349,34 +350,33 @@ ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable, } void -ShadowLayerForwarder::UpdatePictureRect(CompositableClient* aCompositable, - const gfx::IntRect& aRect) +ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable, + const nsTArray& aTextures) { MOZ_ASSERT(aCompositable); MOZ_ASSERT(aCompositable->GetIPDLActor()); - mTxn->AddNoSwapPaint(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect)); -} -void -ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable, - TextureClient* aTexture) -{ - MOZ_ASSERT(aCompositable); - MOZ_ASSERT(aTexture); - MOZ_ASSERT(aCompositable->GetIPDLActor()); - MOZ_ASSERT(aTexture->GetIPDLActor()); + nsAutoTArray textures; - FenceHandle fence = aTexture->GetAcquireFenceHandle(); - mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(), - nullptr, aTexture->GetIPDLActor(), - fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()))); - if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD - && aTexture->HasInternalBuffer()) { - // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot - // race with updates on the main thread. In this case we want the transaction - // to be synchronous. - mTxn->MarkSyncTransaction(); + 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)); + if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) + && t.mTextureClient->HasInternalBuffer()) { + + // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot + // race with updates on the main thread. In this case we want the transaction + // to be synchronous. + mTxn->MarkSyncTransaction(); + } } + mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(), + textures)); } void @@ -399,10 +399,12 @@ ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositabl #ifdef MOZ_WIDGET_GONK void ShadowLayerForwarder::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 @@ -770,7 +772,8 @@ ShadowLayerForwarder::PlatformSyncBeforeUpdate() #endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS) void -ShadowLayerForwarder::Connect(CompositableClient* aCompositable) +ShadowLayerForwarder::Connect(CompositableClient* aCompositable, + ImageContainer* aImageContainer) { #ifdef GFX_COMPOSITOR_LOGGING printf("ShadowLayerForwarder::Connect(Compositable)\n"); diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index b9e676d574..b06a4071a9 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -27,6 +27,7 @@ namespace mozilla { namespace layers { class EditReply; +class ImageContainer; class Layer; class PLayerChild; class PLayerTransactionChild; @@ -123,7 +124,8 @@ public: * Setup the IPDL actor for aCompositable to be part of layers * transactions. */ - void Connect(CompositableClient* aCompositable) override; + virtual void Connect(CompositableClient* aCompositable, + ImageContainer* aImageContainer) override; virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData, TextureFlags aFlags) override; @@ -229,22 +231,17 @@ public: const nsIntRegion& aUpdatedRegion) override; /** - * Communicate the picture rect of an image to the compositor + * See CompositableForwarder::UseTextures */ - void UpdatePictureRect(CompositableClient* aCompositable, - const gfx::IntRect& aRect) override; - - /** - * See CompositableForwarder::UseTexture - */ - virtual void UseTexture(CompositableClient* aCompositable, - TextureClient* aClient) override; + virtual void UseTextures(CompositableClient* aCompositable, + const nsTArray& 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 /** diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 4b141e34a4..f047a4fd06 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -144,9 +144,11 @@ EXPORTS.mozilla.layers += [ 'ipc/FenceUtils.h', 'ipc/ImageBridgeChild.h', 'ipc/ImageBridgeParent.h', + 'ipc/ImageContainerParent.h', 'ipc/ISurfaceAllocator.h', 'ipc/LayerTransactionChild.h', 'ipc/LayerTransactionParent.h', + 'ipc/ShadowLayerChild.h', 'ipc/ShadowLayers.h', 'ipc/ShadowLayersManager.h', 'ipc/SharedBufferManagerChild.h', @@ -301,6 +303,7 @@ UNIFIED_SOURCES += [ 'ipc/FenceUtils.cpp', 'ipc/ImageBridgeChild.cpp', 'ipc/ImageBridgeParent.cpp', + 'ipc/ImageContainerParent.cpp', 'ipc/ISurfaceAllocator.cpp', 'ipc/LayerTransactionChild.cpp', 'ipc/LayerTransactionParent.cpp', @@ -362,6 +365,7 @@ IPDL_SOURCES = [ 'ipc/PCompositable.ipdl', 'ipc/PCompositor.ipdl', 'ipc/PImageBridge.ipdl', + 'ipc/PImageContainer.ipdl', 'ipc/PLayer.ipdl', 'ipc/PLayerTransaction.ipdl', 'ipc/PSharedBufferManager.ipdl', diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index dfce3c592d..820c3626c2 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -181,7 +181,7 @@ static bool CompositeAndCompare(nsRefPtr layerManager, Dr RefPtr drawTarget = CreateDT(); layerManager->BeginTransactionWithDrawTarget(drawTarget, IntRect(0, 0, gCompWidth, gCompHeight)); - layerManager->EndEmptyTransaction(); + layerManager->EndTransaction(TimeStamp::Now()); RefPtr ss = drawTarget->Snapshot(); RefPtr dss = ss->GetDataSurface(); diff --git a/hal/Hal.cpp b/hal/Hal.cpp index 5240a26a6c..316de7e69c 100644 --- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -864,6 +864,13 @@ SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority) PROXY_IF_SANDBOXED(SetCurrentThreadPriority(aThreadPriority)); } +void +SetThreadPriority(PlatformThreadId aThreadId, + hal::ThreadPriority aThreadPriority) +{ + PROXY_IF_SANDBOXED(SetThreadPriority(aThreadId, aThreadPriority)); +} + // From HalTypes.h. const char* ProcessPriorityToString(ProcessPriority aPriority) diff --git a/hal/Hal.h b/hal/Hal.h index fe63de499b..38503e544f 100644 --- a/hal/Hal.h +++ b/hal/Hal.h @@ -10,6 +10,7 @@ #include "mozilla/hal_sandbox/PHal.h" #include "mozilla/HalTypes.h" #include "base/basictypes.h" +#include "base/platform_thread.h" #include "mozilla/Observer.h" #include "mozilla/Types.h" #include "nsTArray.h" @@ -485,6 +486,14 @@ void SetProcessPriority(int aPid, */ void SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority); +/** + * Set a thread priority to appropriate platform-specific value for + * given functionality. Instead of providing arbitrary priority numbers you + * must specify a type of function like THREAD_PRIORITY_COMPOSITOR. + */ +void SetThreadPriority(PlatformThreadId aThreadId, + hal::ThreadPriority aThreadPriority); + /** * Register an observer for the FM radio. */ diff --git a/hal/fallback/FallbackThreadPriority.cpp b/hal/fallback/FallbackThreadPriority.cpp index e548169f0e..dce5dfa82c 100644 --- a/hal/fallback/FallbackThreadPriority.cpp +++ b/hal/fallback/FallbackThreadPriority.cpp @@ -17,5 +17,13 @@ SetCurrentThreadPriority(ThreadPriority aPriority) ThreadPriorityToString(aPriority)); } +void +SetThreadPriority(PlatformThreadId aThreadId, + ThreadPriority aPriority) +{ + HAL_LOG("FallbackThreadPriority - SetThreadPriority(%d, %d)\n", + aThreadId, ThreadPriorityToString(aPriority)); +} + } // namespace hal_impl } // namespace mozilla diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 6e4f923371..973e3f070a 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -1860,7 +1860,7 @@ EnsureThreadPriorityPrefs(ThreadPriorityPrefs* prefs) } static void -SetThreadPriority(pid_t aTid, hal::ThreadPriority aThreadPriority) +DoSetThreadPriority(pid_t aTid, hal::ThreadPriority aThreadPriority) { // See bug 999115, we can only read preferences on the main thread otherwise // we create a race condition in HAL @@ -1911,7 +1911,7 @@ public: NS_IMETHOD Run() { NS_ASSERTION(NS_IsMainThread(), "Can only set thread priorities on main thread"); - hal_impl::SetThreadPriority(mThreadId, mThreadPriority); + hal_impl::DoSetThreadPriority(mThreadId, mThreadPriority); return NS_OK; } @@ -1924,12 +1924,19 @@ private: void SetCurrentThreadPriority(ThreadPriority aThreadPriority) +{ + pid_t threadId = gettid(); + hal_impl::SetThreadPriority(threadId, aThreadPriority); +} + +void +SetThreadPriority(PlatformThreadId aThreadId, + ThreadPriority aThreadPriority) { switch (aThreadPriority) { case THREAD_PRIORITY_COMPOSITOR: { - pid_t threadId = gettid(); nsCOMPtr runnable = - new SetThreadPriorityRunnable(threadId, aThreadPriority); + new SetThreadPriorityRunnable(aThreadId, aThreadPriority); NS_DispatchToMainThread(runnable); break; } diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index 1485ae5642..ba7fb88e9e 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -355,6 +355,13 @@ SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) void SetCurrentThreadPriority(ThreadPriority aThreadPriority) +{ + NS_RUNTIMEABORT("Setting current thread priority cannot be called from sandboxed contexts."); +} + +void +SetThreadPriority(PlatformThreadId aThreadId, + ThreadPriority aThreadPriority) { NS_RUNTIMEABORT("Setting thread priority cannot be called from sandboxed contexts."); } diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index a8165d892c..5f3a37fb6f 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2943,6 +2943,18 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, ? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent()) : aBuilder->GetCurrentScrollParentId()); DisplayListClipState::AutoSaveRestore clipState(aBuilder); + if (!mIsRoot || !usingDisplayport) { + nsRect clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter); + nscoord radii[8]; + bool haveRadii = mOuter->GetPaddingBoxBorderRadii(radii); + // Our override of GetBorderRadii ensures we never have a radius at + // the corners where we have a scrollbar. + if (mClipAllDescendants) { + clipState.ClipContentDescendants(clip, haveRadii ? radii : nullptr); + } else { + clipState.ClipContainingBlockDescendants(clip, haveRadii ? radii : nullptr); + } + } if (usingDisplayport) { // Capture the clip state of the parent scroll frame. This will be saved @@ -2963,17 +2975,6 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, // the entire displayport, but it lets the compositor know to // clip to the scroll port after compositing. clipState.Clear(); - } else { - nsRect clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter); - nscoord radii[8]; - bool haveRadii = mOuter->GetPaddingBoxBorderRadii(radii); - // Our override of GetBorderRadii ensures we never have a radius at - // the corners where we have a scrollbar. - if (mClipAllDescendants) { - clipState.ClipContentDescendants(clip, haveRadii ? radii : nullptr); - } else { - clipState.ClipContainingBlockDescendants(clip, haveRadii ? radii : nullptr); - } } aBuilder->StoreDirtyRectForScrolledContents(mOuter, dirtyRect); diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h index 693f9d9a85..6b32138c77 100644 --- a/layout/ipc/RenderFrameParent.h +++ b/layout/ipc/RenderFrameParent.h @@ -26,7 +26,6 @@ class InputEvent; namespace layers { class APZCTreeManager; class TargetConfig; -class LayerTransactionParent; struct TextureFactoryIdentifier; struct ScrollableLayerGuid; } // namespace layers @@ -42,7 +41,6 @@ class RenderFrameParent : public PRenderFrameParent typedef mozilla::layers::Layer Layer; typedef mozilla::layers::LayerManager LayerManager; typedef mozilla::layers::TargetConfig TargetConfig; - typedef mozilla::layers::LayerTransactionParent LayerTransactionParent; typedef mozilla::ContainerLayerParameters ContainerLayerParameters; typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier; typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 60589ad681..4facd7af95 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -68,7 +68,6 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ - '/dom/media/omx/mediaresourcemanager', '/dom/system/android', '/gfx/skia/skia/include/config', '/gfx/skia/skia/include/core', diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.h b/widget/gonk/nativewindow/FakeSurfaceComposer.h index 9f6bab654b..ab98656cb9 100644 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.h +++ b/widget/gonk/nativewindow/FakeSurfaceComposer.h @@ -42,7 +42,7 @@ public: return "FakeSurfaceComposer"; } - // Instantiate MediaResourceManagerService and register to service manager. + // Instantiate FakeSurfaceComposer and register to service manager. // If service manager is not present, wait until service manager becomes present. static void instantiate(); diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp index f9f0f64559..d9db7fe836 100644 --- a/widget/gonk/nsAppShell.cpp +++ b/widget/gonk/nsAppShell.cpp @@ -34,10 +34,8 @@ #include "base/basictypes.h" #include "GonkPermission.h" +#include "libdisplay/BootAnimation.h" #include "nscore.h" -#ifdef MOZ_OMX_DECODER -#include "MediaResourceManagerService.h" -#endif #include "mozilla/TouchEvents.h" #include "mozilla/FileUtils.h" #include "mozilla/Hal.h" @@ -49,6 +47,7 @@ #include "nativewindow/FakeSurfaceComposer.h" #endif #include "nsAppShell.h" +#include "mozilla/DebugOnly.h" #include "mozilla/dom/Touch.h" #include "nsGkAtoms.h" #include "nsIObserverService.h" @@ -578,7 +577,7 @@ GeckoInputReaderPolicy::setDisplayInfo() nsRefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); uint32_t rotation = nsIScreen::ROTATION_0_DEG; - nsresult rv = screen->GetRotation(&rotation); + DebugOnly rv = screen->GetRotation(&rotation); MOZ_ASSERT(NS_SUCCEEDED(rv)); nsIntRect screenBounds = screen->GetNaturalBounds(); @@ -888,9 +887,6 @@ nsAppShell::Init() printf("*** This is stdout. Most of the useful output will be in logcat.\n"); printf("***\n"); printf("*****************************************************************\n"); -#ifdef MOZ_OMX_DECODER - android::MediaResourceManagerService::instantiate(); -#endif #if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA)) android::FakeSurfaceComposer::instantiate(); #endif @@ -935,6 +931,10 @@ nsAppShell::Observe(nsISupports* aSubject, updateHeadphoneSwitch(); } mEnableDraw = true; + + // System is almost booting up. Stop the bootAnim now. + StopBootAnimation(); + NotifyEvent(); return NS_OK; } diff --git a/xpcom/glue/nsTArray-inl.h b/xpcom/glue/nsTArray-inl.h index 33e70a0420..79a686beaa 100644 --- a/xpcom/glue/nsTArray-inl.h +++ b/xpcom/glue/nsTArray-inl.h @@ -108,6 +108,22 @@ nsTArray_base::UsesAutoArrayBuffer() const bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity, size_t aElemSize); +template +template +typename ActualAlloc::ResultTypeProxy +nsTArray_base::ExtendCapacity(size_type aLength, + size_type aCount, + size_type aElemSize) +{ + mozilla::CheckedInt newLength = aLength; + newLength += aCount; + + if (!newLength.isValid()) { + return ActualAlloc::FailureResult(); + } + return this->EnsureCapacity(newLength.value(), aElemSize); +} + template template typename ActualAlloc::ResultTypeProxy @@ -275,26 +291,23 @@ nsTArray_base::ShiftData(index_type aStart, template template -bool +typename ActualAlloc::ResultTypeProxy nsTArray_base::InsertSlotsAt(index_type aIndex, size_type aCount, size_type aElemSize, size_t aElemAlign) { MOZ_ASSERT(aIndex <= Length(), "Bogus insertion index"); - size_type newLen = Length() + aCount; - EnsureCapacity(newLen, aElemSize); - // Check for out of memory conditions - if (Capacity() < newLen) { - return false; + if (!ActualAlloc::Successful(this->ExtendCapacity(Length(), aCount, aElemSize))) { + return ActualAlloc::FailureResult(); } // Move the existing elements as needed. Note that this will // change our mLength, so no need to call IncrementLength. ShiftData(aIndex, 0, aCount, aElemSize, aElemAlign); - return true; + return ActualAlloc::SuccessResult(); } // nsTArray_base::IsAutoArrayRestorer is an RAII class which takes @@ -418,15 +431,8 @@ nsTArray_base::SwapArrayElements(nsTArray_basemLength = aOther.Length(); - } - if (aOther.mHdr != EmptyHdr()) { - aOther.mHdr->mLength = tempLength; - } + mHdr->mLength = aOther.Length(); + aOther.mHdr->mLength = tempLength; return ActualAlloc::SuccessResult(); } diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index a17855dd05..5881976588 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -13,6 +13,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BinarySearch.h" #include "mozilla/fallible.h" +#include "mozilla/CheckedInt.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" @@ -386,6 +387,17 @@ protected: typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity, size_type aElemSize); + // Extend the storage to accommodate aCount extra elements. + // @param aLength The current size of the array. + // @param aCount The number of elements to add. + // @param aElemSize The size of an array element. + // @return False if insufficient memory is available or the new length + // would overflow; true otherwise. + template + typename ActualAlloc::ResultTypeProxy ExtendCapacity(size_type aLength, + size_type aCount, + size_type aElemSize); + // Tries to resize the storage to the minimum required amount. If this fails, // the array is left as-is. // @param aElemSize The size of an array element. @@ -427,8 +439,9 @@ protected: // @param aElementSize the size of an array element. // @param aElemAlign the alignment in bytes of an array element. template - bool InsertSlotsAt(index_type aIndex, size_type aCount, - size_type aElementSize, size_t aElemAlign); + typename ActualAlloc::ResultTypeProxy + InsertSlotsAt(index_type aIndex, size_type aCount, + size_type aElementSize, size_t aElemAlign); template typename ActualAlloc::ResultTypeProxy @@ -884,7 +897,9 @@ public: // @param aOther The array object to copy. self_type& operator=(const self_type& aOther) { - ReplaceElementsAt(0, Length(), aOther.Elements(), aOther.Length()); + if (this != &aOther) { + ReplaceElementsAt(0, Length(), aOther.Elements(), aOther.Length()); + } return *this; } @@ -893,8 +908,10 @@ public: // @param other The array object to move from. self_type& operator=(self_type&& aOther) { - Clear(); - SwapElements(aOther); + if (this != &aOther) { + Clear(); + SwapElements(aOther); + } return *this; } @@ -1368,6 +1385,7 @@ protected: template elem_type* InsertElementAt(index_type aIndex) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + 1, sizeof(elem_type)))) { return nullptr; @@ -1391,6 +1409,7 @@ protected: template elem_type* InsertElementAt(index_type aIndex, Item&& aItem) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( Length() + 1, sizeof(elem_type)))) { return nullptr; @@ -1497,8 +1516,8 @@ protected: template elem_type* AppendElements(const Item* aArray, size_type aArrayLen) { - if (!ActualAlloc::Successful(this->template EnsureCapacity( - Length() + aArrayLen, sizeof(elem_type)))) { + if (!ActualAlloc::Successful(this->template ExtendCapacity( + Length(), aArrayLen, sizeof(elem_type)))) { return nullptr; } index_type len = Length(); @@ -1538,8 +1557,9 @@ protected: template elem_type* AppendElement(Item&& aItem) { + // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK. if (!ActualAlloc::Successful(this->template EnsureCapacity( - Length() + 1, sizeof(elem_type)))) { + Length() + 1, sizeof(elem_type)))) { return nullptr; } elem_type* elem = Elements() + Length(); @@ -1563,8 +1583,8 @@ public: protected: template elem_type* AppendElements(size_type aCount) { - if (!ActualAlloc::Successful(this->template EnsureCapacity( - Length() + aCount, sizeof(elem_type)))) { + if (!ActualAlloc::Successful(this->template ExtendCapacity( + Length(), aCount, sizeof(elem_type)))) { return nullptr; } elem_type* elems = Elements() + Length(); @@ -1808,9 +1828,8 @@ protected: template elem_type* InsertElementsAt(index_type aIndex, size_type aCount) { - if (!base_type::template InsertSlotsAt(aIndex, aCount, - sizeof(elem_type), - MOZ_ALIGNOF(elem_type))) { + if (!ActualAlloc::Successful(this->template InsertSlotsAt( + aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) { return nullptr; } @@ -1844,9 +1863,8 @@ protected: elem_type* InsertElementsAt(index_type aIndex, size_type aCount, const Item& aItem) { - if (!base_type::template InsertSlotsAt(aIndex, aCount, - sizeof(elem_type), - MOZ_ALIGNOF(elem_type))) { + if (!ActualAlloc::Successful(this->template InsertSlotsAt( + aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) { return nullptr; }