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