xref: /haiku/src/servers/app/drawing/Overlay.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2006-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "Overlay.h"
11 
12 #include <BitmapPrivate.h>
13 
14 #include "HWInterface.h"
15 #include "ServerBitmap.h"
16 
17 
18 //#define TRACE_OVERLAY
19 #ifdef TRACE_OVERLAY
20 #	define TRACE(x...) ktrace_printf(x);
21 #else
22 #	define TRACE(x...) ;
23 #endif
24 
25 
26 const static bigtime_t kOverlayTimeout = 1000000LL;
27 	// after 1 second, the team holding the lock will be killed
28 
29 class SemaphoreLocker {
30 public:
31 	SemaphoreLocker(sem_id semaphore, bigtime_t timeout = B_INFINITE_TIMEOUT)
32 		:
33 		fSemaphore(semaphore)
34 	{
35 		do {
36 			fStatus = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT,
37 				timeout);
38 		} while (fStatus == B_INTERRUPTED);
39 	}
40 
41 	~SemaphoreLocker()
42 	{
43 		if (fStatus == B_OK)
44 			release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
45 	}
46 
47 	status_t LockStatus()
48 	{
49 		return fStatus;
50 	}
51 
52 private:
53 	sem_id		fSemaphore;
54 	status_t	fStatus;
55 };
56 
57 
58 //	#pragma mark -
59 
60 
61 Overlay::Overlay(HWInterface& interface, ServerBitmap* bitmap,
62 		overlay_token token)
63 	:
64 	fHWInterface(interface),
65 	fOverlayBuffer(NULL),
66 	fClientData(NULL),
67 	fOverlayToken(token)
68 {
69 	fSemaphore = create_sem(1, "overlay lock");
70 	fColor = (rgb_color){ 0, 80, 0, 0 };
71 		// TODO: whatever fine color we want to use here...
72 
73 	fWindow.offset_top = 0;
74 	fWindow.offset_left = 0;
75 	fWindow.offset_right = 0;
76 	fWindow.offset_bottom = 0;
77 
78 	fWindow.flags = B_OVERLAY_COLOR_KEY;
79 
80 	_AllocateBuffer(bitmap);
81 
82 	TRACE("overlay: created %p, bitmap %p\n", this, bitmap);
83 }
84 
85 
86 Overlay::~Overlay()
87 {
88 	fHWInterface.ReleaseOverlayChannel(fOverlayToken);
89 	_FreeBuffer();
90 
91 	delete_sem(fSemaphore);
92 	TRACE("overlay: deleted %p\n", this);
93 }
94 
95 
96 status_t
97 Overlay::InitCheck() const
98 {
99 	if (fSemaphore < B_OK)
100 		return fSemaphore;
101 
102 	if (fOverlayBuffer == NULL)
103 		return B_NO_MEMORY;
104 
105 	return B_OK;
106 }
107 
108 
109 status_t
110 Overlay::Resume(ServerBitmap* bitmap)
111 {
112 	SemaphoreLocker locker(fSemaphore, kOverlayTimeout);
113 	if (locker.LockStatus() == B_TIMED_OUT) {
114 		// TODO: kill app!
115 	}
116 
117 	TRACE("overlay: resume %p (lock status %ld)\n", this, locker.LockStatus());
118 
119 	status_t status = _AllocateBuffer(bitmap);
120 	if (status < B_OK)
121 		return status;
122 
123 	fClientData->buffer = (uint8*)fOverlayBuffer->buffer;
124 	return B_OK;
125 }
126 
127 
128 status_t
129 Overlay::Suspend(ServerBitmap* bitmap, bool needTemporary)
130 {
131 	SemaphoreLocker locker(fSemaphore, kOverlayTimeout);
132 	if (locker.LockStatus() == B_TIMED_OUT) {
133 		// TODO: kill app!
134 	}
135 
136 	TRACE("overlay: suspend %p (lock status %ld)\n", this, locker.LockStatus());
137 
138 	_FreeBuffer();
139 	fClientData->buffer = NULL;
140 
141 	return B_OK;
142 }
143 
144 
145 void
146 Overlay::_FreeBuffer()
147 {
148 	fHWInterface.FreeOverlayBuffer(fOverlayBuffer);
149 	fOverlayBuffer = NULL;
150 }
151 
152 
153 status_t
154 Overlay::_AllocateBuffer(ServerBitmap* bitmap)
155 {
156 	fOverlayBuffer = fHWInterface.AllocateOverlayBuffer(bitmap->Width(),
157 		bitmap->Height(), bitmap->ColorSpace());
158 	if (fOverlayBuffer == NULL)
159 		return B_NO_MEMORY;
160 
161 	return B_OK;
162 }
163 
164 
165 void
166 Overlay::SetClientData(overlay_client_data* clientData)
167 {
168 	fClientData = clientData;
169 	fClientData->lock = fSemaphore;
170 	fClientData->buffer = (uint8*)fOverlayBuffer->buffer;
171 }
172 
173 
174 void
175 Overlay::SetFlags(uint32 flags)
176 {
177 	if (flags & B_OVERLAY_FILTER_HORIZONTAL)
178 		fWindow.flags |= B_OVERLAY_HORIZONTAL_FILTERING;
179 	if (flags & B_OVERLAY_FILTER_VERTICAL)
180 		fWindow.flags |= B_OVERLAY_VERTICAL_FILTERING;
181 	if (flags & B_OVERLAY_MIRROR)
182 		fWindow.flags |= B_OVERLAY_HORIZONTAL_MIRRORING;
183 }
184 
185 
186 void
187 Overlay::TakeOverToken(Overlay* other)
188 {
189 	overlay_token token = other->OverlayToken();
190 	if (token == NULL)
191 		return;
192 
193 	fOverlayToken = token;
194 	//other->fOverlayToken = NULL;
195 }
196 
197 
198 const overlay_buffer*
199 Overlay::OverlayBuffer() const
200 {
201 	return fOverlayBuffer;
202 }
203 
204 
205 overlay_client_data*
206 Overlay::ClientData() const
207 {
208 	return fClientData;
209 }
210 
211 
212 overlay_token
213 Overlay::OverlayToken() const
214 {
215 	return fOverlayToken;
216 }
217 
218 
219 void
220 Overlay::Hide()
221 {
222 	if (fOverlayToken == NULL)
223 		return;
224 
225 	fHWInterface.HideOverlay(this);
226 	TRACE("overlay: hide %p\n", this);
227 }
228 
229 
230 void
231 Overlay::SetColorSpace(uint32 colorSpace)
232 {
233 	if ((fWindow.flags & B_OVERLAY_COLOR_KEY) == 0)
234 		return;
235 
236 	uint8 colorShift = 0, greenShift = 0, alphaShift = 0;
237 	rgb_color colorKey = fColor;
238 
239 	switch (colorSpace) {
240 		case B_RGB15:
241 			greenShift = colorShift = 3;
242 			alphaShift = 7;
243 			break;
244 		case B_RGB16:
245 			colorShift = 3;
246 			greenShift = 2;
247 			alphaShift = 8;
248 			break;
249 	}
250 
251 	fWindow.red.value = colorKey.red >> colorShift;
252 	fWindow.green.value = colorKey.green >> greenShift;
253 	fWindow.blue.value = colorKey.blue >> colorShift;
254 	fWindow.alpha.value = colorKey.alpha >> alphaShift;
255 	fWindow.red.mask = 0xff >> colorShift;
256 	fWindow.green.mask = 0xff >> greenShift;
257 	fWindow.blue.mask = 0xff >> colorShift;
258 	fWindow.alpha.mask = 0xff >> alphaShift;
259 }
260 
261 
262 void
263 Overlay::Configure(const BRect& source, const BRect& destination)
264 {
265 	if (fOverlayToken == NULL) {
266 		fOverlayToken = fHWInterface.AcquireOverlayChannel();
267 		if (fOverlayToken == NULL)
268 			return;
269 	}
270 
271 	TRACE("overlay: configure %p\n", this);
272 
273 	fView.h_start = (uint16)source.left;
274 	fView.v_start = (uint16)source.top;
275 	fView.width = (uint16)source.IntegerWidth() + 1;
276 	fView.height = (uint16)source.IntegerHeight() + 1;
277 
278 	fWindow.h_start = (int16)destination.left;
279 	fWindow.v_start = (int16)destination.top;
280 	fWindow.width = (uint16)destination.IntegerWidth() + 1;
281 	fWindow.height = (uint16)destination.IntegerHeight() + 1;
282 
283 	fHWInterface.ConfigureOverlay(this);
284 }
285 
286