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