1/*
2 * Copyright 2001-2012, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 *		DarkWyrm <bpmagic@columbus.rr.com>
8 *		Stephan A��mus <superstippi@gmx.de>
9 *		Axel D��rfler, axeld@pinc-software.de
10 */
11
12
13/*!	Accelerant based HWInterface implementation */
14
15
16#include "AccelerantHWInterface.h"
17
18#include <dirent.h>
19#include <new>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/ioctl.h>
24#include <syslog.h>
25#include <unistd.h>
26
27#include <Accelerant.h>
28#include <Cursor.h>
29#include <driver_settings.h>
30#include <FindDirectory.h>
31#include <graphic_driver.h>
32#include <image.h>
33#include <String.h>
34
35#include <edid.h>
36#include <safemode_defs.h>
37#include <syscalls.h>
38
39#include "AccelerantBuffer.h"
40#include "MallocBuffer.h"
41#include "Overlay.h"
42#include "RGBColor.h"
43#include "ServerConfig.h"
44#include "ServerCursor.h"
45#include "ServerProtocol.h"
46#include "SystemPalette.h"
47
48
49using std::nothrow;
50
51
52#ifdef DEBUG_DRIVER_MODULE
53#	include <stdio.h>
54#	define ATRACE(x) printf x
55#else
56#	define ATRACE(x) ;
57#endif
58
59#define USE_ACCELERATION		0
60#define OFFSCREEN_BACK_BUFFER	0
61
62
63const int32 kDefaultParamsCount = 64;
64
65
66bool
67operator==(const display_mode& a, const display_mode& b)
68{
69	return memcmp(&a, &b, sizeof(display_mode)) == 0;
70}
71
72
73bool
74use_fail_safe_video_mode()
75{
76	char buffer[B_FILE_NAME_LENGTH];
77	size_t size = sizeof(buffer);
78
79	status_t status = _kern_get_safemode_option(
80		B_SAFEMODE_FAIL_SAFE_VIDEO_MODE, buffer, &size);
81	if (status == B_OK) {
82		if (!strncasecmp(buffer, "true", size)
83			|| !strncasecmp(buffer, "yes", size)
84			|| !strncasecmp(buffer, "on", size)
85			|| !strncasecmp(buffer, "enabled", size)) {
86			return true;
87		}
88	}
89
90	return false;
91}
92
93
94//	#pragma mark -
95
96
97AccelerantHWInterface::AccelerantHWInterface()
98	:
99	HWInterface(),
100	fCardFD(-1),
101	fAccelerantImage(-1),
102	fAccelerantHook(NULL),
103	fEngineToken(NULL),
104	fSyncToken(),
105
106	// required hooks
107	fAccAcquireEngine(NULL),
108	fAccReleaseEngine(NULL),
109	fAccSyncToToken(NULL),
110	fAccGetModeCount(NULL),
111	fAccGetModeList(NULL),
112	fAccGetFrameBufferConfig(NULL),
113	fAccSetDisplayMode(NULL),
114	fAccGetDisplayMode(NULL),
115	fAccGetPixelClockLimits(NULL),
116
117	// optional accelerant hooks
118	fAccGetTimingConstraints(NULL),
119	fAccProposeDisplayMode(NULL),
120	fAccFillRect(NULL),
121	fAccInvertRect(NULL),
122	fAccScreenBlit(NULL),
123	fAccSetCursorShape(NULL),
124	fAccSetCursorBitmap(NULL),
125	fAccMoveCursor(NULL),
126	fAccShowCursor(NULL),
127
128	// dpms hooks
129	fAccDPMSCapabilities(NULL),
130	fAccDPMSMode(NULL),
131	fAccSetDPMSMode(NULL),
132
133	fModeCount(0),
134	fModeList(NULL),
135
136	fBackBuffer(NULL),
137	fFrontBuffer(new (nothrow) AccelerantBuffer()),
138	fOffscreenBackBuffer(false),
139
140	fInitialModeSwitch(true),
141
142	fRetraceSemaphore(-1),
143
144	fRectParams(new (nothrow) fill_rect_params[kDefaultParamsCount]),
145	fRectParamsCount(kDefaultParamsCount),
146	fBlitParams(new (nothrow) blit_params[kDefaultParamsCount]),
147	fBlitParamsCount(kDefaultParamsCount)
148{
149	fDisplayMode.virtual_width = 640;
150	fDisplayMode.virtual_height = 480;
151	fDisplayMode.space = B_RGB32;
152
153	// NOTE: I have no clue what I'm doing here.
154//	fSyncToken.counter = 0;
155//	fSyncToken.engine_id = 0;
156	memset(&fSyncToken, 0, sizeof(sync_token));
157}
158
159
160AccelerantHWInterface::~AccelerantHWInterface()
161{
162	delete fBackBuffer;
163	delete fFrontBuffer;
164
165	delete[] fRectParams;
166	delete[] fBlitParams;
167
168	delete[] fModeList;
169}
170
171
172/*!	\brief Opens the first available graphics device and initializes it
173	\return B_OK on success or an appropriate error message on failure.
174*/
175status_t
176AccelerantHWInterface::Initialize()
177{
178	status_t ret = HWInterface::Initialize();
179
180	if (!fRectParams || !fBlitParams)
181		return B_NO_MEMORY;
182
183	if (ret >= B_OK) {
184		for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) {
185			fCardFD = _OpenGraphicsDevice(i);
186			if (fCardFD < 0) {
187				ATRACE(("Failed to open graphics device\n"));
188				continue;
189			}
190
191			if (_OpenAccelerant(fCardFD) == B_OK)
192				break;
193
194			close(fCardFD);
195			// _OpenAccelerant() failed, try to open next graphics card
196		}
197
198		return fCardFD >= 0 ? B_OK : fCardFD;
199	}
200	return ret;
201}
202
203
204/*!	\brief Opens a graphics device for read-write access
205	\param deviceNumber Number identifying which graphics card to open (1 for first card)
206	\return The file descriptor for the opened graphics device
207
208	The deviceNumber is relative to the number of graphics devices that can be successfully
209	opened.  One represents the first card that can be successfully opened (not necessarily
210	the first one listed in the directory).
211	Graphics drivers must be able to be opened more than once, so we really get
212	the first working entry.
213*/
214int
215AccelerantHWInterface::_OpenGraphicsDevice(int deviceNumber)
216{
217	DIR *directory = opendir("/dev/graphics");
218	if (!directory)
219		return -1;
220
221	int device = -1;
222	int count = 0;
223	if (!use_fail_safe_video_mode()) {
224		// TODO: We do not need to avoid the "vesa" driver this way once it has
225		// been ported to the new driver architecture - the special case here
226		// can then be removed.
227		struct dirent *entry;
228		char path[PATH_MAX];
229		while (count < deviceNumber && (entry = readdir(directory)) != NULL) {
230			if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")
231				|| !strcmp(entry->d_name, "vesa"))
232				continue;
233
234			if (device >= 0) {
235				close(device);
236				device = -1;
237			}
238
239			sprintf(path, "/dev/graphics/%s", entry->d_name);
240			device = open(path, B_READ_WRITE);
241			if (device >= 0)
242				count++;
243		}
244	}
245
246	// Open VESA driver if we were not able to get a better one
247	if (count < deviceNumber) {
248		if (deviceNumber == 1) {
249			device = open("/dev/graphics/vesa", B_READ_WRITE);
250			fVGADevice = device;
251				// store the device, so that we can access the planar blitter
252		} else {
253			close(device);
254			device = B_ENTRY_NOT_FOUND;
255		}
256	}
257
258	closedir(directory);
259
260	return device;
261}
262
263
264status_t
265AccelerantHWInterface::_OpenAccelerant(int device)
266{
267	char signature[1024];
268	if (ioctl(device, B_GET_ACCELERANT_SIGNATURE,
269			&signature, sizeof(signature)) != B_OK)
270		return B_ERROR;
271
272	ATRACE(("accelerant signature is: %s\n", signature));
273
274	struct stat accelerant_stat;
275	const static directory_which dirs[] = {
276		B_USER_ADDONS_DIRECTORY,
277		B_COMMON_ADDONS_DIRECTORY,
278		B_SYSTEM_ADDONS_DIRECTORY
279	};
280
281	fAccelerantImage = -1;
282
283	for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) {
284		char path[PATH_MAX];
285		if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
286			continue;
287
288		strcat(path, "/accelerants/");
289		strcat(path, signature);
290		if (stat(path, &accelerant_stat) != 0)
291			continue;
292
293		fAccelerantImage = load_add_on(path);
294		if (fAccelerantImage >= 0) {
295			if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
296				B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
297				ATRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
298				unload_add_on(fAccelerantImage);
299				fAccelerantImage = -1;
300				return B_ERROR;
301			}
302
303			init_accelerant initAccelerant;
304			initAccelerant = (init_accelerant)fAccelerantHook(
305				B_INIT_ACCELERANT, NULL);
306			if (!initAccelerant || initAccelerant(device) != B_OK) {
307				ATRACE(("InitAccelerant unsuccessful\n"));
308				unload_add_on(fAccelerantImage);
309				fAccelerantImage = -1;
310				return B_ERROR;
311			}
312
313			break;
314		}
315	}
316
317	if (fAccelerantImage < B_OK)
318		return B_ERROR;
319
320	if (_SetupDefaultHooks() != B_OK) {
321		syslog(LOG_ERR, "Accelerant %s does not export the required hooks.\n",
322			signature);
323
324		uninit_accelerant uninitAccelerant = (uninit_accelerant)
325			fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
326		if (uninitAccelerant != NULL)
327			uninitAccelerant();
328
329		unload_add_on(fAccelerantImage);
330		return B_ERROR;
331	}
332
333	return B_OK;
334}
335
336
337status_t
338AccelerantHWInterface::_SetupDefaultHooks()
339{
340	// required
341	fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
342	fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
343	fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL);
344	fAccGetModeCount
345		= (accelerant_mode_count)fAccelerantHook(B_ACCELERANT_MODE_COUNT, NULL);
346	fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
347	fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(
348		B_GET_FRAME_BUFFER_CONFIG, NULL);
349	fAccSetDisplayMode
350		= (set_display_mode)fAccelerantHook(B_SET_DISPLAY_MODE, NULL);
351	fAccGetDisplayMode
352		= (get_display_mode)fAccelerantHook(B_GET_DISPLAY_MODE, NULL);
353	fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
354		B_GET_PIXEL_CLOCK_LIMITS, NULL);
355
356	if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
357		|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
358		|| !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
359		return B_ERROR;
360	}
361
362	// optional
363	fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
364		B_GET_TIMING_CONSTRAINTS, NULL);
365	fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
366		B_PROPOSE_DISPLAY_MODE, NULL);
367	fAccGetPreferredDisplayMode = (get_preferred_display_mode)fAccelerantHook(
368		B_GET_PREFERRED_DISPLAY_MODE, NULL);
369	fAccGetMonitorInfo
370		= (get_monitor_info)fAccelerantHook(B_GET_MONITOR_INFO, NULL);
371	fAccGetEDIDInfo = (get_edid_info)fAccelerantHook(B_GET_EDID_INFO, NULL);
372
373	// cursor
374	fAccSetCursorShape
375		= (set_cursor_shape)fAccelerantHook(B_SET_CURSOR_SHAPE, NULL);
376	fAccSetCursorBitmap
377		= (set_cursor_bitmap)fAccelerantHook(B_SET_CURSOR_BITMAP, NULL);
378	fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
379	fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
380
381	// dpms
382	fAccDPMSCapabilities
383		= (dpms_capabilities)fAccelerantHook(B_DPMS_CAPABILITIES, NULL);
384	fAccDPMSMode = (dpms_mode)fAccelerantHook(B_DPMS_MODE, NULL);
385	fAccSetDPMSMode = (set_dpms_mode)fAccelerantHook(B_SET_DPMS_MODE, NULL);
386
387	// overlay
388	fAccOverlayCount = (overlay_count)fAccelerantHook(B_OVERLAY_COUNT, NULL);
389	fAccOverlaySupportedSpaces = (overlay_supported_spaces)fAccelerantHook(
390		B_OVERLAY_SUPPORTED_SPACES, NULL);
391	fAccOverlaySupportedFeatures = (overlay_supported_features)fAccelerantHook(
392		B_OVERLAY_SUPPORTED_FEATURES, NULL);
393	fAccAllocateOverlayBuffer = (allocate_overlay_buffer)fAccelerantHook(
394		B_ALLOCATE_OVERLAY_BUFFER, NULL);
395	fAccReleaseOverlayBuffer = (release_overlay_buffer)fAccelerantHook(
396		B_RELEASE_OVERLAY_BUFFER, NULL);
397	fAccGetOverlayConstraints = (get_overlay_constraints)fAccelerantHook(
398		B_GET_OVERLAY_CONSTRAINTS, NULL);
399	fAccAllocateOverlay
400		= (allocate_overlay)fAccelerantHook(B_ALLOCATE_OVERLAY, NULL);
401	fAccReleaseOverlay
402		= (release_overlay)fAccelerantHook(B_RELEASE_OVERLAY, NULL);
403	fAccConfigureOverlay
404		= (configure_overlay)fAccelerantHook(B_CONFIGURE_OVERLAY, NULL);
405
406	return B_OK;
407}
408
409
410status_t
411AccelerantHWInterface::Shutdown()
412{
413	if (fAccelerantHook != NULL) {
414		uninit_accelerant uninitAccelerant
415			= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
416		if (uninitAccelerant != NULL)
417			uninitAccelerant();
418
419		fAccelerantHook = NULL;
420	}
421
422	if (fAccelerantImage >= 0) {
423		unload_add_on(fAccelerantImage);
424		fAccelerantImage = -1;
425	}
426
427	if (fCardFD >= 0) {
428		close(fCardFD);
429		fCardFD = -1;
430	}
431
432	return B_OK;
433}
434
435
436/*! Finds the mode in the mode list that is closest to the mode specified.
437	As long as the mode list is not empty, this method will always succeed.
438*/
439status_t
440AccelerantHWInterface::_FindBestMode(const display_mode& compareMode,
441	float compareAspectRatio, display_mode& modeFound, int32 *_diff) const
442{
443	int32 bestDiff = 0;
444	int32 bestIndex = -1;
445	for (int32 i = 0; i < fModeCount; i++) {
446		display_mode& mode = fModeList[i];
447		float aspectRatio = 0;
448
449		if (compareAspectRatio != 0 && mode.timing.v_display != 0)
450			aspectRatio = mode.timing.h_display / mode.timing.v_display;
451
452		// compute some random equality score
453		// TODO: check if these scores make sense
454		int32 diff
455			= 1000 * abs(mode.timing.h_display - compareMode.timing.h_display)
456			+ 1000 * abs(mode.timing.v_display - compareMode.timing.v_display)
457			+ abs(mode.timing.h_total * mode.timing.v_total
458					- compareMode.timing.h_total * compareMode.timing.v_total)
459				/ 100
460			+ abs(mode.timing.pixel_clock - compareMode.timing.pixel_clock)
461				/ 100
462			+ (int32)(500 * fabs(aspectRatio - compareAspectRatio))
463			+ 100 * abs(mode.space - compareMode.space);
464
465		if (bestIndex == -1 || diff < bestDiff) {
466			bestDiff = diff;
467			bestIndex = i;
468		}
469	}
470
471	if (bestIndex < 0)
472		return B_ERROR;
473
474	modeFound = fModeList[bestIndex];
475	if (_diff != 0)
476		*_diff = bestDiff;
477
478	return B_OK;
479}
480
481
482/*!	This method is used for the initial mode set only - because that one
483	should really not fail.
484	Basically we try to set all modes as found in the mode list the driver
485	returned, but we start with the one that best fits the originally
486	desired mode.
487	The mode list must have been retrieved already.
488*/
489status_t
490AccelerantHWInterface::_SetFallbackMode(display_mode& newMode) const
491{
492	// At first, we search the closest display mode from the list of
493	// supported modes - if that fails, we just take one
494
495	if (_FindBestMode(newMode, 0, newMode) == B_OK
496		&& fAccSetDisplayMode(&newMode) == B_OK)
497		return B_OK;
498
499	// That failed as well, this looks like a bug in the graphics
500	// driver, but we have to try to be as forgiving as possible
501	// here - just take the first mode that works!
502
503	for (int32 i = 0; i < fModeCount; i++) {
504		newMode = fModeList[i];
505		if (fAccSetDisplayMode(&newMode) == B_OK)
506			return B_OK;
507	}
508
509	// Well, we tried.
510	return B_ERROR;
511}
512
513
514status_t
515AccelerantHWInterface::SetMode(const display_mode& mode)
516{
517	AutoWriteLocker _(this);
518	// TODO: There are places this function can fail,
519	// maybe it needs to roll back changes in case of an
520	// error.
521
522	// prevent from doing the unnecessary
523	if (fModeCount > 0 && fFrontBuffer && fDisplayMode == mode) {
524		// TODO: better comparison of display modes
525		return B_OK;
526	}
527
528	// some safety checks
529	// TODO: more of those!
530	if (!_IsValidMode(mode))
531		return B_BAD_VALUE;
532
533	if (fFrontBuffer == NULL)
534		return B_NO_INIT;
535
536	// just try to set the mode - we let the graphics driver
537	// approve or deny the request, as it should know best
538
539	display_mode newMode = mode;
540
541	bool tryOffscreenBackBuffer = false;
542	fOffscreenBackBuffer = false;
543#if USE_ACCELERATION && OFFSCREEN_BACK_BUFFER
544	if (fVGADevice < 0 && (color_space)newMode.space == B_RGB32) {
545		// we should have an accelerated graphics driver, try
546		// to allocate a frame buffer large enough to contain
547		// the back buffer for double buffered drawing
548		newMode.virtual_height *= 2;
549		tryOffscreenBackBuffer = true;
550	}
551#endif
552
553	status_t status = B_ERROR;
554	if (!use_fail_safe_video_mode() || !fInitialModeSwitch)
555		status = fAccSetDisplayMode(&newMode);
556	if (status != B_OK) {
557		ATRACE(("setting display mode failed\n"));
558		if (!fInitialModeSwitch)
559			return status;
560
561		// undo the offscreen backbuffer trick when trying the various
562		// fall back methods for the initial mode switch
563		// TODO: Do it even then, but it is more involved.
564		if (tryOffscreenBackBuffer) {
565			newMode.virtual_height /= 2;
566			tryOffscreenBackBuffer = false;
567		}
568
569		if (fModeList == NULL) {
570			status = _UpdateModeList();
571			if (status != B_OK)
572				return status;
573		}
574
575		// If this is the initial mode switch, we try a number of fallback
576		// modes first, before we have to fail
577
578		status = use_fail_safe_video_mode()
579			? B_ERROR : _SetFallbackMode(newMode);
580		if (status != B_OK) {
581			// The driver doesn't allow us the mode switch - this usually
582			// means we have a driver that doesn't allow mode switches at
583			// all.
584			// All we can do now is to ask the driver which mode we can
585			// use - this is always necessary for VESA mode, for example.
586			if (fAccGetDisplayMode(&newMode) != B_OK)
587				return B_ERROR;
588
589			// TODO: check if the mode returned is valid!
590			if (!_IsValidMode(newMode))
591				return B_BAD_DATA;
592
593			// TODO: if the mode switch before fails as well, we must forbid
594			//	any uses of this class!
595			status = B_OK;
596		}
597	}
598
599	if (tryOffscreenBackBuffer) {
600		// The offscreen backbuffer was successfully allocated, since
601		// the mode switch succeeded! This should be handled transparently
602		// though and not be reflected in the mode structure, so that
603		// even real virtual screens should work eventually...
604		newMode.virtual_height /= 2;
605		fOffscreenBackBuffer = true;
606	}
607
608	fDisplayMode = newMode;
609	fInitialModeSwitch = false;
610
611	// update frontbuffer
612	fFrontBuffer->SetDisplayMode(fDisplayMode);
613	if (_UpdateFrameBufferConfig() != B_OK) {
614		// TODO: if this fails, we're basically toasted - we need to handle this
615		//	differently to crashing later on!
616		return B_ERROR;
617	}
618
619	// Update the frame buffer used by the on-screen KDL
620#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
621	uint32 depth = (fFrameBufferConfig.bytes_per_row
622		/ fFrontBuffer->Width()) << 3;
623	if (fDisplayMode.space == B_RGB15)
624		depth = 15;
625
626	_kern_frame_buffer_update((addr_t)fFrameBufferConfig.frame_buffer,
627		fFrontBuffer->Width(), fFrontBuffer->Height(),
628		depth, fFrameBufferConfig.bytes_per_row);
629#endif
630
631	// update acceleration hooks
632#if USE_ACCELERATION
633	fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE,
634		(void *)&fDisplayMode);
635	fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE,
636		(void *)&fDisplayMode);
637	fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(
638		B_SCREEN_TO_SCREEN_BLIT, (void *)&fDisplayMode);
639#else
640	fAccFillRect = NULL;
641	fAccInvertRect = NULL;
642	fAccScreenBlit = NULL;
643#endif
644
645	// in case there is no accelerated blit function, using
646	// an offscreen located backbuffer will not be beneficial!
647	if (fAccScreenBlit == NULL)
648		fOffscreenBackBuffer = false;
649
650	// update backbuffer if neccessary
651	if (!fBackBuffer || fBackBuffer->Width() != fFrontBuffer->Width()
652		|| fBackBuffer->Height() != fFrontBuffer->Height()
653		|| fOffscreenBackBuffer
654		|| (fFrontBuffer->ColorSpace() == B_RGB32 && fBackBuffer != NULL
655			&& !HWInterface::IsDoubleBuffered())) {
656		// NOTE: backbuffer is always B_RGBA32, this simplifies the
657		// drawing backend implementation tremendously for the time
658		// being. The color space conversion is handled in CopyBackToFront()
659
660		delete fBackBuffer;
661		fBackBuffer = NULL;
662
663		// TODO: Above not true anymore for single buffered mode!!!
664		// -> fall back to double buffer for fDisplayMode.space != B_RGB32
665		// as intermediate solution...
666		bool doubleBuffered = HWInterface::IsDoubleBuffered();
667		if ((fFrontBuffer->ColorSpace() != B_RGB32
668			&& fFrontBuffer->ColorSpace() != B_RGBA32)
669			|| fVGADevice >= 0 || fOffscreenBackBuffer)
670			doubleBuffered = true;
671#if !USE_ACCELERATION
672		doubleBuffered = true;
673#endif
674
675		if (doubleBuffered) {
676			if (fOffscreenBackBuffer) {
677				fBackBuffer = new(nothrow) AccelerantBuffer(*fFrontBuffer,
678					true);
679			} else {
680				fBackBuffer = new(nothrow) MallocBuffer(fFrontBuffer->Width(),
681					fFrontBuffer->Height());
682			}
683
684			status = fBackBuffer ? fBackBuffer->InitCheck() : B_NO_MEMORY;
685			if (status < B_OK) {
686				delete fBackBuffer;
687				fBackBuffer = NULL;
688				fOffscreenBackBuffer = false;
689				return status;
690			}
691			// clear out backbuffer, alpha is 255 this way
692			memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength());
693		}
694#if 0
695// NOTE: Currently disabled, because it make the double buffered mode flicker
696// again. See HWInterface::Invalidate() for more information.
697		SetAsyncDoubleBuffered(doubleBuffered);
698#endif
699	}
700
701	// update color palette configuration if necessary
702	if (fDisplayMode.space == B_CMAP8)
703		_SetSystemPalette();
704	else if (fDisplayMode.space == B_GRAY8)
705		_SetGrayscalePalette();
706
707	// notify all listeners about the mode change
708	_NotifyFrameBufferChanged();
709
710	return status;
711}
712
713
714void
715AccelerantHWInterface::GetMode(display_mode* mode)
716{
717	if (mode && LockParallelAccess()) {
718		*mode = fDisplayMode;
719		UnlockParallelAccess();
720	}
721}
722
723
724status_t
725AccelerantHWInterface::_UpdateModeList()
726{
727	fModeCount = fAccGetModeCount();
728	if (fModeCount <= 0)
729		return B_ERROR;
730
731	delete[] fModeList;
732	fModeList = new(nothrow) display_mode[fModeCount];
733	if (!fModeList)
734		return B_NO_MEMORY;
735
736	if (fAccGetModeList(fModeList) != B_OK) {
737		ATRACE(("unable to get mode list\n"));
738		return B_ERROR;
739	}
740
741	return B_OK;
742}
743
744
745status_t
746AccelerantHWInterface::_UpdateFrameBufferConfig()
747{
748	if (fAccGetFrameBufferConfig(&fFrameBufferConfig) != B_OK) {
749		ATRACE(("unable to get frame buffer config\n"));
750		return B_ERROR;
751	}
752
753	fFrontBuffer->SetFrameBufferConfig(fFrameBufferConfig);
754
755	return B_OK;
756}
757
758
759status_t
760AccelerantHWInterface::GetDeviceInfo(accelerant_device_info* info)
761{
762	get_accelerant_device_info GetAccelerantDeviceInfo
763		= (get_accelerant_device_info)fAccelerantHook(
764			B_GET_ACCELERANT_DEVICE_INFO, NULL);
765	if (!GetAccelerantDeviceInfo) {
766		ATRACE(("No B_GET_ACCELERANT_DEVICE_INFO hook found\n"));
767		return B_UNSUPPORTED;
768	}
769
770	return GetAccelerantDeviceInfo(info);
771}
772
773
774status_t
775AccelerantHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
776{
777	config = fFrameBufferConfig;
778	return B_OK;
779}
780
781
782status_t
783AccelerantHWInterface::GetModeList(display_mode** _modes, uint32* _count)
784{
785	AutoReadLocker _(this);
786
787	if (_count == NULL || _modes == NULL)
788		return B_BAD_VALUE;
789
790	status_t status = B_OK;
791
792	if (fModeList == NULL)
793		status = _UpdateModeList();
794
795	if (status >= B_OK) {
796		*_modes = new(nothrow) display_mode[fModeCount];
797		if (*_modes) {
798			*_count = fModeCount;
799			memcpy(*_modes, fModeList, sizeof(display_mode) * fModeCount);
800		} else {
801			*_count = 0;
802			status = B_NO_MEMORY;
803		}
804	}
805	return status;
806}
807
808
809status_t
810AccelerantHWInterface::GetPixelClockLimits(display_mode *mode, uint32* _low,
811	uint32* _high)
812{
813	if (mode == NULL || _low == NULL || _high == NULL)
814		return B_BAD_VALUE;
815
816	AutoReadLocker _(this);
817	return fAccGetPixelClockLimits(mode, _low, _high);
818}
819
820
821status_t
822AccelerantHWInterface::GetTimingConstraints(
823	display_timing_constraints* constraints)
824{
825	if (constraints == NULL)
826		return B_BAD_VALUE;
827
828	AutoReadLocker _(this);
829
830	if (fAccGetTimingConstraints)
831		return fAccGetTimingConstraints(constraints);
832
833	return B_UNSUPPORTED;
834}
835
836
837status_t
838AccelerantHWInterface::ProposeMode(display_mode* candidate,
839	const display_mode* _low, const display_mode* _high)
840{
841	if (candidate == NULL || _low == NULL || _high == NULL)
842		return B_BAD_VALUE;
843
844	AutoReadLocker _(this);
845
846	if (fAccProposeDisplayMode == NULL)
847		return B_UNSUPPORTED;
848
849	// avoid const issues
850	display_mode high, low;
851	high = *_high;
852	low = *_low;
853
854	return fAccProposeDisplayMode(candidate, &low, &high);
855}
856
857
858status_t
859AccelerantHWInterface::GetPreferredMode(display_mode* preferredMode)
860{
861	status_t status = B_NOT_SUPPORTED;
862
863	if (fAccGetPreferredDisplayMode != NULL) {
864		status = fAccGetPreferredDisplayMode(preferredMode);
865		if (status == B_OK)
866			return B_OK;
867	}
868
869	if (fAccGetEDIDInfo != NULL) {
870		edid1_info info;
871		uint32 version;
872		status = fAccGetEDIDInfo(&info, sizeof(info), &version);
873		if (status < B_OK)
874			return status;
875		if (version != EDID_VERSION_1)
876			return B_NOT_SUPPORTED;
877
878		if (fModeList == NULL) {
879			status = _UpdateModeList();
880			if (status != B_OK)
881				return status;
882		}
883
884		status = B_NOT_SUPPORTED;
885		display_mode bestMode;
886		int32 bestDiff = INT_MAX;
887
888		// find preferred mode from EDID info
889		for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
890			if (info.detailed_monitor[i].monitor_desc_type
891					!= EDID1_IS_DETAILED_TIMING)
892				continue;
893
894			// construct basic mode and find it in the mode list
895			const edid1_detailed_timing& timing
896				= info.detailed_monitor[i].data.detailed_timing;
897			if (timing.h_active < 640 || timing.v_active < 350)
898				continue;
899
900			float aspectRatio = 0.0f;
901			if (timing.h_size > 0 && timing.v_size > 0)
902				aspectRatio = 1.0f * timing.h_size / timing.v_size;
903
904			display_mode modeFound;
905			display_mode mode;
906
907			mode.timing.pixel_clock = timing.pixel_clock * 10;
908			mode.timing.h_display = timing.h_active;
909			mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
910			mode.timing.h_sync_end = mode.timing.h_sync_start
911				+ timing.h_sync_width;
912			mode.timing.h_total = timing.h_active + timing.h_blank;
913			mode.timing.v_display = timing.v_active;
914			mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
915			mode.timing.v_sync_end = mode.timing.v_sync_start
916				+ timing.v_sync_width;
917			mode.timing.v_total = timing.v_active + timing.v_blank;
918
919			mode.space = B_RGB32;
920			mode.virtual_width = mode.timing.h_display;
921			mode.virtual_height = mode.timing.v_display;
922
923			// TODO: eventually ignore detailed modes for the preferred one
924			// if there are more than one usable?
925			int32 diff;
926			if (_FindBestMode(mode, aspectRatio, modeFound, &diff) == B_OK) {
927				status = B_OK;
928				if (diff < bestDiff) {
929					bestMode = modeFound;
930					bestDiff = diff;
931				}
932			}
933		}
934
935		if (status == B_OK)
936			*preferredMode = bestMode;
937	}
938
939	return status;
940}
941
942
943status_t
944AccelerantHWInterface::GetMonitorInfo(monitor_info* info)
945{
946	status_t status = B_NOT_SUPPORTED;
947
948	if (fAccGetMonitorInfo != NULL) {
949		status = fAccGetMonitorInfo(info);
950		if (status == B_OK)
951			return B_OK;
952	}
953
954	if (fAccGetEDIDInfo == NULL)
955		return status;
956
957	edid1_info edid;
958	uint32 version;
959	status = fAccGetEDIDInfo(&edid, sizeof(edid), &version);
960	if (status < B_OK)
961		return status;
962	if (version != EDID_VERSION_1)
963		return B_NOT_SUPPORTED;
964
965	memset(info, 0, sizeof(monitor_info));
966	strlcpy(info->vendor, edid.vendor.manufacturer, sizeof(info->vendor));
967	if (edid.vendor.serial != 0) {
968		snprintf(info->serial_number, sizeof(info->serial_number), "%" B_PRIu32,
969			edid.vendor.serial);
970	}
971	info->product_id = edid.vendor.prod_id;
972	info->produced.week = edid.vendor.week;
973	info->produced.year = edid.vendor.year;
974	info->width = edid.display.h_size;
975	info->height = edid.display.v_size;
976
977	for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
978		edid1_detailed_monitor *monitor = &edid.detailed_monitor[i];
979
980		switch (monitor->monitor_desc_type) {
981			case EDID1_SERIAL_NUMBER:
982				strlcpy(info->serial_number, monitor->data.serial_number,
983					sizeof(info->serial_number));
984				break;
985
986			case EDID1_MONITOR_NAME:
987				// There can be several of these; in this case we'll just
988				// overwrite the previous entries
989				// TODO: we could append them as well
990				strlcpy(info->name, monitor->data.monitor_name,
991					sizeof(info->name));
992				break;
993
994			case EDID1_MONITOR_RANGES:
995			{
996				edid1_monitor_range& range = monitor->data.monitor_range;
997
998				info->min_horizontal_frequency = range.min_h;
999				info->max_horizontal_frequency = range.max_h;
1000				info->min_vertical_frequency = range.min_v;
1001				info->max_vertical_frequency = range.max_v;
1002				info->max_pixel_clock = range.max_clock * 10000;
1003				break;
1004			}
1005
1006			case EDID1_IS_DETAILED_TIMING:
1007			{
1008				edid1_detailed_timing& timing = monitor->data.detailed_timing;
1009				info->width = timing.h_size / 10.0;
1010				info->height = timing.v_size / 10.0;
1011			}
1012
1013			default:
1014				break;
1015		}
1016	}
1017
1018	return B_OK;
1019}
1020
1021
1022sem_id
1023AccelerantHWInterface::RetraceSemaphore()
1024{
1025	AutoWriteLocker _(this);
1026
1027	if (fRetraceSemaphore != -1)
1028		return fRetraceSemaphore;
1029
1030	accelerant_retrace_semaphore AccelerantRetraceSemaphore =
1031		(accelerant_retrace_semaphore)fAccelerantHook(
1032			B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
1033	if (!AccelerantRetraceSemaphore)
1034		fRetraceSemaphore = B_UNSUPPORTED;
1035	else
1036		fRetraceSemaphore = AccelerantRetraceSemaphore();
1037
1038	return fRetraceSemaphore;
1039}
1040
1041
1042status_t
1043AccelerantHWInterface::WaitForRetrace(bigtime_t timeout)
1044{
1045	sem_id sem = RetraceSemaphore();
1046	if (sem < 0)
1047		return sem;
1048
1049	return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout);
1050}
1051
1052
1053status_t
1054AccelerantHWInterface::SetDPMSMode(uint32 state)
1055{
1056	AutoWriteLocker _(this);
1057
1058	if (!fAccSetDPMSMode)
1059		return B_UNSUPPORTED;
1060
1061	return fAccSetDPMSMode(state);
1062}
1063
1064
1065uint32
1066AccelerantHWInterface::DPMSMode()
1067{
1068	AutoReadLocker _(this);
1069
1070	if (!fAccDPMSMode)
1071		return B_UNSUPPORTED;
1072
1073	return fAccDPMSMode();
1074}
1075
1076
1077uint32
1078AccelerantHWInterface::DPMSCapabilities()
1079{
1080	AutoReadLocker _(this);
1081
1082	if (!fAccDPMSCapabilities)
1083		return B_UNSUPPORTED;
1084
1085	return fAccDPMSCapabilities();
1086}
1087
1088
1089status_t
1090AccelerantHWInterface::GetAccelerantPath(BString& string)
1091{
1092	image_info info;
1093	status_t status = get_image_info(fAccelerantImage, &info);
1094	if (status == B_OK)
1095		string = info.name;
1096	return status;
1097}
1098
1099
1100status_t
1101AccelerantHWInterface::GetDriverPath(BString& string)
1102{
1103	// TODO: this currently assumes that the accelerant's clone info
1104	//	is always the path name of its driver (that's the case for
1105	//	all of our drivers)
1106	char path[B_PATH_NAME_LENGTH];
1107	get_accelerant_clone_info getCloneInfo;
1108	getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(
1109		B_GET_ACCELERANT_CLONE_INFO, NULL);
1110
1111	if (getCloneInfo == NULL)
1112		return B_NOT_SUPPORTED;
1113
1114	getCloneInfo((void*)path);
1115	string.SetTo(path);
1116	return B_OK;
1117}
1118
1119
1120// #pragma mark - acceleration
1121
1122
1123uint32
1124AccelerantHWInterface::AvailableHWAcceleration() const
1125{
1126	uint32 flags = 0;
1127
1128	if (!IsDoubleBuffered() || fOffscreenBackBuffer) {
1129		if (fAccScreenBlit)
1130			flags |= HW_ACC_COPY_REGION;
1131		if (fAccFillRect)
1132			flags |= HW_ACC_FILL_REGION;
1133		if (fAccInvertRect)
1134			flags |= HW_ACC_INVERT_REGION;
1135	}
1136
1137	return flags;
1138}
1139
1140
1141void
1142AccelerantHWInterface::CopyRegion(const clipping_rect* sortedRectList,
1143	uint32 count, int32 xOffset, int32 yOffset)
1144{
1145	_CopyRegion(sortedRectList, count, xOffset, yOffset, fOffscreenBackBuffer);
1146}
1147
1148
1149void
1150AccelerantHWInterface::FillRegion(/*const*/ BRegion& region,
1151	const rgb_color& color, bool autoSync)
1152{
1153	if (fAccFillRect && fAccAcquireEngine) {
1154		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1155				&fEngineToken) >= B_OK) {
1156			// convert the region
1157			uint32 count;
1158			_RegionToRectParams(&region, &count);
1159
1160			// go
1161			fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count);
1162
1163			// done
1164			if (fAccReleaseEngine)
1165				fAccReleaseEngine(fEngineToken, &fSyncToken);
1166
1167			// sync
1168			if (autoSync && fAccSyncToToken)
1169				fAccSyncToToken(&fSyncToken);
1170		}
1171	}
1172}
1173
1174
1175void
1176AccelerantHWInterface::InvertRegion(/*const*/ BRegion& region)
1177{
1178	if (fAccInvertRect && fAccAcquireEngine) {
1179		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1180				&fEngineToken) >= B_OK) {
1181			// convert the region
1182			uint32 count;
1183			_RegionToRectParams(&region, &count);
1184
1185			fAccInvertRect(fEngineToken, fRectParams, count);
1186
1187			if (fAccReleaseEngine)
1188				fAccReleaseEngine(fEngineToken, &fSyncToken);
1189			if (fAccSyncToToken)
1190				fAccSyncToToken(&fSyncToken);
1191		}
1192	}
1193}
1194
1195
1196void
1197AccelerantHWInterface::Sync()
1198{
1199	if (fAccSyncToToken)
1200		fAccSyncToToken(&fSyncToken);
1201}
1202
1203
1204// #pragma mark - overlays
1205
1206
1207overlay_token
1208AccelerantHWInterface::AcquireOverlayChannel()
1209{
1210	if (fAccAllocateOverlay == NULL
1211		|| fAccReleaseOverlay == NULL)
1212		return NULL;
1213
1214	// The current display mode only matters at the time we're planning on
1215	// showing the overlay channel on screen - that's why we can't use
1216	// the B_OVERLAY_COUNT hook.
1217	// TODO: remove fAccOverlayCount if we're not going to need it at all.
1218
1219	return fAccAllocateOverlay();
1220}
1221
1222
1223void
1224AccelerantHWInterface::ReleaseOverlayChannel(overlay_token token)
1225{
1226	if (token == NULL)
1227		return;
1228
1229	fAccReleaseOverlay(token);
1230}
1231
1232
1233status_t
1234AccelerantHWInterface::GetOverlayRestrictions(const Overlay* overlay,
1235	overlay_restrictions* restrictions)
1236{
1237	if (overlay == NULL || restrictions == NULL)
1238		return B_BAD_VALUE;
1239	if (fAccGetOverlayConstraints == NULL)
1240		return B_NOT_SUPPORTED;
1241
1242	overlay_constraints constraints;
1243	status_t status = fAccGetOverlayConstraints(&fDisplayMode,
1244		overlay->OverlayBuffer(), &constraints);
1245	if (status < B_OK)
1246		return status;
1247
1248	memset(restrictions, 0, sizeof(overlay_restrictions));
1249	memcpy(&restrictions->source, &constraints.view, sizeof(overlay_limits));
1250	memcpy(&restrictions->destination, &constraints.window,
1251		sizeof(overlay_limits));
1252	restrictions->min_width_scale = constraints.h_scale.min;
1253	restrictions->max_width_scale = constraints.h_scale.max;
1254	restrictions->min_height_scale = constraints.v_scale.min;
1255	restrictions->max_height_scale = constraints.v_scale.max;
1256
1257	return B_OK;
1258}
1259
1260
1261bool
1262AccelerantHWInterface::CheckOverlayRestrictions(int32 width, int32 height,
1263	color_space colorSpace)
1264{
1265	if (fAccOverlaySupportedSpaces == NULL
1266		|| fAccGetOverlayConstraints == NULL
1267		|| fAccAllocateOverlayBuffer == NULL
1268		|| fAccReleaseOverlayBuffer == NULL)
1269		return false;
1270
1271	// Note: we can't really check the size of the overlay upfront - we
1272	// must assume fAccAllocateOverlayBuffer() will fail in that case.
1273	if (width < 0 || width > 65535 || height < 0 || height > 65535)
1274		return false;
1275
1276	// check color space
1277
1278	const uint32* spaces = fAccOverlaySupportedSpaces(&fDisplayMode);
1279	if (spaces == NULL)
1280		return false;
1281
1282	for (int32 i = 0; spaces[i] != 0; i++) {
1283		if (spaces[i] == (uint32)colorSpace)
1284			return true;
1285	}
1286
1287	return false;
1288}
1289
1290
1291const overlay_buffer*
1292AccelerantHWInterface::AllocateOverlayBuffer(int32 width, int32 height,
1293	color_space space)
1294{
1295	if (fAccAllocateOverlayBuffer == NULL)
1296		return NULL;
1297
1298	return fAccAllocateOverlayBuffer(space, width, height);
1299}
1300
1301
1302void
1303AccelerantHWInterface::FreeOverlayBuffer(const overlay_buffer* buffer)
1304{
1305	if (buffer == NULL || fAccReleaseOverlayBuffer == NULL)
1306		return;
1307
1308	fAccReleaseOverlayBuffer(buffer);
1309}
1310
1311
1312void
1313AccelerantHWInterface::ConfigureOverlay(Overlay* overlay)
1314{
1315	// TODO: this only needs to be done on mode changes!
1316	overlay->SetColorSpace(fDisplayMode.space);
1317
1318	fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
1319		overlay->OverlayWindow(), overlay->OverlayView());
1320}
1321
1322
1323void
1324AccelerantHWInterface::HideOverlay(Overlay* overlay)
1325{
1326	fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
1327		NULL, NULL);
1328}
1329
1330
1331// #pragma mark - cursor
1332
1333
1334void
1335AccelerantHWInterface::SetCursor(ServerCursor* cursor)
1336{
1337	HWInterface::SetCursor(cursor);
1338		// HWInterface claims ownership of cursor.
1339
1340	// cursor should never be NULL, but let us be safe!!
1341	if (cursor == NULL || LockExclusiveAccess() == false)
1342		return;
1343
1344	if (cursor->CursorData() != NULL && fAccSetCursorShape != NULL) {
1345		// BeOS BCursor, 16x16 monochrome
1346		uint8 size = cursor->CursorData()[0];
1347		// CursorData()[1] is color depth (always monochrome)
1348		uint8 xHotSpot = cursor->CursorData()[2];
1349		uint8 yHotSpot = cursor->CursorData()[3];
1350
1351		// Create pointers to the cursor and/xor bit arrays
1352		const uint8* andMask = cursor->CursorData() + 4;
1353		const uint8* xorMask = cursor->CursorData() + 36;
1354
1355		// Time to talk to the accelerant!
1356		fHardwareCursorEnabled = fAccSetCursorShape(size, size, xHotSpot,
1357			yHotSpot, andMask, xorMask) == B_OK;
1358	} else if (fAccSetCursorBitmap != NULL) {
1359		// Bitmap cursor
1360		uint16 xHotSpot = (uint16)cursor->GetHotSpot().x;
1361		uint16 yHotSpot = (uint16)cursor->GetHotSpot().y;
1362
1363		uint16 width = (uint16)cursor->Bounds().Width();
1364		uint16 height = (uint16)cursor->Bounds().Height();
1365
1366		// Time to talk to the accelerant!
1367		fHardwareCursorEnabled = fAccSetCursorBitmap(width, height, xHotSpot,
1368			yHotSpot, cursor->ColorSpace(), (uint16)cursor->BytesPerRow(),
1369			cursor->Bits()) == B_OK;
1370	}
1371
1372	UnlockExclusiveAccess();
1373}
1374
1375
1376void
1377AccelerantHWInterface::SetCursorVisible(bool visible)
1378{
1379	HWInterface::SetCursorVisible(visible);
1380
1381	if (fHardwareCursorEnabled && LockExclusiveAccess()) {
1382		if (fAccShowCursor != NULL)
1383				fAccShowCursor(visible);
1384		else
1385			fHardwareCursorEnabled = false;
1386
1387		UnlockExclusiveAccess();
1388	}
1389}
1390
1391
1392void
1393AccelerantHWInterface::MoveCursorTo(float x, float y)
1394{
1395	HWInterface::MoveCursorTo(x, y);
1396
1397	if (fHardwareCursorEnabled && LockExclusiveAccess()) {
1398		if (fAccMoveCursor != NULL)
1399				fAccMoveCursor((uint16)x, (uint16)y);
1400		else
1401			fHardwareCursorEnabled = false;
1402
1403		UnlockExclusiveAccess();
1404	}
1405}
1406
1407
1408// #pragma mark - buffer access
1409
1410
1411RenderingBuffer*
1412AccelerantHWInterface::FrontBuffer() const
1413{
1414	return fFrontBuffer;
1415}
1416
1417
1418RenderingBuffer*
1419AccelerantHWInterface::BackBuffer() const
1420{
1421	return fBackBuffer;
1422}
1423
1424
1425bool
1426AccelerantHWInterface::IsDoubleBuffered() const
1427{
1428	return fBackBuffer != NULL;
1429}
1430
1431
1432void
1433AccelerantHWInterface::_CopyBackToFront(/*const*/ BRegion& region)
1434{
1435	if (fOffscreenBackBuffer) {
1436		int32 xOffset = 0;
1437		int32 yOffset = -(int32)fFrontBuffer->Height();
1438
1439		int32 count = region.CountRects();
1440		clipping_rect rects[count];
1441		for (int32 i = 0; i < count; i++) {
1442			rects[i] = region.RectAtInt(i);
1443			rects[i].top -= yOffset;
1444			rects[i].bottom -= yOffset;
1445		}
1446
1447		_CopyRegion(rects, count, xOffset, yOffset, false);
1448
1449		return;
1450	}
1451
1452	return HWInterface::_CopyBackToFront(region);
1453}
1454
1455
1456// #pragma mark -
1457
1458
1459void
1460AccelerantHWInterface::_DrawCursor(IntRect area) const
1461{
1462	if (!fHardwareCursorEnabled)
1463		HWInterface::_DrawCursor(area);
1464}
1465
1466
1467void
1468AccelerantHWInterface::_RegionToRectParams(/*const*/ BRegion* region,
1469	uint32* count) const
1470{
1471	*count = region->CountRects();
1472	// TODO: locking!!
1473	if (fRectParamsCount < *count) {
1474		fRectParamsCount = (*count / kDefaultParamsCount + 1)
1475			* kDefaultParamsCount;
1476		// NOTE: realloc() could be used instead...
1477		fill_rect_params* params
1478			= new (nothrow) fill_rect_params[fRectParamsCount];
1479		if (params) {
1480			delete[] fRectParams;
1481			fRectParams = params;
1482		} else {
1483			*count = fRectParamsCount;
1484		}
1485	}
1486
1487	int32 srcOffsetY = fOffscreenBackBuffer ? fFrontBuffer->Height() : 0;
1488
1489	for (uint32 i = 0; i < *count; i++) {
1490		clipping_rect r = region->RectAtInt(i);
1491		fRectParams[i].left = (uint16)r.left;
1492		fRectParams[i].top = (uint16)r.top + srcOffsetY;
1493		fRectParams[i].right = (uint16)r.right;
1494		fRectParams[i].bottom = (uint16)r.bottom + srcOffsetY;
1495	}
1496}
1497
1498
1499void
1500AccelerantHWInterface::_CopyRegion(const clipping_rect* sortedRectList,
1501	uint32 count, int32 xOffset, int32 yOffset, bool inBackBuffer)
1502{
1503	if (fAccScreenBlit && fAccAcquireEngine) {
1504		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1505				&fEngineToken) >= B_OK) {
1506			// make sure the blit_params cache is large enough
1507			// TODO: locking!!
1508			if (fBlitParamsCount < count) {
1509				fBlitParamsCount = (count / kDefaultParamsCount + 1)
1510					* kDefaultParamsCount;
1511				// NOTE: realloc() could be used instead...
1512				blit_params* params
1513					= new (nothrow) blit_params[fBlitParamsCount];
1514				if (params) {
1515					delete[] fBlitParams;
1516					fBlitParams = params;
1517				} else {
1518					count = fBlitParamsCount;
1519				}
1520			}
1521			int32 srcOffsetY = inBackBuffer ? fFrontBuffer->Height() : 0;
1522			// convert the rects
1523			for (uint32 i = 0; i < count; i++) {
1524				fBlitParams[i].src_left = (uint16)sortedRectList[i].left;
1525				fBlitParams[i].src_top = (uint16)sortedRectList[i].top
1526					+ srcOffsetY;
1527
1528				fBlitParams[i].dest_left = (uint16)sortedRectList[i].left
1529					+ xOffset;
1530				fBlitParams[i].dest_top = (uint16)sortedRectList[i].top
1531					+ yOffset + srcOffsetY;
1532
1533				// NOTE: width and height are expressed as distance, not
1534				// pixel count!
1535				fBlitParams[i].width = (uint16)(sortedRectList[i].right
1536					- sortedRectList[i].left);
1537				fBlitParams[i].height = (uint16)(sortedRectList[i].bottom
1538					- sortedRectList[i].top);
1539			}
1540
1541			// go
1542			fAccScreenBlit(fEngineToken, fBlitParams, count);
1543
1544			// done
1545			if (fAccReleaseEngine)
1546				fAccReleaseEngine(fEngineToken, &fSyncToken);
1547
1548			// sync
1549			if (fAccSyncToToken)
1550				fAccSyncToToken(&fSyncToken);
1551		}
1552	}
1553}
1554
1555
1556uint32
1557AccelerantHWInterface::_NativeColor(const rgb_color& color) const
1558{
1559	// NOTE: This functions looks somehow suspicios to me.
1560	// It assumes that all graphics cards have the same native endianess, no?
1561	switch (fDisplayMode.space) {
1562		case B_CMAP8:
1563		case B_GRAY8:
1564			return RGBColor(color).GetColor8();
1565
1566		case B_RGB15_BIG:
1567		case B_RGBA15_BIG:
1568		case B_RGB15_LITTLE:
1569		case B_RGBA15_LITTLE:
1570			return RGBColor(color).GetColor15();
1571
1572		case B_RGB16_BIG:
1573		case B_RGB16_LITTLE:
1574			return RGBColor(color).GetColor16();
1575
1576		case B_RGB32_BIG:
1577		case B_RGBA32_BIG:
1578		case B_RGB32_LITTLE:
1579		case B_RGBA32_LITTLE: {
1580			return (uint32)((color.alpha << 24) | (color.red << 16)
1581				| (color.green << 8) | color.blue);
1582		}
1583	}
1584	return 0;
1585}
1586
1587
1588void
1589AccelerantHWInterface::_SetSystemPalette()
1590{
1591	set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
1592		B_SET_INDEXED_COLORS, NULL);
1593	if (setIndexedColors == NULL)
1594		return;
1595
1596	const rgb_color* palette = SystemPalette();
1597	uint8 colors[3 * 256];
1598		// the color table is an array with 3 bytes per color
1599	uint32 j = 0;
1600
1601	for (int32 i = 0; i < 256; i++) {
1602		colors[j++] = palette[i].red;
1603		colors[j++] = palette[i].green;
1604		colors[j++] = palette[i].blue;
1605	}
1606
1607	setIndexedColors(256, 0, colors, 0);
1608}
1609
1610
1611void
1612AccelerantHWInterface::_SetGrayscalePalette()
1613{
1614	set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
1615		B_SET_INDEXED_COLORS, NULL);
1616	if (setIndexedColors == NULL)
1617		return;
1618
1619	uint8 colors[3 * 256];
1620		// the color table is an array with 3 bytes per color
1621	uint32 j = 0;
1622
1623	if (fFrontBuffer->Width() > fFrontBuffer->BytesPerRow()) {
1624		// VGA 16 color grayscale planar mode
1625		for (int32 i = 0; i < 256; i++) {
1626			colors[j++] = (i & 0xf) * 17;
1627			colors[j++] = (i & 0xf) * 17;
1628			colors[j++] = (i & 0xf) * 17;
1629		}
1630
1631		setIndexedColors(256, 0, colors, 0);
1632	} else {
1633		for (int32 i = 0; i < 256; i++) {
1634			colors[j++] = i;
1635			colors[j++] = i;
1636			colors[j++] = i;
1637		}
1638
1639		setIndexedColors(256, 0, colors, 0);
1640	}
1641}
1642