* 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
This commit is contained in:
Axel Dörfler 2007-06-27 11:29:20 +00:00
parent c57ff65839
commit 117b384e5e
8 changed files with 273 additions and 53 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2006, Haiku. * Copyright 2001-2007, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -19,15 +19,19 @@
#include "ClientMemoryAllocator.h" #include "ClientMemoryAllocator.h"
#include "HWInterface.h" #include "HWInterface.h"
#include "Overlay.h" #include "Overlay.h"
#include "ServerApp.h"
#include "ServerBitmap.h" #include "ServerBitmap.h"
#include "ServerProtocol.h" #include "ServerProtocol.h"
#include "ServerTokenSpace.h" #include "ServerTokenSpace.h"
#include <BitmapPrivate.h> #include <BitmapPrivate.h>
#include <ObjectList.h>
#include <video_overlay.h> #include <video_overlay.h>
#include <AppDefs.h>
#include <Autolock.h> #include <Autolock.h>
#include <Bitmap.h> #include <Bitmap.h>
#include <Message.h>
#include <new> #include <new>
#include <stdio.h> #include <stdio.h>
@ -36,11 +40,18 @@
using std::nothrow; 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; 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 //! 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. \return A new ServerBitmap or NULL if unable to allocate one.
*/ */
ServerBitmap* ServerBitmap*
BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInterface, BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
BRect bounds, color_space space, int32 flags, int32 bytesPerRow, screen_id screen, HWInterface& hwInterface, BRect bounds, color_space space, int32 flags,
uint8* _allocationFlags) int32 bytesPerRow, screen_id screen, uint8* _allocationFlags)
{ {
BAutolock locker(fLock); 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 (bitmap == NULL) {
if (overlayToken != NULL) if (overlayToken != NULL)
hwInterface.ReleaseOverlayChannel(overlayToken); hwInterface.ReleaseOverlayChannel(overlayToken);
@ -112,7 +124,8 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt
uint8* buffer = NULL; uint8* buffer = NULL;
if (flags & B_BITMAP_WILL_OVERLAY) { 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; const overlay_buffer* overlayBuffer = NULL;
overlay_client_data* clientData = NULL; overlay_client_data* clientData = NULL;
@ -123,25 +136,20 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInt
// and buffer location to the BBitmap // and buffer location to the BBitmap
cookie = allocator->Allocate(sizeof(overlay_client_data), cookie = allocator->Allocate(sizeof(overlay_client_data),
(void**)&clientData, newArea); (void**)&clientData, newArea);
if (cookie != NULL) {
overlayBuffer = hwInterface.AllocateOverlayBuffer(bitmap->Width(),
bitmap->Height(), space);
}
} }
if (overlayBuffer != NULL) { if (cookie != NULL) {
overlay->SetOverlayData(overlayBuffer, overlayToken, clientData); overlay->SetClientData(clientData);
bitmap->fAllocator = allocator; bitmap->fAllocator = allocator;
bitmap->fAllocationCookie = cookie; bitmap->fAllocationCookie = cookie;
bitmap->SetOverlay(overlay); bitmap->SetOverlay(overlay);
bitmap->fBytesPerRow = overlayBuffer->bytes_per_row; bitmap->fBytesPerRow = overlayBuffer->bytes_per_row;
buffer = (uint8*)overlayBuffer->buffer; buffer = (uint8*)overlay->OverlayBuffer()->buffer;
if (_allocationFlags) if (_allocationFlags)
*_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0); *_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0);
} else { } else {
hwInterface.ReleaseOverlayChannel(overlayToken);
delete overlay; delete overlay;
allocator->Free(cookie); 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->fBuffer = buffer;
bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap); bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
@ -207,6 +225,68 @@ BitmapManager::DeleteBitmap(ServerBitmap* bitmap)
if (!locker.IsLocked()) if (!locker.IsLocked())
return; return;
if (bitmap->Overlay() != NULL)
fOverlays.AddItem(bitmap);
if (fBitmapList.RemoveItem(bitmap)) if (fBitmapList.RemoveItem(bitmap))
delete 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<ServerApp> 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(&notify);
}
// 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<ServerApp> 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(&notify);
}
// resume overlays
for (int32 i = 0; i < fOverlays.CountItems(); i++) {
ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
bitmap->Overlay()->Resume(bitmap);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2006, Haiku. * Copyright 2001-2007, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -31,8 +31,12 @@ class BitmapManager {
uint8* _allocationFlags = NULL); uint8* _allocationFlags = NULL);
void DeleteBitmap(ServerBitmap* bitmap); void DeleteBitmap(ServerBitmap* bitmap);
void SuspendOverlays();
void ResumeOverlays();
protected: protected:
BList fBitmapList; BList fBitmapList;
BList fOverlays;
BLocker fLock; BLocker fLock;
}; };

