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