Make it possible to reconnect BBitmap to the app_server.

* maintain a list of all BBitmaps
* refactor the client memory allocator class, its possible now to just clone existing client area
This commit is contained in:
czeidler 2012-01-22 14:52:46 +13:00
parent 04209cdd81
commit 577f58763b
9 changed files with 298 additions and 112 deletions

View File

@ -110,10 +110,12 @@ public:
BBitmap& operator=(const BBitmap& source); BBitmap& operator=(const BBitmap& source);
class Private;
private: private:
friend class BView; friend class BView;
friend class BApplication; friend class BApplication;
friend class BPrivate::BPrivateScreen; friend class BPrivate::BPrivateScreen;
friend class Private;
virtual status_t Perform(perform_code d, void* arg); virtual status_t Perform(perform_code d, void* arg);
virtual void _ReservedBitmap1(); virtual void _ReservedBitmap1();
@ -127,6 +129,8 @@ private:
void _CleanUp(); void _CleanUp();
void _AssertPointer(); void _AssertPointer();
void _ReconnectToAppServer();
private: private:
uint8* fBasePointer; uint8* fBasePointer;
int32 fSize; int32 fSize;

View File

@ -6,6 +6,7 @@
#define _BITMAP_PRIVATE_H #define _BITMAP_PRIVATE_H
#include <Bitmap.h>
#include <OS.h> #include <OS.h>
@ -16,4 +17,16 @@ struct overlay_client_data {
uint8* buffer; uint8* buffer;
}; };
void reconnect_bitmaps_to_app_server();
class BBitmap::Private {
public:
Private(BBitmap* bitmap);
void ReconnectToAppServer();
private:
BBitmap* fBitmap;
};
#endif // _BITMAP_PRIVATE_H #endif // _BITMAP_PRIVATE_H

View File

