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	be_app->Lock();
360	be_app->Quit();
361	delete be_app;
362}
363
364
365status_t
366DWindowHWInterface::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*/
405int
406DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber)
407{
408	DIR *directory = opendir("/dev/graphics");
409	if (!directory)
410		return B_ENTRY_NOT_FOUND;
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
457status_t
458DWindowHWInterface::_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...
523sprintf((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
567status_t
568DWindowHWInterface::_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
615status_t
616DWindowHWInterface::_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
631status_t
632DWindowHWInterface::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
652status_t
653DWindowHWInterface::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
745void
746DWindowHWInterface::GetMode(display_mode* mode)
747{
748	if (mode && ReadLock()) {
749		*mode = fDisplayMode;
750		ReadUnlock();
751	}
752}
753
754
755status_t
756DWindowHWInterface::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
775status_t
776DWindowHWInterface::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
789status_t
790DWindowHWInterface::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
845status_t
846DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
847	uint32* high)
848{
849	return B_ERROR;
850}
851
852
853status_t
854DWindowHWInterface::GetTimingConstraints(
855	display_timing_constraints* constraints)
856{
857	return B_ERROR;
858}
859
860
861status_t
862DWindowHWInterface::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
873sem_id
874DWindowHWInterface::RetraceSemaphore()
875{
876	return -1;
877}
878
879
880status_t
881DWindowHWInterface::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
889status_t
890DWindowHWInterface::SetDPMSMode(uint32 state)
891{
892	AutoWriteLocker _(this);
893
894	return BScreen().SetDPMS(state);
895}
896
897
898uint32
899DWindowHWInterface::DPMSMode()
900{
901	AutoReadLocker _(this);
902
903	return BScreen().DPMSState();
904}
905
906
907uint32
908DWindowHWInterface::DPMSCapabilities()
909{
910	AutoReadLocker _(this);
911
912	return BScreen().DPMSCapabilites();
913}
914
915
916status_t
917DWindowHWInterface::SetBrightness(float brightness)
918{
919	AutoReadLocker _(this);
920
921	return BScreen().SetBrightness(brightness);
922}
923
924
925status_t
926DWindowHWInterface::GetBrightness(float* brightness)
927{
928	AutoReadLocker _(this);
929
930	return BScreen().GetBrightness(brightness);
931}
932
933
934uint32
935DWindowHWInterface::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
952void
953DWindowHWInterface::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
1007void
1008DWindowHWInterface::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
1033void
1034DWindowHWInterface::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
1064void
1065DWindowHWInterface::Sync()
1066{
1067	if (fAccSyncToToken)
1068		fAccSyncToToken(&fSyncToken);
1069}
1070
1071
1072RenderingBuffer*
1073DWindowHWInterface::FrontBuffer() const
1074{
1075	return fFrontBuffer.Get();
1076}
1077
1078
1079RenderingBuffer*
1080DWindowHWInterface::BackBuffer() const
1081{
1082	return fFrontBuffer.Get();
1083}
1084
1085
1086bool
1087DWindowHWInterface::IsDoubleBuffered() const
1088{
1089	return false;
1090}
1091
1092
1093status_t
1094DWindowHWInterface::Invalidate(const BRect& frame)
1095{
1096	return HWInterface::Invalidate(frame);
1097}
1098
1099
1100void
1101DWindowHWInterface::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
1117void
1118DWindowHWInterface::_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
1146uint32
1147DWindowHWInterface::_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