xref: /haiku/src/servers/app/drawing/interface/local/AccelerantHWInterface.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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 			&& !HWInterface::IsDoubleBuffered())) {
693 		// NOTE: backbuffer is always B_RGBA32, this simplifies the
694 		// drawing backend implementation tremendously for the time
695 		// being. The color space conversion is handled in CopyBackToFront()
696 
697 		fBackBuffer.Unset();
698 
699 		// TODO: Above not true anymore for single buffered mode!!!
700 		// -> fall back to double buffer for fDisplayMode.space != B_RGB32
701 		// as intermediate solution...
702 		bool doubleBuffered = HWInterface::IsDoubleBuffered();
703 		if ((fFrontBuffer->ColorSpace() != B_RGB32
704 			&& fFrontBuffer->ColorSpace() != B_RGBA32)
705 			|| fVGADevice >= 0 || fOffscreenBackBuffer)
706 			doubleBuffered = true;
707 #if !USE_ACCELERATION
708 		doubleBuffered = true;
709 #endif
710 
711 		if (doubleBuffered) {
712 			if (fOffscreenBackBuffer) {
713 				fBackBuffer.SetTo(
714 					new(nothrow) AccelerantBuffer(*fFrontBuffer.Get(), true));
715 			} else {
716 				fBackBuffer.SetTo(new(nothrow) MallocBuffer(
717 					fFrontBuffer->Width(), fFrontBuffer->Height()));
718 			}
719 
720 			status = fBackBuffer.IsSet()
721 				? fBackBuffer->InitCheck() : B_NO_MEMORY;
722 			if (status < B_OK) {
723 				fBackBuffer.Unset();
724 				fOffscreenBackBuffer = false;
725 				return status;
726 			}
727 			// clear out backbuffer, alpha is 255 this way
728 			memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength());
729 		}
730 #if 0
731 // NOTE: Currently disabled, because it make the double buffered mode flicker
732 // again. See HWInterface::Invalidate() for more information.
733 		SetAsyncDoubleBuffered(doubleBuffered);
734 #endif
735 	}
736 
737 	// update color palette configuration if necessary
738 	if (fDisplayMode.space == B_CMAP8)
739 		_SetSystemPalette();
740 	else if (fDisplayMode.space == B_GRAY8)
741 		_SetGrayscalePalette();
742 
743 	// notify all listeners about the mode change
744 	_NotifyFrameBufferChanged();
745 
746 	return status;
747 }
748 
749 
750 void
751 AccelerantHWInterface::GetMode(display_mode* mode)
752 {
753 	if (mode && LockParallelAccess()) {
754 		*mode = fDisplayMode;
755 		UnlockParallelAccess();
756 	}
757 }
758 
759 
760 status_t
761 AccelerantHWInterface::_UpdateModeList()
762 {
763 	fModeCount = fAccGetModeCount();
764 	if (fModeCount <= 0)
765 		return B_ERROR;
766 
767 	delete[] fModeList;
768 	fModeList = new(nothrow) display_mode[fModeCount];
769 	if (!fModeList)
770 		return B_NO_MEMORY;
771 
772 	if (fAccGetModeList(fModeList) != B_OK) {
773 		ATRACE(("unable to get mode list\n"));
774 		return B_ERROR;
775 	}
776 
777 	return B_OK;
778 }
779 
780 
781 status_t
782 AccelerantHWInterface::_UpdateFrameBufferConfig()
783 {
784 	if (fAccGetFrameBufferConfig(&fFrameBufferConfig) != B_OK) {
785 		ATRACE(("unable to get frame buffer config\n"));
786 		return B_ERROR;
787 	}
788 
789 	fFrontBuffer->SetFrameBufferConfig(fFrameBufferConfig);
790 
791 	return B_OK;
792 }
793 
794 
795 status_t
796 AccelerantHWInterface::GetDeviceInfo(accelerant_device_info* info)
797 {
798 	get_accelerant_device_info GetAccelerantDeviceInfo
799 		= (get_accelerant_device_info)fAccelerantHook(
800 			B_GET_ACCELERANT_DEVICE_INFO, NULL);
801 	if (!GetAccelerantDeviceInfo) {
802 		ATRACE(("No B_GET_ACCELERANT_DEVICE_INFO hook found\n"));
803 		return B_UNSUPPORTED;
804 	}
805 
806 	return GetAccelerantDeviceInfo(info);
807 }
808 
809 
810 status_t
811 AccelerantHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
812 {
813 	config = fFrameBufferConfig;
814 	return B_OK;
815 }
816 
817 
818 status_t
819 AccelerantHWInterface::GetModeList(display_mode** _modes, uint32* _count)
820 {
821 	AutoReadLocker _(this);
822 
823 	if (_count == NULL || _modes == NULL)
824 		return B_BAD_VALUE;
825 
826 	status_t status = B_OK;
827 
828 	if (fModeList == NULL)
829 		status = _UpdateModeList();
830 
831 	if (status >= B_OK) {
832 		*_modes = new(nothrow) display_mode[fModeCount];
833 		if (*_modes) {
834 			*_count = fModeCount;
835 			memcpy(*_modes, fModeList, sizeof(display_mode) * fModeCount);
836 		} else {
837 			*_count = 0;
838 			status = B_NO_MEMORY;
839 		}
840 	}
841 	return status;
842 }
843 
844 
845 status_t
846 AccelerantHWInterface::GetPixelClockLimits(display_mode *mode, uint32* _low,
847 	uint32* _high)
848 {
849 	if (mode == NULL || _low == NULL || _high == NULL)
850 		return B_BAD_VALUE;
851 
852 	AutoReadLocker _(this);
853 	return fAccGetPixelClockLimits(mode, _low, _high);
854 }
855 
856 
857 status_t
858 AccelerantHWInterface::GetTimingConstraints(
859 	display_timing_constraints* constraints)
860 {
861 	if (constraints == NULL)
862 		return B_BAD_VALUE;
863 
864 	AutoReadLocker _(this);
865 
866 	if (fAccGetTimingConstraints)
867 		return fAccGetTimingConstraints(constraints);
868 
869 	return B_UNSUPPORTED;
870 }
871 
872 
873 status_t
874 AccelerantHWInterface::ProposeMode(display_mode* candidate,
875 	const display_mode* _low, const display_mode* _high)
876 {
877 	if (candidate == NULL || _low == NULL || _high == NULL)
878 		return B_BAD_VALUE;
879 
880 	AutoReadLocker _(this);
881 
882 	if (fAccProposeDisplayMode == NULL)
883 		return B_UNSUPPORTED;
884 
885 	// avoid const issues
886 	display_mode high, low;
887 	high = *_high;
888 	low = *_low;
889 
890 	return fAccProposeDisplayMode(candidate, &low, &high);
891 }
892 
893 
894 status_t
895 AccelerantHWInterface::GetPreferredMode(display_mode* preferredMode)
896 {
897 	status_t status = B_NOT_SUPPORTED;
898 
899 	if (fAccGetPreferredDisplayMode != NULL) {
900 		status = fAccGetPreferredDisplayMode(preferredMode);
901 		if (status == B_OK)
902 			return B_OK;
903 	}
904 
905 	if (fAccGetEDIDInfo != NULL) {
906 		edid1_info info;
907 		uint32 version;
908 		status = fAccGetEDIDInfo(&info, sizeof(info), &version);
909 		if (status < B_OK)
910 			return status;
911 		if (version != EDID_VERSION_1)
912 			return B_NOT_SUPPORTED;
913 
914 		if (fModeList == NULL) {
915 			status = _UpdateModeList();
916 			if (status != B_OK)
917 				return status;
918 		}
919 
920 		status = B_NOT_SUPPORTED;
921 		display_mode bestMode;
922 		int32 bestDiff = INT_MAX;
923 
924 		// find preferred mode from EDID info
925 		for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
926 			if (info.detailed_monitor[i].monitor_desc_type
927 					!= EDID1_IS_DETAILED_TIMING)
928 				continue;
929 
930 			// construct basic mode and find it in the mode list
931 			const edid1_detailed_timing& timing
932 				= info.detailed_monitor[i].data.detailed_timing;
933 			if (timing.h_active < 640 || timing.v_active < 350)
934 				continue;
935 
936 			float aspectRatio = 0.0f;
937 			if (timing.h_size > 0 && timing.v_size > 0)
938 				aspectRatio = 1.0f * timing.h_size / timing.v_size;
939 
940 			display_mode modeFound;
941 			display_mode mode;
942 
943 			mode.timing.pixel_clock = timing.pixel_clock * 10;
944 			mode.timing.h_display = timing.h_active;
945 			mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
946 			mode.timing.h_sync_end = mode.timing.h_sync_start
947 				+ timing.h_sync_width;
948 			mode.timing.h_total = timing.h_active + timing.h_blank;
949 			mode.timing.v_display = timing.v_active;
950 			mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
951 			mode.timing.v_sync_end = mode.timing.v_sync_start
952 				+ timing.v_sync_width;
953 			mode.timing.v_total = timing.v_active + timing.v_blank;
954 
955 			mode.space = B_RGB32;
956 			mode.virtual_width = mode.timing.h_display;
957 			mode.virtual_height = mode.timing.v_display;
958 
959 			// TODO: eventually ignore detailed modes for the preferred one
960 			// if there are more than one usable?
961 			int32 diff;
962 			if (_FindBestMode(mode, aspectRatio, modeFound, &diff) == B_OK) {
963 				status = B_OK;
964 				if (diff < bestDiff) {
965 					bestMode = modeFound;
966 					bestDiff = diff;
967 				}
968 			}
969 		}
970 
971 		if (status == B_OK)
972 			*preferredMode = bestMode;
973 	}
974 
975 	return status;
976 }
977 
978 
979 status_t
980 AccelerantHWInterface::GetMonitorInfo(monitor_info* info)
981 {
982 	status_t status = B_NOT_SUPPORTED;
983 
984 	if (fAccGetMonitorInfo != NULL) {
985 		status = fAccGetMonitorInfo(info);
986 		if (status == B_OK)
987 			return B_OK;
988 	}
989 
990 	if (fAccGetEDIDInfo == NULL)
991 		return status;
992 
993 	edid1_info edid;
994 	uint32 version;
995 	status = fAccGetEDIDInfo(&edid, sizeof(edid), &version);
996 	if (status < B_OK)
997 		return status;
998 	if (version != EDID_VERSION_1)
999 		return B_NOT_SUPPORTED;
1000 
1001 	memset(info, 0, sizeof(monitor_info));
1002 	strlcpy(info->vendor, edid.vendor.manufacturer, sizeof(info->vendor));
1003 	if (edid.vendor.serial != 0) {
1004 		snprintf(info->serial_number, sizeof(info->serial_number), "%" B_PRIu32,
1005 			edid.vendor.serial);
1006 	}
1007 	info->product_id = edid.vendor.prod_id;
1008 	info->produced.week = edid.vendor.week;
1009 	info->produced.year = edid.vendor.year;
1010 	info->width = edid.display.h_size;
1011 	info->height = edid.display.v_size;
1012 
1013 	for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
1014 		edid1_detailed_monitor *monitor = &edid.detailed_monitor[i];
1015 
1016 		switch (monitor->monitor_desc_type) {
1017 			case EDID1_SERIAL_NUMBER:
1018 				strlcpy(info->serial_number, monitor->data.serial_number,
1019 					sizeof(info->serial_number));
1020 				break;
1021 
1022 			case EDID1_MONITOR_NAME:
1023 				// There can be several of these; in this case we'll just
1024 				// overwrite the previous entries
1025 				// TODO: we could append them as well
1026 				strlcpy(info->name, monitor->data.monitor_name,
1027 					sizeof(info->name));
1028 				break;
1029 
1030 			case EDID1_MONITOR_RANGES:
1031 			{
1032 				edid1_monitor_range& range = monitor->data.monitor_range;
1033 
1034 				info->min_horizontal_frequency = range.min_h;
1035 				info->max_horizontal_frequency = range.max_h;
1036 				info->min_vertical_frequency = range.min_v;
1037 				info->max_vertical_frequency = range.max_v;
1038 				info->max_pixel_clock = range.max_clock * 10000;
1039 				break;
1040 			}
1041 
1042 			case EDID1_IS_DETAILED_TIMING:
1043 			{
1044 				edid1_detailed_timing& timing = monitor->data.detailed_timing;
1045 				info->width = timing.h_size / 10.0;
1046 				info->height = timing.v_size / 10.0;
1047 			}
1048 
1049 			default:
1050 				break;
1051 		}
1052 	}
1053 
1054 	return B_OK;
1055 }
1056 
1057 
1058 sem_id
1059 AccelerantHWInterface::RetraceSemaphore()
1060 {
1061 	AutoWriteLocker _(this);
1062 
1063 	if (fRetraceSemaphore != -1)
1064 		return fRetraceSemaphore;
1065 
1066 	accelerant_retrace_semaphore AccelerantRetraceSemaphore =
1067 		(accelerant_retrace_semaphore)fAccelerantHook(
1068 			B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
1069 	if (!AccelerantRetraceSemaphore)
1070 		fRetraceSemaphore = B_UNSUPPORTED;
1071 	else
1072 		fRetraceSemaphore = AccelerantRetraceSemaphore();
1073 
1074 	return fRetraceSemaphore;
1075 }
1076 
1077 
1078 status_t
1079 AccelerantHWInterface::WaitForRetrace(bigtime_t timeout)
1080 {
1081 	sem_id sem = RetraceSemaphore();
1082 	if (sem < 0)
1083 		return sem;
1084 
1085 	return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout);
1086 }
1087 
1088 
1089 status_t
1090 AccelerantHWInterface::SetDPMSMode(uint32 state)
1091 {
1092 	AutoWriteLocker _(this);
1093 
1094 	if (!fAccSetDPMSMode)
1095 		return B_UNSUPPORTED;
1096 
1097 	return fAccSetDPMSMode(state);
1098 }
1099 
1100 
1101 uint32
1102 AccelerantHWInterface::DPMSMode()
1103 {
1104 	AutoReadLocker _(this);
1105 
1106 	if (!fAccDPMSMode)
1107 		return B_UNSUPPORTED;
1108 
1109 	return fAccDPMSMode();
1110 }
1111 
1112 
1113 uint32
1114 AccelerantHWInterface::DPMSCapabilities()
1115 {
1116 	AutoReadLocker _(this);
1117 
1118 	if (!fAccDPMSCapabilities)
1119 		return B_UNSUPPORTED;
1120 
1121 	return fAccDPMSCapabilities();
1122 }
1123 
1124 
1125 status_t
1126 AccelerantHWInterface::SetBrightness(float brightness)
1127 {
1128 	AutoReadLocker _(this);
1129 
1130 	if (!fAccSetBrightness)
1131 		return B_UNSUPPORTED;
1132 
1133 	return fAccSetBrightness(brightness);
1134 }
1135 
1136 
1137 status_t
1138 AccelerantHWInterface::GetBrightness(float* brightness)
1139 {
1140 	AutoReadLocker _(this);
1141 
1142 	if (!fAccGetBrightness)
1143 		return B_UNSUPPORTED;
1144 
1145 	return fAccGetBrightness(brightness);
1146 }
1147 
1148 
1149 status_t
1150 AccelerantHWInterface::GetAccelerantPath(BString& string)
1151 {
1152 	image_info info;
1153 	status_t status = get_image_info(fAccelerantImage, &info);
1154 	if (status == B_OK)
1155 		string = info.name;
1156 	return status;
1157 }
1158 
1159 
1160 status_t
1161 AccelerantHWInterface::GetDriverPath(BString& string)
1162 {
1163 	// TODO: this currently assumes that the accelerant's clone info
1164 	//	is always the path name of its driver (that's the case for
1165 	//	all of our drivers)
1166 	char path[B_PATH_NAME_LENGTH];
1167 	get_accelerant_clone_info getCloneInfo;
1168 	getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(
1169 		B_GET_ACCELERANT_CLONE_INFO, NULL);
1170 
1171 	if (getCloneInfo == NULL)
1172 		return B_NOT_SUPPORTED;
1173 
1174 	getCloneInfo((void*)path);
1175 	string.SetTo(path);
1176 	return B_OK;
1177 }
1178 
1179 
1180 // #pragma mark - acceleration
1181 
1182 
1183 uint32
1184 AccelerantHWInterface::AvailableHWAcceleration() const
1185 {
1186 	uint32 flags = 0;
1187 
1188 	if (!IsDoubleBuffered() || fOffscreenBackBuffer) {
1189 		if (fAccScreenBlit)
1190 			flags |= HW_ACC_COPY_REGION;
1191 		if (fAccFillRect)
1192 			flags |= HW_ACC_FILL_REGION;
1193 		if (fAccInvertRect)
1194 			flags |= HW_ACC_INVERT_REGION;
1195 	}
1196 
1197 	return flags;
1198 }
1199 
1200 
1201 void
1202 AccelerantHWInterface::CopyRegion(const clipping_rect* sortedRectList,
1203 	uint32 count, int32 xOffset, int32 yOffset)
1204 {
1205 	_CopyRegion(sortedRectList, count, xOffset, yOffset, fOffscreenBackBuffer);
1206 }
1207 
1208 
1209 void
1210 AccelerantHWInterface::FillRegion(/*const*/ BRegion& region,
1211 	const rgb_color& color, bool autoSync)
1212 {
1213 	if (fAccFillRect && fAccAcquireEngine) {
1214 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1215 				&fEngineToken) >= B_OK) {
1216 			// convert the region
1217 			uint32 count;
1218 			_RegionToRectParams(&region, &count);
1219 
1220 			// go
1221 			fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count);
1222 
1223 			// done
1224 			if (fAccReleaseEngine)
1225 				fAccReleaseEngine(fEngineToken, &fSyncToken);
1226 
1227 			// sync
1228 			if (autoSync && fAccSyncToToken)
1229 				fAccSyncToToken(&fSyncToken);
1230 		}
1231 	}
1232 }
1233 
1234 
1235 void
1236 AccelerantHWInterface::InvertRegion(/*const*/ BRegion& region)
1237 {
1238 	if (fAccInvertRect && fAccAcquireEngine) {
1239 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1240 				&fEngineToken) >= B_OK) {
1241 			// convert the region
1242 			uint32 count;
1243 			_RegionToRectParams(&region, &count);
1244 
1245 			fAccInvertRect(fEngineToken, fRectParams, count);
1246 
1247 			if (fAccReleaseEngine)
1248 				fAccReleaseEngine(fEngineToken, &fSyncToken);
1249 			if (fAccSyncToToken)
1250 				fAccSyncToToken(&fSyncToken);
1251 		}
1252 	}
1253 }
1254 
1255 
1256 void
1257 AccelerantHWInterface::Sync()
1258 {
1259 	if (fAccSyncToToken)
1260 		fAccSyncToToken(&fSyncToken);
1261 }
1262 
1263 
1264 // #pragma mark - overlays
1265 
1266 
1267 overlay_token
1268 AccelerantHWInterface::AcquireOverlayChannel()
1269 {
1270 	if (fAccAllocateOverlay == NULL
1271 		|| fAccReleaseOverlay == NULL)
1272 		return NULL;
1273 
1274 	// The current display mode only matters at the time we're planning on
1275 	// showing the overlay channel on screen - that's why we can't use
1276 	// the B_OVERLAY_COUNT hook.
1277 	// TODO: remove fAccOverlayCount if we're not going to need it at all.
1278 
1279 	return fAccAllocateOverlay();
1280 }
1281 
1282 
1283 void
1284 AccelerantHWInterface::ReleaseOverlayChannel(overlay_token token)
1285 {
1286 	if (token == NULL)
1287 		return;
1288 
1289 	fAccReleaseOverlay(token);
1290 }
1291 
1292 
1293 status_t
1294 AccelerantHWInterface::GetOverlayRestrictions(const Overlay* overlay,
1295 	overlay_restrictions* restrictions)
1296 {
1297 	if (overlay == NULL || restrictions == NULL)
1298 		return B_BAD_VALUE;
1299 	if (fAccGetOverlayConstraints == NULL)
1300 		return B_NOT_SUPPORTED;
1301 
1302 	overlay_constraints constraints;
1303 	status_t status = fAccGetOverlayConstraints(&fDisplayMode,
1304 		overlay->OverlayBuffer(), &constraints);
1305 	if (status < B_OK)
1306 		return status;
1307 
1308 	memset(restrictions, 0, sizeof(overlay_restrictions));
1309 	memcpy(&restrictions->source, &constraints.view, sizeof(overlay_limits));
1310 	memcpy(&restrictions->destination, &constraints.window,
1311 		sizeof(overlay_limits));
1312 	restrictions->min_width_scale = constraints.h_scale.min;
1313 	restrictions->max_width_scale = constraints.h_scale.max;
1314 	restrictions->min_height_scale = constraints.v_scale.min;
1315 	restrictions->max_height_scale = constraints.v_scale.max;
1316 
1317 	return B_OK;
1318 }
1319 
1320 
1321 bool
1322 AccelerantHWInterface::CheckOverlayRestrictions(int32 width, int32 height,
1323 	color_space colorSpace)
1324 {
1325 	if (fAccOverlaySupportedSpaces == NULL
1326 		|| fAccGetOverlayConstraints == NULL
1327 		|| fAccAllocateOverlayBuffer == NULL
1328 		|| fAccReleaseOverlayBuffer == NULL)
1329 		return false;
1330 
1331 	// Note: we can't really check the size of the overlay upfront - we
1332 	// must assume fAccAllocateOverlayBuffer() will fail in that case.
1333 	if (width < 0 || width > 65535 || height < 0 || height > 65535)
1334 		return false;
1335 
1336 	// check color space
1337 
1338 	const uint32* spaces = fAccOverlaySupportedSpaces(&fDisplayMode);
1339 	if (spaces == NULL)
1340 		return false;
1341 
1342 	for (int32 i = 0; spaces[i] != 0; i++) {
1343 		if (spaces[i] == (uint32)colorSpace)
1344 			return true;
1345 	}
1346 
1347 	return false;
1348 }
1349 
1350 
1351 const overlay_buffer*
1352 AccelerantHWInterface::AllocateOverlayBuffer(int32 width, int32 height,
1353 	color_space space)
1354 {
1355 	if (fAccAllocateOverlayBuffer == NULL)
1356 		return NULL;
1357 
1358 	return fAccAllocateOverlayBuffer(space, width, height);
1359 }
1360 
1361 
1362 void
1363 AccelerantHWInterface::FreeOverlayBuffer(const overlay_buffer* buffer)
1364 {
1365 	if (buffer == NULL || fAccReleaseOverlayBuffer == NULL)
1366 		return;
1367 
1368 	fAccReleaseOverlayBuffer(buffer);
1369 }
1370 
1371 
1372 void
1373 AccelerantHWInterface::ConfigureOverlay(Overlay* overlay)
1374 {
1375 	// TODO: this only needs to be done on mode changes!
1376 	overlay->SetColorSpace(fDisplayMode.space);
1377 
1378 	fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
1379 		overlay->OverlayWindow(), overlay->OverlayView());
1380 }
1381 
1382 
1383 void
1384 AccelerantHWInterface::HideOverlay(Overlay* overlay)
1385 {
1386 	fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
1387 		NULL, NULL);
1388 }
1389 
1390 
1391 // #pragma mark - cursor
1392 
1393 
1394 void
1395 AccelerantHWInterface::SetCursor(ServerCursor* cursor)
1396 {
1397 	// cursor should never be NULL, but let us be safe!!
1398 	if (cursor == NULL || LockExclusiveAccess() == false)
1399 		return;
1400 
1401 	bool cursorSet = false;
1402 
1403 	if (fAccSetCursorBitmap != NULL) {
1404 		// Bitmap cursor
1405 		// TODO are x and y switched for this, too?
1406 		uint16 xHotSpot = (uint16)cursor->GetHotSpot().x;
1407 		uint16 yHotSpot = (uint16)cursor->GetHotSpot().y;
1408 
1409 		uint16 width = (uint16)cursor->Bounds().Width();
1410 		uint16 height = (uint16)cursor->Bounds().Height();
1411 
1412 		// Time to talk to the accelerant!
1413 		cursorSet = fAccSetCursorBitmap(width, height, xHotSpot,
1414 			yHotSpot, cursor->ColorSpace(), (uint16)cursor->BytesPerRow(),
1415 			cursor->Bits()) == B_OK;
1416 	} else if (cursor->CursorData() != NULL && fAccSetCursorShape != NULL) {
1417 		// BeOS BCursor, 16x16 monochrome
1418 		uint8 size = cursor->CursorData()[0];
1419 		// CursorData()[1] is color depth (always monochrome)
1420 		// x and y are switched
1421 		uint8 xHotSpot = cursor->CursorData()[3];
1422 		uint8 yHotSpot = cursor->CursorData()[2];
1423 
1424 		// Create pointers to the cursor and/xor bit arrays
1425 		// for the BeOS BCursor there are two 32 byte, 16x16 bit arrays
1426 		// in the first:  1 is black,  0 is white
1427 		// in the second: 1 is opaque, 0 is transparent
1428 		// 1st	2nd
1429 		//  0	 0	 transparent
1430 		//  0	 1	 white
1431 		//  1	 0	 transparent
1432 		//  1	 1	 black
1433 		// for the HW cursor the first is ANDed and the second is XORed
1434 		// AND	XOR
1435 		//  0	 0	 white
1436 		//  0	 1	 black
1437 		//  1	 0	 transparent
1438 		//  1	 1	 reverse
1439 		// so, the first 32 bytes are the XOR mask
1440 		const uint8* xorMask = cursor->CursorData() + 4;
1441 		// the second 32 bytes *NOTed* are the AND mask
1442 		// TODO maybe this should be NOTed when copied to the ServerCursor
1443 		uint8 andMask[32];
1444 		const uint8* transMask = cursor->CursorData() + 36;
1445 		for (int32 i = 0; i < 32; i++)
1446 			andMask[i] = ~transMask[i];
1447 
1448 		// Time to talk to the accelerant!
1449 		cursorSet = fAccSetCursorShape(size, size, xHotSpot,
1450 			yHotSpot, andMask, xorMask) == B_OK;
1451 	}
1452 
1453 	if (cursorSet && !fHardwareCursorEnabled) {
1454 		// we switched from SW to HW, so we need to erase the SW cursor
1455 		if (fCursorVisible && fFloatingOverlaysLock.Lock()) {
1456 			IntRect r = _CursorFrame();
1457 			fCursorVisible = false;
1458 				// so the Invalidate doesn't draw it again
1459 			_RestoreCursorArea();
1460 			Invalidate(r);
1461 			fCursorVisible = true;
1462 			fFloatingOverlaysLock.Unlock();
1463 		}
1464 		// and we need to update our position
1465 		if (fAccMoveCursor != NULL)
1466 			fAccMoveCursor((uint16)fCursorLocation.x,
1467 				(uint16)fCursorLocation.y);
1468 	}
1469 
1470 	if (fAccShowCursor != NULL)
1471 		fAccShowCursor(cursorSet);
1472 
1473 	UnlockExclusiveAccess();
1474 
1475 	fHardwareCursorEnabled = cursorSet;
1476 
1477 	HWInterface::SetCursor(cursor);
1478 		// HWInterface claims ownership of cursor.
1479 }
1480 
1481 
1482 void
1483 AccelerantHWInterface::SetCursorVisible(bool visible)
1484 {
1485 	HWInterface::SetCursorVisible(visible);
1486 
1487 	if (fHardwareCursorEnabled && LockExclusiveAccess()) {
1488 		if (fAccShowCursor != NULL)
1489 				fAccShowCursor(visible);
1490 		else
1491 			fHardwareCursorEnabled = false;
1492 
1493 		UnlockExclusiveAccess();
1494 	}
1495 }
1496 
1497 
1498 void
1499 AccelerantHWInterface::MoveCursorTo(float x, float y)
1500 {
1501 	HWInterface::MoveCursorTo(x, y);
1502 
1503 	if (fHardwareCursorEnabled && LockExclusiveAccess()) {
1504 		if (fAccMoveCursor != NULL)
1505 				fAccMoveCursor((uint16)x, (uint16)y);
1506 		else {
1507 			fHardwareCursorEnabled = false;
1508 			if (fAccShowCursor != NULL)
1509 				fAccShowCursor(false);
1510 		}
1511 
1512 		UnlockExclusiveAccess();
1513 	}
1514 }
1515 
1516 
1517 // #pragma mark - buffer access
1518 
1519 
1520 RenderingBuffer*
1521 AccelerantHWInterface::FrontBuffer() const
1522 {
1523 	return fFrontBuffer.Get();
1524 }
1525 
1526 
1527 RenderingBuffer*
1528 AccelerantHWInterface::BackBuffer() const
1529 {
1530 	return fBackBuffer.Get();
1531 }
1532 
1533 
1534 bool
1535 AccelerantHWInterface::IsDoubleBuffered() const
1536 {
1537 	return fBackBuffer.IsSet();
1538 }
1539 
1540 
1541 void
1542 AccelerantHWInterface::_CopyBackToFront(/*const*/ BRegion& region)
1543 {
1544 	if (fOffscreenBackBuffer) {
1545 		int32 xOffset = 0;
1546 		int32 yOffset = -(int32)fFrontBuffer->Height();
1547 
1548 		int32 count = region.CountRects();
1549 		clipping_rect rects[count];
1550 		for (int32 i = 0; i < count; i++) {
1551 			rects[i] = region.RectAtInt(i);
1552 			rects[i].top -= yOffset;
1553 			rects[i].bottom -= yOffset;
1554 		}
1555 
1556 		_CopyRegion(rects, count, xOffset, yOffset, false);
1557 
1558 		return;
1559 	}
1560 
1561 	return HWInterface::_CopyBackToFront(region);
1562 }
1563 
1564 
1565 // #pragma mark -
1566 
1567 
1568 void
1569 AccelerantHWInterface::_DrawCursor(IntRect area) const
1570 {
1571 	if (!fHardwareCursorEnabled)
1572 		HWInterface::_DrawCursor(area);
1573 }
1574 
1575 
1576 void
1577 AccelerantHWInterface::_RegionToRectParams(/*const*/ BRegion* region,
1578 	uint32* count) const
1579 {
1580 	*count = region->CountRects();
1581 	// TODO: locking!!
1582 	if (fRectParamsCount < *count) {
1583 		fRectParamsCount = (*count / kDefaultParamsCount + 1)
1584 			* kDefaultParamsCount;
1585 		// NOTE: realloc() could be used instead...
1586 		fill_rect_params* params
1587 			= new (nothrow) fill_rect_params[fRectParamsCount];
1588 		if (params) {
1589 			delete[] fRectParams;
1590 			fRectParams = params;
1591 		} else {
1592 			*count = fRectParamsCount;
1593 		}
1594 	}
1595 
1596 	int32 srcOffsetY = fOffscreenBackBuffer ? fFrontBuffer->Height() : 0;
1597 
1598 	for (uint32 i = 0; i < *count; i++) {
1599 		clipping_rect r = region->RectAtInt(i);
1600 		fRectParams[i].left = (uint16)r.left;
1601 		fRectParams[i].top = (uint16)r.top + srcOffsetY;
1602 		fRectParams[i].right = (uint16)r.right;
1603 		fRectParams[i].bottom = (uint16)r.bottom + srcOffsetY;
1604 	}
1605 }
1606 
1607 
1608 void
1609 AccelerantHWInterface::_CopyRegion(const clipping_rect* sortedRectList,
1610 	uint32 count, int32 xOffset, int32 yOffset, bool inBackBuffer)
1611 {
1612 	if (fAccScreenBlit && fAccAcquireEngine) {
1613 		if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken,
1614 				&fEngineToken) >= B_OK) {
1615 			// make sure the blit_params cache is large enough
1616 			// TODO: locking!!
1617 			if (fBlitParamsCount < count) {
1618 				fBlitParamsCount = (count / kDefaultParamsCount + 1)
1619 					* kDefaultParamsCount;
1620 				// NOTE: realloc() could be used instead...
1621 				blit_params* params
1622 					= new (nothrow) blit_params[fBlitParamsCount];
1623 				if (params) {
1624 					delete[] fBlitParams;
1625 					fBlitParams = params;
1626 				} else {
1627 					count = fBlitParamsCount;
1628 				}
1629 			}
1630 			int32 srcOffsetY = inBackBuffer ? fFrontBuffer->Height() : 0;
1631 			// convert the rects
1632 			for (uint32 i = 0; i < count; i++) {
1633 				fBlitParams[i].src_left = (uint16)sortedRectList[i].left;
1634 				fBlitParams[i].src_top = (uint16)sortedRectList[i].top
1635 					+ srcOffsetY;
1636 
1637 				fBlitParams[i].dest_left = (uint16)sortedRectList[i].left
1638 					+ xOffset;
1639 				fBlitParams[i].dest_top = (uint16)sortedRectList[i].top
1640 					+ yOffset + srcOffsetY;
1641 
1642 				// NOTE: width and height are expressed as distance, not
1643 				// pixel count!
1644 				fBlitParams[i].width = (uint16)(sortedRectList[i].right
1645 					- sortedRectList[i].left);
1646 				fBlitParams[i].height = (uint16)(sortedRectList[i].bottom
1647 					- sortedRectList[i].top);
1648 			}
1649 
1650 			// go
1651 			fAccScreenBlit(fEngineToken, fBlitParams, count);
1652 
1653 			// done
1654 			if (fAccReleaseEngine)
1655 				fAccReleaseEngine(fEngineToken, &fSyncToken);
1656 
1657 			// sync
1658 			if (fAccSyncToToken)
1659 				fAccSyncToToken(&fSyncToken);
1660 		}
1661 	}
1662 }
1663 
1664 
1665 uint32
1666 AccelerantHWInterface::_NativeColor(const rgb_color& color) const
1667 {
1668 	// NOTE: This functions looks somehow suspicios to me.
1669 	// It assumes that all graphics cards have the same native endianess, no?
1670 	switch (fDisplayMode.space) {
1671 		case B_CMAP8:
1672 		case B_GRAY8:
1673 			return RGBColor(color).GetColor8();
1674 
1675 		case B_RGB15_BIG:
1676 		case B_RGBA15_BIG:
1677 		case B_RGB15_LITTLE:
1678 		case B_RGBA15_LITTLE:
1679 			return RGBColor(color).GetColor15();
1680 
1681 		case B_RGB16_BIG:
1682 		case B_RGB16_LITTLE:
1683 			return RGBColor(color).GetColor16();
1684 
1685 		case B_RGB32_BIG:
1686 		case B_RGBA32_BIG:
1687 		case B_RGB32_LITTLE:
1688 		case B_RGBA32_LITTLE: {
1689 			return (uint32)((color.alpha << 24) | (color.red << 16)
1690 				| (color.green << 8) | color.blue);
1691 		}
1692 	}
1693 	return 0;
1694 }
1695 
1696 
1697 void
1698 AccelerantHWInterface::_SetSystemPalette()
1699 {
1700 	set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
1701 		B_SET_INDEXED_COLORS, NULL);
1702 	if (setIndexedColors == NULL)
1703 		return;
1704 
1705 	const rgb_color* palette = SystemPalette();
1706 	uint8 colors[3 * 256];
1707 		// the color table is an array with 3 bytes per color
1708 	uint32 j = 0;
1709 
1710 	for (int32 i = 0; i < 256; i++) {
1711 		colors[j++] = palette[i].red;
1712 		colors[j++] = palette[i].green;
1713 		colors[j++] = palette[i].blue;
1714 	}
1715 
1716 	setIndexedColors(256, 0, colors, 0);
1717 }
1718 
1719 
1720 void
1721 AccelerantHWInterface::_SetGrayscalePalette()
1722 {
1723 	set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
1724 		B_SET_INDEXED_COLORS, NULL);
1725 	if (setIndexedColors == NULL)
1726 		return;
1727 
1728 	uint8 colors[3 * 256];
1729 		// the color table is an array with 3 bytes per color
1730 	uint32 j = 0;
1731 
1732 	if (fFrontBuffer->Width() > fFrontBuffer->BytesPerRow()) {
1733 		// VGA 16 color grayscale planar mode
1734 		for (int32 i = 0; i < 256; i++) {
1735 			colors[j++] = (i & 0xf) * 17;
1736 			colors[j++] = (i & 0xf) * 17;
1737 			colors[j++] = (i & 0xf) * 17;
1738 		}
1739 
1740 		setIndexedColors(256, 0, colors, 0);
1741 	} else {
1742 		for (int32 i = 0; i < 256; i++) {
1743 			colors[j++] = i;
1744 			colors[j++] = i;
1745 			colors[j++] = i;
1746 		}
1747 
1748 		setIndexedColors(256, 0, colors, 0);
1749 	}
1750 }
1751