xref: /haiku/src/servers/app/BitmapManager.cpp (revision 68f76d61d74f9f73085105d541b4d0a5e7df0317)
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 
41 using std::nothrow;
42 
43 
44 //! The one and only bitmap manager for the server, created by the AppServer
45 BitmapManager *gBitmapManager = NULL;
46 
47 
48 int
49 compare_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
59 BitmapManager::BitmapManager()
60 	:
61 	fBitmapList(1024),
62 	fLock("BitmapManager Lock")
63 {
64 }
65 
66 
67 //! Deallocates everything associated with the manager
68 BitmapManager::~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 */
85 ServerBitmap*
86 BitmapManager::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 
193 ServerBitmap*
194 BitmapManager::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 */
224 void
225 BitmapManager::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 
240 void
241 BitmapManager::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 
268 void
269 BitmapManager::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