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