xref: /haiku/src/servers/app/drawing/interface/virtual/DWindowHWInterface.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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  *		Michael Lotz <mmlr@mlotz.ch>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 
11 
12 /*!	BView/BDirectWindow/Accelerant combination HWInterface implementation
13 */
14 
15 
16 #include "DWindowHWInterface.h"
17 
18 #include <malloc.h>
19 #include <new>
20 #include <stdio.h>
21 
22 #include <Application.h>
23 #include <Bitmap.h>
24 #include <Cursor.h>
25 #include <DirectWindow.h>
26 #include <Locker.h>
27 #include <Message.h>
28 #include <MessageFilter.h>
29 #include <MessageRunner.h>
30 #include <Region.h>
31 #include <Screen.h>
32 #include <String.h>
33 #include <View.h>
34 
35 #include <Accelerant.h>
36 #include <graphic_driver.h>
37 #include <FindDirectory.h>
38 #include <image.h>
39 #include <dirent.h>
40 #include <sys/ioctl.h>
41 #include <unistd.h>
42 
43 #include <ServerProtocol.h>
44 
45 #include "DWindowBuffer.h"
46 #include "PortLink.h"
47 #include "RGBColor.h"
48 #include "ServerConfig.h"
49 #include "ServerCursor.h"
50 #include "UpdateQueue.h"
51 
52 
53 #ifdef DEBUG_DRIVER_MODULE
54 #	include <stdio.h>
55 #	define STRACE(x) printf x
56 #else
57 #	define STRACE(x) ;
58 #endif
59 
60 
61 const unsigned char kEmptyCursor[] = { 16, 1, 0, 0,
62 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
66 
67 
68 static int32
69 run_app_thread(void* cookie)
70 {
71 	if (BApplication* app = (BApplication*)cookie) {
72 		app->Lock();
73 		app->Run();
74 	}
75 	return 0;
76 }
77 
78 
79 //#define INPUTSERVER_TEST_MODE 1
80 
81 
82 class DView : public BView {
83 public:
84 								DView(BRect bounds);
85 	virtual						~DView();
86 
87 								// DView
88 			void				ForwardMessage(BMessage* message = NULL);
89 
90 private:
91 			port_id				fInputPort;
92 };
93 
94 class DWindow : public BWindow {
95 public:
96 								DWindow(BRect frame,
97 									DWindowHWInterface* interface,
98 									DWindowBuffer* buffer);
99 	virtual						~DWindow();
100 
101 	virtual	bool				QuitRequested();
102 
103 //	virtual	void				DirectConnected(direct_buffer_info* info);
104 
105 	virtual	void				FrameMoved(BPoint newOffset);
106 
107 private:
108 	DWindowHWInterface*			fHWInterface;
109 	DWindowBuffer*				fBuffer;
110 };
111 
112 class DirectMessageFilter : public BMessageFilter {
113 public:
114 								DirectMessageFilter(DView* view);
115 
116 	virtual filter_result		Filter(BMessage *message, BHandler** _target);
117 
118 private:
119 			DView*				fView;
120 };
121 
122 
123 //	#pragma mark -
124 
125 
126 DView::DView(BRect bounds)
127 	:
128 	BView(bounds, "graphics card view", B_FOLLOW_ALL, 0)
129 {
130 	SetViewColor(B_TRANSPARENT_COLOR);
131 #ifndef INPUTSERVER_TEST_MODE
132 	fInputPort = create_port(200, SERVER_INPUT_PORT);
133 #else
134 	fInputPort = create_port(100, "ViewInputDevice");
135 #endif
136 
137 #ifdef ENABLE_INPUT_SERVER_EMULATION
138 	AddFilter(new DirectMessageFilter(this));
139 #endif
140 }
141 
142 
143 DView::~DView()
144 {
145 }
146 
147 
148 /*!	This function emulates the Input Server by sending the *exact* same kind of
149 	messages to the server's port. Being we're using a regular window, it would
150 	make little sense to do anything else.
151 */
152 void
153 DView::ForwardMessage(BMessage* message)
154 {
155 	if (message == NULL)
156 		message = Window()->CurrentMessage();
157 	if (message == NULL)
158 		return;
159 
160 	// remove some fields that potentially mess up our own message processing
161 	BMessage copy = *message;
162 	copy.RemoveName("screen_where");
163 	copy.RemoveName("be:transit");
164 	copy.RemoveName("be:view_where");
165 	copy.RemoveName("be:cursor_needed");
166 
167 	size_t length = copy.FlattenedSize();
168 	char stream[length];
169 
170 	if (copy.Flatten(stream, length) == B_OK)
171 		write_port(fInputPort, 0, stream, length);
172 }
173 
174 
175 //	#pragma mark -
176 
177 
178 DirectMessageFilter::DirectMessageFilter(DView* view)
179 	:
180 	BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
181 	fView(view)
182 {
183 }
184 
185 
186 filter_result
187 DirectMessageFilter::Filter(BMessage* message, BHandler** target)
188 {
189 	switch (message->what) {
190 		case B_KEY_DOWN:
191 		case B_UNMAPPED_KEY_DOWN:
192 		case B_KEY_UP:
193 		case B_UNMAPPED_KEY_UP:
194 		case B_MOUSE_DOWN:
195 		case B_MOUSE_UP:
196 		case B_MOUSE_WHEEL_CHANGED:
197 			fView->ForwardMessage(message);
198 			return B_SKIP_MESSAGE;
199 
200 		case B_MOUSE_MOVED:
201 		{
202 			int32 transit;
203 			if (message->FindInt32("be:transit", &transit) == B_OK
204 				&& transit == B_ENTERED_VIEW) {
205 				// A bug in R5 prevents this call from having an effect if
206 				// called elsewhere, and calling it here works, if we're lucky :-)
207 				BCursor cursor(kEmptyCursor);
208 				fView->SetViewCursor(&cursor, true);
209 			}
210 			fView->ForwardMessage(message);
211 			return B_SKIP_MESSAGE;
212 		}
213 	}
214 
215 	return B_DISPATCH_MESSAGE;
216 }
217 
218 
219 //	#pragma mark -
220 
221 
222 DWindow::DWindow(BRect frame, DWindowHWInterface* interface,
223 		DWindowBuffer* buffer)
224 	:
225 	BWindow(frame, "Haiku App Server", B_TITLED_WINDOW_LOOK,
226 		B_NORMAL_WINDOW_FEEL,
227 		B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_MOVABLE),
228 	fHWInterface(interface),
229 	fBuffer(buffer)
230 {
231 	DView* view = new DView(Bounds());
232 	AddChild(view);
233 	view->MakeFocus();
234 		// make it receive key events
235 }
236 
237 
238 DWindow::~DWindow()
239 {
240 }
241 
242 
243 bool
244 DWindow::QuitRequested()
245 {
246 	port_id serverport = find_port(SERVER_PORT_NAME);
247 
248 	if (serverport >= 0) {
249 		BPrivate::PortLink link(serverport);
250 		link.StartMessage(B_QUIT_REQUESTED);
251 		link.Flush();
252 	} else
253 		printf("ERROR: couldn't find the app_server's main port!");
254 
255 	// we don't quit on ourself, we let us be Quit()!
256 	return false;
257 }
258 
259 
260 /*
261 void
262 DWindow::DirectConnected(direct_buffer_info* info)
263 {
264 //	fDesktop->LockClipping();
265 //
266 //	fEngine.Lock();
267 //
268 	switch(info->buffer_state & B_DIRECT_MODE_MASK) {
269 		case B_DIRECT_START:
270 		case B_DIRECT_MODIFY:
271 			fBuffer->SetTo(info);
272 //			fDesktop->SetOffset(info->window_bounds.left, info->window_bounds.top);
273 			break;
274 		case B_DIRECT_STOP:
275 			fBuffer->SetTo(NULL);
276 			break;
277 	}
278 //
279 //	fDesktop->SetMasterClipping(&fBuffer.WindowClipping());
280 //
281 //	fEngine.Unlock();
282 //
283 //	fDesktop->UnlockClipping();
284 }
285 */
286 
287 
288 void
289 DWindow::FrameMoved(BPoint newOffset)
290 {
291 	fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y);
292 }
293 
294 
295 //	#pragma mark -
296 
297 
298 const int32 kDefaultParamsCount = 64;
299 
300 DWindowHWInterface::DWindowHWInterface()
301 	:
302 	HWInterface(),
303 	fFrontBuffer(new DWindowBuffer()),
304 	fWindow(NULL),
305 
306 	fXOffset(50),
307 	fYOffset(50),
308 
309 	fCardFD(-1),
310 	fAccelerantImage(-1),
311 	fAccelerantHook(NULL),
312 	fEngineToken(NULL),
313 	fSyncToken(),
314 
315 	// required hooks
316 	fAccAcquireEngine(NULL),
317 	fAccReleaseEngine(NULL),
318 	fAccSyncToToken(NULL),
319 	fAccGetModeCount(NULL),
320 	fAccGetModeList(NULL),
321 	fAccGetFrameBufferConfig(NULL),
322 	fAccSetDisplayMode(NULL),
323 	fAccGetDisplayMode(NULL),
324 	fAccGetPixelClockLimits(NULL),
325 
326 	// optional accelerant hooks
327 	fAccGetTimingConstraints(NULL),
328 	fAccProposeDisplayMode(NULL),
329 	fAccFillRect(NULL),
330 	fAccInvertRect(NULL),
331 	fAccScreenBlit(NULL),
332 	fAccSetCursorShape(NULL),
333 	fAccMoveCursor(NULL),
334 	fAccShowCursor(NULL),
335 
336 	fRectParams(new (std::nothrow) fill_rect_params[kDefaultParamsCount]),
337 	fRectParamsCount(kDefaultParamsCount),
338 	fBlitParams(new (std::nothrow) blit_params[kDefaultParamsCount]),
339 	fBlitParamsCount(kDefaultParamsCount)
340 {
341 	fDisplayMode.virtual_width = 800;
342 	fDisplayMode.virtual_height = 600;
343 	fDisplayMode.space = B_RGBA32;
344 
345 	memset(&fSyncToken, 0, sizeof(sync_token));
346 }
347 
348 
349 DWindowHWInterface::~DWindowHWInterface()
350 {
351 	if (fWindow) {
352 		fWindow->Lock();
353 		fWindow->Quit();
354 	}
355 
356 	delete[] fRectParams;
357 	delete[] fBlitParams;
358 
359 	be_app->Lock();
360 	be_app->Quit();
361 	delete be_app;
362 }
363 
364 
365 status_t
366 DWindowHWInterface::Initialize()
367 {
368 	status_t ret = HWInterface::Initialize();
369 
370 	if (!fRectParams || !fBlitParams)
371 		return B_NO_MEMORY;
372 
373 	if (ret >= B_OK) {
374 		for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) {
375 			fCardFD = _OpenGraphicsDevice(i);
376 			if (fCardFD < 0) {
377 				STRACE(("Failed to open graphics device\n"));
378 				continue;
379 			}
380 
381 			if (_OpenAccelerant(fCardFD) == B_OK)
382 				break;
383 
384 			close(fCardFD);
385 			// _OpenAccelerant() failed, try to open next graphics card
386 		}
387 
388 		return fCardFD >= 0 ? B_OK : fCardFD;
389 	}
390 	return ret;
391 }
392 
393 
394 /*!	\brief Opens a graphics device for read-write access
395 	\param deviceNumber Number identifying which graphics card to open (1 for
396 		first card)
397 	\return The file descriptor for the opened graphics device
398 
399 	The deviceNumber is relative to the number of graphics devices that can be
400 	successfully opened.  One represents the first card that can be successfully
401 	opened (not necessarily the first one listed in the directory).
402 	Graphics drivers must be able to be opened more than once, so we really get
403 	the first working entry.
404 */
405 int
406 DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber)
407 {
408 	DIR *directory = opendir("/dev/graphics");
409 	if (!directory)
410 		return -1;
411 
412 	// TODO: We do not need to avoid the "vesa" or "framebuffer" drivers this way
413 	// once they been ported to the new driver architecture - the special case here
414 	// can then be removed.
415 	int count = 0;
416 	struct dirent *entry = NULL;
417 	int current_card_fd = -1;
418 	char path[PATH_MAX];
419 	while (count < deviceNumber && (entry = readdir(directory)) != NULL) {
420 		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")
421 			|| !strcmp(entry->d_name, "vesa") || !strcmp(entry->d_name, "framebuffer"))
422 			continue;
423 
424 		if (current_card_fd >= 0) {
425 			close(current_card_fd);
426 			current_card_fd = -1;
427 		}
428 
429 		sprintf(path, "/dev/graphics/%s", entry->d_name);
430 		current_card_fd = open(path, B_READ_WRITE);
431 		if (current_card_fd >= 0)
432 			count++;
433 	}
434 
435 	// Open VESA or Framebuffer driver if we were not able to get a better one.
436 	if (count < deviceNumber) {
437 		if (deviceNumber == 1) {
438 			sprintf(path, "/dev/graphics/vesa");
439 			current_card_fd = open(path, B_READ_WRITE);
440 			if (current_card_fd < 0) {
441 				sprintf(path, "/dev/graphics/framebuffer");
442 				current_card_fd = open(path, B_READ_WRITE);
443 			}
444 		} else {
445 			close(current_card_fd);
446 			current_card_fd = B_ENTRY_NOT_FOUND;
447 		}
448 	}
449 
450 	if (entry)
451 		fCardNameInDevFS = entry->d_name;
452 
453 	return current_card_fd;
454 }
455 
456 
457 status_t
458 DWindowHWInterface::_OpenAccelerant(int device)
459 {
460 	char signature[1024];
461 	if (ioctl(device, B_GET_ACCELERANT_SIGNATURE,
462 			&signature, sizeof(signature)) != B_OK)
463 		return B_ERROR;
464 
465 	STRACE(("accelerant signature is: %s\n", signature));
466 
467 	struct stat accelerant_stat;
468 	const static directory_which dirs[] = {
469 		B_USER_NONPACKAGED_ADDONS_DIRECTORY,
470 		B_USER_ADDONS_DIRECTORY,
471 		B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
472 		B_SYSTEM_ADDONS_DIRECTORY
473 	};
474 
475 	fAccelerantImage = -1;
476 
477 	for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) {
478 		char path[PATH_MAX];
479 		if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
480 			continue;
481 
482 		strcat(path, "/accelerants/");
483 		strcat(path, signature);
484 		if (stat(path, &accelerant_stat) != 0)
485 			continue;
486 
487 		fAccelerantImage = load_add_on(path);
488 		if (fAccelerantImage >= 0) {
489 			if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
490 				B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
491 				STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
492 				unload_add_on(fAccelerantImage);
493 				fAccelerantImage = -1;
494 				return B_ERROR;
495 			}
496 
497 
498 			accelerant_clone_info_size cloneInfoSize;
499 			cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook(
500 				B_ACCELERANT_CLONE_INFO_SIZE, NULL);
501 			if (!cloneInfoSize) {
502 				STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path));
503 				unload_add_on(fAccelerantImage);
504 				fAccelerantImage = -1;
505 				return B_ERROR;
506 			}
507 
508 			ssize_t cloneSize = cloneInfoSize();
509 			void* cloneInfoData = malloc(cloneSize);
510 
511 //			get_accelerant_clone_info getCloneInfo;
512 //			getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL);
513 //			if (!getCloneInfo) {
514 //				STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path));
515 //				unload_add_on(fAccelerantImage);
516 //				fAccelerantImage = -1;
517 //				return B_ERROR;
518 //			}
519 //			printf("getCloneInfo: %p\n", getCloneInfo);
520 //
521 //			getCloneInfo(cloneInfoData);
522 // TODO: this is what works for the ATI Radeon driver...
523 sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String());
524 
525 			clone_accelerant cloneAccelerant;
526 			cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL);
527 			if (!cloneAccelerant) {
528 				STRACE(("unable to get B_CLONE_ACCELERANT\n"));
529 				unload_add_on(fAccelerantImage);
530 				fAccelerantImage = -1;
531 				free(cloneInfoData);
532 				return B_ERROR;
533 			}
534 			status_t ret = cloneAccelerant(cloneInfoData);
535 			if (ret  != B_OK) {
536 				STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret)));
537 				unload_add_on(fAccelerantImage);
538 				fAccelerantImage = -1;
539 				return B_ERROR;
540 			}
541 
542 			break;
543 		}
544 	}
545 
546 	if (fAccelerantImage < B_OK)
547 		return B_ERROR;
548 
549 	if (_SetupDefaultHooks() != B_OK) {
550 		STRACE(("cannot setup default hooks\n"));
551 
552 		uninit_accelerant uninitAccelerant = (uninit_accelerant)
553 			fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
554 		if (uninitAccelerant != NULL)
555 			uninitAccelerant();
556 
557 		unload_add_on(fAccelerantImage);
558 		return B_ERROR;
559 	} else {
560 		_UpdateFrameBufferConfig();
561 	}
562 
563 	return B_OK;
564 }
565 
566 
567 status_t
568 DWindowHWInterface::_SetupDefaultHooks()
569 {
570 	// required
571 	fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
572 	fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
573 	fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL);
574 	fAccGetModeCount = (accelerant_mode_count)fAccelerantHook(
575 		B_ACCELERANT_MODE_COUNT, NULL);
576 	fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
577 	fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(
578 		B_GET_FRAME_BUFFER_CONFIG, NULL);
579 	fAccSetDisplayMode = (set_display_mode)fAccelerantHook(
580 		B_SET_DISPLAY_MODE, NULL);
581 	fAccGetDisplayMode = (get_display_mode)fAccelerantHook(
582 		B_GET_DISPLAY_MODE, NULL);
583 	fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
584 		B_GET_PIXEL_CLOCK_LIMITS, NULL);
585 
586 	if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
587 		|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
588 		|| !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
589 		return B_ERROR;
590 	}
591 
592 	// optional
593 	fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
594 		B_GET_TIMING_CONSTRAINTS, NULL);
595 	fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
596 		B_PROPOSE_DISPLAY_MODE, NULL);
597 
598 	// cursor
599 	fAccSetCursorShape = (set_cursor_shape)fAccelerantHook(
600 		B_SET_CURSOR_SHAPE, NULL);
601 	fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
602 	fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
603 
604 	// update acceleration hooks
605 	// TODO: would actually have to pass a valid display_mode!
606 	fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL);
607 	fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL);
608 	fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(
609 		B_SCREEN_TO_SCREEN_BLIT, NULL);
610 
611 	return B_OK;
612 }
613 
614 
615 status_t
616 DWindowHWInterface::_UpdateFrameBufferConfig()
617 {
618 	frame_buffer_config config;
619 	if (fAccGetFrameBufferConfig(&config) != B_OK) {
620 		STRACE(("unable to get frame buffer config\n"));
621 		return B_ERROR;
622 	}
623 
624 	fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width,
625 		fDisplayMode.virtual_height, (color_space)fDisplayMode.space);
626 
627 	return B_OK;
628 }
629 
630 
631 status_t
632 DWindowHWInterface::Shutdown()
633 {
634 	printf("DWindowHWInterface::Shutdown()\n");
635 	if (fAccelerantHook) {
636 		uninit_accelerant UninitAccelerant
637 			= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
638 		if (UninitAccelerant)
639 			UninitAccelerant();
640 	}
641 
642 	if (fAccelerantImage >= 0)
643 		unload_add_on(fAccelerantImage);
644 
645 	if (fCardFD >= 0)
646 		close(fCardFD);
647 
648 	return B_OK;
649 }
650 
651 
652 status_t
653 DWindowHWInterface::SetMode(const display_mode& mode)
654 {
655 	AutoWriteLocker _(this);
656 
657 	status_t ret = B_OK;
658 	// prevent from doing the unnecessary
659 	if (fFrontBuffer.IsSet()
660 		&& fDisplayMode.virtual_width == mode.virtual_width
661 		&& fDisplayMode.virtual_height == mode.virtual_height
662 		&& fDisplayMode.space == mode.space)
663 		return ret;
664 
665 	// check if we support the mode
666 
667 	display_mode *modes;
668 	uint32 modeCount, i;
669 	if (GetModeList(&modes, &modeCount) != B_OK)
670 		return B_NO_MEMORY;
671 
672 	for (i = 0; i < modeCount; i++) {
673 		// we only care for the bare minimum
674 		if (modes[i].virtual_width == mode.virtual_width
675 			&& modes[i].virtual_height == mode.virtual_height
676 			&& modes[i].space == mode.space) {
677 			// take over settings
678 			fDisplayMode = modes[i];
679 			break;
680 		}
681 	}
682 
683 	delete[] modes;
684 
685 	if (i == modeCount)
686 		return B_BAD_VALUE;
687 
688 	BRect frame(0.0, 0.0,
689 				fDisplayMode.virtual_width - 1,
690 				fDisplayMode.virtual_height - 1);
691 
692 	// create the window if we don't have one already
693 	if (!fWindow) {
694 		// if the window has not been created yet, the BApplication
695 		// has not been created either, but we need one to display
696 		// a real BWindow in the test environment.
697 		// be_app->Run() needs to be called in another thread
698 		BApplication* app = new BApplication(
699 			"application/x-vnd.Haiku-test-app_server");
700 		app->Unlock();
701 
702 		thread_id appThread = spawn_thread(run_app_thread, "app thread",
703 										   B_NORMAL_PRIORITY, app);
704 		if (appThread >= B_OK)
705 			ret = resume_thread(appThread);
706 		else
707 			ret = appThread;
708 
709 		if (ret < B_OK)
710 			return ret;
711 
712 		fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this,
713 			fFrontBuffer.Get());
714 
715 		// fire up the window thread but don't show it on screen yet
716 		fWindow->Hide();
717 		fWindow->Show();
718 	}
719 
720 	if (fWindow->Lock()) {
721 		// free and reallocate the bitmaps while the window is locked,
722 		// so that the view does not accidentally draw a freed bitmap
723 
724 		if (ret >= B_OK) {
725 			// change the window size and update the bitmap used for drawing
726 			fWindow->ResizeTo(frame.Width(), frame.Height());
727 		}
728 
729 		// window is hidden when this function is called the first time
730 		if (fWindow->IsHidden())
731 			fWindow->Show();
732 
733 		fWindow->Unlock();
734 	} else {
735 		ret = B_ERROR;
736 	}
737 
738 	_UpdateFrameBufferConfig();
739 	_NotifyFrameBufferChanged();
740 
741 	return ret;
742 }
743 
744 
745 void
746 DWindowHWInterface::GetMode(display_mode* mode)
747 {
748 	if (mode && ReadLock()) {
749 		*mode = fDisplayMode;
750 		ReadUnlock();
751 	}
752 }
753 
754 
755 status_t
756 DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info)
757 {
758 	// We really don't have to provide anything here because this is strictly
759 	// a software-only driver, but we'll have some fun, anyway.
760 	if (ReadLock()) {
761 		info->version = 100;
762 		sprintf(info->name, "Haiku, Inc. DWindowHWInterface");
763 		sprintf(info->chipset, "Haiku, Inc. Chipset");
764 		sprintf(info->serial_no, "3.14159265358979323846");
765 		info->memory = 134217728;	// 128 MB, not that we really have that much. :)
766 		info->dac_speed = 0xFFFFFFFF;	// *heh*
767 
768 		ReadUnlock();
769 	}
770 
771 	return B_OK;
772 }
773 
774 
775 status_t
776 DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
777 {
778 	if (!fFrontBuffer.IsSet())
779 		return B_ERROR;
780 
781 	config.frame_buffer = fFrontBuffer->Bits();
782 	config.frame_buffer_dma = NULL;
783 	config.bytes_per_row = fFrontBuffer->BytesPerRow();
784 
785 	return B_OK;
786 }
787 
788 
789 status_t
790 DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count)
791 {
792 	AutoReadLocker _(this);
793 
794 #if 1
795 	// setup a whole bunch of different modes
796 	const struct resolution { int32 width, height; } resolutions[] = {
797 		{640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960},
798 		{1280, 1024}, {1400, 1050}, {1600, 1200}
799 	};
800 	uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]);
801 //	const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32};
802 	uint32 count = resolutionCount/* * 4*/;
803 
804 	display_mode* modes = new(std::nothrow) display_mode[count];
805 	if (modes == NULL)
806 		return B_NO_MEMORY;
807 
808 	*_modes = modes;
809 	*_count = count;
810 
811 	int32 index = 0;
812 	for (uint32 i = 0; i < resolutionCount; i++) {
813 		modes[index].virtual_width = resolutions[i].width;
814 		modes[index].virtual_height = resolutions[i].height;
815 		modes[index].space = B_RGB32;
816 
817 		modes[index].h_display_start = 0;
818 		modes[index].v_display_start = 0;
819 		modes[index].timing.h_display = resolutions[i].width;
820 		modes[index].timing.v_display = resolutions[i].height;
821 		modes[index].timing.h_total = 22000;
822 		modes[index].timing.v_total = 22000;
823 		modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total
824 			* modes[index].timing.v_total * 60) / 1000;
825 		modes[index].flags = B_PARALLEL_ACCESS;
826 
827 		index++;
828 	}
829 #else
830 	// support only a single mode, useful
831 	// for testing a specific mode
832 	display_mode *modes = new(std::nothrow) display_mode[1];
833 	modes[0].virtual_width = 800;
834 	modes[0].virtual_height = 600;
835 	modes[0].space = B_BRGB32;
836 
837 	*_modes = modes;
838 	*_count = 1;
839 #endif
840 
841 	return B_OK;
842 }
843 
844 
845 status_t
846 DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
847 	uint32* high)
848 {
849 	return B_ERROR;
850 }
851 
852 
853 status_t
854 DWindowHWInterface::GetTimingConstraints(
855 	display_timing_constraints* constraints)
856 {
857 	return B_ERROR;
858 }
859 
860 
861 status_t
862 DWindowHWInterface::ProposeMode(display_mode* candidate,
863 	const display_mode* low, const display_mode* high)
864 {
865 	// We should be able to get away with this because we're not dealing with
866 	// any specific hardware. This is a Good Thing(TM) because we can support
867 	// any hardware we wish within reasonable expectaions and programmer
868 	// laziness. :P
869 	return B_OK;
870 }
871 
872 
873 sem_id
874 DWindowHWInterface::RetraceSemaphore()
875 {
876 	return -1;
877 }
878 
879 
880 status_t
881 DWindowHWInterface::WaitForRetrace(bigtime_t timeout)
882 {
883 	// Locking shouldn't be necessary here - R5 should handle this for us. :)
884 	BScreen screen;
885 	return screen.WaitForRetrace(timeout);
886 }
887 
888 
889 status_t
890 DWindowHWInterface::SetDPMSMode(uint32 state)
891 {
892 	AutoWriteLocker _(this);
893 
894 	return BScreen().SetDPMS(state);
895 }
896 
897 
898 uint32
899 DWindowHWInterface::DPMSMode()
900 {
901 	AutoReadLocker _(this);
902 
903 	return BScreen().DPMSState();
904 }
905 
906 
907 uint32
908 DWindowHWInterface::DPMSCapabilities()
909 {
910 	AutoReadLocker _(this);
911 
912 	return BScreen().DPMSCapabilites();
913 }
914 
915 
916 status_t
917 DWindowHWInterface::SetBrightness(float brightness)
918 {
919 	AutoReadLocker _(this);
920 
921 	return BScreen().SetBrightness(brightness);
922 }
923 
924 
925 status_t
926 DWindowHWInterface::GetBrightness(float* brightness)
927 {
928 	AutoReadLocker _(this);
929 
930 	return BScreen().GetBrightness(brightness);
931 }
932 
933 
934 uint32
935 DWindowHWInterface::AvailableHWAcceleration() const
936 {
937 	uint32 flags = 0;
938 
939 	if (!IsDoubleBuffered()) {
940 		if (fAccScreenBlit)
941 			flags |= HW_ACC_COPY_REGION;
942 		if (fAccFillRect)
943 			flags |= HW_ACC_FILL_REGION;
944 		if (fAccInvertRect)
945 			flags |= HW_ACC_INVERT_REGION;
946 	}
947 
948 	return flags;
949 }
950 
951 
952 void
953 DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList,
954 	uint32 count, int32 xOffset, int32 yOffset)
955 {
956 	if (fAccScreenBlit && fAccAcquireEngine) {
957 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
958 				&fEngineToken) >= B_OK) {
959 			// make sure the blit_params cache is large enough
960 			if (fBlitParamsCount < count) {
961 				fBlitParamsCount = (count / kDefaultParamsCount + 1)
962 					* kDefaultParamsCount;
963 				// NOTE: realloc() could be used instead...
964 				blit_params* params
965 					= new(std::nothrow) blit_params[fBlitParamsCount];
966 				if (params) {
967 					delete[] fBlitParams;
968 					fBlitParams = params;
969 				} else {
970 					count = fBlitParamsCount;
971 				}
972 			}
973 			// convert the rects
974 			for (uint32 i = 0; i < count; i++) {
975 				fBlitParams[i].src_left
976 					= (uint16)sortedRectList[i].left + fXOffset;
977 				fBlitParams[i].src_top
978 					= (uint16)sortedRectList[i].top + fYOffset;
979 
980 				fBlitParams[i].dest_left
981 					= (uint16)sortedRectList[i].left + xOffset + fXOffset;
982 				fBlitParams[i].dest_top
983 					= (uint16)sortedRectList[i].top + yOffset + fYOffset;
984 
985 				// NOTE: width and height are expressed as distance, not count!
986 				fBlitParams[i].width = (uint16)(sortedRectList[i].right
987 					- sortedRectList[i].left);
988 				fBlitParams[i].height = (uint16)(sortedRectList[i].bottom
989 					- sortedRectList[i].top);
990 			}
991 
992 			// go
993 			fAccScreenBlit(fEngineToken, fBlitParams, count);
994 
995 			// done
996 			if (fAccReleaseEngine)
997 				fAccReleaseEngine(fEngineToken, &fSyncToken);
998 
999 			// sync
1000 			if (fAccSyncToToken)
1001 				fAccSyncToToken(&fSyncToken);
1002 		}
1003 	}
1004 }
1005 
1006 
1007 void
1008 DWindowHWInterface::FillRegion(/*const*/ BRegion& region,
1009 	const rgb_color& color, bool autoSync)
1010 {
1011 	if (fAccFillRect && fAccAcquireEngine) {
1012 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1013 				&fEngineToken) >= B_OK) {
1014 			// convert the region
1015 			uint32 count;
1016 			_RegionToRectParams(&region, &count);
1017 
1018 			// go
1019 			fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count);
1020 
1021 			// done
1022 			if (fAccReleaseEngine)
1023 				fAccReleaseEngine(fEngineToken, &fSyncToken);
1024 
1025 			// sync
1026 			if (autoSync && fAccSyncToToken)
1027 				fAccSyncToToken(&fSyncToken);
1028 		}
1029 	}
1030 }
1031 
1032 
1033 void
1034 DWindowHWInterface::InvertRegion(/*const*/ BRegion& region)
1035 {
1036 	if (fAccInvertRect && fAccAcquireEngine) {
1037 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1038 				&fEngineToken) >= B_OK) {
1039 			// convert the region
1040 			uint32 count;
1041 			_RegionToRectParams(&region, &count);
1042 
1043 			// go
1044 			fAccInvertRect(fEngineToken, fRectParams, count);
1045 
1046 			// done
1047 			if (fAccReleaseEngine)
1048 				fAccReleaseEngine(fEngineToken, &fSyncToken);
1049 
1050 			// sync
1051 			if (fAccSyncToToken)
1052 				fAccSyncToToken(&fSyncToken);
1053 
1054 		} else {
1055 			fprintf(stderr, "AcquireEngine failed!\n");
1056 		}
1057 	} else {
1058 		fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but "
1059 			"hook not available!\n");
1060 	}
1061 }
1062 
1063 
1064 void
1065 DWindowHWInterface::Sync()
1066 {
1067 	if (fAccSyncToToken)
1068 		fAccSyncToToken(&fSyncToken);
1069 }
1070 
1071 
1072 RenderingBuffer*
1073 DWindowHWInterface::FrontBuffer() const
1074 {
1075 	return fFrontBuffer.Get();
1076 }
1077 
1078 
1079 RenderingBuffer*
1080 DWindowHWInterface::BackBuffer() const
1081 {
1082 	return fFrontBuffer.Get();
1083 }
1084 
1085 
1086 bool
1087 DWindowHWInterface::IsDoubleBuffered() const
1088 {
1089 	return false;
1090 }
1091 
1092 
1093 status_t
1094 DWindowHWInterface::Invalidate(const BRect& frame)
1095 {
1096 	return HWInterface::Invalidate(frame);
1097 }
1098 
1099 
1100 void
1101 DWindowHWInterface::SetOffset(int32 left, int32 top)
1102 {
1103 	if (!WriteLock())
1104 		return;
1105 
1106 	fXOffset = left;
1107 	fYOffset = top;
1108 
1109 	_UpdateFrameBufferConfig();
1110 
1111 	// TODO: someone would have to call DrawingEngine::Update() now!
1112 
1113 	WriteUnlock();
1114 }
1115 
1116 
1117 void
1118 DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region,
1119 	uint32* count) const
1120 {
1121 	*count = region->CountRects();
1122 	if (fRectParamsCount < *count) {
1123 		fRectParamsCount = (*count / kDefaultParamsCount + 1)
1124 			* kDefaultParamsCount;
1125 		// NOTE: realloc() could be used instead...
1126 		fill_rect_params* params
1127 			= new(std::nothrow) fill_rect_params[fRectParamsCount];
1128 		if (params) {
1129 			delete[] fRectParams;
1130 			fRectParams = params;
1131 		} else {
1132 			*count = fRectParamsCount;
1133 		}
1134 	}
1135 
1136 	for (uint32 i = 0; i < *count; i++) {
1137 		clipping_rect r = region->RectAtInt(i);
1138 		fRectParams[i].left = (uint16)r.left + fXOffset;
1139 		fRectParams[i].top = (uint16)r.top + fYOffset;
1140 		fRectParams[i].right = (uint16)r.right + fXOffset;
1141 		fRectParams[i].bottom = (uint16)r.bottom + fYOffset;
1142 	}
1143 }
1144 
1145 
1146 uint32
1147 DWindowHWInterface::_NativeColor(const rgb_color& color) const
1148 {
1149 	// NOTE: This functions looks somehow suspicios to me.
1150 	// It assumes that all graphics cards have the same native endianess, no?
1151 	switch (fDisplayMode.space) {
1152 		case B_CMAP8:
1153 		case B_GRAY8:
1154 			return RGBColor(color).GetColor8();
1155 
1156 		case B_RGB15_BIG:
1157 		case B_RGBA15_BIG:
1158 		case B_RGB15_LITTLE:
1159 		case B_RGBA15_LITTLE:
1160 			return RGBColor(color).GetColor15();
1161 
1162 		case B_RGB16_BIG:
1163 		case B_RGB16_LITTLE:
1164 			return RGBColor(color).GetColor16();
1165 
1166 		case B_RGB32_BIG:
1167 		case B_RGBA32_BIG:
1168 		case B_RGB32_LITTLE:
1169 		case B_RGBA32_LITTLE: {
1170 			uint32 native = (color.alpha << 24) | (color.red << 16)
1171 				| (color.green << 8) | (color.blue);
1172 			return native;
1173 		}
1174 	}
1175 	return 0;
1176 }
1177