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