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