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