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