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_FLOATING_ALL_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_ADDONS_DIRECTORY,
469		B_COMMON_ADDONS_DIRECTORY,
470		B_SYSTEM_ADDONS_DIRECTORY
471	};
472
473	fAccelerantImage = -1;
474
475	for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) {
476		char path[PATH_MAX];
477		if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
478			continue;
479
480		strcat(path, "/accelerants/");
481		strcat(path, signature);
482		if (stat(path, &accelerant_stat) != 0)
483			continue;
484
485		fAccelerantImage = load_add_on(path);
486		if (fAccelerantImage >= 0) {
487			if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
488				B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
489				STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
490				unload_add_on(fAccelerantImage);
491				fAccelerantImage = -1;
492				return B_ERROR;
493			}
494
495
496			accelerant_clone_info_size cloneInfoSize;
497			cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook(
498				B_ACCELERANT_CLONE_INFO_SIZE, NULL);
499			if (!cloneInfoSize) {
500				STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path));
501				unload_add_on(fAccelerantImage);
502				fAccelerantImage = -1;
503				return B_ERROR;
504			}
505
506			ssize_t cloneSize = cloneInfoSize();
507			void* cloneInfoData = malloc(cloneSize);
508
509//			get_accelerant_clone_info getCloneInfo;
510//			getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL);
511//			if (!getCloneInfo) {
512//				STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path));
513//				unload_add_on(fAccelerantImage);
514//				fAccelerantImage = -1;
515//				return B_ERROR;
516//			}
517//			printf("getCloneInfo: %p\n", getCloneInfo);
518//
519//			getCloneInfo(cloneInfoData);
520// TODO: this is what works for the ATI Radeon driver...
521sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String());
522
523			clone_accelerant cloneAccelerant;
524			cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL);
525			if (!cloneAccelerant) {
526				STRACE(("unable to get B_CLONE_ACCELERANT\n"));
527				unload_add_on(fAccelerantImage);
528				fAccelerantImage = -1;
529				return B_ERROR;
530			}
531			status_t ret = cloneAccelerant(cloneInfoData);
532			if (ret  != B_OK) {
533				STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret)));
534				unload_add_on(fAccelerantImage);
535				fAccelerantImage = -1;
536				return B_ERROR;
537			}
538
539			break;
540		}
541	}
542
543	if (fAccelerantImage < B_OK)
544		return B_ERROR;
545
546	if (_SetupDefaultHooks() != B_OK) {
547		STRACE(("cannot setup default hooks\n"));
548
549		uninit_accelerant uninitAccelerant = (uninit_accelerant)
550			fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
551		if (uninitAccelerant != NULL)
552			uninitAccelerant();
553
554		unload_add_on(fAccelerantImage);
555		return B_ERROR;
556	} else {
557		_UpdateFrameBufferConfig();
558	}
559
560	return B_OK;
561}
562
563
564status_t
565DWindowHWInterface::_SetupDefaultHooks()
566{
567	// required
568	fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
569	fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
570	fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL);
571	fAccGetModeCount = (accelerant_mode_count)fAccelerantHook(
572		B_ACCELERANT_MODE_COUNT, NULL);
573	fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
574	fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(
575		B_GET_FRAME_BUFFER_CONFIG, NULL);
576	fAccSetDisplayMode = (set_display_mode)fAccelerantHook(
577		B_SET_DISPLAY_MODE, NULL);
578	fAccGetDisplayMode = (get_display_mode)fAccelerantHook(
579		B_GET_DISPLAY_MODE, NULL);
580	fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
581		B_GET_PIXEL_CLOCK_LIMITS, NULL);
582
583	if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
584		|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
585		|| !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
586		return B_ERROR;
587	}
588
589	// optional
590	fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
591		B_GET_TIMING_CONSTRAINTS, NULL);
592	fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
593		B_PROPOSE_DISPLAY_MODE, NULL);
594
595	// cursor
596	fAccSetCursorShape = (set_cursor_shape)fAccelerantHook(
597		B_SET_CURSOR_SHAPE, NULL);
598	fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
599	fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
600
601	// update acceleration hooks
602	// TODO: would actually have to pass a valid display_mode!
603	fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL);
604	fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL);
605	fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(
606		B_SCREEN_TO_SCREEN_BLIT, NULL);
607
608	return B_OK;
609}
610
611
612status_t
613DWindowHWInterface::_UpdateFrameBufferConfig()
614{
615	frame_buffer_config config;
616	if (fAccGetFrameBufferConfig(&config) != B_OK) {
617		STRACE(("unable to get frame buffer config\n"));
618		return B_ERROR;
619	}
620
621	fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width,
622		fDisplayMode.virtual_height, (color_space)fDisplayMode.space);
623
624	return B_OK;
625}
626
627
628status_t
629DWindowHWInterface::Shutdown()
630{
631	printf("DWindowHWInterface::Shutdown()\n");
632	if (fAccelerantHook) {
633		uninit_accelerant UninitAccelerant
634			= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
635		if (UninitAccelerant)
636			UninitAccelerant();
637	}
638
639	if (fAccelerantImage >= 0)
640		unload_add_on(fAccelerantImage);
641
642	if (fCardFD >= 0)
643		close(fCardFD);
644
645	return B_OK;
646}
647
648
649status_t
650DWindowHWInterface::SetMode(const display_mode& mode)
651{
652	AutoWriteLocker _(this);
653
654	status_t ret = B_OK;
655	// prevent from doing the unnecessary
656	if (fFrontBuffer
657		&& fDisplayMode.virtual_width == mode.virtual_width
658		&& fDisplayMode.virtual_height == mode.virtual_height
659		&& fDisplayMode.space == mode.space)
660		return ret;
661
662	// check if we support the mode
663
664	display_mode *modes;
665	uint32 modeCount, i;
666	if (GetModeList(&modes, &modeCount) != B_OK)
667		return B_NO_MEMORY;
668
669	for (i = 0; i < modeCount; i++) {
670		// we only care for the bare minimum
671		if (modes[i].virtual_width == mode.virtual_width
672			&& modes[i].virtual_height == mode.virtual_height
673			&& modes[i].space == mode.space) {
674			// take over settings
675			fDisplayMode = modes[i];
676			break;
677		}
678	}
679
680	delete[] modes;
681
682	if (i == modeCount)
683		return B_BAD_VALUE;
684
685	BRect frame(0.0, 0.0,
686				fDisplayMode.virtual_width - 1,
687				fDisplayMode.virtual_height - 1);
688
689	// create the window if we don't have one already
690	if (!fWindow) {
691		// if the window has not been created yet, the BApplication
692		// has not been created either, but we need one to display
693		// a real BWindow in the test environment.
694		// be_app->Run() needs to be called in another thread
695		BApplication* app = new BApplication("application/x-vnd.haiku-app-server");
696		app->Unlock();
697
698		thread_id appThread = spawn_thread(run_app_thread, "app thread",
699										   B_NORMAL_PRIORITY, app);
700		if (appThread >= B_OK)
701			ret = resume_thread(appThread);
702		else
703			ret = appThread;
704
705		if (ret < B_OK)
706			return ret;
707
708		fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this,
709			fFrontBuffer);
710
711		// fire up the window thread but don't show it on screen yet
712		fWindow->Hide();
713		fWindow->Show();
714	}
715
716	if (fWindow->Lock()) {
717		// free and reallocate the bitmaps while the window is locked,
718		// so that the view does not accidentally draw a freed bitmap
719
720		if (ret >= B_OK) {
721			// change the window size and update the bitmap used for drawing
722			fWindow->ResizeTo(frame.Width(), frame.Height());
723		}
724
725		// window is hidden when this function is called the first time
726		if (fWindow->IsHidden())
727			fWindow->Show();
728
729		fWindow->Unlock();
730	} else {
731		ret = B_ERROR;
732	}
733
734	_UpdateFrameBufferConfig();
735	_NotifyFrameBufferChanged();
736
737	return ret;
738}
739
740
741void
742DWindowHWInterface::GetMode(display_mode* mode)
743{
744	if (mode && ReadLock()) {
745		*mode = fDisplayMode;
746		ReadUnlock();
747	}
748}
749
750
751status_t
752DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info)
753{
754	// We really don't have to provide anything here because this is strictly
755	// a software-only driver, but we'll have some fun, anyway.
756	if (ReadLock()) {
757		info->version = 100;
758		sprintf(info->name, "Haiku, Inc. DWindowHWInterface");
759		sprintf(info->chipset, "Haiku, Inc. Chipset");
760		sprintf(info->serial_no, "3.14159265358979323846");
761		info->memory = 134217728;	// 128 MB, not that we really have that much. :)
762		info->dac_speed = 0xFFFFFFFF;	// *heh*
763
764		ReadUnlock();
765	}
766
767	return B_OK;
768}
769
770
771status_t
772DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
773{
774	if (fFrontBuffer == NULL)
775		return B_ERROR;
776
777	config.frame_buffer = fFrontBuffer->Bits();
778	config.frame_buffer_dma = NULL;
779	config.bytes_per_row = fFrontBuffer->BytesPerRow();
780
781	return B_OK;
782}
783
784
785status_t
786DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count)
787{
788	AutoReadLocker _(this);
789
790#if 1
791	// setup a whole bunch of different modes
792	const struct resolution { int32 width, height; } resolutions[] = {
793		{640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960},
794		{1280, 1024}, {1400, 1050}, {1600, 1200}
795	};
796	uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]);
797//	const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32};
798	uint32 count = resolutionCount/* * 4*/;
799
800	display_mode* modes = new(std::nothrow) display_mode[count];
801	if (modes == NULL)
802		return B_NO_MEMORY;
803
804	*_modes = modes;
805	*_count = count;
806
807	int32 index = 0;
808	for (uint32 i = 0; i < resolutionCount; i++) {
809		modes[index].virtual_width = resolutions[i].width;
810		modes[index].virtual_height = resolutions[i].height;
811		modes[index].space = B_RGB32;
812
813		modes[index].h_display_start = 0;
814		modes[index].v_display_start = 0;
815		modes[index].timing.h_display = resolutions[i].width;
816		modes[index].timing.v_display = resolutions[i].height;
817		modes[index].timing.h_total = 22000;
818		modes[index].timing.v_total = 22000;
819		modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total
820			* modes[index].timing.v_total * 60) / 1000;
821		modes[index].flags = B_PARALLEL_ACCESS;
822
823		index++;
824	}
825#else
826	// support only a single mode, useful
827	// for testing a specific mode
828	display_mode *modes = new(std::nothrow) display_mode[1];
829	modes[0].virtual_width = 800;
830	modes[0].virtual_height = 600;
831	modes[0].space = B_BRGB32;
832
833	*_modes = modes;
834	*_count = 1;
835#endif
836
837	return B_OK;
838}
839
840
841status_t
842DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
843	uint32* high)
844{
845	return B_ERROR;
846}
847
848
849status_t
850DWindowHWInterface::GetTimingConstraints(
851	display_timing_constraints* constraints)
852{
853	return B_ERROR;
854}
855
856
857status_t
858DWindowHWInterface::ProposeMode(display_mode* candidate,
859	const display_mode* low, const display_mode* high)
860{
861	// We should be able to get away with this because we're not dealing with
862	// any specific hardware. This is a Good Thing(TM) because we can support
863	// any hardware we wish within reasonable expectaions and programmer
864	// laziness. :P
865	return B_OK;
866}
867
868
869sem_id
870DWindowHWInterface::RetraceSemaphore()
871{
872	return -1;
873}
874
875
876status_t
877DWindowHWInterface::WaitForRetrace(bigtime_t timeout)
878{
879	// Locking shouldn't be necessary here - R5 should handle this for us. :)
880	BScreen screen;
881	return screen.WaitForRetrace(timeout);
882}
883
884
885status_t
886DWindowHWInterface::SetDPMSMode(uint32 state)
887{
888	AutoWriteLocker _(this);
889
890	return BScreen().SetDPMS(state);
891}
892
893
894uint32
895DWindowHWInterface::DPMSMode()
896{
897	AutoReadLocker _(this);
898
899	return BScreen().DPMSState();
900}
901
902
903uint32
904DWindowHWInterface::DPMSCapabilities()
905{
906	AutoReadLocker _(this);
907
908	return BScreen().DPMSCapabilites();
909}
910
911
912uint32
913DWindowHWInterface::AvailableHWAcceleration() const
914{
915	uint32 flags = 0;
916
917	if (!IsDoubleBuffered()) {
918		if (fAccScreenBlit)
919			flags |= HW_ACC_COPY_REGION;
920		if (fAccFillRect)
921			flags |= HW_ACC_FILL_REGION;
922		if (fAccInvertRect)
923			flags |= HW_ACC_INVERT_REGION;
924	}
925
926	return flags;
927}
928
929
930void
931DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList,
932	uint32 count, int32 xOffset, int32 yOffset)
933{
934	if (fAccScreenBlit && fAccAcquireEngine) {
935		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
936				&fEngineToken) >= B_OK) {
937			// make sure the blit_params cache is large enough
938			if (fBlitParamsCount < count) {
939				fBlitParamsCount = (count / kDefaultParamsCount + 1)
940					* kDefaultParamsCount;
941				// NOTE: realloc() could be used instead...
942				blit_params* params
943					= new(std::nothrow) blit_params[fBlitParamsCount];
944				if (params) {
945					delete[] fBlitParams;
946					fBlitParams = params;
947				} else {
948					count = fBlitParamsCount;
949				}
950			}
951			// convert the rects
952			for (uint32 i = 0; i < count; i++) {
953				fBlitParams[i].src_left
954					= (uint16)sortedRectList[i].left + fXOffset;
955				fBlitParams[i].src_top
956					= (uint16)sortedRectList[i].top + fYOffset;
957
958				fBlitParams[i].dest_left
959					= (uint16)sortedRectList[i].left + xOffset + fXOffset;
960				fBlitParams[i].dest_top
961					= (uint16)sortedRectList[i].top + yOffset + fYOffset;
962
963				// NOTE: width and height are expressed as distance, not count!
964				fBlitParams[i].width = (uint16)(sortedRectList[i].right
965					- sortedRectList[i].left);
966				fBlitParams[i].height = (uint16)(sortedRectList[i].bottom
967					- sortedRectList[i].top);
968			}
969
970			// go
971			fAccScreenBlit(fEngineToken, fBlitParams, count);
972
973			// done
974			if (fAccReleaseEngine)
975				fAccReleaseEngine(fEngineToken, &fSyncToken);
976
977			// sync
978			if (fAccSyncToToken)
979				fAccSyncToToken(&fSyncToken);
980		}
981	}
982}
983
984
985void
986DWindowHWInterface::FillRegion(/*const*/ BRegion& region,
987	const rgb_color& color, bool autoSync)
988{
989	if (fAccFillRect && fAccAcquireEngine) {
990		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
991				&fEngineToken) >= B_OK) {
992			// convert the region
993			uint32 count;
994			_RegionToRectParams(&region, &count);
995
996			// go
997			fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count);
998
999			// done
1000			if (fAccReleaseEngine)
1001				fAccReleaseEngine(fEngineToken, &fSyncToken);
1002
1003			// sync
1004			if (autoSync && fAccSyncToToken)
1005				fAccSyncToToken(&fSyncToken);
1006		}
1007	}
1008}
1009
1010
1011void
1012DWindowHWInterface::InvertRegion(/*const*/ BRegion& region)
1013{
1014	if (fAccInvertRect && fAccAcquireEngine) {
1015		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1016				&fEngineToken) >= B_OK) {
1017			// convert the region
1018			uint32 count;
1019			_RegionToRectParams(&region, &count);
1020
1021			// go
1022			fAccInvertRect(fEngineToken, fRectParams, count);
1023
1024			// done
1025			if (fAccReleaseEngine)
1026				fAccReleaseEngine(fEngineToken, &fSyncToken);
1027
1028			// sync
1029			if (fAccSyncToToken)
1030				fAccSyncToToken(&fSyncToken);
1031
1032		} else {
1033			fprintf(stderr, "AcquireEngine failed!\n");
1034		}
1035	} else {
1036		fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but "
1037			"hook not available!\n");
1038	}
1039}
1040
1041
1042void
1043DWindowHWInterface::Sync()
1044{
1045	if (fAccSyncToToken)
1046		fAccSyncToToken(&fSyncToken);
1047}
1048
1049
1050RenderingBuffer*
1051DWindowHWInterface::FrontBuffer() const
1052{
1053	return fFrontBuffer;
1054}
1055
1056
1057RenderingBuffer*
1058DWindowHWInterface::BackBuffer() const
1059{
1060	return fFrontBuffer;
1061}
1062
1063
1064bool
1065DWindowHWInterface::IsDoubleBuffered() const
1066{
1067	return false;
1068}
1069
1070
1071status_t
1072DWindowHWInterface::Invalidate(const BRect& frame)
1073{
1074	return HWInterface::Invalidate(frame);
1075}
1076
1077
1078void
1079DWindowHWInterface::SetOffset(int32 left, int32 top)
1080{
1081	if (!WriteLock())
1082		return;
1083
1084	fXOffset = left;
1085	fYOffset = top;
1086
1087	_UpdateFrameBufferConfig();
1088
1089	// TODO: someone would have to call DrawingEngine::Update() now!
1090
1091	WriteUnlock();
1092}
1093
1094
1095void
1096DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region,
1097	uint32* count) const
1098{
1099	*count = region->CountRects();
1100	if (fRectParamsCount < *count) {
1101		fRectParamsCount = (*count / kDefaultParamsCount + 1)
1102			* kDefaultParamsCount;
1103		// NOTE: realloc() could be used instead...
1104		fill_rect_params* params
1105			= new(std::nothrow) fill_rect_params[fRectParamsCount];
1106		if (params) {
1107			delete[] fRectParams;
1108			fRectParams = params;
1109		} else {
1110			*count = fRectParamsCount;
1111		}
1112	}
1113
1114	for (uint32 i = 0; i < *count; i++) {
1115		clipping_rect r = region->RectAtInt(i);
1116		fRectParams[i].left = (uint16)r.left + fXOffset;
1117		fRectParams[i].top = (uint16)r.top + fYOffset;
1118		fRectParams[i].right = (uint16)r.right + fXOffset;
1119		fRectParams[i].bottom = (uint16)r.bottom + fYOffset;
1120	}
1121}
1122
1123
1124uint32
1125DWindowHWInterface::_NativeColor(const rgb_color& color) const
1126{
1127	// NOTE: This functions looks somehow suspicios to me.
1128	// It assumes that all graphics cards have the same native endianess, no?
1129	switch (fDisplayMode.space) {
1130		case B_CMAP8:
1131		case B_GRAY8:
1132			return RGBColor(color).GetColor8();
1133
1134		case B_RGB15_BIG:
1135		case B_RGBA15_BIG:
1136		case B_RGB15_LITTLE:
1137		case B_RGBA15_LITTLE:
1138			return RGBColor(color).GetColor15();
1139
1140		case B_RGB16_BIG:
1141		case B_RGB16_LITTLE:
1142			return RGBColor(color).GetColor16();
1143
1144		case B_RGB32_BIG:
1145		case B_RGBA32_BIG:
1146		case B_RGB32_LITTLE:
1147		case B_RGBA32_LITTLE: {
1148			uint32 native = (color.alpha << 24) | (color.red << 16)
1149				| (color.green << 8) | (color.blue);
1150			return native;
1151		}
1152	}
1153	return 0;
1154}
1155