@ -32,6 +32,8 @@
#include <ApplicationPrivate.h> #include <ApplicationPrivate.h>
#include <AppServerLink.h> #include <AppServerLink.h>
#include <Autolock.h>
#include <ObjectList.h>
#include <ServerMemoryAllocator.h> #include <ServerMemoryAllocator.h>
#include <ServerProtocol.h> #include <ServerProtocol.h>
@ -42,6 +44,35 @@
using namespace BPrivate; using namespace BPrivate;
static BObjectList<BBitmap> sBitmapList;
static BLocker sBitmapListLock;
void
reconnect_bitmaps_to_app_server()
{
BAutolock _(sBitmapListLock);
for (int32 i = 0; i < sBitmapList.CountItems(); i++) {
BBitmap::Private bitmap(sBitmapList.ItemAt(i));
bitmap.ReconnectToAppServer();
}
}
BBitmap::Private::Private(BBitmap* bitmap)
:
fBitmap(bitmap)
{
}
void
BBitmap::Private::ReconnectToAppServer()
{
fBitmap->_ReconnectToAppServer();
}
/*! \brief Returns the number of bytes per row needed to store the actual /*! \brief Returns the number of bytes per row needed to store the actual
bitmap data (not including any padding) given a color space and a bitmap data (not including any padding) given a color space and a
row width. row width.
@ -1087,6 +1118,9 @@ BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags,
fAreaOffset = -1; fAreaOffset = -1;
// NOTE: why not "0" in case of error? // NOTE: why not "0" in case of error?
fFlags = flags; fFlags = flags;
} else {
BAutolock _(sBitmapListLock);
sBitmapList.AddItem(this);
} }
} }
fWindow = NULL; fWindow = NULL;
@ -1157,6 +1191,9 @@ BBitmap::_CleanUp()
fArea = -1; fArea = -1;
fServerToken = -1; fServerToken = -1;
fAreaOffset = -1; fAreaOffset = -1;
BAutolock _(sBitmapListLock);
sBitmapList.RemoveItem(this);
} }
fBasePointer = NULL; fBasePointer = NULL;
} }
@ -1174,3 +1211,27 @@ BBitmap::_AssertPointer()
} }
} }
void
BBitmap::_ReconnectToAppServer()
{
BPrivate::AppServerLink link;
link.StartMessage(AS_RECONNECT_BITMAP);
link.Attach<BRect>(fBounds);
link.Attach<color_space>(fColorSpace);
link.Attach<uint32>(fFlags);
link.Attach<int32>(fBytesPerRow);
link.Attach<int32>(0);
link.Attach<int32>(fArea);
link.Attach<int32>(fAreaOffset);
status_t error;
if (link.FlushWithReply(error) == B_OK && error == B_OK) {
// server side success
// Get token
link.Read<int32>(&fServerToken);
link.Read<area_id>(&fServerArea);
}
}

View File

@ -68,14 +68,8 @@ BitmapManager::BitmapManager()
BitmapManager::~BitmapManager() BitmapManager::~BitmapManager()
{ {
int32 count = fBitmapList.CountItems(); int32 count = fBitmapList.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++)
if (ServerBitmap* bitmap = (ServerBitmap*)fBitmapList.ItemAt(i)) { delete (ServerBitmap*)fBitmapList.ItemAt(i);
if (bitmap->AllocationCookie() != NULL)
debugger("We're not supposed to keep our cookies...");
delete bitmap;
}
}
} }
@ -94,7 +88,6 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
int32 bytesPerRow, int32 screen, uint8* _allocationFlags) int32 bytesPerRow, int32 screen, uint8* _allocationFlags)
{ {
BAutolock locker(fLock); BAutolock locker(fLock);
if (!locker.IsLocked()) if (!locker.IsLocked())
return NULL; return NULL;
@ -112,7 +105,7 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
} }
} }
ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags, ServerBitmap* bitmap = new(std::nothrow) ServerBitmap(bounds, space, flags,
bytesPerRow); bytesPerRow);
if (bitmap == NULL) { if (bitmap == NULL) {
if (overlayToken != NULL) if (overlayToken != NULL)
@ -121,11 +114,10 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
return NULL; return NULL;
} }
void* cookie = NULL;
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, bitmap, Overlay* overlay = new(std::nothrow) Overlay(hwInterface, bitmap,
overlayToken); overlayToken);
overlay_client_data* clientData = NULL; overlay_client_data* clientData = NULL;
@ -134,32 +126,29 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
if (overlay != NULL && overlay->InitCheck() == B_OK) { if (overlay != NULL && overlay->InitCheck() == B_OK) {
// allocate client memory to communicate the overlay semaphore // allocate client memory to communicate the overlay semaphore
// and buffer location to the BBitmap // and buffer location to the BBitmap
cookie = allocator->Allocate(sizeof(overlay_client_data), clientData = (overlay_client_data*)bitmap->fClientMemory.Allocate(
(void**)&clientData, newArea); allocator, sizeof(overlay_client_data), newArea);
} }
if (cookie != NULL) { if (clientData != NULL) {
overlay->SetClientData(clientData); overlay->SetClientData(clientData);
bitmap->fAllocator = allocator; bitmap->fMemory = &bitmap->fClientMemory;
bitmap->fAllocationCookie = cookie;
bitmap->SetOverlay(overlay); bitmap->SetOverlay(overlay);
bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row; bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row;
buffer = (uint8*)overlay->OverlayBuffer()->buffer; buffer = (uint8*)overlay->OverlayBuffer()->buffer;
if (_allocationFlags) if (_allocationFlags)
*_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0); *_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0);
} else { } else
delete overlay; delete overlay;
allocator->Free(cookie);
}
} else if (allocator != NULL) { } else if (allocator != NULL) {
// standard bitmaps // standard bitmaps
bool newArea; bool newArea;
cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea); buffer = (uint8*)bitmap->fClientMemory.Allocate(allocator,
if (cookie != NULL) { bitmap->BitsLength(), newArea);
bitmap->fAllocator = allocator; if (buffer != NULL) {
bitmap->fAllocationCookie = cookie; bitmap->fMemory = &bitmap->fClientMemory;
if (_allocationFlags) if (_allocationFlags)
*_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0); *_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0);
@ -168,8 +157,7 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
// server side only bitmaps // server side only bitmaps
buffer = (uint8*)malloc(bitmap->BitsLength()); buffer = (uint8*)malloc(bitmap->BitsLength());
if (buffer != NULL) { if (buffer != NULL) {
bitmap->fAllocator = NULL; bitmap->fMemory = NULL;
bitmap->fAllocationCookie = NULL;
if (_allocationFlags) if (_allocationFlags)
*_allocationFlags = kHeap; *_allocationFlags = kHeap;
@ -202,6 +190,37 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
} }
ServerBitmap*
BitmapManager::CloneFromClient(area_id clientArea, int32 areaOffset,
BRect bounds, color_space space, uint32 flags, int32 bytesPerRow)
{
BAutolock locker(fLock);
if (!locker.IsLocked())
return NULL;
ServerBitmap* bitmap = new(std::nothrow) ServerBitmap(bounds, space, flags,
bytesPerRow);
if (bitmap == NULL)
return NULL;
ClonedAreaMemory* memory = new(std::nothrow) ClonedAreaMemory;
if (memory == NULL) {
delete bitmap;
return NULL;
}
int8* buffer = (int8*)memory->Clone(clientArea, areaOffset);
if (buffer == NULL) {
delete bitmap;
delete memory;
return NULL;
}
bitmap->fMemory = memory;
bitmap->fBuffer = memory->Address();
bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
return bitmap;
}
/*! \brief Called when a ServerBitmap is deleted. /*! \brief Called when a ServerBitmap is deleted.
*/ */
void void

