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 && !HWInterface::IsDoubleBuffered())) { 693 // NOTE: backbuffer is always B_RGBA32, this simplifies the 694 // drawing backend implementation tremendously for the time 695 // being. The color space conversion is handled in CopyBackToFront() 696 697 fBackBuffer.Unset(); 698 699 // TODO: Above not true anymore for single buffered mode!!! 700 // -> fall back to double buffer for fDisplayMode.space != B_RGB32 701 // as intermediate solution... 702 bool doubleBuffered = HWInterface::IsDoubleBuffered(); 703 if ((fFrontBuffer->ColorSpace() != B_RGB32 704 && fFrontBuffer->ColorSpace() != B_RGBA32) 705 || fVGADevice >= 0 || fOffscreenBackBuffer) 706 doubleBuffered = true; 707 #if !USE_ACCELERATION 708 doubleBuffered = true; 709 #endif 710 711 if (doubleBuffered) { 712 if (fOffscreenBackBuffer) { 713 fBackBuffer.SetTo( 714 new(nothrow) AccelerantBuffer(*fFrontBuffer.Get(), true)); 715 } else { 716 fBackBuffer.SetTo(new(nothrow) MallocBuffer( 717 fFrontBuffer->Width(), fFrontBuffer->Height())); 718 } 719 720 status = fBackBuffer.IsSet() 721 ? fBackBuffer->InitCheck() : B_NO_MEMORY; 722 if (status < B_OK) { 723 fBackBuffer.Unset(); 724 fOffscreenBackBuffer = false; 725 return status; 726 } 727 // clear out backbuffer, alpha is 255 this way 728 memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength()); 729 } 730 #if 0 731 // NOTE: Currently disabled, because it make the double buffered mode flicker 732 // again. See HWInterface::Invalidate() for more information. 733 SetAsyncDoubleBuffered(doubleBuffered); 734 #endif 735 } 736 737 // update color palette configuration if necessary 738 if (fDisplayMode.space == B_CMAP8) 739 _SetSystemPalette(); 740 else if (fDisplayMode.space == B_GRAY8) 741 _SetGrayscalePalette(); 742 743 // notify all listeners about the mode change 744 _NotifyFrameBufferChanged(); 745 746 return status; 747 } 748 749 750 void 751 AccelerantHWInterface::GetMode(display_mode* mode) 752 { 753 if (mode && LockParallelAccess()) { 754 *mode = fDisplayMode; 755 UnlockParallelAccess(); 756 } 757 } 758 759 760 status_t 761 AccelerantHWInterface::_UpdateModeList() 762 { 763 fModeCount = fAccGetModeCount(); 764 if (fModeCount <= 0) 765 return B_ERROR; 766 767 delete[] fModeList; 768 fModeList = new(nothrow) display_mode[fModeCount]; 769 if (!fModeList) 770 return B_NO_MEMORY; 771 772 if (fAccGetModeList(fModeList) != B_OK) { 773 ATRACE(("unable to get mode list\n")); 774 return B_ERROR; 775 } 776 777 return B_OK; 778 } 779 780 781 status_t 782 AccelerantHWInterface::_UpdateFrameBufferConfig() 783 { 784 if (fAccGetFrameBufferConfig(&fFrameBufferConfig) != B_OK) { 785 ATRACE(("unable to get frame buffer config\n")); 786 return B_ERROR; 787 } 788 789 fFrontBuffer->SetFrameBufferConfig(fFrameBufferConfig); 790 791 return B_OK; 792 } 793 794 795 status_t 796 AccelerantHWInterface::GetDeviceInfo(accelerant_device_info* info) 797 { 798 get_accelerant_device_info GetAccelerantDeviceInfo 799 = (get_accelerant_device_info)fAccelerantHook( 800 B_GET_ACCELERANT_DEVICE_INFO, NULL); 801 if (!GetAccelerantDeviceInfo) { 802 ATRACE(("No B_GET_ACCELERANT_DEVICE_INFO hook found\n")); 803 return B_UNSUPPORTED; 804 } 805 806 return GetAccelerantDeviceInfo(info); 807 } 808 809 810 status_t 811 AccelerantHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 812 { 813 config = fFrameBufferConfig; 814 return B_OK; 815 } 816 817 818 status_t 819 AccelerantHWInterface::GetModeList(display_mode** _modes, uint32* _count) 820 { 821 AutoReadLocker _(this); 822 823 if (_count == NULL || _modes == NULL) 824 return B_BAD_VALUE; 825 826 status_t status = B_OK; 827 828 if (fModeList == NULL) 829 status = _UpdateModeList(); 830 831 if (status >= B_OK) { 832 *_modes = new(nothrow) display_mode[fModeCount]; 833 if (*_modes) { 834 *_count = fModeCount; 835 memcpy(*_modes, fModeList, sizeof(display_mode) * fModeCount); 836 } else { 837 *_count = 0; 838 status = B_NO_MEMORY; 839 } 840 } 841 return status; 842 } 843 844 845 status_t 846 AccelerantHWInterface::GetPixelClockLimits(display_mode *mode, uint32* _low, 847 uint32* _high) 848 { 849 if (mode == NULL || _low == NULL || _high == NULL) 850 return B_BAD_VALUE; 851 852 AutoReadLocker _(this); 853 return fAccGetPixelClockLimits(mode, _low, _high); 854 } 855 856 857 status_t 858 AccelerantHWInterface::GetTimingConstraints( 859 display_timing_constraints* constraints) 860 { 861 if (constraints == NULL) 862 return B_BAD_VALUE; 863 864 AutoReadLocker _(this); 865 866 if (fAccGetTimingConstraints) 867 return fAccGetTimingConstraints(constraints); 868 869 return B_UNSUPPORTED; 870 } 871 872 873 status_t 874 AccelerantHWInterface::ProposeMode(display_mode* candidate, 875 const display_mode* _low, const display_mode* _high) 876 { 877 if (candidate == NULL || _low == NULL || _high == NULL) 878 return B_BAD_VALUE; 879 880 AutoReadLocker _(this); 881 882 if (fAccProposeDisplayMode == NULL) 883 return B_UNSUPPORTED; 884 885 // avoid const issues 886 display_mode high, low; 887 high = *_high; 888 low = *_low; 889 890 return fAccProposeDisplayMode(candidate, &low, &high); 891 } 892 893 894 status_t 895 AccelerantHWInterface::GetPreferredMode(display_mode* preferredMode) 896 { 897 status_t status = B_NOT_SUPPORTED; 898 899 if (fAccGetPreferredDisplayMode != NULL) { 900 status = fAccGetPreferredDisplayMode(preferredMode); 901 if (status == B_OK) 902 return B_OK; 903 } 904 905 if (fAccGetEDIDInfo != NULL) { 906 edid1_info info; 907 uint32 version; 908 status = fAccGetEDIDInfo(&info, sizeof(info), &version); 909 if (status < B_OK) 910 return status; 911 if (version != EDID_VERSION_1) 912 return B_NOT_SUPPORTED; 913 914 if (fModeList == NULL) { 915 status = _UpdateModeList(); 916 if (status != B_OK) 917 return status; 918 } 919 920 status = B_NOT_SUPPORTED; 921 display_mode bestMode; 922 int32 bestDiff = INT_MAX; 923 924 // find preferred mode from EDID info 925 for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { 926 if (info.detailed_monitor[i].monitor_desc_type 927 != EDID1_IS_DETAILED_TIMING) 928 continue; 929 930 // construct basic mode and find it in the mode list 931 const edid1_detailed_timing& timing 932 = info.detailed_monitor[i].data.detailed_timing; 933 if (timing.h_active < 640 || timing.v_active < 350) 934 continue; 935 936 float aspectRatio = 0.0f; 937 if (timing.h_size > 0 && timing.v_size > 0) 938 aspectRatio = 1.0f * timing.h_size / timing.v_size; 939 940 display_mode modeFound; 941 display_mode mode; 942 943 mode.timing.pixel_clock = timing.pixel_clock * 10; 944 mode.timing.h_display = timing.h_active; 945 mode.timing.h_sync_start = timing.h_active + timing.h_sync_off; 946 mode.timing.h_sync_end = mode.timing.h_sync_start 947 + timing.h_sync_width; 948 mode.timing.h_total = timing.h_active + timing.h_blank; 949 mode.timing.v_display = timing.v_active; 950 mode.timing.v_sync_start = timing.v_active + timing.v_sync_off; 951 mode.timing.v_sync_end = mode.timing.v_sync_start 952 + timing.v_sync_width; 953 mode.timing.v_total = timing.v_active + timing.v_blank; 954 955 mode.space = B_RGB32; 956 mode.virtual_width = mode.timing.h_display; 957 mode.virtual_height = mode.timing.v_display; 958 959 // TODO: eventually ignore detailed modes for the preferred one 960 // if there are more than one usable? 961 int32 diff; 962 if (_FindBestMode(mode, aspectRatio, modeFound, &diff) == B_OK) { 963 status = B_OK; 964 if (diff < bestDiff) { 965 bestMode = modeFound; 966 bestDiff = diff; 967 } 968 } 969 } 970 971 if (status == B_OK) 972 *preferredMode = bestMode; 973 } 974 975 return status; 976 } 977 978 979 status_t 980 AccelerantHWInterface::GetMonitorInfo(monitor_info* info) 981 { 982 status_t status = B_NOT_SUPPORTED; 983 984 if (fAccGetMonitorInfo != NULL) { 985 status = fAccGetMonitorInfo(info); 986 if (status == B_OK) 987 return B_OK; 988 } 989 990 if (fAccGetEDIDInfo == NULL) 991 return status; 992 993 edid1_info edid; 994 uint32 version; 995 status = fAccGetEDIDInfo(&edid, sizeof(edid), &version); 996 if (status < B_OK) 997 return status; 998 if (version != EDID_VERSION_1) 999 return B_NOT_SUPPORTED; 1000 1001 memset(info, 0, sizeof(monitor_info)); 1002 strlcpy(info->vendor, edid.vendor.manufacturer, sizeof(info->vendor)); 1003 if (edid.vendor.serial != 0) { 1004 snprintf(info->serial_number, sizeof(info->serial_number), "%" B_PRIu32, 1005 edid.vendor.serial); 1006 } 1007 info->product_id = edid.vendor.prod_id; 1008 info->produced.week = edid.vendor.week; 1009 info->produced.year = edid.vendor.year; 1010 info->width = edid.display.h_size; 1011 info->height = edid.display.v_size; 1012 1013 for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { 1014 edid1_detailed_monitor *monitor = &edid.detailed_monitor[i]; 1015 1016 switch (monitor->monitor_desc_type) { 1017 case EDID1_SERIAL_NUMBER: 1018 strlcpy(info->serial_number, monitor->data.serial_number, 1019 sizeof(info->serial_number)); 1020 break; 1021 1022 case EDID1_MONITOR_NAME: 1023 // There can be several of these; in this case we'll just 1024 // overwrite the previous entries 1025 // TODO: we could append them as well 1026 strlcpy(info->name, monitor->data.monitor_name, 1027 sizeof(info->name)); 1028 break; 1029 1030 case EDID1_MONITOR_RANGES: 1031 { 1032 edid1_monitor_range& range = monitor->data.monitor_range; 1033 1034 info->min_horizontal_frequency = range.min_h; 1035 info->max_horizontal_frequency = range.max_h; 1036 info->min_vertical_frequency = range.min_v; 1037 info->max_vertical_frequency = range.max_v; 1038 info->max_pixel_clock = range.max_clock * 10000; 1039 break; 1040 } 1041 1042 case EDID1_IS_DETAILED_TIMING: 1043 { 1044 edid1_detailed_timing& timing = monitor->data.detailed_timing; 1045 info->width = timing.h_size / 10.0; 1046 info->height = timing.v_size / 10.0; 1047 } 1048 1049 default: 1050 break; 1051 } 1052 } 1053 1054 return B_OK; 1055 } 1056 1057 1058 sem_id 1059 AccelerantHWInterface::RetraceSemaphore() 1060 { 1061 AutoWriteLocker _(this); 1062 1063 if (fRetraceSemaphore != -1) 1064 return fRetraceSemaphore; 1065 1066 accelerant_retrace_semaphore AccelerantRetraceSemaphore = 1067 (accelerant_retrace_semaphore)fAccelerantHook( 1068 B_ACCELERANT_RETRACE_SEMAPHORE, NULL); 1069 if (!AccelerantRetraceSemaphore) 1070 fRetraceSemaphore = B_UNSUPPORTED; 1071 else 1072 fRetraceSemaphore = AccelerantRetraceSemaphore(); 1073 1074 return fRetraceSemaphore; 1075 } 1076 1077 1078 status_t 1079 AccelerantHWInterface::WaitForRetrace(bigtime_t timeout) 1080 { 1081 sem_id sem = RetraceSemaphore(); 1082 if (sem < 0) 1083 return sem; 1084 1085 return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout); 1086 } 1087 1088 1089 status_t 1090 AccelerantHWInterface::SetDPMSMode(uint32 state) 1091 { 1092 AutoWriteLocker _(this); 1093 1094 if (!fAccSetDPMSMode) 1095 return B_UNSUPPORTED; 1096 1097 return fAccSetDPMSMode(state); 1098 } 1099 1100 1101 uint32 1102 AccelerantHWInterface::DPMSMode() 1103 { 1104 AutoReadLocker _(this); 1105 1106 if (!fAccDPMSMode) 1107 return B_UNSUPPORTED; 1108 1109 return fAccDPMSMode(); 1110 } 1111 1112 1113 uint32 1114 AccelerantHWInterface::DPMSCapabilities() 1115 { 1116 AutoReadLocker _(this); 1117 1118 if (!fAccDPMSCapabilities) 1119 return B_UNSUPPORTED; 1120 1121 return fAccDPMSCapabilities(); 1122 } 1123 1124 1125 status_t 1126 AccelerantHWInterface::SetBrightness(float brightness) 1127 { 1128 AutoReadLocker _(this); 1129 1130 if (!fAccSetBrightness) 1131 return B_UNSUPPORTED; 1132 1133 return fAccSetBrightness(brightness); 1134 } 1135 1136 1137 status_t 1138 AccelerantHWInterface::GetBrightness(float* brightness) 1139 { 1140 AutoReadLocker _(this); 1141 1142 if (!fAccGetBrightness) 1143 return B_UNSUPPORTED; 1144 1145 return fAccGetBrightness(brightness); 1146 } 1147 1148 1149 status_t 1150 AccelerantHWInterface::GetAccelerantPath(BString& string) 1151 { 1152 image_info info; 1153 status_t status = get_image_info(fAccelerantImage, &info); 1154 if (status == B_OK) 1155 string = info.name; 1156 return status; 1157 } 1158 1159 1160 status_t 1161 AccelerantHWInterface::GetDriverPath(BString& string) 1162 { 1163 // TODO: this currently assumes that the accelerant's clone info 1164 // is always the path name of its driver (that's the case for 1165 // all of our drivers) 1166 char path[B_PATH_NAME_LENGTH]; 1167 get_accelerant_clone_info getCloneInfo; 1168 getCloneInfo = (get_accelerant_clone_info)fAccelerantHook( 1169 B_GET_ACCELERANT_CLONE_INFO, NULL); 1170 1171 if (getCloneInfo == NULL) 1172 return B_NOT_SUPPORTED; 1173 1174 getCloneInfo((void*)path); 1175 string.SetTo(path); 1176 return B_OK; 1177 } 1178 1179 1180 // #pragma mark - acceleration 1181 1182 1183 uint32 1184 AccelerantHWInterface::AvailableHWAcceleration() const 1185 { 1186 uint32 flags = 0; 1187 1188 if (!IsDoubleBuffered() || fOffscreenBackBuffer) { 1189 if (fAccScreenBlit) 1190 flags |= HW_ACC_COPY_REGION; 1191 if (fAccFillRect) 1192 flags |= HW_ACC_FILL_REGION; 1193 if (fAccInvertRect) 1194 flags |= HW_ACC_INVERT_REGION; 1195 } 1196 1197 return flags; 1198 } 1199 1200 1201 void 1202 AccelerantHWInterface::CopyRegion(const clipping_rect* sortedRectList, 1203 uint32 count, int32 xOffset, int32 yOffset) 1204 { 1205 _CopyRegion(sortedRectList, count, xOffset, yOffset, fOffscreenBackBuffer); 1206 } 1207 1208 1209 void 1210 AccelerantHWInterface::FillRegion(/*const*/ BRegion& region, 1211 const rgb_color& color, bool autoSync) 1212 { 1213 if (fAccFillRect && fAccAcquireEngine) { 1214 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1215 &fEngineToken) >= B_OK) { 1216 // convert the region 1217 uint32 count; 1218 _RegionToRectParams(®ion, &count); 1219 1220 // go 1221 fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count); 1222 1223 // done 1224 if (fAccReleaseEngine) 1225 fAccReleaseEngine(fEngineToken, &fSyncToken); 1226 1227 // sync 1228 if (autoSync && fAccSyncToToken) 1229 fAccSyncToToken(&fSyncToken); 1230 } 1231 } 1232 } 1233 1234 1235 void 1236 AccelerantHWInterface::InvertRegion(/*const*/ BRegion& region) 1237 { 1238 if (fAccInvertRect && fAccAcquireEngine) { 1239 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1240 &fEngineToken) >= B_OK) { 1241 // convert the region 1242 uint32 count; 1243 _RegionToRectParams(®ion, &count); 1244 1245 fAccInvertRect(fEngineToken, fRectParams, count); 1246 1247 if (fAccReleaseEngine) 1248 fAccReleaseEngine(fEngineToken, &fSyncToken); 1249 if (fAccSyncToToken) 1250 fAccSyncToToken(&fSyncToken); 1251 } 1252 } 1253 } 1254 1255 1256 void 1257 AccelerantHWInterface::Sync() 1258 { 1259 if (fAccSyncToToken) 1260 fAccSyncToToken(&fSyncToken); 1261 } 1262 1263 1264 // #pragma mark - overlays 1265 1266 1267 overlay_token 1268 AccelerantHWInterface::AcquireOverlayChannel() 1269 { 1270 if (fAccAllocateOverlay == NULL 1271 || fAccReleaseOverlay == NULL) 1272 return NULL; 1273 1274 // The current display mode only matters at the time we're planning on 1275 // showing the overlay channel on screen - that's why we can't use 1276 // the B_OVERLAY_COUNT hook. 1277 // TODO: remove fAccOverlayCount if we're not going to need it at all. 1278 1279 return fAccAllocateOverlay(); 1280 } 1281 1282 1283 void 1284 AccelerantHWInterface::ReleaseOverlayChannel(overlay_token token) 1285 { 1286 if (token == NULL) 1287 return; 1288 1289 fAccReleaseOverlay(token); 1290 } 1291 1292 1293 status_t 1294 AccelerantHWInterface::GetOverlayRestrictions(const Overlay* overlay, 1295 overlay_restrictions* restrictions) 1296 { 1297 if (overlay == NULL || restrictions == NULL) 1298 return B_BAD_VALUE; 1299 if (fAccGetOverlayConstraints == NULL) 1300 return B_NOT_SUPPORTED; 1301 1302 overlay_constraints constraints; 1303 status_t status = fAccGetOverlayConstraints(&fDisplayMode, 1304 overlay->OverlayBuffer(), &constraints); 1305 if (status < B_OK) 1306 return status; 1307 1308 memset(restrictions, 0, sizeof(overlay_restrictions)); 1309 memcpy(&restrictions->source, &constraints.view, sizeof(overlay_limits)); 1310 memcpy(&restrictions->destination, &constraints.window, 1311 sizeof(overlay_limits)); 1312 restrictions->min_width_scale = constraints.h_scale.min; 1313 restrictions->max_width_scale = constraints.h_scale.max; 1314 restrictions->min_height_scale = constraints.v_scale.min; 1315 restrictions->max_height_scale = constraints.v_scale.max; 1316 1317 return B_OK; 1318 } 1319 1320 1321 bool 1322 AccelerantHWInterface::CheckOverlayRestrictions(int32 width, int32 height, 1323 color_space colorSpace) 1324 { 1325 if (fAccOverlaySupportedSpaces == NULL 1326 || fAccGetOverlayConstraints == NULL 1327 || fAccAllocateOverlayBuffer == NULL 1328 || fAccReleaseOverlayBuffer == NULL) 1329 return false; 1330 1331 // Note: we can't really check the size of the overlay upfront - we 1332 // must assume fAccAllocateOverlayBuffer() will fail in that case. 1333 if (width < 0 || width > 65535 || height < 0 || height > 65535) 1334 return false; 1335 1336 // check color space 1337 1338 const uint32* spaces = fAccOverlaySupportedSpaces(&fDisplayMode); 1339 if (spaces == NULL) 1340 return false; 1341 1342 for (int32 i = 0; spaces[i] != 0; i++) { 1343 if (spaces[i] == (uint32)colorSpace) 1344 return true; 1345 } 1346 1347 return false; 1348 } 1349 1350 1351 const overlay_buffer* 1352 AccelerantHWInterface::AllocateOverlayBuffer(int32 width, int32 height, 1353 color_space space) 1354 { 1355 if (fAccAllocateOverlayBuffer == NULL) 1356 return NULL; 1357 1358 return fAccAllocateOverlayBuffer(space, width, height); 1359 } 1360 1361 1362 void 1363 AccelerantHWInterface::FreeOverlayBuffer(const overlay_buffer* buffer) 1364 { 1365 if (buffer == NULL || fAccReleaseOverlayBuffer == NULL) 1366 return; 1367 1368 fAccReleaseOverlayBuffer(buffer); 1369 } 1370 1371 1372 void 1373 AccelerantHWInterface::ConfigureOverlay(Overlay* overlay) 1374 { 1375 // TODO: this only needs to be done on mode changes! 1376 overlay->SetColorSpace(fDisplayMode.space); 1377 1378 fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(), 1379 overlay->OverlayWindow(), overlay->OverlayView()); 1380 } 1381 1382 1383 void 1384 AccelerantHWInterface::HideOverlay(Overlay* overlay) 1385 { 1386 fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(), 1387 NULL, NULL); 1388 } 1389 1390 1391 // #pragma mark - cursor 1392 1393 1394 void 1395 AccelerantHWInterface::SetCursor(ServerCursor* cursor) 1396 { 1397 // cursor should never be NULL, but let us be safe!! 1398 if (cursor == NULL || LockExclusiveAccess() == false) 1399 return; 1400 1401 bool cursorSet = false; 1402 1403 if (fAccSetCursorBitmap != NULL) { 1404 // Bitmap cursor 1405 // TODO are x and y switched for this, too? 1406 uint16 xHotSpot = (uint16)cursor->GetHotSpot().x; 1407 uint16 yHotSpot = (uint16)cursor->GetHotSpot().y; 1408 1409 uint16 width = (uint16)cursor->Bounds().Width(); 1410 uint16 height = (uint16)cursor->Bounds().Height(); 1411 1412 // Time to talk to the accelerant! 1413 cursorSet = fAccSetCursorBitmap(width, height, xHotSpot, 1414 yHotSpot, cursor->ColorSpace(), (uint16)cursor->BytesPerRow(), 1415 cursor->Bits()) == B_OK; 1416 } else if (cursor->CursorData() != NULL && fAccSetCursorShape != NULL) { 1417 // BeOS BCursor, 16x16 monochrome 1418 uint8 size = cursor->CursorData()[0]; 1419 // CursorData()[1] is color depth (always monochrome) 1420 // x and y are switched 1421 uint8 xHotSpot = cursor->CursorData()[3]; 1422 uint8 yHotSpot = cursor->CursorData()[2]; 1423 1424 // Create pointers to the cursor and/xor bit arrays 1425 // for the BeOS BCursor there are two 32 byte, 16x16 bit arrays 1426 // in the first: 1 is black, 0 is white 1427 // in the second: 1 is opaque, 0 is transparent 1428 // 1st 2nd 1429 // 0 0 transparent 1430 // 0 1 white 1431 // 1 0 transparent 1432 // 1 1 black 1433 // for the HW cursor the first is ANDed and the second is XORed 1434 // AND XOR 1435 // 0 0 white 1436 // 0 1 black 1437 // 1 0 transparent 1438 // 1 1 reverse 1439 // so, the first 32 bytes are the XOR mask 1440 const uint8* xorMask = cursor->CursorData() + 4; 1441 // the second 32 bytes *NOTed* are the AND mask 1442 // TODO maybe this should be NOTed when copied to the ServerCursor 1443 uint8 andMask[32]; 1444 const uint8* transMask = cursor->CursorData() + 36; 1445 for (int32 i = 0; i < 32; i++) 1446 andMask[i] = ~transMask[i]; 1447 1448 // Time to talk to the accelerant! 1449 cursorSet = fAccSetCursorShape(size, size, xHotSpot, 1450 yHotSpot, andMask, xorMask) == B_OK; 1451 } 1452 1453 if (cursorSet && !fHardwareCursorEnabled) { 1454 // we switched from SW to HW, so we need to erase the SW cursor 1455 if (fCursorVisible && fFloatingOverlaysLock.Lock()) { 1456 IntRect r = _CursorFrame(); 1457 fCursorVisible = false; 1458 // so the Invalidate doesn't draw it again 1459 _RestoreCursorArea(); 1460 Invalidate(r); 1461 fCursorVisible = true; 1462 fFloatingOverlaysLock.Unlock(); 1463 } 1464 // and we need to update our position 1465 if (fAccMoveCursor != NULL) 1466 fAccMoveCursor((uint16)fCursorLocation.x, 1467 (uint16)fCursorLocation.y); 1468 } 1469 1470 if (fAccShowCursor != NULL) 1471 fAccShowCursor(cursorSet); 1472 1473 UnlockExclusiveAccess(); 1474 1475 fHardwareCursorEnabled = cursorSet; 1476 1477 HWInterface::SetCursor(cursor); 1478 // HWInterface claims ownership of cursor. 1479 } 1480 1481 1482 void 1483 AccelerantHWInterface::SetCursorVisible(bool visible) 1484 { 1485 HWInterface::SetCursorVisible(visible); 1486 1487 if (fHardwareCursorEnabled && LockExclusiveAccess()) { 1488 if (fAccShowCursor != NULL) 1489 fAccShowCursor(visible); 1490 else 1491 fHardwareCursorEnabled = false; 1492 1493 UnlockExclusiveAccess(); 1494 } 1495 } 1496 1497 1498 void 1499 AccelerantHWInterface::MoveCursorTo(float x, float y) 1500 { 1501 HWInterface::MoveCursorTo(x, y); 1502 1503 if (fHardwareCursorEnabled && LockExclusiveAccess()) { 1504 if (fAccMoveCursor != NULL) 1505 fAccMoveCursor((uint16)x, (uint16)y); 1506 else { 1507 fHardwareCursorEnabled = false; 1508 if (fAccShowCursor != NULL) 1509 fAccShowCursor(false); 1510 } 1511 1512 UnlockExclusiveAccess(); 1513 } 1514 } 1515 1516 1517 // #pragma mark - buffer access 1518 1519 1520 RenderingBuffer* 1521 AccelerantHWInterface::FrontBuffer() const 1522 { 1523 return fFrontBuffer.Get(); 1524 } 1525 1526 1527 RenderingBuffer* 1528 AccelerantHWInterface::BackBuffer() const 1529 { 1530 return fBackBuffer.Get(); 1531 } 1532 1533 1534 bool 1535 AccelerantHWInterface::IsDoubleBuffered() const 1536 { 1537 return fBackBuffer.IsSet(); 1538 } 1539 1540 1541 void 1542 AccelerantHWInterface::_CopyBackToFront(/*const*/ BRegion& region) 1543 { 1544 if (fOffscreenBackBuffer) { 1545 int32 xOffset = 0; 1546 int32 yOffset = -(int32)fFrontBuffer->Height(); 1547 1548 int32 count = region.CountRects(); 1549 clipping_rect rects[count]; 1550 for (int32 i = 0; i < count; i++) { 1551 rects[i] = region.RectAtInt(i); 1552 rects[i].top -= yOffset; 1553 rects[i].bottom -= yOffset; 1554 } 1555 1556 _CopyRegion(rects, count, xOffset, yOffset, false); 1557 1558 return; 1559 } 1560 1561 return HWInterface::_CopyBackToFront(region); 1562 } 1563 1564 1565 // #pragma mark - 1566 1567 1568 void 1569 AccelerantHWInterface::_DrawCursor(IntRect area) const 1570 { 1571 if (!fHardwareCursorEnabled) 1572 HWInterface::_DrawCursor(area); 1573 } 1574 1575 1576 void 1577 AccelerantHWInterface::_RegionToRectParams(/*const*/ BRegion* region, 1578 uint32* count) const 1579 { 1580 *count = region->CountRects(); 1581 // TODO: locking!! 1582 if (fRectParamsCount < *count) { 1583 fRectParamsCount = (*count / kDefaultParamsCount + 1) 1584 * kDefaultParamsCount; 1585 // NOTE: realloc() could be used instead... 1586 fill_rect_params* params 1587 = new (nothrow) fill_rect_params[fRectParamsCount]; 1588 if (params) { 1589 delete[] fRectParams; 1590 fRectParams = params; 1591 } else { 1592 *count = fRectParamsCount; 1593 } 1594 } 1595 1596 int32 srcOffsetY = fOffscreenBackBuffer ? fFrontBuffer->Height() : 0; 1597 1598 for (uint32 i = 0; i < *count; i++) { 1599 clipping_rect r = region->RectAtInt(i); 1600 fRectParams[i].left = (uint16)r.left; 1601 fRectParams[i].top = (uint16)r.top + srcOffsetY; 1602 fRectParams[i].right = (uint16)r.right; 1603 fRectParams[i].bottom = (uint16)r.bottom + srcOffsetY; 1604 } 1605 } 1606 1607 1608 void 1609 AccelerantHWInterface::_CopyRegion(const clipping_rect* sortedRectList, 1610 uint32 count, int32 xOffset, int32 yOffset, bool inBackBuffer) 1611 { 1612 if (fAccScreenBlit && fAccAcquireEngine) { 1613 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1614 &fEngineToken) >= B_OK) { 1615 // make sure the blit_params cache is large enough 1616 // TODO: locking!! 1617 if (fBlitParamsCount < count) { 1618 fBlitParamsCount = (count / kDefaultParamsCount + 1) 1619 * kDefaultParamsCount; 1620 // NOTE: realloc() could be used instead... 1621 blit_params* params 1622 = new (nothrow) blit_params[fBlitParamsCount]; 1623 if (params) { 1624 delete[] fBlitParams; 1625 fBlitParams = params; 1626 } else { 1627 count = fBlitParamsCount; 1628 } 1629 } 1630 int32 srcOffsetY = inBackBuffer ? fFrontBuffer->Height() : 0; 1631 // convert the rects 1632 for (uint32 i = 0; i < count; i++) { 1633 fBlitParams[i].src_left = (uint16)sortedRectList[i].left; 1634 fBlitParams[i].src_top = (uint16)sortedRectList[i].top 1635 + srcOffsetY; 1636 1637 fBlitParams[i].dest_left = (uint16)sortedRectList[i].left 1638 + xOffset; 1639 fBlitParams[i].dest_top = (uint16)sortedRectList[i].top 1640 + yOffset + srcOffsetY; 1641 1642 // NOTE: width and height are expressed as distance, not 1643 // pixel count! 1644 fBlitParams[i].width = (uint16)(sortedRectList[i].right 1645 - sortedRectList[i].left); 1646 fBlitParams[i].height = (uint16)(sortedRectList[i].bottom 1647 - sortedRectList[i].top); 1648 } 1649 1650 // go 1651 fAccScreenBlit(fEngineToken, fBlitParams, count); 1652 1653 // done 1654 if (fAccReleaseEngine) 1655 fAccReleaseEngine(fEngineToken, &fSyncToken); 1656 1657 // sync 1658 if (fAccSyncToToken) 1659 fAccSyncToToken(&fSyncToken); 1660 } 1661 } 1662 } 1663 1664 1665 uint32 1666 AccelerantHWInterface::_NativeColor(const rgb_color& color) const 1667 { 1668 // NOTE: This functions looks somehow suspicios to me. 1669 // It assumes that all graphics cards have the same native endianess, no? 1670 switch (fDisplayMode.space) { 1671 case B_CMAP8: 1672 case B_GRAY8: 1673 return RGBColor(color).GetColor8(); 1674 1675 case B_RGB15_BIG: 1676 case B_RGBA15_BIG: 1677 case B_RGB15_LITTLE: 1678 case B_RGBA15_LITTLE: 1679 return RGBColor(color).GetColor15(); 1680 1681 case B_RGB16_BIG: 1682 case B_RGB16_LITTLE: 1683 return RGBColor(color).GetColor16(); 1684 1685 case B_RGB32_BIG: 1686 case B_RGBA32_BIG: 1687 case B_RGB32_LITTLE: 1688 case B_RGBA32_LITTLE: { 1689 return (uint32)((color.alpha << 24) | (color.red << 16) 1690 | (color.green << 8) | color.blue); 1691 } 1692 } 1693 return 0; 1694 } 1695 1696 1697 void 1698 AccelerantHWInterface::_SetSystemPalette() 1699 { 1700 set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook( 1701 B_SET_INDEXED_COLORS, NULL); 1702 if (setIndexedColors == NULL) 1703 return; 1704 1705 const rgb_color* palette = SystemPalette(); 1706 uint8 colors[3 * 256]; 1707 // the color table is an array with 3 bytes per color 1708 uint32 j = 0; 1709 1710 for (int32 i = 0; i < 256; i++) { 1711 colors[j++] = palette[i].red; 1712 colors[j++] = palette[i].green; 1713 colors[j++] = palette[i].blue; 1714 } 1715 1716 setIndexedColors(256, 0, colors, 0); 1717 } 1718 1719 1720 void 1721 AccelerantHWInterface::_SetGrayscalePalette() 1722 { 1723 set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook( 1724 B_SET_INDEXED_COLORS, NULL); 1725 if (setIndexedColors == NULL) 1726 return; 1727 1728 uint8 colors[3 * 256]; 1729 // the color table is an array with 3 bytes per color 1730 uint32 j = 0; 1731 1732 if (fFrontBuffer->Width() > fFrontBuffer->BytesPerRow()) { 1733 // VGA 16 color grayscale planar mode 1734 for (int32 i = 0; i < 256; i++) { 1735 colors[j++] = (i & 0xf) * 17; 1736 colors[j++] = (i & 0xf) * 17; 1737 colors[j++] = (i & 0xf) * 17; 1738 } 1739 1740 setIndexedColors(256, 0, colors, 0); 1741 } else { 1742 for (int32 i = 0; i < 256; i++) { 1743 colors[j++] = i; 1744 colors[j++] = i; 1745 colors[j++] = i; 1746 } 1747 1748 setIndexedColors(256, 0, colors, 0); 1749 } 1750 } 1751