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