View File

@ -33,6 +33,11 @@ public:
int32 screen = B_MAIN_SCREEN_ID.id, int32 screen = B_MAIN_SCREEN_ID.id,
uint8* _allocationFlags = NULL); uint8* _allocationFlags = NULL);
ServerBitmap* CloneFromClient(area_id clientArea,
int32 areaOffset, BRect bounds,
color_space space, uint32 flags,
int32 bytesPerRow = -1);
void BitmapRemoved(ServerBitmap* bitmap); void BitmapRemoved(ServerBitmap* bitmap);
void SuspendOverlays(); void SuspendOverlays();

View File

@ -35,8 +35,7 @@ typedef chunk_list::Iterator chunk_iterator;
ClientMemoryAllocator::ClientMemoryAllocator(ServerApp* application) ClientMemoryAllocator::ClientMemoryAllocator(ServerApp* application)
: :
fApplication(application), fApplication(application)
fLock("client memory lock")
{ {
} }
@ -64,15 +63,8 @@ ClientMemoryAllocator::~ClientMemoryAllocator()
} }
status_t
ClientMemoryAllocator::InitCheck()
{
return fLock.InitCheck() < B_OK ? fLock.InitCheck() : B_OK;
}
void* void*
ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea) ClientMemoryAllocator::Allocate(size_t size, block** _address, bool& newArea)
{ {
// Search best matching free block from the list // Search best matching free block from the list
@ -100,8 +92,8 @@ ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea)
if (best->size == size) { if (best->size == size) {
// The simple case: the free block has exactly the size we wanted to have // The simple case: the free block has exactly the size we wanted to have
fFreeBlocks.Remove(best); fFreeBlocks.Remove(best);
*_address = best->base; *_address = best;
return best; return best->base;
} }
// TODO: maybe we should have the user reserve memory in its object // TODO: maybe we should have the user reserve memory in its object
@ -118,19 +110,17 @@ ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea)
best->base += size; best->base += size;
best->size -= size; best->size -= size;
*_address = usedBlock->base; *_address = usedBlock;
return usedBlock; return usedBlock->base;
} }
void void
ClientMemoryAllocator::Free(void* cookie) ClientMemoryAllocator::Free(block* freeBlock)
{ {
if (cookie == NULL) if (freeBlock == NULL)
return; return;
struct block* freeBlock = (struct block*)cookie;
// search for an adjacent free block // search for an adjacent free block
block_iterator iterator = fFreeBlocks.GetIterator(); block_iterator iterator = fFreeBlocks.GetIterator();
@ -185,49 +175,9 @@ ClientMemoryAllocator::Free(void* cookie)
} }
area_id
ClientMemoryAllocator::Area(void* cookie)
{
struct block* block = (struct block*)cookie;
if (block != NULL)
return block->chunk->area;
return B_ERROR;
}
uint32
ClientMemoryAllocator::AreaOffset(void* cookie)
{
struct block* block = (struct block*)cookie;
if (block != NULL)
return block->base - block->chunk->base;
return 0;
}
bool
ClientMemoryAllocator::Lock()
{
return fLock.ReadLock();
}
void
ClientMemoryAllocator::Unlock()
{
fLock.ReadUnlock();
}
void void
ClientMemoryAllocator::Dump() ClientMemoryAllocator::Dump()
{ {
AutoReadLocker locker(fLock);
debug_printf("Application %ld, %s: chunks:\n", fApplication->ClientTeam(), debug_printf("Application %ld, %s: chunks:\n", fApplication->ClientTeam(),
fApplication->Signature()); fApplication->Signature());
@ -333,3 +283,101 @@ ClientMemoryAllocator::_AllocateChunk(size_t size, bool& newArea)
return block; return block;
} }
ClientMemory::ClientMemory()
:
fBlock(NULL)
{
}
ClientMemory::~ClientMemory()
{
if (fBlock != NULL)
fAllocator->Free(fBlock);
}
void*
ClientMemory::Allocate(ClientMemoryAllocator* allocator, size_t size,
bool& newArea)
{
fAllocator = allocator;
return fAllocator->Allocate(size, &fBlock, newArea);
}
area_id
ClientMemory::Area()
{
if (fBlock != NULL)
return fBlock->chunk->area;
return B_ERROR;
}
uint8*
ClientMemory::Address()
{
if (fBlock != NULL)
return fBlock->base;
return 0;
}
uint32
ClientMemory::AreaOffset()
{
if (fBlock != NULL)
return fBlock->base - fBlock->chunk->base;
return 0;
}
ClonedAreaMemory::ClonedAreaMemory()
:
fClonedArea(-1),
fOffset(0),
fBase(NULL)
{
}
ClonedAreaMemory::~ClonedAreaMemory()
{
if (fClonedArea >= 0)
delete_area(fClonedArea);
}
void*
ClonedAreaMemory::Clone(area_id area, uint32 offset)
{
fClonedArea = clone_area("server_memory", (void**)&fBase, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, area);
if (fBase == NULL)
return NULL;
fOffset = offset;
return Address();
}
area_id
ClonedAreaMemory::Area()
{
return fClonedArea;
}
uint8*
ClonedAreaMemory::Address()
{
return fBase + fOffset;
}
uint32
ClonedAreaMemory::AreaOffset()
{
return fOffset;
}

