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