xref: /haiku/src/servers/app/BitmapManager.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
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, uint32 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 		// NOTE: the client handles clearing to white in case the flags
192 		// indicate this is needed
193 	} else {
194 		// Allocation failed for buffer or bitmap list
195 		delete bitmap;
196 		bitmap = NULL;
197 	}
198 
199 	return bitmap;
200 }
201 
202 
203 /*!
204 	\brief Deletes a ServerBitmap.
205 	\param bitmap The bitmap to delete
206 */
207 void
208 BitmapManager::DeleteBitmap(ServerBitmap* bitmap)
209 {
210 	if (bitmap == NULL || !bitmap->_Release()) {
211 		// there are other references to this bitmap, we don't have to delete it yet
212 		return;
213 	}
214 
215 	BAutolock locker(fLock);
216 	if (!locker.IsLocked())
217 		return;
218 
219 	if (bitmap->Overlay() != NULL)
220 		fOverlays.AddItem(bitmap);
221 
222 	if (fBitmapList.RemoveItem(bitmap))
223 		delete bitmap;
224 }
225 
226 
227 void
228 BitmapManager::SuspendOverlays()
229 {
230 	BAutolock locker(fLock);
231 	if (!locker.IsLocked())
232 		return;
233 
234 	// first, tell all applications owning an overlay to release their locks
235 
236 	BObjectList<ServerApp> apps;
237 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
238 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
239 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
240 	}
241 	for (int32 i = 0; i < apps.CountItems(); i++) {
242 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
243 		apps.ItemAt(i)->SendMessageToClient(&notify);
244 	}
245 
246 	// suspend overlays
247 
248 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
249 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
250 		bitmap->Overlay()->Suspend(bitmap, false);
251 	}
252 }
253 
254 
255 void
256 BitmapManager::ResumeOverlays()
257 {
258 	BAutolock locker(fLock);
259 	if (!locker.IsLocked())
260 		return;
261 
262 	// first, tell all applications owning an overlay that
263 	// they can reacquire their locks
264 
265 	BObjectList<ServerApp> apps;
266 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
267 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
268 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
269 	}
270 	for (int32 i = 0; i < apps.CountItems(); i++) {
271 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
272 		apps.ItemAt(i)->SendMessageToClient(&notify);
273 	}
274 
275 	// resume overlays
276 
277 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
278 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
279 
280 		bitmap->Overlay()->Resume(bitmap);
281 	}
282 }
283 
284