diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 32e52d8f48..6b0b5d2c74 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -336,7 +336,7 @@ enum cursor_which { enum { kAllocator, kNewAllocatorArea, - kArea, + kFramebuffer, kHeap }; diff --git a/src/kits/interface/Bitmap.cpp b/src/kits/interface/Bitmap.cpp index 31964930c1..8b3c49ae8a 100644 --- a/src/kits/interface/Bitmap.cpp +++ b/src/kits/interface/Bitmap.cpp @@ -928,12 +928,12 @@ BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, int8 allocationType; link.Read(&allocationType); - if (allocationType == kArea) { - // TODO: implement me (server-side as well), needed for overlays + if (allocationType == kFramebuffer) { + link.Read((addr_t*)&fBasePointer); + link.Read(&fBytesPerRow); + fServerArea = B_ERROR; - fAreaOffset = -1; - // that signals the cleanup code to delete our area - fBasePointer = NULL; + fAreaOffset = 0; } else { link.Read(&fServerArea); link.Read(&fAreaOffset); @@ -1012,11 +1012,6 @@ BBitmap::_CleanUp() // TODO: we may want to delete parts of the server memory areas here! - if (fAreaOffset == -1) { - // we own that area, so we have to delete it - delete_area(fArea); - } - fArea = -1; fServerToken = -1; fAreaOffset = -1; diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index fde062affd..03ad528fb8 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -16,18 +16,22 @@ */ -#include -#include -#include +#include "BitmapManager.h" + +#include "ClientMemoryAllocator.h" +#include "HWInterface.h" +#include "ServerBitmap.h" +#include "ServerProtocol.h" +#include "ServerTokenSpace.h" + +#include #include #include -#include "BitmapManager.h" -#include "ClientMemoryAllocator.h" -#include "ServerBitmap.h" -#include "ServerProtocol.h" -#include "ServerTokenSpace.h" +#include +#include +#include using std::nothrow; @@ -73,8 +77,8 @@ BitmapManager::~BitmapManager() \return A new ServerBitmap or NULL if unable to allocate one. */ ServerBitmap* -BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, BRect bounds, - color_space space, int32 flags, int32 bytesPerRow, screen_id screen, +BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, HWInterface& hwInterface, + BRect bounds, color_space space, int32 flags, int32 bytesPerRow, screen_id screen, int8* _allocationType) { BAutolock locker(fLock); @@ -83,17 +87,52 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, BRect bounds, return NULL; // TODO: create an overlay bitmap if graphics card supports it -if (flags & B_BITMAP_WILL_OVERLAY) - return NULL; + if (flags & B_BITMAP_WILL_OVERLAY) { + if (!hwInterface.WriteLock() + || !hwInterface.CheckOverlayRestrictions(bounds.IntegerWidth() + 1, + bounds.IntegerHeight() + 1, space)) { + hwInterface.WriteUnlock(); + return NULL; + } + + // We now hold the HWInterface write lock! + // Keeping the interface locked makes sure the overlay is still + // available when we allocate the buffer + } ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags, bytesPerRow); - if (bitmap == NULL) + if (bitmap == NULL) { + if (flags & B_BITMAP_WILL_OVERLAY) + hwInterface.WriteUnlock(); + return NULL; + } void* cookie = NULL; uint8* buffer = NULL; - if (allocator != NULL) { + if (flags & B_BITMAP_WILL_OVERLAY) { + OverlayCookie* overlayCookie = new (std::nothrow) OverlayCookie(hwInterface); + const overlay_buffer* overlayBuffer = NULL; + + if (overlayCookie != NULL) { + overlayBuffer = hwInterface.AllocateOverlayBuffer(bitmap->Width(), + bitmap->Height(), space); + } + + hwInterface.WriteUnlock(); + + if (overlayBuffer != NULL) { + overlayCookie->SetOverlayBuffer(overlayBuffer); + bitmap->fAllocationCookie = overlayCookie; + bitmap->fBytesPerRow = overlayBuffer->bytes_per_row; + + buffer = (uint8*)overlayBuffer->buffer; + if (_allocationType) + *_allocationType = kFramebuffer; + } else + delete overlayCookie; + } else if (allocator != NULL) { bool newArea; cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea); if (cookie != NULL) { diff --git a/src/servers/app/BitmapManager.h b/src/servers/app/BitmapManager.h index 74ed2ba983..dc68e16562 100644 --- a/src/servers/app/BitmapManager.h +++ b/src/servers/app/BitmapManager.h @@ -16,6 +16,7 @@ #include class ClientMemoryAllocator; +class HWInterface; class ServerBitmap; class BitmapManager { @@ -23,7 +24,8 @@ class BitmapManager { BitmapManager(); virtual ~BitmapManager(); - ServerBitmap* CreateBitmap(ClientMemoryAllocator* allocator, BRect bounds, + ServerBitmap* CreateBitmap(ClientMemoryAllocator* allocator, + HWInterface& hwInterface, BRect bounds, color_space space, int32 flags, int32 bytesPerRow = -1, screen_id screen = B_MAIN_SCREEN_ID, int8* _allocationType = NULL); diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 7a17fb5c7c..e7adbf98a3 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -589,8 +589,10 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&flags); link.Read(&bytesPerRow); if (link.Read(&screenID) == B_OK) { - bitmap = gBitmapManager->CreateBitmap(&fMemoryAllocator, frame, - colorSpace, flags, bytesPerRow, screenID, &allocationType); + // TODO: choose the right HWInterface with regards to the screenID + bitmap = gBitmapManager->CreateBitmap(&fMemoryAllocator, + *fDesktop->HWInterface(), frame, colorSpace, flags, bytesPerRow, + screenID, &allocationType); } STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n", @@ -601,8 +603,9 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Attach(bitmap->Token()); fLink.Attach(allocationType); - if (allocationType == kArea) { - // TODO: implement me! + if (allocationType == kFramebuffer) { + fLink.Attach((addr_t)bitmap->Bits()); + fLink.Attach(bitmap->BytesPerRow()); } else { fLink.Attach(fMemoryAllocator.Area(bitmap->AllocationCookie())); fLink.Attach(fMemoryAllocator.AreaOffset(bitmap->AllocationCookie())); diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp index d96b560b21..290d09f305 100644 --- a/src/servers/app/ServerBitmap.cpp +++ b/src/servers/app/ServerBitmap.cpp @@ -10,6 +10,7 @@ #include "ServerBitmap.h" #include "ClientMemoryAllocator.h" #include "ColorConversion.h" +#include "HWInterface.h" #include #include @@ -17,6 +18,24 @@ using std::nothrow; +/*! + A word about memory housekeeping and why it's implemented this way: + + The reason why this looks so complicated is to optimize the most common + path (bitmap creation from the application), and don't cause any further + memory allocations for maintaining memory in that case. + If a bitmap was allocated this way, both, the fAllocator and fAllocationCookie + members are used. + + For overlays, the creation speed is not crucial, that's why we can easily live + with the overhead of some heap allocations. The fAllocationCookie will point + to an OverlayCookie object that will also free the buffer upon destruction. + + If the memory was allocated on the app_server heap, neither fAllocator, nor + fAllocationCookie are used, and the buffer is just freed in that case when + the bitmap is destructed. This method is mainly used for cursors. +*/ + /*! \brief Constructor called by the BitmapManager (only). @@ -46,7 +65,7 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, fSpace(space), fFlags(flags), fBitsPerPixel(0) - // TODO: what about fToken and fOffset ?!? + // fToken is initialized (if used) by the BitmapManager { _HandleSpace(space, bytesPerRow); } @@ -83,9 +102,10 @@ ServerBitmap::~ServerBitmap() { if (fAllocator != NULL) fAllocator->Free(AllocationCookie()); - else if (fAllocationCookie != NULL) - delete_area((area_id)fAllocationCookie); - else + else if (fAllocationCookie != NULL) { + delete (OverlayCookie *)fAllocationCookie; + // deleting the cookie will also free the buffer + } else free(fBuffer); } @@ -267,9 +287,6 @@ ServerBitmap::Area() const if (fAllocator != NULL) return fAllocator->Area(AllocationCookie()); - if (fAllocationCookie != NULL) - return (area_id)fAllocationCookie; - return B_ERROR; } @@ -284,6 +301,16 @@ ServerBitmap::AreaOffset() const } +const overlay_buffer* +ServerBitmap::OverlayBuffer() const +{ + if (fAllocator != NULL || fAllocationCookie == NULL) + return NULL; + + return ((OverlayCookie*)fAllocationCookie)->OverlayBuffer(); +} + + void ServerBitmap::PrintToStream() { @@ -328,3 +355,35 @@ UtilityBitmap::UtilityBitmap(const uint8* alreadyPaddedData, UtilityBitmap::~UtilityBitmap() { } + + +// #pragma mark - + + +OverlayCookie::OverlayCookie(HWInterface& interface) + : + fHWInterface(interface), + fOverlayBuffer(NULL) +{ +} + + +OverlayCookie::~OverlayCookie() +{ + fHWInterface.FreeOverlayBuffer(fOverlayBuffer); +} + + +void +OverlayCookie::SetOverlayBuffer(const overlay_buffer* overlayBuffer) +{ + fOverlayBuffer = overlayBuffer; +} + + +const overlay_buffer* +OverlayCookie::OverlayBuffer() +{ + return fOverlayBuffer; +} + diff --git a/src/servers/app/ServerBitmap.h b/src/servers/app/ServerBitmap.h index 51606a42f8..16f7cf0109 100644 --- a/src/servers/app/ServerBitmap.h +++ b/src/servers/app/ServerBitmap.h @@ -13,9 +13,12 @@ #include #include +#include + class BitmapManager; class ClientMemoryAllocator; +class HWInterface; /*! \class ServerBitmap ServerBitmap.h @@ -61,6 +64,8 @@ class ServerBitmap { area_id Area() const; uint32 AreaOffset() const; + const overlay_buffer* OverlayBuffer() const; + //! Does a shallow copy of the bitmap passed to it inline void ShallowCopy(const ServerBitmap *from); @@ -129,6 +134,20 @@ class UtilityBitmap : public ServerBitmap { virtual ~UtilityBitmap(); }; +//! An allocation cookie for overlays +class OverlayCookie { + public: + OverlayCookie(HWInterface& interface); + ~OverlayCookie(); + + void SetOverlayBuffer(const overlay_buffer* overlayBuffer); + const overlay_buffer* OverlayBuffer(); + + private: + HWInterface& fHWInterface; + const overlay_buffer* fOverlayBuffer; +}; + // ShallowCopy void ServerBitmap::ShallowCopy(const ServerBitmap* from) diff --git a/src/servers/app/WorkspacesLayer.cpp b/src/servers/app/WorkspacesLayer.cpp index 31c25a5847..7deea1be2f 100644 --- a/src/servers/app/WorkspacesLayer.cpp +++ b/src/servers/app/WorkspacesLayer.cpp @@ -192,17 +192,22 @@ WorkspacesLayer::_DrawWindow(DrawingEngine* drawingEngine, const BRect& workspac tabFrame.top = frame.top - 1; tabFrame.bottom = frame.top - 1; + tabFrame = tabFrame & workspaceFrame; - backgroundRegion.Exclude(tabFrame); - backgroundRegion.Exclude(frame); - - if (decorator != NULL) + if (decorator != NULL && tabFrame.IsValid()) { drawingEngine->StrokeLine(tabFrame.LeftTop(), tabFrame.RightBottom(), yellow); + backgroundRegion.Exclude(tabFrame); + } drawingEngine->StrokeRect(frame, frameColor); - frame.InsetBy(1, 1); - drawingEngine->FillRect(frame, white); + frame = frame & workspaceFrame; + if (frame.IsValid()) { + backgroundRegion.Exclude(frame); + + frame.InsetBy(1, 1); + drawingEngine->FillRect(frame, white); + } // draw title diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index 5db2de2ab1..2ce301a9a1 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -101,6 +101,8 @@ AccelerantHWInterface::AccelerantHWInterface() fBackBuffer(NULL), fFrontBuffer(new (nothrow) AccelerantBuffer()), + fUsedOverlays(0), + fRectParams(new (nothrow) fill_rect_params[kDefaultParamsCount]), fRectParamsCount(kDefaultParamsCount), fBlitParams(new (nothrow) blit_params[kDefaultParamsCount]), @@ -684,6 +686,72 @@ AccelerantHWInterface::AvailableHWAcceleration() const return flags; } + +bool +AccelerantHWInterface::CheckOverlayRestrictions(int32 width, int32 height, + color_space colorSpace) +{ + // check if the current display mode supports overlay + + if (fAccOverlayCount == NULL + || fAccOverlaySupportedSpaces == NULL + || fAccGetOverlayConstraints == NULL + || fAccAllocateOverlayBuffer == NULL + || fAccReleaseOverlayBuffer == NULL + || (fDisplayMode.flags & B_SUPPORTS_OVERLAYS) == 0) + return false; + + // check if there is an overlay buffer available + + uint32 available = fAccOverlayCount(&fDisplayMode); + if ((int32)available <= fUsedOverlays) + return false; + + // Note: we can't really check the size of the overlay upfront - we + // must assume fAccAllocateOverlayBuffer() will fail in that case. + if (width < 0 || width > 65535 || height < 0 || height > 65535) + return false; + + // check color space + + const uint32* spaces = fAccOverlaySupportedSpaces(&fDisplayMode); + if (spaces == NULL) + return false; + + for (int32 i = 0; spaces[i] != 0; i++) { + if (spaces[i] == (uint32)colorSpace) + return true; + } + + return false; +} + + +const overlay_buffer* +AccelerantHWInterface::AllocateOverlayBuffer(int32 width, int32 height, color_space space) +{ + if (fAccAllocateOverlayBuffer == NULL) + return NULL; + + const overlay_buffer* buffer = fAccAllocateOverlayBuffer(space, width, height); + if (buffer != NULL) + atomic_add(&fUsedOverlays, 1); + + return buffer; +} + + +void +AccelerantHWInterface::FreeOverlayBuffer(const overlay_buffer* buffer) +{ + if (buffer == NULL || fAccReleaseOverlayBuffer == NULL) + return; + + atomic_add(&fUsedOverlays, -1); + fAccReleaseOverlayBuffer(buffer); +} + + // CopyRegion void AccelerantHWInterface::CopyRegion(const clipping_rect* sortedRectList, diff --git a/src/servers/app/drawing/AccelerantHWInterface.h b/src/servers/app/drawing/AccelerantHWInterface.h index 5a03903f92..5e9e30b816 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.h +++ b/src/servers/app/drawing/AccelerantHWInterface.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku. + * Copyright 2005-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -55,6 +55,14 @@ public: // query for available hardware accleration and perform it virtual uint32 AvailableHWAcceleration() const; + // overlay support + virtual bool CheckOverlayRestrictions(int32 width, int32 height, + color_space colorSpace); + virtual const overlay_buffer* AllocateOverlayBuffer(int32 width, int32 height, + color_space space); + virtual void FreeOverlayBuffer(const overlay_buffer* buffer); + + // accelerated drawing virtual void CopyRegion(const clipping_rect* sortedRectList, uint32 count, int32 xOffset, int32 yOffset); @@ -66,18 +74,18 @@ public: virtual void Sync(); // cursor handling -virtual void SetCursor(ServerCursor* cursor); -virtual void SetCursorVisible(bool visible); -virtual void MoveCursorTo(const float& x, + virtual void SetCursor(ServerCursor* cursor); + virtual void SetCursorVisible(bool visible); + virtual void MoveCursorTo(const float& x, const float& y); // frame buffer access -virtual RenderingBuffer* FrontBuffer() const; -virtual RenderingBuffer* BackBuffer() const; -virtual bool IsDoubleBuffered() const; + virtual RenderingBuffer* FrontBuffer() const; + virtual RenderingBuffer* BackBuffer() const; + virtual bool IsDoubleBuffered() const; protected: -virtual void _DrawCursor(BRect area) const; + virtual void _DrawCursor(BRect area) const; private: int _OpenGraphicsDevice(int deviceNumber); @@ -134,13 +142,15 @@ private: frame_buffer_config fFrameBufferConfig; int fModeCount; - display_mode *fModeList; + display_mode* fModeList; - MallocBuffer *fBackBuffer; - AccelerantBuffer *fFrontBuffer; + MallocBuffer* fBackBuffer; + AccelerantBuffer* fFrontBuffer; display_mode fDisplayMode; + vint32 fUsedOverlays; + mutable fill_rect_params* fRectParams; mutable uint32 fRectParamsCount; mutable blit_params* fBlitParams; diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index e158145c4e..8b7098d3cb 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -301,6 +301,27 @@ HWInterface::CopyBackToFront(const BRect& frame) return B_BAD_VALUE; } + +bool +HWInterface::CheckOverlayRestrictions(int32 width, int32 height, color_space colorSpace) +{ + return false; +} + + +const overlay_buffer* +HWInterface::AllocateOverlayBuffer(int32 width, int32 height, color_space space) +{ + return NULL; +} + + +void +HWInterface::FreeOverlayBuffer(const overlay_buffer* buffer) +{ +} + + // HideSoftwareCursor bool HWInterface::HideSoftwareCursor(const BRect& area) diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index 3dfd818d64..171e6b69f5 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -9,12 +9,15 @@ #define HW_INTERFACE_H +#include "MultiLocker.h" + +#include + #include #include #include #include -#include "MultiLocker.h" class RenderingBuffer; class RGBColor; @@ -22,6 +25,7 @@ class ServerBitmap; class ServerCursor; class UpdateQueue; class BString; +struct overlay_buffer; enum { HW_ACC_COPY_REGION = 0x00000001, @@ -92,6 +96,13 @@ class HWInterface : public MultiLocker { void SetDragBitmap(const ServerBitmap* bitmap, const BPoint& offsetFromCursor); + // overlay support + virtual bool CheckOverlayRestrictions(int32 width, int32 height, + color_space colorSpace); + virtual const overlay_buffer* AllocateOverlayBuffer(int32 width, int32 height, + color_space space); + virtual void FreeOverlayBuffer(const overlay_buffer* buffer); + // frame buffer access (you need to ReadLock!) RenderingBuffer* DrawingBuffer() const; virtual RenderingBuffer* FrontBuffer() const = 0; diff --git a/src/servers/app/drawing/Painter/Jamfile b/src/servers/app/drawing/Painter/Jamfile index 4c5886aee6..25257df2f9 100644 --- a/src/servers/app/drawing/Painter/Jamfile +++ b/src/servers/app/drawing/Painter/Jamfile @@ -4,7 +4,7 @@ SetSubDirSupportedPlatformsBeOSCompatible ; AddSubDirSupportedPlatforms libbe_test ; UseLibraryHeaders agg ; -UsePrivateHeaders app interface shared ; +UsePrivateHeaders app graphics interface shared ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ;