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