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