xref: /haiku/src/servers/app/BitmapManager.cpp (revision b6b0567fbd186f8ce8a0c90bdc7a7b5b4c649678)
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)b - (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 		if (ServerBitmap* bitmap = (ServerBitmap*)fBitmapList.ItemAt(i)) {
73 			if (bitmap->AllocationCookie() != NULL)
74 				debugger("We're not supposed to keep our cookies...");
75 
76 			delete bitmap;
77 		}
78 	}
79 }
80 
81 
82 /*!	\brief Allocates a new ServerBitmap.
83 
84 	\param bounds Size of the bitmap
85 	\param space Color space of the bitmap
86 	\param flags Bitmap flags as defined in Bitmap.h
87 	\param bytesPerRow Number of bytes per row.
88 	\param screen Screen id of the screen associated with it. Unused.
89 	\return A new ServerBitmap or NULL if unable to allocate one.
90 */
91 ServerBitmap*
92 BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator,
93 	HWInterface& hwInterface, BRect bounds, color_space space, uint32 flags,
94 	int32 bytesPerRow, int32 screen, uint8* _allocationFlags)
95 {
96 	BAutolock locker(fLock);
97 
98 	if (!locker.IsLocked())
99 		return NULL;
100 
101 	overlay_token overlayToken = NULL;
102 
103 	if (flags & B_BITMAP_WILL_OVERLAY) {
104 		if (!hwInterface.CheckOverlayRestrictions(bounds.IntegerWidth() + 1,
105 				bounds.IntegerHeight() + 1, space))
106 			return NULL;
107 
108 		if (flags & B_BITMAP_RESERVE_OVERLAY_CHANNEL) {
109 			overlayToken = hwInterface.AcquireOverlayChannel();
110 			if (overlayToken == NULL)
111 				return NULL;
112 		}
113 	}
114 
115 	ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags,
116 		bytesPerRow);
117 	if (bitmap == NULL) {
118 		if (overlayToken != NULL)
119 			hwInterface.ReleaseOverlayChannel(overlayToken);
120 
121 		return NULL;
122 	}
123 
124 	void* cookie = NULL;
125 	uint8* buffer = NULL;
126 
127 	if (flags & B_BITMAP_WILL_OVERLAY) {
128 		Overlay* overlay = new (std::nothrow) Overlay(hwInterface, bitmap,
129 			overlayToken);
130 
131 		overlay_client_data* clientData = NULL;
132 		bool newArea = false;
133 
134 		if (overlay != NULL && overlay->InitCheck() == B_OK) {
135 			// allocate client memory to communicate the overlay semaphore
136 			// and buffer location to the BBitmap
137 			cookie = allocator->Allocate(sizeof(overlay_client_data),
138 				(void**)&clientData, newArea);
139 		}
140 
141 		if (cookie != NULL) {
142 			overlay->SetClientData(clientData);
143 
144 			bitmap->fAllocator = allocator;
145 			bitmap->fAllocationCookie = cookie;
146 			bitmap->SetOverlay(overlay);
147 			bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row;
148 
149 			buffer = (uint8*)overlay->OverlayBuffer()->buffer;
150 			if (_allocationFlags)
151 				*_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0);
152 		} else {
153 			delete overlay;
154 			allocator->Free(cookie);
155 		}
156 	} else if (allocator != NULL) {
157 		// standard bitmaps
158 		bool newArea;
159 		cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea);
160 		if (cookie != NULL) {
161 			bitmap->fAllocator = allocator;
162 			bitmap->fAllocationCookie = cookie;
163 
164 			if (_allocationFlags)
165 				*_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0);
166 		}
167 	} else {
168 		// server side only bitmaps
169 		buffer = (uint8*)malloc(bitmap->BitsLength());
170 		if (buffer != NULL) {
171 			bitmap->fAllocator = NULL;
172 			bitmap->fAllocationCookie = NULL;
173 
174 			if (_allocationFlags)
175 				*_allocationFlags = kHeap;
176 		}
177 	}
178 
179 	bool success = false;
180 	if (buffer != NULL) {
181 		success = fBitmapList.AddItem(bitmap);
182 		if (success && bitmap->Overlay() != NULL) {
183 			success = fOverlays.AddItem(bitmap);
184 			if (!success)
185 				fBitmapList.RemoveItem(bitmap);
186 		}
187 	}
188 
189 	if (success) {
190 		bitmap->fBuffer = buffer;
191 		bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap);
192 		// NOTE: the client handles clearing to white in case the flags
193 		// indicate this is needed
194 	} else {
195 		// Allocation failed for buffer or bitmap list
196 		delete bitmap;
197 		bitmap = NULL;
198 	}
199 
200 	return bitmap;
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
212 		// it yet
213 		return;
214 	}
215 
216 	BAutolock locker(fLock);
217 	if (!locker.IsLocked())
218 		return;
219 
220 	if (bitmap->Overlay() != NULL)
221 		fOverlays.RemoveItem(bitmap);
222 
223 	if (fBitmapList.RemoveItem(bitmap))
224 		delete bitmap;
225 }
226 
227 
228 void
229 BitmapManager::SuspendOverlays()
230 {
231 	BAutolock locker(fLock);
232 	if (!locker.IsLocked())
233 		return;
234 
235 	// first, tell all applications owning an overlay to release their locks
236 
237 	BObjectList<ServerApp> apps;
238 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
239 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
240 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
241 	}
242 	for (int32 i = 0; i < apps.CountItems(); i++) {
243 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
244 		apps.ItemAt(i)->SendMessageToClient(&notify);
245 	}
246 
247 	// suspend overlays
248 
249 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
250 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
251 		bitmap->Overlay()->Suspend(bitmap, false);
252 	}
253 }
254 
255 
256 void
257 BitmapManager::ResumeOverlays()
258 {
259 	BAutolock locker(fLock);
260 	if (!locker.IsLocked())
261 		return;
262 
263 	// first, tell all applications owning an overlay that
264 	// they can reacquire their locks
265 
266 	BObjectList<ServerApp> apps;
267 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
268 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
269 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
270 	}
271 	for (int32 i = 0; i < apps.CountItems(); i++) {
272 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
273 		apps.ItemAt(i)->SendMessageToClient(&notify);
274 	}
275 
276 	// resume overlays
277 
278 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
279 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
280 
281 		bitmap->Overlay()->Resume(bitmap);
282 	}
283 }
284 
285