View File

@ -624,6 +624,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
Signature(), frame.Width() + 1, frame.Height() + 1)); Signature(), frame.Width() + 1, frame.Height() + 1));
if (bitmap != NULL && fBitmapList.AddItem(bitmap)) { if (bitmap != NULL && fBitmapList.AddItem(bitmap)) {
bitmap->SetOwner(this);
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
fLink.Attach<int32>(bitmap->Token()); fLink.Attach<int32>(bitmap->Token());
fLink.Attach<uint8>(allocationFlags); fLink.Attach<uint8>(allocationFlags);
@ -633,8 +635,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
if (allocationFlags & kFramebuffer) if (allocationFlags & kFramebuffer)
fLink.Attach<int32>(bitmap->BytesPerRow()); fLink.Attach<int32>(bitmap->BytesPerRow());
} else } else {
if (bitmap != NULL)
gBitmapManager->DeleteBitmap(bitmap);
fLink.StartMessage(B_NO_MEMORY); fLink.StartMessage(B_NO_MEMORY);
}
fLink.Flush(); fLink.Flush();
break; break;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2006, Haiku. * Copyright 2001-2007, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -68,7 +68,8 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space,
fBytesPerRow(0), fBytesPerRow(0),
fSpace(space), fSpace(space),
fFlags(flags), fFlags(flags),
fBitsPerPixel(0) fBitsPerPixel(0),
fOwner(NULL)
// fToken is initialized (if used) by the BitmapManager // fToken is initialized (if used) by the BitmapManager
{ {
_HandleSpace(space, bytesPerRow); _HandleSpace(space, bytesPerRow);
@ -76,7 +77,7 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space,
//! Copy constructor does not copy the buffer. //! Copy constructor does not copy the buffer.
ServerBitmap::ServerBitmap(const ServerBitmap* bmp) ServerBitmap::ServerBitmap(const ServerBitmap* bitmap)
: :
fAllocator(NULL), fAllocator(NULL),
fAllocationCookie(NULL), fAllocationCookie(NULL),
@ -84,13 +85,14 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bmp)
fBuffer(NULL), fBuffer(NULL),
fReferenceCount(1) fReferenceCount(1)
{ {
if (bmp) { if (bitmap) {
fWidth = bmp->fWidth; fWidth = bitmap->fWidth;
fHeight = bmp->fHeight; fHeight = bitmap->fHeight;
fBytesPerRow = bmp->fBytesPerRow; fBytesPerRow = bitmap->fBytesPerRow;
fSpace = bmp->fSpace; fSpace = bitmap->fSpace;
fFlags = bmp->fFlags; fFlags = bitmap->fFlags;
fBitsPerPixel = bmp->fBitsPerPixel; fBitsPerPixel = bitmap->fBitsPerPixel;
fOwner = bitmap->fOwner;
} else { } else {
fWidth = 0; fWidth = 0;
fHeight = 0; fHeight = 0;
@ -98,6 +100,7 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bmp)
fSpace = B_NO_COLOR_SPACE; fSpace = B_NO_COLOR_SPACE;
fFlags = 0; fFlags = 0;
fBitsPerPixel = 0; fBitsPerPixel = 0;
fOwner = NULL;
} }
} }
@ -305,9 +308,9 @@ ServerBitmap::AreaOffset() const
void 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 void
ServerBitmap::PrintToStream() ServerBitmap::PrintToStream()
{ {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2006, Haiku. * Copyright 2001-2007, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -20,6 +20,7 @@ class BitmapManager;
class ClientMemoryAllocator; class ClientMemoryAllocator;
class HWInterface; class HWInterface;
class Overlay; class Overlay;
class ServerApp;
/*! /*!
@ -66,9 +67,12 @@ class ServerBitmap {
area_id Area() const; area_id Area() const;
uint32 AreaOffset() const; uint32 AreaOffset() const;
void SetOverlay(::Overlay* cookie); void SetOverlay(::Overlay* overlay);
::Overlay* Overlay() const; ::Overlay* Overlay() const;
void SetOwner(ServerApp* owner);
ServerApp* Owner() const;
//! Does a shallow copy of the bitmap passed to it //! Does a shallow copy of the bitmap passed to it
inline void ShallowCopy(const ServerBitmap *from); inline void ShallowCopy(const ServerBitmap *from);
@ -116,6 +120,8 @@ protected:
color_space fSpace; color_space fSpace;
int32 fFlags; int32 fFlags;
int fBitsPerPixel; int fBitsPerPixel;
ServerApp* fOwner;
int32 fToken; int32 fToken;
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2006, Haiku, Inc. * Copyright (c) 2001-2007, Haiku, Inc.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Authors: * Authors:
@ -9,6 +9,12 @@
*/ */
#include "ServerScreen.h"
#include "BitmapManager.h"
#include "DrawingEngine.h"
#include "HWInterface.h"
#include <Accelerant.h> #include <Accelerant.h>
#include <Point.h> #include <Point.h>
#include <GraphicsDefs.h> #include <GraphicsDefs.h>
@ -16,11 +22,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "DrawingEngine.h"
#include "HWInterface.h"
#include "ServerScreen.h"
static float static float
get_mode_frequency(const display_mode& mode) get_mode_frequency(const display_mode& mode)
@ -87,9 +88,13 @@ Screen::Shutdown()
status_t status_t
Screen::SetMode(display_mode mode, bool makeDefault) Screen::SetMode(display_mode mode, bool makeDefault)
{ {
gBitmapManager->SuspendOverlays();
status_t status = fHWInterface->SetMode(mode); status_t status = fHWInterface->SetMode(mode);
// any attached DrawingEngines will be notified // any attached DrawingEngines will be notified
gBitmapManager->ResumeOverlays();
if (status >= B_OK) if (status >= B_OK)
fIsDefault = makeDefault; fIsDefault = makeDefault;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. * Copyright 2006-2007, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -7,15 +7,54 @@
*/ */
#include "HWInterface.h"
#include "Overlay.h" #include "Overlay.h"
#include "HWInterface.h"
#include "ServerBitmap.h"
#include <BitmapPrivate.h> #include <BitmapPrivate.h>
#include <InterfaceDefs.h> #include <InterfaceDefs.h>
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), fHWInterface(interface),
fOverlayBuffer(NULL), fOverlayBuffer(NULL),
@ -32,13 +71,15 @@ Overlay::Overlay(HWInterface& interface)
fWindow.offset_bottom = 0; fWindow.offset_bottom = 0;
fWindow.flags = B_OVERLAY_COLOR_KEY; fWindow.flags = B_OVERLAY_COLOR_KEY;
_AllocateBuffer(bitmap);
} }
Overlay::~Overlay() Overlay::~Overlay()
{ {
fHWInterface.ReleaseOverlayChannel(fOverlayToken); fHWInterface.ReleaseOverlayChannel(fOverlayToken);
fHWInterface.FreeOverlayBuffer(fOverlayBuffer); _FreeBuffer();
delete_sem(fSemaphore); delete_sem(fSemaphore);
} }
@ -47,17 +88,71 @@ Overlay::~Overlay()
status_t status_t
Overlay::InitCheck() const 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 void
Overlay::SetOverlayData(const overlay_buffer* overlayBuffer, Overlay::_FreeBuffer()
overlay_token token, overlay_client_data* clientData)
{ {
fOverlayBuffer = overlayBuffer; fHWInterface.FreeOverlayBuffer(fOverlayBuffer);
fOverlayToken = token; 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 = clientData;
fClientData->lock = fSemaphore; fClientData->lock = fSemaphore;
fClientData->buffer = (uint8*)fOverlayBuffer->buffer; fClientData->buffer = (uint8*)fOverlayBuffer->buffer;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. * Copyright 2006-2007, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -15,18 +15,22 @@
class HWInterface; class HWInterface;
class ServerBitmap;
struct overlay_client_data; struct overlay_client_data;
class Overlay { class Overlay {
public: public:
Overlay(HWInterface& interface); Overlay(HWInterface& interface, ServerBitmap* bitmap,
overlay_token token);
~Overlay(); ~Overlay();
status_t InitCheck() const; status_t InitCheck() const;
void SetOverlayData(const overlay_buffer* overlayBuffer, status_t Suspend(ServerBitmap* bitmap, bool needTemporary);
overlay_token token, overlay_client_data* clientData); status_t Resume(ServerBitmap* bitmap);
void SetClientData(overlay_client_data* clientData);
void SetFlags(uint32 flags); void SetFlags(uint32 flags);
void TakeOverToken(Overlay* other); void TakeOverToken(Overlay* other);
@ -51,6 +55,9 @@ class Overlay {
void Hide(); void Hide();
private: private:
void _FreeBuffer();
status_t _AllocateBuffer(ServerBitmap* bitmap);
HWInterface& fHWInterface; HWInterface& fHWInterface;
const overlay_buffer* fOverlayBuffer; const overlay_buffer* fOverlayBuffer;
overlay_client_data* fClientData; overlay_client_data* fClientData;