From 117b384e5ea73689b02264424911b0848be47962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 27 Jun 2007 11:29:20 +0000 Subject: [PATCH] * Implemented the overlay suspend/resume protocol on mode changes; not really tested yet. Also, BBitmap::LockBits() should probably fail when the Bits() are NULL. * The downside is that many more classes now know of each other. * Cleaned up the work divided between the BitmapManager and the Overlay class. * Fixed a memory leak in AS_CREATE_BITMAP in case the bitmap could not be added to the ServerApp's bitmap list. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21512 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/BitmapManager.cpp | 116 +++++++++++++++++++++++----- src/servers/app/BitmapManager.h | 6 +- src/servers/app/ServerApp.cpp | 8 +- src/servers/app/ServerBitmap.cpp | 41 +++++++--- src/servers/app/ServerBitmap.h | 10 ++- src/servers/app/ServerScreen.cpp | 17 ++-- src/servers/app/drawing/Overlay.cpp | 113 ++++++++++++++++++++++++--- src/servers/app/drawing/Overlay.h | 15 +++- 8 files changed, 273 insertions(+), 53 deletions(-) diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index d7a357a623..7c1f2dbae4 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006, Haiku. + * Copyright 2001-2007, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -19,15 +19,19 @@ #include "ClientMemoryAllocator.h" #include "HWInterface.h" #include "Overlay.h" +#include "ServerApp.h" #include "ServerBitmap.h" #include "ServerProtocol.h" #include "ServerTokenSpace.h" #include +#include #include +#include #include #include +#include #include #include @@ -36,11 +40,18 @@ using std::nothrow; -//! The bitmap allocator for the server. Memory is allocated/freed by the AppServer class +//! The one and only bitmap manager for the server, created by the AppServer BitmapManager *gBitmapManager = NULL; -//! Number of bytes to allocate to each area used for bitmap storage -#define BITMAP_AREA_SIZE B_PAGE_SIZE * 16 + +int +compare_app_pointer(const ServerApp* a, const ServerApp* b) +{ + return (addr_t)b - (addr_t)b; +} + + +// #pragma mark - //! Sets up stuff to be ready to allocate space for bitmaps @@ -77,9 +88,9 @@ BitmapManager::~BitmapManager() \return A new ServerBitmap or NULL if unable to allocate one. */ ServerBitmap* -BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInterface, - BRect bounds, color_space space, int32 flags, int32 bytesPerRow, screen_id screen, - uint8* _allocationFlags) +BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, + HWInterface& hwInterface, BRect bounds, color_space space, int32 flags, + int32 bytesPerRow, screen_id screen, uint8* _allocationFlags) { BAutolock locker(fLock); @@ -100,7 +111,8 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt } } - ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags, bytesPerRow); + ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags, + bytesPerRow); if (bitmap == NULL) { if (overlayToken != NULL) hwInterface.ReleaseOverlayChannel(overlayToken); @@ -112,7 +124,8 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt uint8* buffer = NULL; if (flags & B_BITMAP_WILL_OVERLAY) { - Overlay* overlay = new (std::nothrow) Overlay(hwInterface); + Overlay* overlay = new (std::nothrow) Overlay(hwInterface, bitmap, + overlayToken); const overlay_buffer* overlayBuffer = NULL; overlay_client_data* clientData = NULL; @@ -123,25 +136,20 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt // and buffer location to the BBitmap cookie = allocator->Allocate(sizeof(overlay_client_data), (void**)&clientData, newArea); - if (cookie != NULL) { - overlayBuffer = hwInterface.AllocateOverlayBuffer(bitmap->Width(), - bitmap->Height(), space); - } } - if (overlayBuffer != NULL) { - overlay->SetOverlayData(overlayBuffer, overlayToken, clientData); + if (cookie != NULL) { + overlay->SetClientData(clientData); bitmap->fAllocator = allocator; bitmap->fAllocationCookie = cookie; bitmap->SetOverlay(overlay); bitmap->fBytesPerRow = overlayBuffer->bytes_per_row; - buffer = (uint8*)overlayBuffer->buffer; + buffer = (uint8*)overlay->OverlayBuffer()->buffer; if (_allocationFlags) *_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0); } else { - hwInterface.ReleaseOverlayChannel(overlayToken); delete overlay; allocator->Free(cookie); } @@ -168,7 +176,17 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt } } - if (buffer && fBitmapList.AddItem(bitmap)) { + bool success = false; + if (buffer != NULL) { + success = fBitmapList.AddItem(bitmap); + if (success && bitmap->Overlay() != NULL) { + success = fOverlays.AddItem(bitmap); + if (!success) + fBitmapList.RemoveItem(bitmap); + } + } + + if (success) { bitmap->fBuffer = buffer; bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap); @@ -207,6 +225,68 @@ BitmapManager::DeleteBitmap(ServerBitmap* bitmap) if (!locker.IsLocked()) return; + if (bitmap->Overlay() != NULL) + fOverlays.AddItem(bitmap); + if (fBitmapList.RemoveItem(bitmap)) delete bitmap; } + + +void +BitmapManager::SuspendOverlays() +{ + BAutolock locker(fLock); + if (!locker.IsLocked()) + return; + + // first, tell all applications owning an overlay to release their locks + + BObjectList apps; + for (int32 i = 0; i < fOverlays.CountItems(); i++) { + ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i); + apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer); + } + for (int32 i = 0; i < apps.CountItems(); i++) { + BMessage notify(B_RELEASE_OVERLAY_LOCK); + apps.ItemAt(i)->SendMessageToClient(¬ify); + } + + // suspend overlays + + for (int32 i = 0; i < fOverlays.CountItems(); i++) { + ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i); + bitmap->Overlay()->Suspend(bitmap, false); + } +} + + +void +BitmapManager::ResumeOverlays() +{ + BAutolock locker(fLock); + if (!locker.IsLocked()) + return; + + // first, tell all applications owning an overlay that + // they can reacquire their locks + + BObjectList apps; + for (int32 i = 0; i < fOverlays.CountItems(); i++) { + ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i); + apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer); + } + for (int32 i = 0; i < apps.CountItems(); i++) { + BMessage notify(B_RELEASE_OVERLAY_LOCK); + apps.ItemAt(i)->SendMessageToClient(¬ify); + } + + // resume overlays + + for (int32 i = 0; i < fOverlays.CountItems(); i++) { + ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i); + + bitmap->Overlay()->Resume(bitmap); + } +} + diff --git a/src/servers/app/BitmapManager.h b/src/servers/app/BitmapManager.h index 62e0000da0..4b94cb9e29 100644 --- a/src/servers/app/BitmapManager.h +++ b/src/servers/app/BitmapManager.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006, Haiku. + * Copyright 2001-2007, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -31,8 +31,12 @@ class BitmapManager { uint8* _allocationFlags = NULL); void DeleteBitmap(ServerBitmap* bitmap); + void SuspendOverlays(); + void ResumeOverlays(); + protected: BList fBitmapList; + BList fOverlays; BLocker fLock; }; diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index c50214ff19..dd6fab462e 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -624,6 +624,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) Signature(), frame.Width() + 1, frame.Height() + 1)); if (bitmap != NULL && fBitmapList.AddItem(bitmap)) { + bitmap->SetOwner(this); + fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); fLink.Attach(allocationFlags); @@ -633,8 +635,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (allocationFlags & kFramebuffer) fLink.Attach(bitmap->BytesPerRow()); - } else + } else { + if (bitmap != NULL) + gBitmapManager->DeleteBitmap(bitmap); + fLink.StartMessage(B_NO_MEMORY); + } fLink.Flush(); break; diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp index 87aca3752c..80fe6e3c91 100644 --- a/src/servers/app/ServerBitmap.cpp +++ b/src/servers/app/ServerBitmap.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006, Haiku. + * Copyright 2001-2007, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -68,7 +68,8 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, fBytesPerRow(0), fSpace(space), fFlags(flags), - fBitsPerPixel(0) + fBitsPerPixel(0), + fOwner(NULL) // fToken is initialized (if used) by the BitmapManager { _HandleSpace(space, bytesPerRow); @@ -76,7 +77,7 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, //! Copy constructor does not copy the buffer. -ServerBitmap::ServerBitmap(const ServerBitmap* bmp) +ServerBitmap::ServerBitmap(const ServerBitmap* bitmap) : fAllocator(NULL), fAllocationCookie(NULL), @@ -84,13 +85,14 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bmp) fBuffer(NULL), fReferenceCount(1) { - if (bmp) { - fWidth = bmp->fWidth; - fHeight = bmp->fHeight; - fBytesPerRow = bmp->fBytesPerRow; - fSpace = bmp->fSpace; - fFlags = bmp->fFlags; - fBitsPerPixel = bmp->fBitsPerPixel; + if (bitmap) { + fWidth = bitmap->fWidth; + fHeight = bitmap->fHeight; + fBytesPerRow = bitmap->fBytesPerRow; + fSpace = bitmap->fSpace; + fFlags = bitmap->fFlags; + fBitsPerPixel = bitmap->fBitsPerPixel; + fOwner = bitmap->fOwner; } else { fWidth = 0; fHeight = 0; @@ -98,6 +100,7 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bmp) fSpace = B_NO_COLOR_SPACE; fFlags = 0; fBitsPerPixel = 0; + fOwner = NULL; } } @@ -305,9 +308,9 @@ ServerBitmap::AreaOffset() const void -ServerBitmap::SetOverlay(::Overlay* cookie) +ServerBitmap::SetOverlay(::Overlay* overlay) { - fOverlay = cookie; + fOverlay = overlay; } @@ -318,6 +321,20 @@ ServerBitmap::Overlay() const } +void +ServerBitmap::SetOwner(ServerApp* owner) +{ + fOwner = owner; +} + + +ServerApp* +ServerBitmap::Owner() const +{ + return fOwner; +} + + void ServerBitmap::PrintToStream() { diff --git a/src/servers/app/ServerBitmap.h b/src/servers/app/ServerBitmap.h index ee2a527374..9ea5478edc 100644 --- a/src/servers/app/ServerBitmap.h +++ b/src/servers/app/ServerBitmap.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006, Haiku. + * Copyright 2001-2007, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -20,6 +20,7 @@ class BitmapManager; class ClientMemoryAllocator; class HWInterface; class Overlay; +class ServerApp; /*! @@ -66,9 +67,12 @@ class ServerBitmap { area_id Area() const; uint32 AreaOffset() const; - void SetOverlay(::Overlay* cookie); + void SetOverlay(::Overlay* overlay); ::Overlay* Overlay() const; + void SetOwner(ServerApp* owner); + ServerApp* Owner() const; + //! Does a shallow copy of the bitmap passed to it inline void ShallowCopy(const ServerBitmap *from); @@ -116,6 +120,8 @@ protected: color_space fSpace; int32 fFlags; int fBitsPerPixel; + + ServerApp* fOwner; int32 fToken; }; diff --git a/src/servers/app/ServerScreen.cpp b/src/servers/app/ServerScreen.cpp index 2dbbbd0d31..14e5ecc675 100644 --- a/src/servers/app/ServerScreen.cpp +++ b/src/servers/app/ServerScreen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2006, Haiku, Inc. + * Copyright (c) 2001-2007, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -9,6 +9,12 @@ */ +#include "ServerScreen.h" + +#include "BitmapManager.h" +#include "DrawingEngine.h" +#include "HWInterface.h" + #include #include #include @@ -16,11 +22,6 @@ #include #include -#include "DrawingEngine.h" -#include "HWInterface.h" - -#include "ServerScreen.h" - static float get_mode_frequency(const display_mode& mode) @@ -87,9 +88,13 @@ Screen::Shutdown() status_t Screen::SetMode(display_mode mode, bool makeDefault) { + gBitmapManager->SuspendOverlays(); + status_t status = fHWInterface->SetMode(mode); // any attached DrawingEngines will be notified + gBitmapManager->ResumeOverlays(); + if (status >= B_OK) fIsDefault = makeDefault; diff --git a/src/servers/app/drawing/Overlay.cpp b/src/servers/app/drawing/Overlay.cpp index fe6f024dfe..5159216a27 100644 --- a/src/servers/app/drawing/Overlay.cpp +++ b/src/servers/app/drawing/Overlay.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. + * Copyright 2006-2007, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -7,15 +7,54 @@ */ -#include "HWInterface.h" #include "Overlay.h" +#include "HWInterface.h" +#include "ServerBitmap.h" + #include #include -Overlay::Overlay(HWInterface& interface) +const static bigtime_t kOverlayTimeout = 1000000LL; + // after 1 second, the team holding the lock will be killed + +class SemaphoreLocker { + public: + SemaphoreLocker(sem_id semaphore, + bigtime_t timeout = B_INFINITE_TIMEOUT) + : fSemaphore(semaphore) + { + do { + fStatus = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, + timeout); + } while (fStatus == B_INTERRUPTED); + } + + ~SemaphoreLocker() + { + if (fStatus == B_OK) + release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE); + } + + status_t + LockStatus() + { + return fStatus; + } + + private: + sem_id fSemaphore; + status_t fStatus; +}; + + +// #pragma mark - + + +Overlay::Overlay(HWInterface& interface, ServerBitmap* bitmap, + overlay_token token) : fHWInterface(interface), fOverlayBuffer(NULL), @@ -32,13 +71,15 @@ Overlay::Overlay(HWInterface& interface) fWindow.offset_bottom = 0; fWindow.flags = B_OVERLAY_COLOR_KEY; + + _AllocateBuffer(bitmap); } Overlay::~Overlay() { fHWInterface.ReleaseOverlayChannel(fOverlayToken); - fHWInterface.FreeOverlayBuffer(fOverlayBuffer); + _FreeBuffer(); delete_sem(fSemaphore); } @@ -47,17 +88,71 @@ Overlay::~Overlay() status_t Overlay::InitCheck() const { - return fSemaphore >= B_OK ? B_OK : fSemaphore; + if (fSemaphore < B_OK) + return fSemaphore; + + if (fOverlayBuffer == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +status_t +Overlay::Resume(ServerBitmap* bitmap) +{ + SemaphoreLocker locker(fSemaphore, kOverlayTimeout); + if (locker.LockStatus() == B_TIMED_OUT) { + // TODO: kill app! + } + + status_t status = _AllocateBuffer(bitmap); + if (status < B_OK) + return status; + + fClientData->buffer = (uint8*)fOverlayBuffer->buffer; + return B_OK; +} + + +status_t +Overlay::Suspend(ServerBitmap* bitmap, bool needTemporary) +{ + SemaphoreLocker locker(fSemaphore, kOverlayTimeout); + if (locker.LockStatus() == B_TIMED_OUT) { + // TODO: kill app! + } + + _FreeBuffer(); + fClientData->buffer = NULL; + + return B_OK; } void -Overlay::SetOverlayData(const overlay_buffer* overlayBuffer, - overlay_token token, overlay_client_data* clientData) +Overlay::_FreeBuffer() { - fOverlayBuffer = overlayBuffer; - fOverlayToken = token; + fHWInterface.FreeOverlayBuffer(fOverlayBuffer); + fOverlayBuffer = NULL; +} + +status_t +Overlay::_AllocateBuffer(ServerBitmap* bitmap) +{ + fOverlayBuffer = fHWInterface.AllocateOverlayBuffer(bitmap->Width(), + bitmap->Height(), bitmap->ColorSpace()); + if (fOverlayBuffer == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +void +Overlay::SetClientData(overlay_client_data* clientData) +{ fClientData = clientData; fClientData->lock = fSemaphore; fClientData->buffer = (uint8*)fOverlayBuffer->buffer; diff --git a/src/servers/app/drawing/Overlay.h b/src/servers/app/drawing/Overlay.h index 9152e0dbc4..16d99f0ffa 100644 --- a/src/servers/app/drawing/Overlay.h +++ b/src/servers/app/drawing/Overlay.h @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. + * Copyright 2006-2007, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -15,18 +15,22 @@ class HWInterface; +class ServerBitmap; struct overlay_client_data; class Overlay { public: - Overlay(HWInterface& interface); + Overlay(HWInterface& interface, ServerBitmap* bitmap, + overlay_token token); ~Overlay(); status_t InitCheck() const; - void SetOverlayData(const overlay_buffer* overlayBuffer, - overlay_token token, overlay_client_data* clientData); + status_t Suspend(ServerBitmap* bitmap, bool needTemporary); + status_t Resume(ServerBitmap* bitmap); + + void SetClientData(overlay_client_data* clientData); void SetFlags(uint32 flags); void TakeOverToken(Overlay* other); @@ -51,6 +55,9 @@ class Overlay { void Hide(); private: + void _FreeBuffer(); + status_t _AllocateBuffer(ServerBitmap* bitmap); + HWInterface& fHWInterface; const overlay_buffer* fOverlayBuffer; overlay_client_data* fClientData;