added 1 changeset to branch 'refs/remotes/looncraz-github/ScreenStream' old head: ae3ce3190da12590acfaee7ef0d8b7dfcdb0e320 new head: 3b9c31af129f241563a843427f274d21d68adb96 overview: https://github.com/looncraz/haiku/compare/ae3ce3190da1...3b9c31af129f ---------------------------------------------------------------------------- 3b9c31af129f: Locking, Update Batching Add locking on the UpdateStream lifecycle in HWInterface Add bounds limiting to UpdateStream (BScreenStream to come) Have updates spool together in a single BRegion for up to 8888us so we aren't iterating through a (growing) list of UpdateStreams Still need to handle the case of premature application death, otherwise we will end up with stray UpdateStreams, with up to te BRegions allocated, and two merges per frame @ 60hz. Wasteful. Also, experiencing random crashes, but always in malloc(). Not always in my call chain, either. Only happens if a non-empty BRegion is being sent over a ServerLink, so there may be an issue there. More testing to come tomorrow. [ looncraz <looncraz@xxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: 3b9c31af129f241563a843427f274d21d68adb96 Author: looncraz <looncraz@xxxxxxxxxxxx> Date: Sat Mar 28 05:42:36 2015 UTC ---------------------------------------------------------------------------- 4 files changed, 120 insertions(+), 31 deletions(-) src/servers/app/drawing/HWInterface.cpp | 64 ++++++++++++++++++++++------ src/servers/app/drawing/HWInterface.h | 6 ++- src/servers/app/drawing/UpdateStream.cpp | 60 ++++++++++++++++++++------ src/servers/app/drawing/UpdateStream.h | 21 ++++++--- ---------------------------------------------------------------------------- diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index 0f63e41..4c57983 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -59,6 +59,7 @@ HWInterface::HWInterface(bool doubleBuffered, bool enableUpdateQueue) fUpdateExecutor(NULL), fListeners(20), fUpdateStreams(5), + fLastUpdateBatch(system_time()), fNextUpdateStreamID(1) { SetAsyncDoubleBuffered(doubleBuffered && enableUpdateQueue); @@ -346,9 +347,17 @@ HWInterface::IsDoubleBuffered() const UpdateStream* HWInterface::CreateUpdateStream() { - UpdateStream* stream - = new(std::nothrow) UpdateStream(fNextUpdateStreamID++); - fUpdateStreams.AddItem(stream); + LockExclusiveAccess(); + UpdateStream* stream = NULL; + + if (DrawingBuffer() != NULL) + stream = new(std::nothrow) UpdateStream(fNextUpdateStreamID++, + DrawingBuffer()->Bounds(), &fRegionPool); + + if (stream != NULL) + fUpdateStreams.AddItem(stream); + + UnlockExclusiveAccess(); return stream; } @@ -359,25 +368,32 @@ HWInterface::DeleteUpdateStream(UpdateStream* stream) if (stream == NULL) return B_BAD_VALUE; + status_t error = B_BAD_INDEX; + + LockExclusiveAccess(); if (fUpdateStreams.RemoveItem(stream)) { delete stream; - return B_OK; + error = B_OK; } + UnlockExclusiveAccess(); - return B_ERROR; + return error; } UpdateStream* HWInterface::FindUpdateStream(uint32 clientID) { + LockParallelAccess(); UpdateStream* stream = NULL; for (int index = 0; index < fUpdateStreams.CountItems(); ++index) { stream = (UpdateStream*)fUpdateStreams.ItemAt(index); - if (stream->ID() == clientID) + if (stream->ID() == clientID) { + UnlockParallelAccess(); return stream; + } } - + UnlockParallelAccess(); return NULL; } @@ -432,11 +448,16 @@ HWInterface::CopyBackToFront(const BRect& frame) RenderingBuffer* frontBuffer = FrontBuffer(); RenderingBuffer* backBuffer = BackBuffer(); - if (!backBuffer || !frontBuffer) + IntRect area(frame); + + if (!backBuffer || !frontBuffer) { + if (area.IsValid()) + _NotifyUpdateStreams(area); + return B_NO_INIT; + } // we need to mess with the area, but it is const - IntRect area(frame); IntRect bufferClip(backBuffer->Bounds()); if (area.IsValid() && area.Intersects(bufferClip)) { @@ -457,6 +478,7 @@ HWInterface::CopyBackToFront(const BRect& frame) if (cursorLocked) fFloatingOverlaysLock.Unlock(); + _NotifyUpdateStreams(area); return B_OK; } return B_BAD_VALUE; @@ -477,19 +499,26 @@ HWInterface::_CopyBackToFront(/*const*/ BRegion& region) // offset to left top pixel in source buffer (always B_RGBA32) uint8* srcOffset = src + r.top * srcBPR + r.left * 4; _CopyToFront(srcOffset, srcBPR, r.left, r.top, r.right, r.bottom); - _NotifyUpdateStreams(r); } } void -HWInterface::_NotifyUpdateStreams(const clipping_rect& frame) -{ +HWInterface::_NotifyUpdateStreams(const IntRect& frame) +{ // only called while already locked + if (system_time() - fLastUpdateBatch < 8888) { + fUpdateBatchRegion.Include((clipping_rect)frame); + return; + } + + fLastUpdateBatch = system_time(); UpdateStream* stream = NULL; for (int index = 0; index < fUpdateStreams.CountItems(); ++index) { stream = (UpdateStream*)fUpdateStreams.ItemAt(index); - stream->Include(frame); + stream->Include(fUpdateBatchRegion); } + + fUpdateBatchRegion.MakeEmpty(); } @@ -1147,6 +1176,15 @@ HWInterface::_AdoptDragBitmap(const ServerBitmap* bitmap, const BPoint& offset) void HWInterface::_NotifyFrameBufferChanged() { + if (DrawingBuffer() != NULL) { + UpdateStream* stream = NULL; + IntRect frame = DrawingBuffer()->Bounds(); + for (int index = 0; index < fUpdateStreams.CountItems(); ++index) { + stream = (UpdateStream*)fUpdateStreams.ItemAt(index); + stream->SetFrame(frame); + } + } + BList listeners(fListeners); int32 count = listeners.CountItems(); for (int32 i = 0; i < count; i++) { diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index d405298..7f7142c 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -20,6 +20,7 @@ #include "IntRect.h" #include "MultiLocker.h" +#include "RegionPool.h" #include "ServerCursor.h" @@ -172,7 +173,7 @@ public: protected: virtual void _CopyBackToFront(/*const*/ BRegion& region); - virtual void _NotifyUpdateStreams(const clipping_rect& frame); + virtual void _NotifyUpdateStreams(const IntRect& frame); public: // TODO: Just a quick and primitive way to get single buffered mode working. @@ -269,7 +270,10 @@ private: BList fListeners; BList fUpdateStreams; + BRegion fUpdateBatchRegion; + bigtime_t fLastUpdateBatch; uint32 fNextUpdateStreamID; + RegionPool fRegionPool; }; #endif // HW_INTERFACE_H diff --git a/src/servers/app/drawing/UpdateStream.cpp b/src/servers/app/drawing/UpdateStream.cpp index 42b7a75..d11b636 100644 --- a/src/servers/app/drawing/UpdateStream.cpp +++ b/src/servers/app/drawing/UpdateStream.cpp @@ -15,35 +15,58 @@ */ -UpdateStream::UpdateStream(uint32 id) +UpdateStream::UpdateStream(uint32 id, const IntRect& frame, + RegionPool* regionPool) : - fID(id) - {} + fID(id), + fRegion(regionPool->GetRegion()), + fMaskRegion(NULL), + fFrame(regionPool->GetRegion()), + fRegionPool(regionPool) + { + fFrame->Set((clipping_rect&)frame); + } UpdateStream::~UpdateStream() -{} +{ + fRegionPool->Recycle(fRegion); + fRegionPool->Recycle(fFrame); + + if (fMaskRegion != NULL) + fRegionPool->Recycle(fMaskRegion); +} void UpdateStream::Include(const clipping_rect& frame) { - fRegion.Include(frame); + fRegion->Include(frame); +} + + +void +UpdateStream::Include(const BRegion& region) +{ + fRegion->Include(®ion); } void UpdateStream::MakeEmpty() { - fRegion.MakeEmpty(); + fRegion->MakeEmpty(); } const BRegion& UpdateStream::GetRegion() const { - fRegion.Exclude(&fMaskRegion); - return fRegion; + if (fMaskRegion != NULL) + fRegion->Exclude(fMaskRegion); + + fRegion->IntersectWith(fFrame); + return *fRegion; } @@ -60,28 +83,41 @@ UpdateStream::ID() const void UpdateStream::SetMaskRegion(const BRegion& mask) { - fMaskRegion = mask; + if (fMaskRegion == NULL) + fMaskRegion = fRegionPool->GetRegion(); + + *fMaskRegion = mask; } void UpdateStream::UnsetMaskRegion() { - fMaskRegion.MakeEmpty(); + if (fMaskRegion) { + fMaskRegion->MakeEmpty(); + fRegionPool->Recycle(fMaskRegion); + fMaskRegion = NULL; + } } -BRegion& +BRegion* UpdateStream::GetMaskRegion() { return fMaskRegion; } -const BRegion& +const BRegion* UpdateStream::GetMaskRegion() const { return fMaskRegion; } +void +UpdateStream::SetFrame(const IntRect& frame) +{ + fFrame->Set((clipping_rect&)frame); +} + diff --git a/src/servers/app/drawing/UpdateStream.h b/src/servers/app/drawing/UpdateStream.h index d37dcd1..b020b0a 100644 --- a/src/servers/app/drawing/UpdateStream.h +++ b/src/servers/app/drawing/UpdateStream.h @@ -6,12 +6,18 @@ #include <OS.h> +#include "IntRect.h" +#include "RegionPool.h" + + class UpdateStream { public: - UpdateStream(uint32 id); + UpdateStream(uint32 id, const IntRect& frame, + RegionPool* regionPool); ~UpdateStream(); void Include(const clipping_rect& frame); + void Include(const BRegion& region); void MakeEmpty(); const BRegion& GetRegion() const; @@ -20,13 +26,18 @@ public: void SetMaskRegion(const BRegion& mask); void UnsetMaskRegion(); - BRegion& GetMaskRegion(); - const BRegion& GetMaskRegion() const; + BRegion* GetMaskRegion(); + const BRegion* GetMaskRegion() const; + + void SetFrame(const IntRect& frame); private: uint32 fID; - mutable BRegion fRegion; - BRegion fMaskRegion; + mutable BRegion* fRegion; + BRegion* fMaskRegion; + BRegion* fFrame; + + RegionPool* fRegionPool; };