1/*
2 * Copyright 2001-2009, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		Axel D��rfler, axeld@pinc-software.de
8 */
9
10
11/*!	Whenever a ServerBitmap associated with a client-side BBitmap needs to be
12	created or destroyed, the BitmapManager needs to handle it. It takes care of
13	all memory management related to them.
14*/
15
16
17#include "BitmapManager.h"
18
19#include "ClientMemoryAllocator.h"
20#include "HWInterface.h"
21#include "Overlay.h"
22#include "ServerApp.h"
23#include "ServerBitmap.h"
24#include "ServerProtocol.h"
25#include "ServerTokenSpace.h"
26
27#include <BitmapPrivate.h>
28#include <ObjectList.h>
29#include <video_overlay.h>
30
31#include <AppDefs.h>
32#include <Autolock.h>
33#include <Bitmap.h>
34#include <Message.h>
35
36#include <new>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41using std::nothrow;
42
43
44//! The one and only bitmap manager for the server, created by the AppServer
45BitmapManager *gBitmapManager = NULL;
46
47
48int
49compare_app_pointer(const ServerApp* a, const ServerApp* b)
50{
51	return (addr_t)a - (addr_t)b;
52}
53
54
55//	#pragma mark -
56
57
58//! Sets up stuff to be ready to allocate space for bitmaps
59BitmapManager::BitmapManager()
60	:
61	fBitmapList(1024),
62	fLock("BitmapManager Lock")
63{
64}
65
66
67//! Deallocates everything associated with the manager
68BitmapManager::~BitmapManager()
69{
70	int32 count = fBitmapList.CountItems();
71	for (int32 i = 0; i < count; i++)
72		delete (ServerBitmap*)fBitmapList.ItemAt(i);
73}
74
75
76/*!	\brief Allocates a new ServerBitmap.
77
78	\param bounds Size of the bitmap
79	\param space Color space of the bitmap
80	\param flags Bitmap flags as defined in Bitmap.h
81	\param bytesPerRow Number of bytes per row.
82	\param screen Screen id of the screen associated with it. Unused.
83	\return A new ServerBitmap or NULL if unable to allocate one.
84*/
85ServerBitmap*
86BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
87	HWInterface& hwInterface, BRect bounds, color_space space, uint32 flags,
88	int32 bytesPerRow, int32 screen, uint8* _allocationFlags)
89{
90	BAutolock locker(fLock);
91	if (!locker.IsLocked())
92		return NULL;
93
94	overlay_token overlayToken = NULL;
95
96	if (flags & B_BITMAP_WILL_OVERLAY) {
97		if (!hwInterface.CheckOverlayRestrictions(bounds.IntegerWidth() + 1,
98				bounds.IntegerHeight() + 1, space))
99			return NULL;
100
101		if (flags & B_BITMAP_RESERVE_OVERLAY_CHANNEL) {
102			overlayToken = hwInterface.AcquireOverlayChannel();
103			if (overlayToken == NULL)
104				return NULL;
105		}
106	}
107
108	ServerBitmap* bitmap = new(std::nothrow) ServerBitmap(bounds, space, flags,
109		bytesPerRow);
110	if (bitmap == NULL) {
111		if (overlayToken != NULL)
112			hwInterface.ReleaseOverlayChannel(overlayToken);
113
114		return NULL;
115	}
116
117	uint8* buffer = NULL;
118
119	if (flags & B_BITMAP_WILL_OVERLAY) {
120		Overlay* overlay = new(std::nothrow) Overlay(hwInterface, bitmap,
121			overlayToken);
122
123		overlay_client_data* clientData = NULL;
124		bool newArea = false;
125
126		if (overlay != NULL && overlay->InitCheck() == B_OK) {
127			// allocate client memory to communicate the overlay semaphore
128			// and buffer location to the BBitmap
129			clientData = (overlay_client_data*)bitmap->fClientMemory.Allocate(
130				allocator, sizeof(overlay_client_data), newArea);
131		}
132
133		if (clientData != NULL) {
134			overlay->SetClientData(clientData);
135
136			bitmap->fMemory = &bitmap->fClientMemory;
137			bitmap->SetOverlay(overlay);
138			bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row;
139
140			buffer = (uint8*)overlay->OverlayBuffer()->buffer;
141			if (_allocationFlags)
142				*_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0);
143		} else
144			delete overlay;
145	} else if (allocator != NULL) {
146		// standard bitmaps
147		bool newArea;
148		buffer = (uint8*)bitmap->fClientMemory.Allocate(allocator,
149			bitmap->BitsLength(), newArea);
150		if (buffer != NULL) {
151			bitmap->fMemory = &bitmap->fClientMemory;
152
153			if (_allocationFlags)
154				*_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0);
155		}
156	} else {
157		// server side only bitmaps
158		buffer = (uint8*)malloc(bitmap->BitsLength());
159		if (buffer != NULL) {
160			bitmap->fMemory = NULL;
161
162			if (_allocationFlags)
163				*_allocationFlags = kHeap;
164		}
165	}
166
167	bool success = false;
168	if (buffer != NULL) {
169		success = fBitmapList.AddItem(bitmap);
170		if (success && bitmap->Overlay() != NULL) {
171			success = fOverlays.AddItem(bitmap);
172			if (!success)
173				fBitmapList.RemoveItem(bitmap);
174		}
175	}
176
177	if (success) {
178		bitmap->fBuffer = buffer;
179		bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
180		// NOTE: the client handles clearing to white in case the flags
181		// indicate this is needed
182	} else {
183		// Allocation failed for buffer or bitmap list
184		free(buffer);
185		delete bitmap;
186		bitmap = NULL;
187	}
188
189	return bitmap;
190}
191
192
193ServerBitmap*
194BitmapManager::CloneFromClient(area_id clientArea, int32 areaOffset,
195	BRect bounds, color_space space, uint32 flags, int32 bytesPerRow)
196{
197	BAutolock locker(fLock);
198	if (!locker.IsLocked())
199		return NULL;
200	BReference<ServerBitmap> bitmap(new(std::nothrow) ServerBitmap(bounds, space, flags,
201		bytesPerRow), true);
202	if (bitmap == NULL)
203		return NULL;
204
205	ClonedAreaMemory* memory = new(std::nothrow) ClonedAreaMemory;
206	if (memory == NULL) {
207		return NULL;
208	}
209	int8* buffer = (int8*)memory->Clone(clientArea, areaOffset);
210	if (buffer == NULL) {
211		delete memory;
212		return NULL;
213	}
214
215	bitmap->fMemory = memory;
216	bitmap->fBuffer = memory->Address();
217	bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
218	return bitmap.Detach();
219}
220
221
222/*!	\brief Called when a ServerBitmap is deleted.
223*/
224void
225BitmapManager::BitmapRemoved(ServerBitmap* bitmap)
226{
227	BAutolock locker(fLock);
228	if (!locker.IsLocked())
229		return;
230
231	gTokenSpace.RemoveToken(bitmap->Token());
232
233	if (bitmap->Overlay() != NULL)
234		fOverlays.RemoveItem(bitmap);
235
236	fBitmapList.RemoveItem(bitmap);
237}
238
239
240void
241BitmapManager::SuspendOverlays()
242{
243	BAutolock locker(fLock);
244	if (!locker.IsLocked())
245		return;
246
247	// first, tell all applications owning an overlay to release their locks
248
249	BObjectList<ServerApp> apps;
250	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
251		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
252		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
253	}
254	for (int32 i = 0; i < apps.CountItems(); i++) {
255		BMessage notify(B_RELEASE_OVERLAY_LOCK);
256		apps.ItemAt(i)->SendMessageToClient(&notify);
257	}
258
259	// suspend overlays
260
261	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
262		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
263		bitmap->Overlay()->Suspend(bitmap, false);
264	}
265}
266
267
268void
269BitmapManager::ResumeOverlays()
270{
271	BAutolock locker(fLock);
272	if (!locker.IsLocked())
273		return;
274
275	// first, tell all applications owning an overlay that
276	// they can reacquire their locks
277
278	BObjectList<ServerApp> apps;
279	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
280		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
281		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
282	}
283	for (int32 i = 0; i < apps.CountItems(); i++) {
284		BMessage notify(B_RELEASE_OVERLAY_LOCK);
285		apps.ItemAt(i)->SendMessageToClient(&notify);
286	}
287
288	// resume overlays
289
290	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
291		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
292
293		bitmap->Overlay()->Resume(bitmap);
294	}
295}
296
297