xref: /haiku/src/servers/app/BitmapManager.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 Called when a ServerBitmap is deleted.
205 */
206 void
207 BitmapManager::BitmapRemoved(ServerBitmap* bitmap)
208 {
209 	BAutolock locker(fLock);
210 	if (!locker.IsLocked())
211 		return;
212 
213 	if (bitmap->Overlay() != NULL)
214 		fOverlays.RemoveItem(bitmap);
215 
216 	fBitmapList.RemoveItem(bitmap);
217 }
218 
219 
220 void
221 BitmapManager::SuspendOverlays()
222 {
223 	BAutolock locker(fLock);
224 	if (!locker.IsLocked())
225 		return;
226 
227 	// first, tell all applications owning an overlay to release their locks
228 
229 	BObjectList<ServerApp> apps;
230 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
231 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
232 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
233 	}
234 	for (int32 i = 0; i < apps.CountItems(); i++) {
235 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
236 		apps.ItemAt(i)->SendMessageToClient(&notify);
237 	}
238 
239 	// suspend overlays
240 
241 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
242 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
243 		bitmap->Overlay()->Suspend(bitmap, false);
244 	}
245 }
246 
247 
248 void
249 BitmapManager::ResumeOverlays()
250 {
251 	BAutolock locker(fLock);
252 	if (!locker.IsLocked())
253 		return;
254 
255 	// first, tell all applications owning an overlay that
256 	// they can reacquire their locks
257 
258 	BObjectList<ServerApp> apps;
259 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
260 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
261 		apps.BinaryInsert(bitmap->Owner(), &compare_app_pointer);
262 	}
263 	for (int32 i = 0; i < apps.CountItems(); i++) {
264 		BMessage notify(B_RELEASE_OVERLAY_LOCK);
265 		apps.ItemAt(i)->SendMessageToClient(&notify);
266 	}
267 
268 	// resume overlays
269 
270 	for (int32 i = 0; i < fOverlays.CountItems(); i++) {
271 		ServerBitmap* bitmap = (ServerBitmap*)fOverlays.ItemAt(i);
272 
273 		bitmap->Overlay()->Resume(bitmap);
274 	}
275 }
276 
277