View File

@ -39,17 +39,9 @@ public:
ClientMemoryAllocator(ServerApp* application); ClientMemoryAllocator(ServerApp* application);
~ClientMemoryAllocator(); ~ClientMemoryAllocator();
status_t InitCheck(); void* Allocate(size_t size, block** _address,
void* Allocate(size_t size, void** _address,
bool& newArea); bool& newArea);
void Free(void* cookie); void Free(block* cookie);
area_id Area(void* cookie);
uint32 AreaOffset(void* cookie);
bool Lock();
void Unlock();
void Dump(); void Dump();
@ -58,10 +50,57 @@ private:
private: private:
ServerApp* fApplication; ServerApp* fApplication;
MultiLocker fLock;
chunk_list fChunks; chunk_list fChunks;
block_list fFreeBlocks; block_list fFreeBlocks;
}; };
class AreaMemory {
public:
virtual ~AreaMemory() {}
virtual area_id Area() = 0;
virtual uint8* Address() = 0;
virtual uint32 AreaOffset() = 0;
};
class ClientMemory : public AreaMemory {
public:
ClientMemory();
virtual ~ClientMemory();
void* Allocate(ClientMemoryAllocator* allocator,
size_t size, bool& newArea);
virtual area_id Area();
virtual uint8* Address();
virtual uint32 AreaOffset();
private:
ClientMemoryAllocator* fAllocator;
block* fBlock;
};
/*! Just clones an existing area. */
class ClonedAreaMemory : public AreaMemory{
public:
ClonedAreaMemory();
virtual ~ClonedAreaMemory();
void* Clone(area_id area, uint32 offset);
virtual area_id Area();
virtual uint8* Address();
virtual uint32 AreaOffset();
private:
area_id fClonedArea;
uint32 fOffset;
uint8* fBase;
};
#endif /* CLIENT_MEMORY_ALLOCATOR_H */ #endif /* CLIENT_MEMORY_ALLOCATOR_H */

