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