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 61const 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 68static int32 69run_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 82class DView : public BView { 83public: 84 DView(BRect bounds); 85 virtual ~DView(); 86 87 // DView 88 void ForwardMessage(BMessage* message = NULL); 89 90private: 91 port_id fInputPort; 92}; 93 94class DWindow : public BWindow { 95public: 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 107private: 108 DWindowHWInterface* fHWInterface; 109 DWindowBuffer* fBuffer; 110}; 111 112class DirectMessageFilter : public BMessageFilter { 113public: 114 DirectMessageFilter(DView* view); 115 116 virtual filter_result Filter(BMessage *message, BHandler** _target); 117 118private: 119 DView* fView; 120}; 121 122 123// #pragma mark - 124 125 126DView::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 143DView::~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*/ 152void 153DView::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 178DirectMessageFilter::DirectMessageFilter(DView* view) 179 : 180 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 181 fView(view) 182{ 183} 184 185 186filter_result 187DirectMessageFilter::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 222DWindow::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 238DWindow::~DWindow() 239{ 240} 241 242 243bool 244DWindow::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/* 261void 262DWindow::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 288void 289DWindow::FrameMoved(BPoint newOffset) 290{ 291 fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y); 292} 293 294 295// #pragma mark - 296 297 298const int32 kDefaultParamsCount = 64; 299 300DWindowHWInterface::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 349DWindowHWInterface::~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 365status_t 366DWindowHWInterface::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*/ 405int 406DWindowHWInterface::_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 457status_t 458DWindowHWInterface::_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... 523sprintf((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 567status_t 568DWindowHWInterface::_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 615status_t 616DWindowHWInterface::_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 631status_t 632DWindowHWInterface::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 652status_t 653DWindowHWInterface::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 745void 746DWindowHWInterface::GetMode(display_mode* mode) 747{ 748 if (mode && ReadLock()) { 749 *mode = fDisplayMode; 750 ReadUnlock(); 751 } 752} 753 754 755status_t 756DWindowHWInterface::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 775status_t 776DWindowHWInterface::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 789status_t 790DWindowHWInterface::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 845status_t 846DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 847 uint32* high) 848{ 849 return B_ERROR; 850} 851 852 853status_t 854DWindowHWInterface::GetTimingConstraints( 855 display_timing_constraints* constraints) 856{ 857 return B_ERROR; 858} 859 860 861status_t 862DWindowHWInterface::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 873sem_id 874DWindowHWInterface::RetraceSemaphore() 875{ 876 return -1; 877} 878 879 880status_t 881DWindowHWInterface::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 889status_t 890DWindowHWInterface::SetDPMSMode(uint32 state) 891{ 892 AutoWriteLocker _(this); 893 894 return BScreen().SetDPMS(state); 895} 896 897 898uint32 899DWindowHWInterface::DPMSMode() 900{ 901 AutoReadLocker _(this); 902 903 return BScreen().DPMSState(); 904} 905 906 907uint32 908DWindowHWInterface::DPMSCapabilities() 909{ 910 AutoReadLocker _(this); 911 912 return BScreen().DPMSCapabilites(); 913} 914 915 916status_t 917DWindowHWInterface::SetBrightness(float brightness) 918{ 919 AutoReadLocker _(this); 920 921 return BScreen().SetBrightness(brightness); 922} 923 924 925status_t 926DWindowHWInterface::GetBrightness(float* brightness) 927{ 928 AutoReadLocker _(this); 929 930 return BScreen().GetBrightness(brightness); 931} 932 933 934uint32 935DWindowHWInterface::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 952void 953DWindowHWInterface::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 1007void 1008DWindowHWInterface::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 1033void 1034DWindowHWInterface::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 1064void 1065DWindowHWInterface::Sync() 1066{ 1067 if (fAccSyncToToken) 1068 fAccSyncToToken(&fSyncToken); 1069} 1070 1071 1072RenderingBuffer* 1073DWindowHWInterface::FrontBuffer() const 1074{ 1075 return fFrontBuffer.Get(); 1076} 1077 1078 1079RenderingBuffer* 1080DWindowHWInterface::BackBuffer() const 1081{ 1082 return fFrontBuffer.Get(); 1083} 1084 1085 1086bool 1087DWindowHWInterface::IsDoubleBuffered() const 1088{ 1089 return false; 1090} 1091 1092 1093status_t 1094DWindowHWInterface::Invalidate(const BRect& frame) 1095{ 1096 return HWInterface::Invalidate(frame); 1097} 1098 1099 1100void 1101DWindowHWInterface::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 1117void 1118DWindowHWInterface::_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 1146uint32 1147DWindowHWInterface::_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