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