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