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