View File

@ -59,8 +59,7 @@ using namespace BPrivate;
ServerBitmap::ServerBitmap(BRect rect, color_space space, uint32 flags, ServerBitmap::ServerBitmap(BRect rect, color_space space, uint32 flags,
int32 bytesPerRow, screen_id screen) int32 bytesPerRow, screen_id screen)
: :
fAllocator(NULL), fMemory(NULL),
fAllocationCookie(NULL),
fOverlay(NULL), fOverlay(NULL),
fBuffer(NULL), fBuffer(NULL),
// WARNING: '1' is added to the width and height. // WARNING: '1' is added to the width and height.
@ -84,8 +83,7 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, uint32 flags,
//! Copy constructor does not copy the buffer. //! Copy constructor does not copy the buffer.
ServerBitmap::ServerBitmap(const ServerBitmap* bitmap) ServerBitmap::ServerBitmap(const ServerBitmap* bitmap)
: :
fAllocator(NULL), fMemory(NULL),
fAllocationCookie(NULL),
fOverlay(NULL), fOverlay(NULL),
fBuffer(NULL), fBuffer(NULL),
fOwner(NULL) fOwner(NULL)
@ -108,9 +106,10 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bitmap)
ServerBitmap::~ServerBitmap() ServerBitmap::~ServerBitmap()
{ {
if (fAllocator != NULL) if (fMemory != NULL) {
fAllocator->Free(AllocationCookie()); if (fMemory != &fClientMemory)
else delete fMemory;
} else
delete[] fBuffer; delete[] fBuffer;
delete fOverlay; delete fOverlay;
@ -162,8 +161,8 @@ ServerBitmap::ImportBits(const void *bits, int32 bitsLength, int32 bytesPerRow,
area_id area_id
ServerBitmap::Area() const ServerBitmap::Area() const
{ {
if (fAllocator != NULL) if (fMemory != NULL)
return fAllocator->Area(AllocationCookie()); return fMemory->Area();
return B_ERROR; return B_ERROR;
} }
@ -172,8 +171,8 @@ ServerBitmap::Area() const
uint32 uint32
ServerBitmap::AreaOffset() const ServerBitmap::AreaOffset() const
{ {
if (fAllocator != NULL) if (fMemory != NULL)
return fAllocator->AreaOffset(AllocationCookie()); return fMemory->AreaOffset();
return 0; return 0;
} }

View File

@ -16,9 +16,10 @@
#include <Referenceable.h> #include <Referenceable.h>
#include "ClientMemoryAllocator.h"
class BitmapManager; class BitmapManager;
class ClientMemoryAllocator;
class HWInterface; class HWInterface;
class Overlay; class Overlay;
class ServerApp; class ServerApp;
@ -60,9 +61,6 @@ public:
inline int32 Token() const inline int32 Token() const
{ return fToken; } { return fToken; }
inline void* AllocationCookie() const
{ return fAllocationCookie; }
area_id Area() const; area_id Area() const;
uint32 AreaOffset() const; uint32 AreaOffset() const;
@ -96,8 +94,8 @@ protected:
void AllocateBuffer(); void AllocateBuffer();
protected: protected:
ClientMemoryAllocator* fAllocator; ClientMemory fClientMemory;
void* fAllocationCookie; AreaMemory* fMemory;
::Overlay* fOverlay; ::Overlay* fOverlay;
uint8* fBuffer; uint8* fBuffer;