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:
SemaphoreLocker(sem_id semaphore,bigtime_t timeout=B_INFINITE_TIMEOUT)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
~SemaphoreLocker()41 ~SemaphoreLocker()
42 {
43 if (fStatus == B_OK)
44 release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
45 }
46
LockStatus()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
Overlay(HWInterface & interface,ServerBitmap * bitmap,overlay_token token)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
~Overlay()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
InitCheck() const97 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
Resume(ServerBitmap * bitmap)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
Suspend(ServerBitmap * bitmap,bool needTemporary)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
_FreeBuffer()146 Overlay::_FreeBuffer()
147 {
148 fHWInterface.FreeOverlayBuffer(fOverlayBuffer);
149 fOverlayBuffer = NULL;
150 }
151
152
153 status_t
_AllocateBuffer(ServerBitmap * bitmap)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
SetClientData(overlay_client_data * clientData)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
SetFlags(uint32 flags)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
TakeOverToken(Overlay * other)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*
OverlayBuffer() const199 Overlay::OverlayBuffer() const
200 {
201 return fOverlayBuffer;
202 }
203
204
205 overlay_client_data*
ClientData() const206 Overlay::ClientData() const
207 {
208 return fClientData;
209 }
210
211
212 overlay_token
OverlayToken() const213 Overlay::OverlayToken() const
214 {
215 return fOverlayToken;
216 }
217
218
219 void
Hide()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
SetColorSpace(uint32 colorSpace)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
Configure(const BRect & source,const BRect & destination)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