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