xref: /haiku/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp (revision 99d1318ec02694fc520a0dc38ae38565db7e8c3c)
1 /*
2  * Copyright 2009, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include "RemoteHWInterface.h"
10 #include "RemoteDrawingEngine.h"
11 #include "RemoteEventStream.h"
12 #include "RemoteMessage.h"
13 
14 #include "NetReceiver.h"
15 #include "NetSender.h"
16 #include "StreamingRingBuffer.h"
17 
18 #include "SystemPalette.h"
19 
20 #include <Autolock.h>
21 #include <NetEndpoint.h>
22 
23 #include <new>
24 #include <string.h>
25 
26 
27 #define TRACE(x...)				/*debug_printf("RemoteHWInterface: " x)*/
28 #define TRACE_ALWAYS(x...)		debug_printf("RemoteHWInterface: " x)
29 #define TRACE_ERROR(x...)		debug_printf("RemoteHWInterface: " x)
30 
31 
32 struct callback_info {
33 	uint32				token;
34 	RemoteHWInterface::CallbackFunction	callback;
35 	void*				cookie;
36 };
37 
38 
39 RemoteHWInterface::RemoteHWInterface(const char* target)
40 	:
41 	HWInterface(),
42 	fTarget(target),
43 	fIsConnected(false),
44 	fProtocolVersion(100),
45 	fConnectionSpeed(0),
46 	fListenPort(10901),
47 	fListenEndpoint(NULL),
48 	fSendBuffer(NULL),
49 	fReceiveBuffer(NULL),
50 	fSender(NULL),
51 	fReceiver(NULL),
52 	fEventThread(-1),
53 	fEventStream(NULL),
54 	fCallbackLocker("callback locker")
55 {
56 	memset(&fFallbackMode, 0, sizeof(fFallbackMode));
57 	fFallbackMode.virtual_width = 640;
58 	fFallbackMode.virtual_height = 480;
59 	fFallbackMode.space = B_RGB32;
60 	_FillDisplayModeTiming(fFallbackMode);
61 
62 	fCurrentMode = fClientMode = fFallbackMode;
63 
64 	if (sscanf(fTarget, "%" B_SCNu16, &fListenPort) != 1) {
65 		fInitStatus = B_BAD_VALUE;
66 		return;
67 	}
68 
69 	fListenEndpoint.SetTo(new(std::nothrow) BNetEndpoint());
70 	if (!fListenEndpoint.IsSet()) {
71 		fInitStatus = B_NO_MEMORY;
72 		return;
73 	}
74 
75 	fInitStatus = fListenEndpoint->Bind(fListenPort);
76 	if (fInitStatus != B_OK)
77 		return;
78 
79 	fSendBuffer.SetTo(new(std::nothrow) StreamingRingBuffer(16 * 1024));
80 	if (!fSendBuffer.IsSet()) {
81 		fInitStatus = B_NO_MEMORY;
82 		return;
83 	}
84 
85 	fInitStatus = fSendBuffer->InitCheck();
86 	if (fInitStatus != B_OK)
87 		return;
88 
89 	fReceiveBuffer.SetTo(new(std::nothrow) StreamingRingBuffer(16 * 1024));
90 	if (!fReceiveBuffer.IsSet()) {
91 		fInitStatus = B_NO_MEMORY;
92 		return;
93 	}
94 
95 	fInitStatus = fReceiveBuffer->InitCheck();
96 	if (fInitStatus != B_OK)
97 		return;
98 
99 	fReceiver.SetTo(new(std::nothrow) NetReceiver(fListenEndpoint.Get(), fReceiveBuffer.Get(),
100 		_NewConnectionCallback, this));
101 	if (!fReceiver.IsSet()) {
102 		fInitStatus = B_NO_MEMORY;
103 		return;
104 	}
105 
106 	fEventStream.SetTo(new(std::nothrow) RemoteEventStream());
107 	if (!fEventStream.IsSet()) {
108 		fInitStatus = B_NO_MEMORY;
109 		return;
110 	}
111 
112 	fEventThread = spawn_thread(_EventThreadEntry, "remote event thread",
113 		B_NORMAL_PRIORITY, this);
114 	if (fEventThread < 0) {
115 		fInitStatus = fEventThread;
116 		return;
117 	}
118 
119 	resume_thread(fEventThread);
120 }
121 
122 
123 RemoteHWInterface::~RemoteHWInterface()
124 {
125 	//TODO: check order
126 	fReceiver.Unset();
127 	fReceiveBuffer.Unset();
128 
129 	fSendBuffer.Unset();
130 	fSender.Unset();
131 
132 	fListenEndpoint.Unset();
133 
134 	fEventStream.Unset();
135 }
136 
137 
138 status_t
139 RemoteHWInterface::Initialize()
140 {
141 	return fInitStatus;
142 }
143 
144 
145 status_t
146 RemoteHWInterface::Shutdown()
147 {
148 	_Disconnect();
149 	return B_OK;
150 }
151 
152 
153 DrawingEngine*
154 RemoteHWInterface::CreateDrawingEngine()
155 {
156 	return new(std::nothrow) RemoteDrawingEngine(this);
157 }
158 
159 
160 EventStream*
161 RemoteHWInterface::CreateEventStream()
162 {
163 	return fEventStream.Get();
164 }
165 
166 
167 status_t
168 RemoteHWInterface::AddCallback(uint32 token, CallbackFunction callback,
169 	void* cookie)
170 {
171 	BAutolock lock(fCallbackLocker);
172 	int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
173 	if (index >= 0)
174 		return B_NAME_IN_USE;
175 
176 	callback_info* info = new(std::nothrow) callback_info;
177 	if (info == NULL)
178 		return B_NO_MEMORY;
179 
180 	info->token = token;
181 	info->callback = callback;
182 	info->cookie = cookie;
183 
184 	fCallbacks.AddItem(info, -index - 1);
185 	return B_OK;
186 }
187 
188 
189 bool
190 RemoteHWInterface::RemoveCallback(uint32 token)
191 {
192 	BAutolock lock(fCallbackLocker);
193 	int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
194 	if (index < 0)
195 		return false;
196 
197 	delete fCallbacks.RemoveItemAt(index);
198 	return true;
199 }
200 
201 
202 callback_info*
203 RemoteHWInterface::_FindCallback(uint32 token)
204 {
205 	BAutolock lock(fCallbackLocker);
206 	return fCallbacks.BinarySearchByKey(token, &_CallbackCompare);
207 }
208 
209 
210 int
211 RemoteHWInterface::_CallbackCompare(const uint32* key,
212 	const callback_info* info)
213 {
214 	if (info->token == *key)
215 		return 0;
216 
217 	if (info->token < *key)
218 		return -1;
219 
220 	return 1;
221 }
222 
223 
224 int32
225 RemoteHWInterface::_EventThreadEntry(void* data)
226 {
227 	return ((RemoteHWInterface*)data)->_EventThread();
228 }
229 
230 
231 status_t
232 RemoteHWInterface::_EventThread()
233 {
234 	RemoteMessage message(fReceiveBuffer.Get(), NULL);
235 	while (true) {
236 		uint16 code;
237 		status_t result = message.NextMessage(code);
238 		if (result != B_OK) {
239 			TRACE_ERROR("failed to read message from receiver: %s\n",
240 				strerror(result));
241 			return result;
242 		}
243 
244 		TRACE("got message code %" B_PRIu16 " with %" B_PRIu32 " bytes\n", code,
245 			message.DataLeft());
246 
247 		if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) {
248 			// an input event, dispatch to the event stream
249 			if (fEventStream->EventReceived(message))
250 				continue;
251 		}
252 
253 		switch (code) {
254 			case RP_INIT_CONNECTION:
255 			{
256 				RemoteMessage reply(NULL, fSendBuffer.Get());
257 				reply.Start(RP_INIT_CONNECTION);
258 				status_t result = reply.Flush();
259 				(void)result;
260 				TRACE("init connection result: %s\n", strerror(result));
261 				break;
262 			}
263 
264 			case RP_UPDATE_DISPLAY_MODE:
265 			{
266 				int32 width, height;
267 				message.Read(width);
268 				result = message.Read(height);
269 				if (result != B_OK) {
270 					TRACE_ERROR("failed to read display mode\n");
271 					break;
272 				}
273 
274 				fIsConnected = true;
275 				fClientMode.virtual_width = width;
276 				fClientMode.virtual_height = height;
277 				_FillDisplayModeTiming(fClientMode);
278 				_NotifyScreenChanged();
279 				break;
280 			}
281 
282 			case RP_GET_SYSTEM_PALETTE:
283 			{
284 				RemoteMessage reply(NULL, fSendBuffer.Get());
285 				reply.Start(RP_GET_SYSTEM_PALETTE_RESULT);
286 
287 				const color_map *map = SystemColorMap();
288 				uint32 count = (uint32)B_COUNT_OF(map->color_list);
289 
290 				reply.Add(count);
291 				for (size_t i = 0; i < count; i++) {
292 					const rgb_color &color = map->color_list[i];
293 					reply.Add(color.red);
294 					reply.Add(color.green);
295 					reply.Add(color.blue);
296 					reply.Add(color.alpha);
297 				}
298 
299 				break;
300 			}
301 
302 			default:
303 			{
304 				uint32 token;
305 				if (message.Read(token) == B_OK) {
306 					callback_info* info = _FindCallback(token);
307 					if (info != NULL && info->callback(info->cookie, message))
308 						break;
309 				}
310 
311 				TRACE_ERROR("unhandled remote event code %u\n", code);
312 				break;
313 			}
314 		}
315 	}
316 }
317 
318 
319 status_t
320 RemoteHWInterface::_NewConnectionCallback(void *cookie, BNetEndpoint &endpoint)
321 {
322 	return ((RemoteHWInterface *)cookie)->_NewConnection(endpoint);
323 }
324 
325 
326 status_t
327 RemoteHWInterface::_NewConnection(BNetEndpoint &endpoint)
328 {
329 	fSender.Unset();
330 
331 	fSendBuffer->MakeEmpty();
332 
333 	BNetEndpoint *sendEndpoint = new(std::nothrow) BNetEndpoint(endpoint);
334 	if (sendEndpoint == NULL)
335 		return B_NO_MEMORY;
336 
337 	fSender.SetTo(new(std::nothrow) NetSender(sendEndpoint, fSendBuffer.Get()));
338 	if (!fSender.IsSet()) {
339 		delete sendEndpoint;
340 		return B_NO_MEMORY;
341 	}
342 
343 	return B_OK;
344 }
345 
346 
347 void
348 RemoteHWInterface::_Disconnect()
349 {
350 	if (fIsConnected) {
351 		RemoteMessage message(NULL, fSendBuffer.Get());
352 		message.Start(RP_CLOSE_CONNECTION);
353 		message.Flush();
354 		fIsConnected = false;
355 	}
356 
357 	if (fListenEndpoint.IsSet())
358 		fListenEndpoint->Close();
359 }
360 
361 
362 status_t
363 RemoteHWInterface::SetMode(const display_mode& mode)
364 {
365 	TRACE("set mode: %" B_PRIu16 " %" B_PRIu16 "\n", mode.virtual_width,
366 		mode.virtual_height);
367 	fCurrentMode = mode;
368 	return B_OK;
369 }
370 
371 
372 void
373 RemoteHWInterface::GetMode(display_mode* mode)
374 {
375 	if (mode == NULL || !ReadLock())
376 		return;
377 
378 	*mode = fCurrentMode;
379 	ReadUnlock();
380 
381 	TRACE("get mode: %" B_PRIu16 " %" B_PRIu16 "\n", mode->virtual_width,
382 		mode->virtual_height);
383 }
384 
385 
386 status_t
387 RemoteHWInterface::GetPreferredMode(display_mode* mode)
388 {
389 	*mode = fClientMode;
390 	return B_OK;
391 }
392 
393 
394 status_t
395 RemoteHWInterface::GetDeviceInfo(accelerant_device_info* info)
396 {
397 	if (!ReadLock())
398 		return B_ERROR;
399 
400 	info->version = fProtocolVersion;
401 	info->dac_speed = fConnectionSpeed;
402 	info->memory = 33554432; // 32MB
403 	strlcpy(info->name, "Haiku, Inc. RemoteHWInterface", sizeof(info->name));
404 	strlcpy(info->chipset, "Haiku, Inc. Chipset", sizeof(info->chipset));
405 	strlcpy(info->serial_no, fTarget, sizeof(info->serial_no));
406 
407 	ReadUnlock();
408 	return B_OK;
409 }
410 
411 
412 status_t
413 RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
414 {
415 	// We don't actually have a frame buffer.
416 	return B_UNSUPPORTED;
417 }
418 
419 
420 status_t
421 RemoteHWInterface::GetModeList(display_mode** _modes, uint32* _count)
422 {
423 	AutoReadLocker _(this);
424 
425 	display_mode* modes = new(std::nothrow) display_mode[2];
426 	if (modes == NULL)
427 		return B_NO_MEMORY;
428 
429 	modes[0] = fFallbackMode;
430 	modes[1] = fClientMode;
431 	*_modes = modes;
432 	*_count = 2;
433 
434 	return B_OK;
435 }
436 
437 
438 status_t
439 RemoteHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
440 	uint32* high)
441 {
442 	TRACE("get pixel clock limits unsupported\n");
443 	return B_UNSUPPORTED;
444 }
445 
446 
447 status_t
448 RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints)
449 {
450 	TRACE("get timing constraints unsupported\n");
451 	return B_UNSUPPORTED;
452 }
453 
454 
455 status_t
456 RemoteHWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
457 	const display_mode* high)
458 {
459 	TRACE("propose mode: %" B_PRIu16 " %" B_PRIu16 "\n",
460 		candidate->virtual_width, candidate->virtual_height);
461 	return B_OK;
462 }
463 
464 
465 status_t
466 RemoteHWInterface::SetDPMSMode(uint32 state)
467 {
468 	return B_UNSUPPORTED;
469 }
470 
471 
472 uint32
473 RemoteHWInterface::DPMSMode()
474 {
475 	return B_UNSUPPORTED;
476 }
477 
478 
479 uint32
480 RemoteHWInterface::DPMSCapabilities()
481 {
482 	return 0;
483 }
484 
485 
486 status_t
487 RemoteHWInterface::SetBrightness(float)
488 {
489 	return B_UNSUPPORTED;
490 }
491 
492 
493 status_t
494 RemoteHWInterface::GetBrightness(float*)
495 {
496 	return B_UNSUPPORTED;
497 }
498 
499 
500 sem_id
501 RemoteHWInterface::RetraceSemaphore()
502 {
503 	return -1;
504 }
505 
506 
507 status_t
508 RemoteHWInterface::WaitForRetrace(bigtime_t timeout)
509 {
510 	return B_UNSUPPORTED;
511 }
512 
513 
514 void
515 RemoteHWInterface::SetCursor(ServerCursor* cursor)
516 {
517 	HWInterface::SetCursor(cursor);
518 	RemoteMessage message(NULL, fSendBuffer.Get());
519 	message.Start(RP_SET_CURSOR);
520 	message.AddCursor(CursorAndDragBitmap().Get());
521 }
522 
523 
524 void
525 RemoteHWInterface::SetCursorVisible(bool visible)
526 {
527 	HWInterface::SetCursorVisible(visible);
528 	RemoteMessage message(NULL, fSendBuffer.Get());
529 	message.Start(RP_SET_CURSOR_VISIBLE);
530 	message.Add(visible);
531 }
532 
533 
534 void
535 RemoteHWInterface::MoveCursorTo(float x, float y)
536 {
537 	HWInterface::MoveCursorTo(x, y);
538 	RemoteMessage message(NULL, fSendBuffer.Get());
539 	message.Start(RP_MOVE_CURSOR_TO);
540 	message.Add(x);
541 	message.Add(y);
542 }
543 
544 
545 void
546 RemoteHWInterface::SetDragBitmap(const ServerBitmap* bitmap,
547 	const BPoint& offsetFromCursor)
548 {
549 	HWInterface::SetDragBitmap(bitmap, offsetFromCursor);
550 	RemoteMessage message(NULL, fSendBuffer.Get());
551 	message.Start(RP_SET_CURSOR);
552 	message.AddCursor(CursorAndDragBitmap().Get());
553 }
554 
555 
556 RenderingBuffer*
557 RemoteHWInterface::FrontBuffer() const
558 {
559 	return NULL;
560 }
561 
562 
563 RenderingBuffer*
564 RemoteHWInterface::BackBuffer() const
565 {
566 	return NULL;
567 }
568 
569 
570 bool
571 RemoteHWInterface::IsDoubleBuffered() const
572 {
573 	return false;
574 }
575 
576 
577 status_t
578 RemoteHWInterface::InvalidateRegion(const BRegion& region)
579 {
580 	RemoteMessage message(NULL, fSendBuffer.Get());
581 	message.Start(RP_INVALIDATE_REGION);
582 	message.AddRegion(region);
583 	return B_OK;
584 }
585 
586 
587 status_t
588 RemoteHWInterface::Invalidate(const BRect& frame)
589 {
590 	RemoteMessage message(NULL, fSendBuffer.Get());
591 	message.Start(RP_INVALIDATE_RECT);
592 	message.Add(frame);
593 	return B_OK;
594 }
595 
596 
597 status_t
598 RemoteHWInterface::CopyBackToFront(const BRect& frame)
599 {
600 	return B_OK;
601 }
602 
603 
604 void
605 RemoteHWInterface::_FillDisplayModeTiming(display_mode &mode)
606 {
607 	mode.timing.pixel_clock
608 		= (uint64_t)mode.virtual_width * mode.virtual_height * 60 / 1000;
609 	mode.timing.h_display = mode.timing.h_sync_start = mode.timing.h_sync_end
610 		= mode.timing.h_total = mode.virtual_width;
611 	mode.timing.v_display = mode.timing.v_sync_start = mode.timing.v_sync_end
612 		= mode.timing.v_total = mode.virtual_height;
613 }
614