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
61const 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
68static int32
69run_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
82class DView : public BView {
83public:
84								DView(BRect bounds);
85	virtual						~DView();
86
87								// DView
88			void				ForwardMessage(BMessage* message = NULL);
89
90private:
91			port_id				fInputPort;
92};
93
94class DWindow : public BWindow {
95public:
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
107private:
108	DWindowHWInterface*			fHWInterface;
109	DWindowBuffer*				fBuffer;
110};
111
112class DirectMessageFilter : public BMessageFilter {
113public:
114								DirectMessageFilter(DView* view);
115
116	virtual filter_result		Filter(BMessage *message, BHandler** _target);
117
118private:
119			DView*				fView;
120};
121
122
123//	#pragma mark -
124
125
126DView::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
143DView::~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*/
152void
153DView::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
178DirectMessageFilter::DirectMessageFilter(DView* view)
179	:
180	BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
181	fView(view)
182{
183}
184
185
186filter_result
187DirectMessageFilter::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
222DWindow::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
238DWindow::~DWindow()
239{
240}
241
242
243bool
244DWindow::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/*
261void
262DWindow::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
288void
289DWindow::FrameMoved(BPoint newOffset)
290{
291	fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y);
292}
293
294
295//	#pragma mark -
296
297
298const int32 kDefaultParamsCount = 64;
299
300DWindowHWInterface::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
349DWindowHWInterface::~DWindowHWInterface()
350{
351	if (fWindow) {
352		fWindow->Lock();
353		fWindow->Quit();
354	}
355
356	delete[] fRectParams;
357	delete[] fBlitParams;
358
359	delete fFrontBuffer;
360
361	be_app->Lock();
362	be_app->Quit();
363	delete be_app;
364}
365
366
367status_t
368DWindowHWInterface::Initialize()
369{
370	status_t ret = HWInterface::Initialize();
371
372	if (!fRectParams || !fBlitParams)
373		return B_NO_MEMORY;
374
375	if (ret >= B_OK) {
376		for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) {
377			fCardFD = _OpenGraphicsDevice(i);
378			if (fCardFD < 0) {
379				STRACE(("Failed to open graphics device\n"));
380				continue;
381			}
382
383			if (_OpenAccelerant(fCardFD) == B_OK)
384				break;
385
386			close(fCardFD);
387			// _OpenAccelerant() failed, try to open next graphics card
388		}
389
390		return fCardFD >= 0 ? B_OK : fCardFD;
391	}
392	return ret;
393}
394
395
396/*!	\brief Opens a graphics device for read-write access
397	\param deviceNumber Number identifying which graphics card to open (1 for
398		first card)
399	\return The file descriptor for the opened graphics device
400
401	The deviceNumber is relative to the number of graphics devices that can be
402	successfully opened.  One represents the first card that can be successfully
403	opened (not necessarily the first one listed in the directory).
404	Graphics drivers must be able to be opened more than once, so we really get
405	the first working entry.
406*/
407int
408DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber)
409{
410	DIR *directory = opendir("/dev/graphics");
411	if (!directory)
412		return -1;
413
414	// ToDo: the former R5 "stub" driver is called "vesa" under Haiku; however,
415	//	we do not need to avoid this driver this way when is has been ported
416	//	to the new driver architecture - the special case here can then be
417	//	removed.
418	int count = 0;
419	struct dirent *entry = NULL;
420	int current_card_fd = -1;
421	char path[PATH_MAX];
422	while (count < deviceNumber && (entry = readdir(directory)) != NULL) {
423		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") ||
424			!strcmp(entry->d_name, "stub") || !strcmp(entry->d_name, "vesa"))
425			continue;
426
427		if (current_card_fd >= 0) {
428			close(current_card_fd);
429			current_card_fd = -1;
430		}
431
432		sprintf(path, "/dev/graphics/%s", entry->d_name);
433		current_card_fd = open(path, B_READ_WRITE);
434		if (current_card_fd >= 0)
435			count++;
436	}
437
438	// Open VESA driver if we were not able to get a better one
439	if (count < deviceNumber) {
440		if (deviceNumber == 1) {
441			sprintf(path, "/dev/graphics/vesa");
442			current_card_fd = open(path, B_READ_WRITE);
443		} else {
444			close(current_card_fd);
445			current_card_fd = B_ENTRY_NOT_FOUND;
446		}
447	}
448
449	if (entry)
450		fCardNameInDevFS = entry->d_name;
451
452	return current_card_fd;
453}
454
455
456status_t
457DWindowHWInterface::_OpenAccelerant(int device)
458{
459	char signature[1024];
460	if (ioctl(device, B_GET_ACCELERANT_SIGNATURE,
461			&signature, sizeof(signature)) != B_OK)
462		return B_ERROR;
463
464	STRACE(("accelerant signature is: %s\n", signature));
465
466	struct stat accelerant_stat;
467	const static directory_which dirs[] = {
468		B_USER_NONPACKAGED_ADDONS_DIRECTORY,
469		B_USER_ADDONS_DIRECTORY,
470		B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
471		B_SYSTEM_ADDONS_DIRECTORY
472	};
473
474	fAccelerantImage = -1;
475
476	for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) {
477		char path[PATH_MAX];
478		if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
479			continue;
480
481		strcat(path, "/accelerants/");
482		strcat(path, signature);
483		if (stat(path, &accelerant_stat) != 0)
484			continue;
485
486		fAccelerantImage = load_add_on(path);
487		if (fAccelerantImage >= 0) {
488			if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
489				B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
490				STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
491				unload_add_on(fAccelerantImage);
492				fAccelerantImage = -1;
493				return B_ERROR;
494			}
495
496
497			accelerant_clone_info_size cloneInfoSize;
498			cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook(
499				B_ACCELERANT_CLONE_INFO_SIZE, NULL);
500			if (!cloneInfoSize) {
501				STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path));
502				unload_add_on(fAccelerantImage);
503				fAccelerantImage = -1;
504				return B_ERROR;
505			}
506
507			ssize_t cloneSize = cloneInfoSize();
508			void* cloneInfoData = malloc(cloneSize);
509
510//			get_accelerant_clone_info getCloneInfo;
511//			getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL);
512//			if (!getCloneInfo) {
513//				STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path));
514//				unload_add_on(fAccelerantImage);
515//				fAccelerantImage = -1;
516//				return B_ERROR;
517//			}
518//			printf("getCloneInfo: %p\n", getCloneInfo);
519//
520//			getCloneInfo(cloneInfoData);
521// TODO: this is what works for the ATI Radeon driver...
522sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String());
523
524			clone_accelerant cloneAccelerant;
525			cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL);
526			if (!cloneAccelerant) {
527				STRACE(("unable to get B_CLONE_ACCELERANT\n"));
528				unload_add_on(fAccelerantImage);
529				fAccelerantImage = -1;
530				free(cloneInfoData);
531				return B_ERROR;
532			}
533			status_t ret = cloneAccelerant(cloneInfoData);
534			if (ret  != B_OK) {
535				STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret)));
536				unload_add_on(fAccelerantImage);
537				fAccelerantImage = -1;
538				return B_ERROR;
539			}
540
541			break;
542		}
543	}
544
545	if (fAccelerantImage < B_OK)
546		return B_ERROR;
547
548	if (_SetupDefaultHooks() != B_OK) {
549		STRACE(("cannot setup default hooks\n"));
550
551		uninit_accelerant uninitAccelerant = (uninit_accelerant)
552			fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
553		if (uninitAccelerant != NULL)
554			uninitAccelerant();
555
556		unload_add_on(fAccelerantImage);
557		return B_ERROR;
558	} else {
559		_UpdateFrameBufferConfig();
560	}
561
562	return B_OK;
563}
564
565
566status_t
567DWindowHWInterface::_SetupDefaultHooks()
568{
569	// required
570	fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
571	fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
572	fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL);
573	fAccGetModeCount = (accelerant_mode_count)fAccelerantHook(
574		B_ACCELERANT_MODE_COUNT, NULL);
575	fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
576	fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(
577		B_GET_FRAME_BUFFER_CONFIG, NULL);
578	fAccSetDisplayMode = (set_display_mode)fAccelerantHook(
579		B_SET_DISPLAY_MODE, NULL);
580	fAccGetDisplayMode = (get_display_mode)fAccelerantHook(
581		B_GET_DISPLAY_MODE, NULL);
582	fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
583		B_GET_PIXEL_CLOCK_LIMITS, NULL);
584
585	if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
586		|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
587		|| !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
588		return B_ERROR;
589	}
590
591	// optional
592	fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
593		B_GET_TIMING_CONSTRAINTS, NULL);
594	fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
595		B_PROPOSE_DISPLAY_MODE, NULL);
596
597	// cursor
598	fAccSetCursorShape = (set_cursor_shape)fAccelerantHook(
599		B_SET_CURSOR_SHAPE, NULL);
600	fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
601	fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
602
603	// update acceleration hooks
604	// TODO: would actually have to pass a valid display_mode!
605	fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL);
606	fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL);
607	fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(
608		B_SCREEN_TO_SCREEN_BLIT, NULL);
609
610	return B_OK;
611}
612
613
614status_t
615DWindowHWInterface::_UpdateFrameBufferConfig()
616{
617	frame_buffer_config config;
618	if (fAccGetFrameBufferConfig(&config) != B_OK) {
619		STRACE(("unable to get frame buffer config\n"));
620		return B_ERROR;
621	}
622
623	fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width,
624		fDisplayMode.virtual_height, (color_space)fDisplayMode.space);
625
626	return B_OK;
627}
628
629
630status_t
631DWindowHWInterface::Shutdown()
632{
633	printf("DWindowHWInterface::Shutdown()\n");
634	if (fAccelerantHook) {
635		uninit_accelerant UninitAccelerant
636			= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
637		if (UninitAccelerant)
638			UninitAccelerant();
639	}
640
641	if (fAccelerantImage >= 0)
642		unload_add_on(fAccelerantImage);
643
644	if (fCardFD >= 0)
645		close(fCardFD);
646
647	return B_OK;
648}
649
650
651status_t
652DWindowHWInterface::SetMode(const display_mode& mode)
653{
654	AutoWriteLocker _(this);
655
656	status_t ret = B_OK;
657	// prevent from doing the unnecessary
658	if (fFrontBuffer
659		&& fDisplayMode.virtual_width == mode.virtual_width
660		&& fDisplayMode.virtual_height == mode.virtual_height
661		&& fDisplayMode.space == mode.space)
662		return ret;
663
664	// check if we support the mode
665
666	display_mode *modes;
667	uint32 modeCount, i;
668	if (GetModeList(&modes, &modeCount) != B_OK)
669		return B_NO_MEMORY;
670
671	for (i = 0; i < modeCount; i++) {
672		// we only care for the bare minimum
673		if (modes[i].virtual_width == mode.virtual_width
674			&& modes[i].virtual_height == mode.virtual_height
675			&& modes[i].space == mode.space) {
676			// take over settings
677			fDisplayMode = modes[i];
678			break;
679		}
680	}
681
682	delete[] modes;
683
684	if (i == modeCount)
685		return B_BAD_VALUE;
686
687	BRect frame(0.0, 0.0,
688				fDisplayMode.virtual_width - 1,
689				fDisplayMode.virtual_height - 1);
690
691	// create the window if we don't have one already
692	if (!fWindow) {
693		// if the window has not been created yet, the BApplication
694		// has not been created either, but we need one to display
695		// a real BWindow in the test environment.
696		// be_app->Run() needs to be called in another thread
697		BApplication* app = new BApplication(
698			"application/x-vnd.Haiku-test-app_server");
699		app->Unlock();
700
701		thread_id appThread = spawn_thread(run_app_thread, "app thread",
702										   B_NORMAL_PRIORITY, app);
703		if (appThread >= B_OK)
704			ret = resume_thread(appThread);
705		else
706			ret = appThread;
707
708		if (ret < B_OK)
709			return ret;
710
711		fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this,
712			fFrontBuffer);
713
714		// fire up the window thread but don't show it on screen yet
715		fWindow->Hide();
716		fWindow->Show();
717	}
718
719	if (fWindow->Lock()) {
720		// free and reallocate the bitmaps while the window is locked,
721		// so that the view does not accidentally draw a freed bitmap
722
723		if (ret >= B_OK) {
724			// change the window size and update the bitmap used for drawing
725			fWindow->ResizeTo(frame.Width(), frame.Height());
726		}
727
728		// window is hidden when this function is called the first time
729		if (fWindow->IsHidden())
730			fWindow->Show();
731
732		fWindow->Unlock();
733	} else {
734		ret = B_ERROR;
735	}
736
737	_UpdateFrameBufferConfig();
738	_NotifyFrameBufferChanged();
739
740	return ret;
741}
742
743
744void
745DWindowHWInterface::GetMode(display_mode* mode)
746{
747	if (mode && ReadLock()) {
748		*mode = fDisplayMode;
749		ReadUnlock();
750	}
751}
752
753
754status_t
755DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info)
756{
757	// We really don't have to provide anything here because this is strictly
758	// a software-only driver, but we'll have some fun, anyway.
759	if (ReadLock()) {
760		info->version = 100;
761		sprintf(info->name, "Haiku, Inc. DWindowHWInterface");
762		sprintf(info->chipset, "Haiku, Inc. Chipset");
763		sprintf(info->serial_no, "3.14159265358979323846");
764		info->memory = 134217728;	// 128 MB, not that we really have that much. :)
765		info->dac_speed = 0xFFFFFFFF;	// *heh*
766
767		ReadUnlock();
768	}
769
770	return B_OK;
771}
772
773
774status_t
775DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
776{
777	if (fFrontBuffer == NULL)
778		return B_ERROR;
779
780	config.frame_buffer = fFrontBuffer->Bits();
781	config.frame_buffer_dma = NULL;
782	config.bytes_per_row = fFrontBuffer->BytesPerRow();
783
784	return B_OK;
785}
786
787
788status_t
789DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count)
790{
791	AutoReadLocker _(this);
792
793#if 1
794	// setup a whole bunch of different modes
795	const struct resolution { int32 width, height; } resolutions[] = {
796		{640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960},
797		{1280, 1024}, {1400, 1050}, {1600, 1200}
798	};
799	uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]);
800//	const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32};
801	uint32 count = resolutionCount/* * 4*/;
802
803	display_mode* modes = new(std::nothrow) display_mode[count];
804	if (modes == NULL)
805		return B_NO_MEMORY;
806
807	*_modes = modes;
808	*_count = count;
809
810	int32 index = 0;
811	for (uint32 i = 0; i < resolutionCount; i++) {
812		modes[index].virtual_width = resolutions[i].width;
813		modes[index].virtual_height = resolutions[i].height;
814		modes[index].space = B_RGB32;
815
816		modes[index].h_display_start = 0;
817		modes[index].v_display_start = 0;
818		modes[index].timing.h_display = resolutions[i].width;
819		modes[index].timing.v_display = resolutions[i].height;
820		modes[index].timing.h_total = 22000;
821		modes[index].timing.v_total = 22000;
822		modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total
823			* modes[index].timing.v_total * 60) / 1000;
824		modes[index].flags = B_PARALLEL_ACCESS;
825
826		index++;
827	}
828#else
829	// support only a single mode, useful
830	// for testing a specific mode
831	display_mode *modes = new(std::nothrow) display_mode[1];
832	modes[0].virtual_width = 800;
833	modes[0].virtual_height = 600;
834	modes[0].space = B_BRGB32;
835
836	*_modes = modes;
837	*_count = 1;
838#endif
839
840	return B_OK;
841}
842
843
844status_t
845DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
846	uint32* high)
847{
848	return B_ERROR;
849}
850
851
852status_t
853DWindowHWInterface::GetTimingConstraints(
854	display_timing_constraints* constraints)
855{
856	return B_ERROR;
857}
858
859
860status_t
861DWindowHWInterface::ProposeMode(display_mode* candidate,
862	const display_mode* low, const display_mode* high)
863{
864	// We should be able to get away with this because we're not dealing with
865	// any specific hardware. This is a Good Thing(TM) because we can support
866	// any hardware we wish within reasonable expectaions and programmer
867	// laziness. :P
868	return B_OK;
869}
870
871
872sem_id
873DWindowHWInterface::RetraceSemaphore()
874{
875	return -1;
876}
877
878
879status_t
880DWindowHWInterface::WaitForRetrace(bigtime_t timeout)
881{
882	// Locking shouldn't be necessary here - R5 should handle this for us. :)
883	BScreen screen;
884	return screen.WaitForRetrace(timeout);
885}
886
887
888status_t
889DWindowHWInterface::SetDPMSMode(uint32 state)
890{
891	AutoWriteLocker _(this);
892
893	return BScreen().SetDPMS(state);
894}
895
896
897uint32
898DWindowHWInterface::DPMSMode()
899{
900	AutoReadLocker _(this);
901
902	return BScreen().DPMSState();
903}
904
905
906uint32
907DWindowHWInterface::DPMSCapabilities()
908{
909	AutoReadLocker _(this);
910
911	return BScreen().DPMSCapabilites();
912}
913
914
915status_t
916DWindowHWInterface::SetBrightness(float brightness)
917{
918	AutoReadLocker _(this);
919
920	return BScreen().SetBrightness(brightness);
921}
922
923
924status_t
925DWindowHWInterface::GetBrightness(float* brightness)
926{
927	AutoReadLocker _(this);
928
929	return BScreen().GetBrightness(brightness);
930}
931
932
933uint32
934DWindowHWInterface::AvailableHWAcceleration() const
935{
936	uint32 flags = 0;
937
938	if (!IsDoubleBuffered()) {
939		if (fAccScreenBlit)
940			flags |= HW_ACC_COPY_REGION;
941		if (fAccFillRect)
942			flags |= HW_ACC_FILL_REGION;
943		if (fAccInvertRect)
944			flags |= HW_ACC_INVERT_REGION;
945	}
946
947	return flags;
948}
949
950
951void
952DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList,
953	uint32 count, int32 xOffset, int32 yOffset)
954{
955	if (fAccScreenBlit && fAccAcquireEngine) {
956		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
957				&fEngineToken) >= B_OK) {
958			// make sure the blit_params cache is large enough
959			if (fBlitParamsCount < count) {
960				fBlitParamsCount = (count / kDefaultParamsCount + 1)
961					* kDefaultParamsCount;
962				// NOTE: realloc() could be used instead...
963				blit_params* params
964					= new(std::nothrow) blit_params[fBlitParamsCount];
965				if (params) {
966					delete[] fBlitParams;
967					fBlitParams = params;
968				} else {
969					count = fBlitParamsCount;
970				}
971			}
972			// convert the rects
973			for (uint32 i = 0; i < count; i++) {
974				fBlitParams[i].src_left
975					= (uint16)sortedRectList[i].left + fXOffset;
976				fBlitParams[i].src_top
977					= (uint16)sortedRectList[i].top + fYOffset;
978
979				fBlitParams[i].dest_left
980					= (uint16)sortedRectList[i].left + xOffset + fXOffset;
981				fBlitParams[i].dest_top
982					= (uint16)sortedRectList[i].top + yOffset + fYOffset;
983
984				// NOTE: width and height are expressed as distance, not count!
985				fBlitParams[i].width = (uint16)(sortedRectList[i].right
986					- sortedRectList[i].left);
987				fBlitParams[i].height = (uint16)(sortedRectList[i].bottom
988					- sortedRectList[i].top);
989			}
990
991			// go
992			fAccScreenBlit(fEngineToken, fBlitParams, count);
993
994			// done
995			if (fAccReleaseEngine)
996				fAccReleaseEngine(fEngineToken, &fSyncToken);
997
998			// sync
999			if (fAccSyncToToken)
1000				fAccSyncToToken(&fSyncToken);
1001		}
1002	}
1003}
1004
1005
1006void
1007DWindowHWInterface::FillRegion(/*const*/ BRegion& region,
1008	const rgb_color& color, bool autoSync)
1009{
1010	if (fAccFillRect && fAccAcquireEngine) {
1011		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1012				&fEngineToken) >= B_OK) {
1013			// convert the region
1014			uint32 count;
1015			_RegionToRectParams(&region, &count);
1016
1017			// go
1018			fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count);
1019
1020			// done
1021			if (fAccReleaseEngine)
1022				fAccReleaseEngine(fEngineToken, &fSyncToken);
1023
1024			// sync
1025			if (autoSync && fAccSyncToToken)
1026				fAccSyncToToken(&fSyncToken);
1027		}
1028	}
1029}
1030
1031
1032void
1033DWindowHWInterface::InvertRegion(/*const*/ BRegion& region)
1034{
1035	if (fAccInvertRect && fAccAcquireEngine) {
1036		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1037				&fEngineToken) >= B_OK) {
1038			// convert the region
1039			uint32 count;
1040			_RegionToRectParams(&region, &count);
1041
1042			// go
1043			fAccInvertRect(fEngineToken, fRectParams, count);
1044
1045			// done
1046			if (fAccReleaseEngine)
1047				fAccReleaseEngine(fEngineToken, &fSyncToken);
1048
1049			// sync
1050			if (fAccSyncToToken)
1051				fAccSyncToToken(&fSyncToken);
1052
1053		} else {
1054			fprintf(stderr, "AcquireEngine failed!\n");
1055		}
1056	} else {
1057		fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but "
1058			"hook not available!\n");
1059	}
1060}
1061
1062
1063void
1064DWindowHWInterface::Sync()
1065{
1066	if (fAccSyncToToken)
1067		fAccSyncToToken(&fSyncToken);
1068}
1069
1070
1071RenderingBuffer*
1072DWindowHWInterface::FrontBuffer() const
1073{
1074	return fFrontBuffer;
1075}
1076
1077
1078RenderingBuffer*
1079DWindowHWInterface::BackBuffer() const
1080{
1081	return fFrontBuffer;
1082}
1083
1084
1085bool
1086DWindowHWInterface::IsDoubleBuffered() const
1087{
1088	return false;
1089}
1090
1091
1092status_t
1093DWindowHWInterface::Invalidate(const BRect& frame)
1094{
1095	return HWInterface::Invalidate(frame);
1096}
1097
1098
1099void
1100DWindowHWInterface::SetOffset(int32 left, int32 top)
1101{
1102	if (!WriteLock())
1103		return;
1104
1105	fXOffset = left;
1106	fYOffset = top;
1107
1108	_UpdateFrameBufferConfig();
1109
1110	// TODO: someone would have to call DrawingEngine::Update() now!
1111
1112	WriteUnlock();
1113}
1114
1115
1116void
1117DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region,
1118	uint32* count) const
1119{
1120	*count = region->CountRects();
1121	if (fRectParamsCount < *count) {
1122		fRectParamsCount = (*count / kDefaultParamsCount + 1)
1123			* kDefaultParamsCount;
1124		// NOTE: realloc() could be used instead...
1125		fill_rect_params* params
1126			= new(std::nothrow) fill_rect_params[fRectParamsCount];
1127		if (params) {
1128			delete[] fRectParams;
1129			fRectParams = params;
1130		} else {
1131			*count = fRectParamsCount;
1132		}
1133	}
1134
1135	for (uint32 i = 0; i < *count; i++) {
1136		clipping_rect r = region->RectAtInt(i);
1137		fRectParams[i].left = (uint16)r.left + fXOffset;
1138		fRectParams[i].top = (uint16)r.top + fYOffset;
1139		fRectParams[i].right = (uint16)r.right + fXOffset;
1140		fRectParams[i].bottom = (uint16)r.bottom + fYOffset;
1141	}
1142}
1143
1144
1145uint32
1146DWindowHWInterface::_NativeColor(const rgb_color& color) const
1147{
1148	// NOTE: This functions looks somehow suspicios to me.
1149	// It assumes that all graphics cards have the same native endianess, no?
1150	switch (fDisplayMode.space) {
1151		case B_CMAP8:
1152		case B_GRAY8:
1153			return RGBColor(color).GetColor8();
1154
1155		case B_RGB15_BIG:
1156		case B_RGBA15_BIG:
1157		case B_RGB15_LITTLE:
1158		case B_RGBA15_LITTLE:
1159			return RGBColor(color).GetColor15();
1160
1161		case B_RGB16_BIG:
1162		case B_RGB16_LITTLE:
1163			return RGBColor(color).GetColor16();
1164
1165		case B_RGB32_BIG:
1166		case B_RGBA32_BIG:
1167		case B_RGB32_LITTLE:
1168		case B_RGBA32_LITTLE: {
1169			uint32 native = (color.alpha << 24) | (color.red << 16)
1170				| (color.green << 8) | (color.blue);
1171			return native;
1172		}
1173	}
1174	return 0;
1175}
1176