xref: /haiku/src/servers/app/BitmapManager.cpp (revision 582da17386c4a192ca30270d6b0b95f561cf5843)
1 /*
2  * Copyright 2001-2007, 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 <string.h>
39 
40 using std::nothrow;
41 
42 
43 //! The one and only bitmap manager for the server, created by the AppServer
44 BitmapManager *gBitmapManager = NULL;
45 
46 
47 int
48 compare_app_pointer(const ServerApp* a, const ServerApp* b)
49 {
50 	return (addr_t)b - (addr_t)b;
51 }
52 
53 
54 //	#pragma mark -
55 
56 
57 //! Sets up stuff to be ready to allocate space for bitmaps
58 BitmapManager::BitmapManager()
59 	:
60 	fBitmapList(1024),
61 	fLock("BitmapManager Lock")
62 {
63 }
64 
65 
66 //! Deallocates everything associated with the manager
67 BitmapManager::~BitmapManager()
68 {
69 	int32 count = fBitmapList.CountItems();
70 	for (int32 i = 0; i < count; i++) {
71 		if (ServerBitmap* bitmap = (ServerBitmap*)fBitmapList.ItemAt(i)) {
72 			if (bitmap->AllocationCookie() != NULL)
73 				debugger("We're not supposed to keep our cookies...");
74 
75 			delete bitmap;
76 		}
77 	}
78 }
79 
80 
81 /*!
82 	\brief Allocates a new ServerBitmap.
83 	\param bounds Size of the bitmap
84 	\param space Color space of the bitmap
85 	\param flags Bitmap flags as defined in Bitmap.h
86 	\param bytesPerRow Number of bytes per row.
87 	\param screen Screen id of the screen associated with it. Unused.
88 	\return A new ServerBitmap or NULL if unable to allocate one.
89 */
90 ServerBitmap*
91 BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
92 	HWInterface& hwInterface, BRect bounds, color_space space, int32 flags,
93 	int32 bytesPerRow, screen_id screen, uint8* _allocationFlags)
94 {
95 	BAutolock locker(fLock);
96 
97 	if (!locker.IsLocked())
98 		return NULL;
99 
100 	overlay_token overlayToken = NULL;
101 
102 	if (flags & B_BITMAP_WILL_OVERLAY) {
103 		if (!hwInterface.CheckOverlayRestrictions(bounds.IntegerWidth() + 1,
104 				bounds.IntegerHeight() + 1, space))
105 			return NULL;
106 
107 		if (flags & B_BITMAP_RESERVE_OVERLAY_CHANNEL) {
108 			overlayToken = hwInterface.AcquireOverlayChannel();
109 			if (overlayToken == NULL)
110 				return NULL;
111 		}
112 	}
113 
114 	ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags,
115 		bytesPerRow);
116 	if (bitmap == NULL) {
117 		if (overlayToken != NULL)
118 			hwInterface.ReleaseOverlayChannel(overlayToken);
119 
120 		return NULL;
121 	}
122 
123 	void* cookie = NULL;
124 	uint8* buffer = NULL;
125 
126 	if (flags & B_BITMAP_WILL_OVERLAY) {
127 		Overlay* overlay = new (std::nothrow) Overlay(hwInterface, bitmap,
128 			overlayToken);
129 
130 		overlay_client_data* clientData = NULL;
131 		bool newArea = false;
132 
133 		if (overlay != NULL && overlay->InitCheck() == B_OK) {
134 			// allocate client memory to communicate the overlay semaphore
135 			// and buffer location to the BBitmap
136 			cookie = allocator->Allocate(sizeof(overlay_client_data),
137 				(void**)&clientData, newArea);
138 		}
139 
140 		if (cookie != NULL) {
141 			overlay->SetClientData(clientData);
142 
143 			bitmap->fAllocator = allocator;
144 			bitmap->fAllocationCookie = cookie;
145 			bitmap->SetOverlay(overlay);
146 			bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row;
147 
148 			buffer = (uint8*)overlay->OverlayBuffer()->buffer;
149 			if (_allocationFlags)
150 				*_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0);
151 		} else {
152 			delete overlay;
153 			allocator->Free(cookie);
154 		}
155 	} else if (allocator != NULL) {
156 		// standard bitmaps
157 		bool newArea;
158 		cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea);
159 		if (cookie != NULL) {
160 			bitmap->fAllocator = allocator;
161 			bitmap->fAllocationCookie = cookie;
162 
163 			if (_allocationFlags)
164 				*_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0);
165 		}
166 	} else {
167 		// server side only bitmaps
168 		buffer = (uint8*)malloc(bitmap->BitsLength());
169 		if (buffer != NULL) {
170 			bitmap->fAllocator = NULL;
171 			bitmap->fAllocationCookie = NULL;
172 
173 			if (_allocationFlags)
174 				*_allocationFlags = kHeap;
175 		}
176 	}
177 
178 	bool success = false;
179 	if (buffer != NULL) {
180 		success = fBitmapList.AddItem(bitmap);
181 		if (success && bitmap->Overlay() != NULL) {
182 			success = fOverlays.AddItem(bitmap);
183 			if (!success)
184 				fBitmapList.RemoveItem(bitmap);
185 		}
186 	}
187 
188 	if (success) {
189 		bitmap->fBuffer = buffer;
190 		bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
191 
192 		if (flags & B_BITMAP_CLEAR_TO_WHITE) {
193 			if (space == B_CMAP8) {
194 				// "255" is the "transparent magic" index for B_CMAP8 bitmaps
195 				memset(bitmap->Bits(), 65, bitmap->BitsLength());
196 			} else {
197 				// should work for most colorspaces
198 				memset(bitmap->Bits(), 0xff, bitmap->BitsLength());
199 			}
200 		}
201 	} else {
202 		// Allocation failed for buffer or bitmap list
203 		delete bitmap;
204 		bitmap = NULL;
205 	}
206 
207 	return bitmap;
208 }
209 
210 
211 /*!
212 	\brief Deletes a ServerBitmap.
213 	\param bitmap The bitmap to delete
214 */
215 void
216 BitmapManager::DeleteBitmap(ServerBitmap* bitmap)
217 {
218 	if (bitmap == NULL || !bitmap->_Release()) {
219 		// there are other references to this bitmap, we don't have to delete it yet
220 		return;
221 	}
222 
223 	BAutolock locker(fLock);
224 	if (!locker.IsLocked())
225 		return;
226 
227 	if (bitmap->Overlay() != NULL)
228 		fOverlays.AddItem(bitmap);
229 
230 	if (fBitmapList.RemoveItem(bitmap))
231 		delete bitmap;
232 }
233 
234 
235 void
236 BitmapManager::SuspendOverlays()
237 {
238 	BAutolock locker(fLock);
239 	if (!locker.IsLocked())
240 		return;
241 
242 	// first, tell all applications owning an overlay to release their locks
243 
244 	BObjectList<ServerApp> apps;
245 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
246 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
247 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
248 	}
249 	for (int32 i = 0; i < apps.CountItems(); i++) {
250 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
251 		apps.ItemAt(i)->SendMessageToClient(&notify);
252 	}
253 
254 	// suspend overlays
255 
256 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
257 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
258 		bitmap->Overlay()->Suspend(bitmap, false);
259 	}
260 }
261 
262 
263 void
264 BitmapManager::ResumeOverlays()
265 {
266 	BAutolock locker(fLock);
267 	if (!locker.IsLocked())
268 		return;
269 
270 	// first, tell all applications owning an overlay that
271 	// they can reacquire their locks
272 
273 	BObjectList<ServerApp> apps;
274 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
275 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
276 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
277 	}
278 	for (int32 i = 0; i < apps.CountItems(); i++) {
279 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
280 		apps.ItemAt(i)->SendMessageToClient(&notify);
281 	}
282 
283 	// resume overlays
284 
285 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
286 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
287 
288 		bitmap->Overlay()->Resume(bitmap);
289 	}
290 }
291 
292