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