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