* 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.
*
* 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 <BitmapPrivate.h>
#include <ObjectList.h>
#include <video_overlay.h>
#include <AppDefs.h>
#include <Autolock.h>
#include <Bitmap.h>
#include <Message.h>
#include <new>
#include <stdio.h>
@ -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<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.
*
* 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;
};

View File

@ -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<int32>(bitmap->Token());
fLink.Attach<uint8>(allocationFlags);
@ -633,8 +635,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
if (allocationFlags & kFramebuffer)
fLink.Attach<int32>(bitmap->BytesPerRow());
} else
} else {
if (bitmap != NULL)
gBitmapManager->DeleteBitmap(bitmap);
fLink.StartMessage(B_NO_MEMORY);
}
fLink.Flush();
break;

View File

@ -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()
{

View File

@ -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;
};

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.
*
* Authors:
@ -9,6 +9,12 @@
*/
#include "ServerScreen.h"
#include "BitmapManager.h"
#include "DrawingEngine.h"
#include "HWInterface.h"
#include <Accelerant.h>
#include <Point.h>
#include <GraphicsDefs.h>
@ -16,11 +22,6 @@
#include <stdlib.h>
#include <stdio.h>
#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;

View File

@ -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 <BitmapPrivate.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),
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;

View File

@ -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;