1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Michael Lotz <mmlr@mlotz.ch> 8 * Stephan Aßmus <superstippi@gmx.de> 9 */ 10 11 12 /*! BView/BDirectWindow/Accelerant combination HWInterface implementation 13 */ 14 15 16 #include "DWindowHWInterface.h" 17 18 #include <malloc.h> 19 #include <new> 20 #include <stdio.h> 21 22 #include <Application.h> 23 #include <Bitmap.h> 24 #include <Cursor.h> 25 #include <DirectWindow.h> 26 #include <Locker.h> 27 #include <Message.h> 28 #include <MessageFilter.h> 29 #include <MessageRunner.h> 30 #include <Region.h> 31 #include <Screen.h> 32 #include <String.h> 33 #include <View.h> 34 35 #include <Accelerant.h> 36 #include <graphic_driver.h> 37 #include <FindDirectory.h> 38 #include <image.h> 39 #include <dirent.h> 40 #include <sys/ioctl.h> 41 #include <unistd.h> 42 43 #include <ServerProtocol.h> 44 45 #include "DWindowBuffer.h" 46 #include "PortLink.h" 47 #include "RGBColor.h" 48 #include "ServerConfig.h" 49 #include "ServerCursor.h" 50 #include "UpdateQueue.h" 51 52 53 #ifdef DEBUG_DRIVER_MODULE 54 # include <stdio.h> 55 # define STRACE(x) printf x 56 #else 57 # define STRACE(x) ; 58 #endif 59 60 61 const unsigned char kEmptyCursor[] = { 16, 1, 0, 0, 62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 66 67 68 static int32 69 run_app_thread(void* cookie) 70 { 71 if (BApplication* app = (BApplication*)cookie) { 72 app->Lock(); 73 app->Run(); 74 } 75 return 0; 76 } 77 78 79 //#define INPUTSERVER_TEST_MODE 1 80 81 82 class DView : public BView { 83 public: 84 DView(BRect bounds); 85 virtual ~DView(); 86 87 // DView 88 void ForwardMessage(BMessage* message = NULL); 89 90 private: 91 port_id fInputPort; 92 }; 93 94 class DWindow : public BWindow { 95 public: 96 DWindow(BRect frame, 97 DWindowHWInterface* interface, 98 DWindowBuffer* buffer); 99 virtual ~DWindow(); 100 101 virtual bool QuitRequested(); 102 103 // virtual void DirectConnected(direct_buffer_info* info); 104 105 virtual void FrameMoved(BPoint newOffset); 106 107 private: 108 DWindowHWInterface* fHWInterface; 109 DWindowBuffer* fBuffer; 110 }; 111 112 class DirectMessageFilter : public BMessageFilter { 113 public: 114 DirectMessageFilter(DView* view); 115 116 virtual filter_result Filter(BMessage *message, BHandler** _target); 117 118 private: 119 DView* fView; 120 }; 121 122 123 // #pragma mark - 124 125 126 DView::DView(BRect bounds) 127 : 128 BView(bounds, "graphics card view", B_FOLLOW_ALL, 0) 129 { 130 SetViewColor(B_TRANSPARENT_COLOR); 131 #ifndef INPUTSERVER_TEST_MODE 132 fInputPort = create_port(200, SERVER_INPUT_PORT); 133 #else 134 fInputPort = create_port(100, "ViewInputDevice"); 135 #endif 136 137 #ifdef ENABLE_INPUT_SERVER_EMULATION 138 AddFilter(new DirectMessageFilter(this)); 139 #endif 140 } 141 142 143 DView::~DView() 144 { 145 } 146 147 148 /*! This function emulates the Input Server by sending the *exact* same kind of 149 messages to the server's port. Being we're using a regular window, it would 150 make little sense to do anything else. 151 */ 152 void 153 DView::ForwardMessage(BMessage* message) 154 { 155 if (message == NULL) 156 message = Window()->CurrentMessage(); 157 if (message == NULL) 158 return; 159 160 // remove some fields that potentially mess up our own message processing 161 BMessage copy = *message; 162 copy.RemoveName("screen_where"); 163 copy.RemoveName("be:transit"); 164 copy.RemoveName("be:view_where"); 165 copy.RemoveName("be:cursor_needed"); 166 167 size_t length = copy.FlattenedSize(); 168 char stream[length]; 169 170 if (copy.Flatten(stream, length) == B_OK) 171 write_port(fInputPort, 0, stream, length); 172 } 173 174 175 // #pragma mark - 176 177 178 DirectMessageFilter::DirectMessageFilter(DView* view) 179 : 180 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 181 fView(view) 182 { 183 } 184 185 186 filter_result 187 DirectMessageFilter::Filter(BMessage* message, BHandler** target) 188 { 189 switch (message->what) { 190 case B_KEY_DOWN: 191 case B_UNMAPPED_KEY_DOWN: 192 case B_KEY_UP: 193 case B_UNMAPPED_KEY_UP: 194 case B_MOUSE_DOWN: 195 case B_MOUSE_UP: 196 case B_MOUSE_WHEEL_CHANGED: 197 fView->ForwardMessage(message); 198 return B_SKIP_MESSAGE; 199 200 case B_MOUSE_MOVED: 201 { 202 int32 transit; 203 if (message->FindInt32("be:transit", &transit) == B_OK 204 && transit == B_ENTERED_VIEW) { 205 // A bug in R5 prevents this call from having an effect if 206 // called elsewhere, and calling it here works, if we're lucky :-) 207 BCursor cursor(kEmptyCursor); 208 fView->SetViewCursor(&cursor, true); 209 } 210 fView->ForwardMessage(message); 211 return B_SKIP_MESSAGE; 212 } 213 } 214 215 return B_DISPATCH_MESSAGE; 216 } 217 218 219 // #pragma mark - 220 221 222 DWindow::DWindow(BRect frame, DWindowHWInterface* interface, 223 DWindowBuffer* buffer) 224 : 225 BWindow(frame, "Haiku App Server", B_TITLED_WINDOW_LOOK, 226 B_NORMAL_WINDOW_FEEL, 227 B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_MOVABLE), 228 fHWInterface(interface), 229 fBuffer(buffer) 230 { 231 DView* view = new DView(Bounds()); 232 AddChild(view); 233 view->MakeFocus(); 234 // make it receive key events 235 } 236 237 238 DWindow::~DWindow() 239 { 240 } 241 242 243 bool 244 DWindow::QuitRequested() 245 { 246 port_id serverport = find_port(SERVER_PORT_NAME); 247 248 if (serverport >= 0) { 249 BPrivate::PortLink link(serverport); 250 link.StartMessage(B_QUIT_REQUESTED); 251 link.Flush(); 252 } else 253 printf("ERROR: couldn't find the app_server's main port!"); 254 255 // we don't quit on ourself, we let us be Quit()! 256 return false; 257 } 258 259 260 /* 261 void 262 DWindow::DirectConnected(direct_buffer_info* info) 263 { 264 // fDesktop->LockClipping(); 265 // 266 // fEngine.Lock(); 267 // 268 switch(info->buffer_state & B_DIRECT_MODE_MASK) { 269 case B_DIRECT_START: 270 case B_DIRECT_MODIFY: 271 fBuffer->SetTo(info); 272 // fDesktop->SetOffset(info->window_bounds.left, info->window_bounds.top); 273 break; 274 case B_DIRECT_STOP: 275 fBuffer->SetTo(NULL); 276 break; 277 } 278 // 279 // fDesktop->SetMasterClipping(&fBuffer.WindowClipping()); 280 // 281 // fEngine.Unlock(); 282 // 283 // fDesktop->UnlockClipping(); 284 } 285 */ 286 287 288 void 289 DWindow::FrameMoved(BPoint newOffset) 290 { 291 fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y); 292 } 293 294 295 // #pragma mark - 296 297 298 const int32 kDefaultParamsCount = 64; 299 300 DWindowHWInterface::DWindowHWInterface() 301 : 302 HWInterface(), 303 fFrontBuffer(new DWindowBuffer()), 304 fWindow(NULL), 305 306 fXOffset(50), 307 fYOffset(50), 308 309 fCardFD(-1), 310 fAccelerantImage(-1), 311 fAccelerantHook(NULL), 312 fEngineToken(NULL), 313 fSyncToken(), 314 315 // required hooks 316 fAccAcquireEngine(NULL), 317 fAccReleaseEngine(NULL), 318 fAccSyncToToken(NULL), 319 fAccGetModeCount(NULL), 320 fAccGetModeList(NULL), 321 fAccGetFrameBufferConfig(NULL), 322 fAccSetDisplayMode(NULL), 323 fAccGetDisplayMode(NULL), 324 fAccGetPixelClockLimits(NULL), 325 326 // optional accelerant hooks 327 fAccGetTimingConstraints(NULL), 328 fAccProposeDisplayMode(NULL), 329 fAccFillRect(NULL), 330 fAccInvertRect(NULL), 331 fAccScreenBlit(NULL), 332 fAccSetCursorShape(NULL), 333 fAccMoveCursor(NULL), 334 fAccShowCursor(NULL), 335 336 fRectParams(new (std::nothrow) fill_rect_params[kDefaultParamsCount]), 337 fRectParamsCount(kDefaultParamsCount), 338 fBlitParams(new (std::nothrow) blit_params[kDefaultParamsCount]), 339 fBlitParamsCount(kDefaultParamsCount) 340 { 341 fDisplayMode.virtual_width = 800; 342 fDisplayMode.virtual_height = 600; 343 fDisplayMode.space = B_RGBA32; 344 345 memset(&fSyncToken, 0, sizeof(sync_token)); 346 } 347 348 349 DWindowHWInterface::~DWindowHWInterface() 350 { 351 if (fWindow) { 352 fWindow->Lock(); 353 fWindow->Quit(); 354 } 355 356 delete[] fRectParams; 357 delete[] fBlitParams; 358 359 be_app->Lock(); 360 be_app->Quit(); 361 delete be_app; 362 } 363 364 365 status_t 366 DWindowHWInterface::Initialize() 367 { 368 status_t ret = HWInterface::Initialize(); 369 370 if (!fRectParams || !fBlitParams) 371 return B_NO_MEMORY; 372 373 if (ret >= B_OK) { 374 for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) { 375 fCardFD = _OpenGraphicsDevice(i); 376 if (fCardFD < 0) { 377 STRACE(("Failed to open graphics device\n")); 378 continue; 379 } 380 381 if (_OpenAccelerant(fCardFD) == B_OK) 382 break; 383 384 close(fCardFD); 385 // _OpenAccelerant() failed, try to open next graphics card 386 } 387 388 return fCardFD >= 0 ? B_OK : fCardFD; 389 } 390 return ret; 391 } 392 393 394 /*! \brief Opens a graphics device for read-write access 395 \param deviceNumber Number identifying which graphics card to open (1 for 396 first card) 397 \return The file descriptor for the opened graphics device 398 399 The deviceNumber is relative to the number of graphics devices that can be 400 successfully opened. One represents the first card that can be successfully 401 opened (not necessarily the first one listed in the directory). 402 Graphics drivers must be able to be opened more than once, so we really get 403 the first working entry. 404 */ 405 int 406 DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber) 407 { 408 DIR *directory = opendir("/dev/graphics"); 409 if (!directory) 410 return B_ENTRY_NOT_FOUND; 411 412 // TODO: We do not need to avoid the "vesa" or "framebuffer" drivers this way 413 // once they been ported to the new driver architecture - the special case here 414 // can then be removed. 415 int count = 0; 416 struct dirent *entry = NULL; 417 int current_card_fd = -1; 418 char path[PATH_MAX]; 419 while (count < deviceNumber && (entry = readdir(directory)) != NULL) { 420 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") 421 || !strcmp(entry->d_name, "vesa") || !strcmp(entry->d_name, "framebuffer")) 422 continue; 423 424 if (current_card_fd >= 0) { 425 close(current_card_fd); 426 current_card_fd = -1; 427 } 428 429 sprintf(path, "/dev/graphics/%s", entry->d_name); 430 current_card_fd = open(path, B_READ_WRITE); 431 if (current_card_fd >= 0) 432 count++; 433 } 434 435 // Open VESA or Framebuffer driver if we were not able to get a better one. 436 if (count < deviceNumber) { 437 if (deviceNumber == 1) { 438 sprintf(path, "/dev/graphics/vesa"); 439 current_card_fd = open(path, B_READ_WRITE); 440 if (current_card_fd < 0) { 441 sprintf(path, "/dev/graphics/framebuffer"); 442 current_card_fd = open(path, B_READ_WRITE); 443 } 444 } else { 445 close(current_card_fd); 446 current_card_fd = B_ENTRY_NOT_FOUND; 447 } 448 } 449 450 if (entry) 451 fCardNameInDevFS = entry->d_name; 452 453 return current_card_fd; 454 } 455 456 457 status_t 458 DWindowHWInterface::_OpenAccelerant(int device) 459 { 460 char signature[1024]; 461 if (ioctl(device, B_GET_ACCELERANT_SIGNATURE, 462 &signature, sizeof(signature)) != B_OK) 463 return B_ERROR; 464 465 STRACE(("accelerant signature is: %s\n", signature)); 466 467 struct stat accelerant_stat; 468 const static directory_which dirs[] = { 469 B_USER_NONPACKAGED_ADDONS_DIRECTORY, 470 B_USER_ADDONS_DIRECTORY, 471 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 472 B_SYSTEM_ADDONS_DIRECTORY 473 }; 474 475 fAccelerantImage = -1; 476 477 for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { 478 char path[PATH_MAX]; 479 if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) 480 continue; 481 482 strcat(path, "/accelerants/"); 483 strcat(path, signature); 484 if (stat(path, &accelerant_stat) != 0) 485 continue; 486 487 fAccelerantImage = load_add_on(path); 488 if (fAccelerantImage >= 0) { 489 if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT, 490 B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) { 491 STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n")); 492 unload_add_on(fAccelerantImage); 493 fAccelerantImage = -1; 494 return B_ERROR; 495 } 496 497 498 accelerant_clone_info_size cloneInfoSize; 499 cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook( 500 B_ACCELERANT_CLONE_INFO_SIZE, NULL); 501 if (!cloneInfoSize) { 502 STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path)); 503 unload_add_on(fAccelerantImage); 504 fAccelerantImage = -1; 505 return B_ERROR; 506 } 507 508 ssize_t cloneSize = cloneInfoSize(); 509 void* cloneInfoData = malloc(cloneSize); 510 511 // get_accelerant_clone_info getCloneInfo; 512 // getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL); 513 // if (!getCloneInfo) { 514 // STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path)); 515 // unload_add_on(fAccelerantImage); 516 // fAccelerantImage = -1; 517 // return B_ERROR; 518 // } 519 // printf("getCloneInfo: %p\n", getCloneInfo); 520 // 521 // getCloneInfo(cloneInfoData); 522 // TODO: this is what works for the ATI Radeon driver... 523 sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String()); 524 525 clone_accelerant cloneAccelerant; 526 cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL); 527 if (!cloneAccelerant) { 528 STRACE(("unable to get B_CLONE_ACCELERANT\n")); 529 unload_add_on(fAccelerantImage); 530 fAccelerantImage = -1; 531 free(cloneInfoData); 532 return B_ERROR; 533 } 534 status_t ret = cloneAccelerant(cloneInfoData); 535 if (ret != B_OK) { 536 STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret))); 537 unload_add_on(fAccelerantImage); 538 fAccelerantImage = -1; 539 return B_ERROR; 540 } 541 542 break; 543 } 544 } 545 546 if (fAccelerantImage < B_OK) 547 return B_ERROR; 548 549 if (_SetupDefaultHooks() != B_OK) { 550 STRACE(("cannot setup default hooks\n")); 551 552 uninit_accelerant uninitAccelerant = (uninit_accelerant) 553 fAccelerantHook(B_UNINIT_ACCELERANT, NULL); 554 if (uninitAccelerant != NULL) 555 uninitAccelerant(); 556 557 unload_add_on(fAccelerantImage); 558 return B_ERROR; 559 } else { 560 _UpdateFrameBufferConfig(); 561 } 562 563 return B_OK; 564 } 565 566 567 status_t 568 DWindowHWInterface::_SetupDefaultHooks() 569 { 570 // required 571 fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL); 572 fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL); 573 fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL); 574 fAccGetModeCount = (accelerant_mode_count)fAccelerantHook( 575 B_ACCELERANT_MODE_COUNT, NULL); 576 fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL); 577 fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook( 578 B_GET_FRAME_BUFFER_CONFIG, NULL); 579 fAccSetDisplayMode = (set_display_mode)fAccelerantHook( 580 B_SET_DISPLAY_MODE, NULL); 581 fAccGetDisplayMode = (get_display_mode)fAccelerantHook( 582 B_GET_DISPLAY_MODE, NULL); 583 fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook( 584 B_GET_PIXEL_CLOCK_LIMITS, NULL); 585 586 if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig 587 || !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode 588 || !fAccGetDisplayMode || !fAccGetPixelClockLimits) { 589 return B_ERROR; 590 } 591 592 // optional 593 fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook( 594 B_GET_TIMING_CONSTRAINTS, NULL); 595 fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook( 596 B_PROPOSE_DISPLAY_MODE, NULL); 597 598 // cursor 599 fAccSetCursorShape = (set_cursor_shape)fAccelerantHook( 600 B_SET_CURSOR_SHAPE, NULL); 601 fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL); 602 fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL); 603 604 // update acceleration hooks 605 // TODO: would actually have to pass a valid display_mode! 606 fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL); 607 fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL); 608 fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook( 609 B_SCREEN_TO_SCREEN_BLIT, NULL); 610 611 return B_OK; 612 } 613 614 615 status_t 616 DWindowHWInterface::_UpdateFrameBufferConfig() 617 { 618 frame_buffer_config config; 619 if (fAccGetFrameBufferConfig(&config) != B_OK) { 620 STRACE(("unable to get frame buffer config\n")); 621 return B_ERROR; 622 } 623 624 fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width, 625 fDisplayMode.virtual_height, (color_space)fDisplayMode.space); 626 627 return B_OK; 628 } 629 630 631 status_t 632 DWindowHWInterface::Shutdown() 633 { 634 printf("DWindowHWInterface::Shutdown()\n"); 635 if (fAccelerantHook) { 636 uninit_accelerant UninitAccelerant 637 = (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL); 638 if (UninitAccelerant) 639 UninitAccelerant(); 640 } 641 642 if (fAccelerantImage >= 0) 643 unload_add_on(fAccelerantImage); 644 645 if (fCardFD >= 0) 646 close(fCardFD); 647 648 return B_OK; 649 } 650 651 652 status_t 653 DWindowHWInterface::SetMode(const display_mode& mode) 654 { 655 AutoWriteLocker _(this); 656 657 status_t ret = B_OK; 658 // prevent from doing the unnecessary 659 if (fFrontBuffer.IsSet() 660 && fDisplayMode.virtual_width == mode.virtual_width 661 && fDisplayMode.virtual_height == mode.virtual_height 662 && fDisplayMode.space == mode.space) 663 return ret; 664 665 // check if we support the mode 666 667 display_mode *modes; 668 uint32 modeCount, i; 669 if (GetModeList(&modes, &modeCount) != B_OK) 670 return B_NO_MEMORY; 671 672 for (i = 0; i < modeCount; i++) { 673 // we only care for the bare minimum 674 if (modes[i].virtual_width == mode.virtual_width 675 && modes[i].virtual_height == mode.virtual_height 676 && modes[i].space == mode.space) { 677 // take over settings 678 fDisplayMode = modes[i]; 679 break; 680 } 681 } 682 683 delete[] modes; 684 685 if (i == modeCount) 686 return B_BAD_VALUE; 687 688 BRect frame(0.0, 0.0, 689 fDisplayMode.virtual_width - 1, 690 fDisplayMode.virtual_height - 1); 691 692 // create the window if we don't have one already 693 if (!fWindow) { 694 // if the window has not been created yet, the BApplication 695 // has not been created either, but we need one to display 696 // a real BWindow in the test environment. 697 // be_app->Run() needs to be called in another thread 698 BApplication* app = new BApplication( 699 "application/x-vnd.Haiku-test-app_server"); 700 app->Unlock(); 701 702 thread_id appThread = spawn_thread(run_app_thread, "app thread", 703 B_NORMAL_PRIORITY, app); 704 if (appThread >= B_OK) 705 ret = resume_thread(appThread); 706 else 707 ret = appThread; 708 709 if (ret < B_OK) 710 return ret; 711 712 fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this, 713 fFrontBuffer.Get()); 714 715 // fire up the window thread but don't show it on screen yet 716 fWindow->Hide(); 717 fWindow->Show(); 718 } 719 720 if (fWindow->Lock()) { 721 // free and reallocate the bitmaps while the window is locked, 722 // so that the view does not accidentally draw a freed bitmap 723 724 if (ret >= B_OK) { 725 // change the window size and update the bitmap used for drawing 726 fWindow->ResizeTo(frame.Width(), frame.Height()); 727 } 728 729 // window is hidden when this function is called the first time 730 if (fWindow->IsHidden()) 731 fWindow->Show(); 732 733 fWindow->Unlock(); 734 } else { 735 ret = B_ERROR; 736 } 737 738 _UpdateFrameBufferConfig(); 739 _NotifyFrameBufferChanged(); 740 741 return ret; 742 } 743 744 745 void 746 DWindowHWInterface::GetMode(display_mode* mode) 747 { 748 if (mode && ReadLock()) { 749 *mode = fDisplayMode; 750 ReadUnlock(); 751 } 752 } 753 754 755 status_t 756 DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info) 757 { 758 // We really don't have to provide anything here because this is strictly 759 // a software-only driver, but we'll have some fun, anyway. 760 if (ReadLock()) { 761 info->version = 100; 762 sprintf(info->name, "Haiku, Inc. DWindowHWInterface"); 763 sprintf(info->chipset, "Haiku, Inc. Chipset"); 764 sprintf(info->serial_no, "3.14159265358979323846"); 765 info->memory = 134217728; // 128 MB, not that we really have that much. :) 766 info->dac_speed = 0xFFFFFFFF; // *heh* 767 768 ReadUnlock(); 769 } 770 771 return B_OK; 772 } 773 774 775 status_t 776 DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 777 { 778 if (!fFrontBuffer.IsSet()) 779 return B_ERROR; 780 781 config.frame_buffer = fFrontBuffer->Bits(); 782 config.frame_buffer_dma = NULL; 783 config.bytes_per_row = fFrontBuffer->BytesPerRow(); 784 785 return B_OK; 786 } 787 788 789 status_t 790 DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count) 791 { 792 AutoReadLocker _(this); 793 794 #if 1 795 // setup a whole bunch of different modes 796 const struct resolution { int32 width, height; } resolutions[] = { 797 {640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960}, 798 {1280, 1024}, {1400, 1050}, {1600, 1200} 799 }; 800 uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]); 801 // const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32}; 802 uint32 count = resolutionCount/* * 4*/; 803 804 display_mode* modes = new(std::nothrow) display_mode[count]; 805 if (modes == NULL) 806 return B_NO_MEMORY; 807 808 *_modes = modes; 809 *_count = count; 810 811 int32 index = 0; 812 for (uint32 i = 0; i < resolutionCount; i++) { 813 modes[index].virtual_width = resolutions[i].width; 814 modes[index].virtual_height = resolutions[i].height; 815 modes[index].space = B_RGB32; 816 817 modes[index].h_display_start = 0; 818 modes[index].v_display_start = 0; 819 modes[index].timing.h_display = resolutions[i].width; 820 modes[index].timing.v_display = resolutions[i].height; 821 modes[index].timing.h_total = 22000; 822 modes[index].timing.v_total = 22000; 823 modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total 824 * modes[index].timing.v_total * 60) / 1000; 825 modes[index].flags = B_PARALLEL_ACCESS; 826 827 index++; 828 } 829 #else 830 // support only a single mode, useful 831 // for testing a specific mode 832 display_mode *modes = new(std::nothrow) display_mode[1]; 833 modes[0].virtual_width = 800; 834 modes[0].virtual_height = 600; 835 modes[0].space = B_BRGB32; 836 837 *_modes = modes; 838 *_count = 1; 839 #endif 840 841 return B_OK; 842 } 843 844 845 status_t 846 DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 847 uint32* high) 848 { 849 return B_ERROR; 850 } 851 852 853 status_t 854 DWindowHWInterface::GetTimingConstraints( 855 display_timing_constraints* constraints) 856 { 857 return B_ERROR; 858 } 859 860 861 status_t 862 DWindowHWInterface::ProposeMode(display_mode* candidate, 863 const display_mode* low, const display_mode* high) 864 { 865 // We should be able to get away with this because we're not dealing with 866 // any specific hardware. This is a Good Thing(TM) because we can support 867 // any hardware we wish within reasonable expectaions and programmer 868 // laziness. :P 869 return B_OK; 870 } 871 872 873 sem_id 874 DWindowHWInterface::RetraceSemaphore() 875 { 876 return -1; 877 } 878 879 880 status_t 881 DWindowHWInterface::WaitForRetrace(bigtime_t timeout) 882 { 883 // Locking shouldn't be necessary here - R5 should handle this for us. :) 884 BScreen screen; 885 return screen.WaitForRetrace(timeout); 886 } 887 888 889 status_t 890 DWindowHWInterface::SetDPMSMode(uint32 state) 891 { 892 AutoWriteLocker _(this); 893 894 return BScreen().SetDPMS(state); 895 } 896 897 898 uint32 899 DWindowHWInterface::DPMSMode() 900 { 901 AutoReadLocker _(this); 902 903 return BScreen().DPMSState(); 904 } 905 906 907 uint32 908 DWindowHWInterface::DPMSCapabilities() 909 { 910 AutoReadLocker _(this); 911 912 return BScreen().DPMSCapabilites(); 913 } 914 915 916 status_t 917 DWindowHWInterface::SetBrightness(float brightness) 918 { 919 AutoReadLocker _(this); 920 921 return BScreen().SetBrightness(brightness); 922 } 923 924 925 status_t 926 DWindowHWInterface::GetBrightness(float* brightness) 927 { 928 AutoReadLocker _(this); 929 930 return BScreen().GetBrightness(brightness); 931 } 932 933 934 uint32 935 DWindowHWInterface::AvailableHWAcceleration() const 936 { 937 uint32 flags = 0; 938 939 if (!IsDoubleBuffered()) { 940 if (fAccScreenBlit) 941 flags |= HW_ACC_COPY_REGION; 942 if (fAccFillRect) 943 flags |= HW_ACC_FILL_REGION; 944 if (fAccInvertRect) 945 flags |= HW_ACC_INVERT_REGION; 946 } 947 948 return flags; 949 } 950 951 952 void 953 DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList, 954 uint32 count, int32 xOffset, int32 yOffset) 955 { 956 if (fAccScreenBlit && fAccAcquireEngine) { 957 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 958 &fEngineToken) >= B_OK) { 959 // make sure the blit_params cache is large enough 960 if (fBlitParamsCount < count) { 961 fBlitParamsCount = (count / kDefaultParamsCount + 1) 962 * kDefaultParamsCount; 963 // NOTE: realloc() could be used instead... 964 blit_params* params 965 = new(std::nothrow) blit_params[fBlitParamsCount]; 966 if (params) { 967 delete[] fBlitParams; 968 fBlitParams = params; 969 } else { 970 count = fBlitParamsCount; 971 } 972 } 973 // convert the rects 974 for (uint32 i = 0; i < count; i++) { 975 fBlitParams[i].src_left 976 = (uint16)sortedRectList[i].left + fXOffset; 977 fBlitParams[i].src_top 978 = (uint16)sortedRectList[i].top + fYOffset; 979 980 fBlitParams[i].dest_left 981 = (uint16)sortedRectList[i].left + xOffset + fXOffset; 982 fBlitParams[i].dest_top 983 = (uint16)sortedRectList[i].top + yOffset + fYOffset; 984 985 // NOTE: width and height are expressed as distance, not count! 986 fBlitParams[i].width = (uint16)(sortedRectList[i].right 987 - sortedRectList[i].left); 988 fBlitParams[i].height = (uint16)(sortedRectList[i].bottom 989 - sortedRectList[i].top); 990 } 991 992 // go 993 fAccScreenBlit(fEngineToken, fBlitParams, count); 994 995 // done 996 if (fAccReleaseEngine) 997 fAccReleaseEngine(fEngineToken, &fSyncToken); 998 999 // sync 1000 if (fAccSyncToToken) 1001 fAccSyncToToken(&fSyncToken); 1002 } 1003 } 1004 } 1005 1006 1007 void 1008 DWindowHWInterface::FillRegion(/*const*/ BRegion& region, 1009 const rgb_color& color, bool autoSync) 1010 { 1011 if (fAccFillRect && fAccAcquireEngine) { 1012 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1013 &fEngineToken) >= B_OK) { 1014 // convert the region 1015 uint32 count; 1016 _RegionToRectParams(®ion, &count); 1017 1018 // go 1019 fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count); 1020 1021 // done 1022 if (fAccReleaseEngine) 1023 fAccReleaseEngine(fEngineToken, &fSyncToken); 1024 1025 // sync 1026 if (autoSync && fAccSyncToToken) 1027 fAccSyncToToken(&fSyncToken); 1028 } 1029 } 1030 } 1031 1032 1033 void 1034 DWindowHWInterface::InvertRegion(/*const*/ BRegion& region) 1035 { 1036 if (fAccInvertRect && fAccAcquireEngine) { 1037 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1038 &fEngineToken) >= B_OK) { 1039 // convert the region 1040 uint32 count; 1041 _RegionToRectParams(®ion, &count); 1042 1043 // go 1044 fAccInvertRect(fEngineToken, fRectParams, count); 1045 1046 // done 1047 if (fAccReleaseEngine) 1048 fAccReleaseEngine(fEngineToken, &fSyncToken); 1049 1050 // sync 1051 if (fAccSyncToToken) 1052 fAccSyncToToken(&fSyncToken); 1053 1054 } else { 1055 fprintf(stderr, "AcquireEngine failed!\n"); 1056 } 1057 } else { 1058 fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but " 1059 "hook not available!\n"); 1060 } 1061 } 1062 1063 1064 void 1065 DWindowHWInterface::Sync() 1066 { 1067 if (fAccSyncToToken) 1068 fAccSyncToToken(&fSyncToken); 1069 } 1070 1071 1072 RenderingBuffer* 1073 DWindowHWInterface::FrontBuffer() const 1074 { 1075 return fFrontBuffer.Get(); 1076 } 1077 1078 1079 RenderingBuffer* 1080 DWindowHWInterface::BackBuffer() const 1081 { 1082 return fFrontBuffer.Get(); 1083 } 1084 1085 1086 bool 1087 DWindowHWInterface::IsDoubleBuffered() const 1088 { 1089 return false; 1090 } 1091 1092 1093 status_t 1094 DWindowHWInterface::Invalidate(const BRect& frame) 1095 { 1096 return HWInterface::Invalidate(frame); 1097 } 1098 1099 1100 void 1101 DWindowHWInterface::SetOffset(int32 left, int32 top) 1102 { 1103 if (!WriteLock()) 1104 return; 1105 1106 fXOffset = left; 1107 fYOffset = top; 1108 1109 _UpdateFrameBufferConfig(); 1110 1111 // TODO: someone would have to call DrawingEngine::Update() now! 1112 1113 WriteUnlock(); 1114 } 1115 1116 1117 void 1118 DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region, 1119 uint32* count) const 1120 { 1121 *count = region->CountRects(); 1122 if (fRectParamsCount < *count) { 1123 fRectParamsCount = (*count / kDefaultParamsCount + 1) 1124 * kDefaultParamsCount; 1125 // NOTE: realloc() could be used instead... 1126 fill_rect_params* params 1127 = new(std::nothrow) fill_rect_params[fRectParamsCount]; 1128 if (params) { 1129 delete[] fRectParams; 1130 fRectParams = params; 1131 } else { 1132 *count = fRectParamsCount; 1133 } 1134 } 1135 1136 for (uint32 i = 0; i < *count; i++) { 1137 clipping_rect r = region->RectAtInt(i); 1138 fRectParams[i].left = (uint16)r.left + fXOffset; 1139 fRectParams[i].top = (uint16)r.top + fYOffset; 1140 fRectParams[i].right = (uint16)r.right + fXOffset; 1141 fRectParams[i].bottom = (uint16)r.bottom + fYOffset; 1142 } 1143 } 1144 1145 1146 uint32 1147 DWindowHWInterface::_NativeColor(const rgb_color& color) const 1148 { 1149 // NOTE: This functions looks somehow suspicios to me. 1150 // It assumes that all graphics cards have the same native endianess, no? 1151 switch (fDisplayMode.space) { 1152 case B_CMAP8: 1153 case B_GRAY8: 1154 return RGBColor(color).GetColor8(); 1155 1156 case B_RGB15_BIG: 1157 case B_RGBA15_BIG: 1158 case B_RGB15_LITTLE: 1159 case B_RGBA15_LITTLE: 1160 return RGBColor(color).GetColor15(); 1161 1162 case B_RGB16_BIG: 1163 case B_RGB16_LITTLE: 1164 return RGBColor(color).GetColor16(); 1165 1166 case B_RGB32_BIG: 1167 case B_RGBA32_BIG: 1168 case B_RGB32_LITTLE: 1169 case B_RGBA32_LITTLE: { 1170 uint32 native = (color.alpha << 24) | (color.red << 16) 1171 | (color.green << 8) | (color.blue); 1172 return native; 1173 } 1174 } 1175 return 0; 1176 } 1177