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