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_FLOATING_ALL_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 delete fFrontBuffer; 360 361 be_app->Lock(); 362 be_app->Quit(); 363 delete be_app; 364} 365 366 367status_t 368DWindowHWInterface::Initialize() 369{ 370 status_t ret = HWInterface::Initialize(); 371 372 if (!fRectParams || !fBlitParams) 373 return B_NO_MEMORY; 374 375 if (ret >= B_OK) { 376 for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) { 377 fCardFD = _OpenGraphicsDevice(i); 378 if (fCardFD < 0) { 379 STRACE(("Failed to open graphics device\n")); 380 continue; 381 } 382 383 if (_OpenAccelerant(fCardFD) == B_OK) 384 break; 385 386 close(fCardFD); 387 // _OpenAccelerant() failed, try to open next graphics card 388 } 389 390 return fCardFD >= 0 ? B_OK : fCardFD; 391 } 392 return ret; 393} 394 395 396/*! \brief Opens a graphics device for read-write access 397 \param deviceNumber Number identifying which graphics card to open (1 for 398 first card) 399 \return The file descriptor for the opened graphics device 400 401 The deviceNumber is relative to the number of graphics devices that can be 402 successfully opened. One represents the first card that can be successfully 403 opened (not necessarily the first one listed in the directory). 404 Graphics drivers must be able to be opened more than once, so we really get 405 the first working entry. 406*/ 407int 408DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber) 409{ 410 DIR *directory = opendir("/dev/graphics"); 411 if (!directory) 412 return -1; 413 414 // ToDo: the former R5 "stub" driver is called "vesa" under Haiku; however, 415 // we do not need to avoid this driver this way when is has been ported 416 // to the new driver architecture - the special case here can then be 417 // removed. 418 int count = 0; 419 struct dirent *entry = NULL; 420 int current_card_fd = -1; 421 char path[PATH_MAX]; 422 while (count < deviceNumber && (entry = readdir(directory)) != NULL) { 423 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") || 424 !strcmp(entry->d_name, "stub") || !strcmp(entry->d_name, "vesa")) 425 continue; 426 427 if (current_card_fd >= 0) { 428 close(current_card_fd); 429 current_card_fd = -1; 430 } 431 432 sprintf(path, "/dev/graphics/%s", entry->d_name); 433 current_card_fd = open(path, B_READ_WRITE); 434 if (current_card_fd >= 0) 435 count++; 436 } 437 438 // Open VESA driver if we were not able to get a better one 439 if (count < deviceNumber) { 440 if (deviceNumber == 1) { 441 sprintf(path, "/dev/graphics/vesa"); 442 current_card_fd = open(path, B_READ_WRITE); 443 } else { 444 close(current_card_fd); 445 current_card_fd = B_ENTRY_NOT_FOUND; 446 } 447 } 448 449 if (entry) 450 fCardNameInDevFS = entry->d_name; 451 452 return current_card_fd; 453} 454 455 456status_t 457DWindowHWInterface::_OpenAccelerant(int device) 458{ 459 char signature[1024]; 460 if (ioctl(device, B_GET_ACCELERANT_SIGNATURE, 461 &signature, sizeof(signature)) != B_OK) 462 return B_ERROR; 463 464 STRACE(("accelerant signature is: %s\n", signature)); 465 466 struct stat accelerant_stat; 467 const static directory_which dirs[] = { 468 B_USER_ADDONS_DIRECTORY, 469 B_COMMON_ADDONS_DIRECTORY, 470 B_SYSTEM_ADDONS_DIRECTORY 471 }; 472 473 fAccelerantImage = -1; 474 475 for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { 476 char path[PATH_MAX]; 477 if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) 478 continue; 479 480 strcat(path, "/accelerants/"); 481 strcat(path, signature); 482 if (stat(path, &accelerant_stat) != 0) 483 continue; 484 485 fAccelerantImage = load_add_on(path); 486 if (fAccelerantImage >= 0) { 487 if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT, 488 B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) { 489 STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n")); 490 unload_add_on(fAccelerantImage); 491 fAccelerantImage = -1; 492 return B_ERROR; 493 } 494 495 496 accelerant_clone_info_size cloneInfoSize; 497 cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook( 498 B_ACCELERANT_CLONE_INFO_SIZE, NULL); 499 if (!cloneInfoSize) { 500 STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path)); 501 unload_add_on(fAccelerantImage); 502 fAccelerantImage = -1; 503 return B_ERROR; 504 } 505 506 ssize_t cloneSize = cloneInfoSize(); 507 void* cloneInfoData = malloc(cloneSize); 508 509// get_accelerant_clone_info getCloneInfo; 510// getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL); 511// if (!getCloneInfo) { 512// STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path)); 513// unload_add_on(fAccelerantImage); 514// fAccelerantImage = -1; 515// return B_ERROR; 516// } 517// printf("getCloneInfo: %p\n", getCloneInfo); 518// 519// getCloneInfo(cloneInfoData); 520// TODO: this is what works for the ATI Radeon driver... 521sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String()); 522 523 clone_accelerant cloneAccelerant; 524 cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL); 525 if (!cloneAccelerant) { 526 STRACE(("unable to get B_CLONE_ACCELERANT\n")); 527 unload_add_on(fAccelerantImage); 528 fAccelerantImage = -1; 529 return B_ERROR; 530 } 531 status_t ret = cloneAccelerant(cloneInfoData); 532 if (ret != B_OK) { 533 STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret))); 534 unload_add_on(fAccelerantImage); 535 fAccelerantImage = -1; 536 return B_ERROR; 537 } 538 539 break; 540 } 541 } 542 543 if (fAccelerantImage < B_OK) 544 return B_ERROR; 545 546 if (_SetupDefaultHooks() != B_OK) { 547 STRACE(("cannot setup default hooks\n")); 548 549 uninit_accelerant uninitAccelerant = (uninit_accelerant) 550 fAccelerantHook(B_UNINIT_ACCELERANT, NULL); 551 if (uninitAccelerant != NULL) 552 uninitAccelerant(); 553 554 unload_add_on(fAccelerantImage); 555 return B_ERROR; 556 } else { 557 _UpdateFrameBufferConfig(); 558 } 559 560 return B_OK; 561} 562 563 564status_t 565DWindowHWInterface::_SetupDefaultHooks() 566{ 567 // required 568 fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL); 569 fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL); 570 fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL); 571 fAccGetModeCount = (accelerant_mode_count)fAccelerantHook( 572 B_ACCELERANT_MODE_COUNT, NULL); 573 fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL); 574 fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook( 575 B_GET_FRAME_BUFFER_CONFIG, NULL); 576 fAccSetDisplayMode = (set_display_mode)fAccelerantHook( 577 B_SET_DISPLAY_MODE, NULL); 578 fAccGetDisplayMode = (get_display_mode)fAccelerantHook( 579 B_GET_DISPLAY_MODE, NULL); 580 fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook( 581 B_GET_PIXEL_CLOCK_LIMITS, NULL); 582 583 if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig 584 || !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode 585 || !fAccGetDisplayMode || !fAccGetPixelClockLimits) { 586 return B_ERROR; 587 } 588 589 // optional 590 fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook( 591 B_GET_TIMING_CONSTRAINTS, NULL); 592 fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook( 593 B_PROPOSE_DISPLAY_MODE, NULL); 594 595 // cursor 596 fAccSetCursorShape = (set_cursor_shape)fAccelerantHook( 597 B_SET_CURSOR_SHAPE, NULL); 598 fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL); 599 fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL); 600 601 // update acceleration hooks 602 // TODO: would actually have to pass a valid display_mode! 603 fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL); 604 fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL); 605 fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook( 606 B_SCREEN_TO_SCREEN_BLIT, NULL); 607 608 return B_OK; 609} 610 611 612status_t 613DWindowHWInterface::_UpdateFrameBufferConfig() 614{ 615 frame_buffer_config config; 616 if (fAccGetFrameBufferConfig(&config) != B_OK) { 617 STRACE(("unable to get frame buffer config\n")); 618 return B_ERROR; 619 } 620 621 fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width, 622 fDisplayMode.virtual_height, (color_space)fDisplayMode.space); 623 624 return B_OK; 625} 626 627 628status_t 629DWindowHWInterface::Shutdown() 630{ 631 printf("DWindowHWInterface::Shutdown()\n"); 632 if (fAccelerantHook) { 633 uninit_accelerant UninitAccelerant 634 = (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL); 635 if (UninitAccelerant) 636 UninitAccelerant(); 637 } 638 639 if (fAccelerantImage >= 0) 640 unload_add_on(fAccelerantImage); 641 642 if (fCardFD >= 0) 643 close(fCardFD); 644 645 return B_OK; 646} 647 648 649status_t 650DWindowHWInterface::SetMode(const display_mode& mode) 651{ 652 AutoWriteLocker _(this); 653 654 status_t ret = B_OK; 655 // prevent from doing the unnecessary 656 if (fFrontBuffer 657 && fDisplayMode.virtual_width == mode.virtual_width 658 && fDisplayMode.virtual_height == mode.virtual_height 659 && fDisplayMode.space == mode.space) 660 return ret; 661 662 // check if we support the mode 663 664 display_mode *modes; 665 uint32 modeCount, i; 666 if (GetModeList(&modes, &modeCount) != B_OK) 667 return B_NO_MEMORY; 668 669 for (i = 0; i < modeCount; i++) { 670 // we only care for the bare minimum 671 if (modes[i].virtual_width == mode.virtual_width 672 && modes[i].virtual_height == mode.virtual_height 673 && modes[i].space == mode.space) { 674 // take over settings 675 fDisplayMode = modes[i]; 676 break; 677 } 678 } 679 680 delete[] modes; 681 682 if (i == modeCount) 683 return B_BAD_VALUE; 684 685 BRect frame(0.0, 0.0, 686 fDisplayMode.virtual_width - 1, 687 fDisplayMode.virtual_height - 1); 688 689 // create the window if we don't have one already 690 if (!fWindow) { 691 // if the window has not been created yet, the BApplication 692 // has not been created either, but we need one to display 693 // a real BWindow in the test environment. 694 // be_app->Run() needs to be called in another thread 695 BApplication* app = new BApplication("application/x-vnd.haiku-app-server"); 696 app->Unlock(); 697 698 thread_id appThread = spawn_thread(run_app_thread, "app thread", 699 B_NORMAL_PRIORITY, app); 700 if (appThread >= B_OK) 701 ret = resume_thread(appThread); 702 else 703 ret = appThread; 704 705 if (ret < B_OK) 706 return ret; 707 708 fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this, 709 fFrontBuffer); 710 711 // fire up the window thread but don't show it on screen yet 712 fWindow->Hide(); 713 fWindow->Show(); 714 } 715 716 if (fWindow->Lock()) { 717 // free and reallocate the bitmaps while the window is locked, 718 // so that the view does not accidentally draw a freed bitmap 719 720 if (ret >= B_OK) { 721 // change the window size and update the bitmap used for drawing 722 fWindow->ResizeTo(frame.Width(), frame.Height()); 723 } 724 725 // window is hidden when this function is called the first time 726 if (fWindow->IsHidden()) 727 fWindow->Show(); 728 729 fWindow->Unlock(); 730 } else { 731 ret = B_ERROR; 732 } 733 734 _UpdateFrameBufferConfig(); 735 _NotifyFrameBufferChanged(); 736 737 return ret; 738} 739 740 741void 742DWindowHWInterface::GetMode(display_mode* mode) 743{ 744 if (mode && ReadLock()) { 745 *mode = fDisplayMode; 746 ReadUnlock(); 747 } 748} 749 750 751status_t 752DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info) 753{ 754 // We really don't have to provide anything here because this is strictly 755 // a software-only driver, but we'll have some fun, anyway. 756 if (ReadLock()) { 757 info->version = 100; 758 sprintf(info->name, "Haiku, Inc. DWindowHWInterface"); 759 sprintf(info->chipset, "Haiku, Inc. Chipset"); 760 sprintf(info->serial_no, "3.14159265358979323846"); 761 info->memory = 134217728; // 128 MB, not that we really have that much. :) 762 info->dac_speed = 0xFFFFFFFF; // *heh* 763 764 ReadUnlock(); 765 } 766 767 return B_OK; 768} 769 770 771status_t 772DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 773{ 774 if (fFrontBuffer == NULL) 775 return B_ERROR; 776 777 config.frame_buffer = fFrontBuffer->Bits(); 778 config.frame_buffer_dma = NULL; 779 config.bytes_per_row = fFrontBuffer->BytesPerRow(); 780 781 return B_OK; 782} 783 784 785status_t 786DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count) 787{ 788 AutoReadLocker _(this); 789 790#if 1 791 // setup a whole bunch of different modes 792 const struct resolution { int32 width, height; } resolutions[] = { 793 {640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960}, 794 {1280, 1024}, {1400, 1050}, {1600, 1200} 795 }; 796 uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]); 797// const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32}; 798 uint32 count = resolutionCount/* * 4*/; 799 800 display_mode* modes = new(std::nothrow) display_mode[count]; 801 if (modes == NULL) 802 return B_NO_MEMORY; 803 804 *_modes = modes; 805 *_count = count; 806 807 int32 index = 0; 808 for (uint32 i = 0; i < resolutionCount; i++) { 809 modes[index].virtual_width = resolutions[i].width; 810 modes[index].virtual_height = resolutions[i].height; 811 modes[index].space = B_RGB32; 812 813 modes[index].h_display_start = 0; 814 modes[index].v_display_start = 0; 815 modes[index].timing.h_display = resolutions[i].width; 816 modes[index].timing.v_display = resolutions[i].height; 817 modes[index].timing.h_total = 22000; 818 modes[index].timing.v_total = 22000; 819 modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total 820 * modes[index].timing.v_total * 60) / 1000; 821 modes[index].flags = B_PARALLEL_ACCESS; 822 823 index++; 824 } 825#else 826 // support only a single mode, useful 827 // for testing a specific mode 828 display_mode *modes = new(std::nothrow) display_mode[1]; 829 modes[0].virtual_width = 800; 830 modes[0].virtual_height = 600; 831 modes[0].space = B_BRGB32; 832 833 *_modes = modes; 834 *_count = 1; 835#endif 836 837 return B_OK; 838} 839 840 841status_t 842DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 843 uint32* high) 844{ 845 return B_ERROR; 846} 847 848 849status_t 850DWindowHWInterface::GetTimingConstraints( 851 display_timing_constraints* constraints) 852{ 853 return B_ERROR; 854} 855 856 857status_t 858DWindowHWInterface::ProposeMode(display_mode* candidate, 859 const display_mode* low, const display_mode* high) 860{ 861 // We should be able to get away with this because we're not dealing with 862 // any specific hardware. This is a Good Thing(TM) because we can support 863 // any hardware we wish within reasonable expectaions and programmer 864 // laziness. :P 865 return B_OK; 866} 867 868 869sem_id 870DWindowHWInterface::RetraceSemaphore() 871{ 872 return -1; 873} 874 875 876status_t 877DWindowHWInterface::WaitForRetrace(bigtime_t timeout) 878{ 879 // Locking shouldn't be necessary here - R5 should handle this for us. :) 880 BScreen screen; 881 return screen.WaitForRetrace(timeout); 882} 883 884 885status_t 886DWindowHWInterface::SetDPMSMode(uint32 state) 887{ 888 AutoWriteLocker _(this); 889 890 return BScreen().SetDPMS(state); 891} 892 893 894uint32 895DWindowHWInterface::DPMSMode() 896{ 897 AutoReadLocker _(this); 898 899 return BScreen().DPMSState(); 900} 901 902 903uint32 904DWindowHWInterface::DPMSCapabilities() 905{ 906 AutoReadLocker _(this); 907 908 return BScreen().DPMSCapabilites(); 909} 910 911 912uint32 913DWindowHWInterface::AvailableHWAcceleration() const 914{ 915 uint32 flags = 0; 916 917 if (!IsDoubleBuffered()) { 918 if (fAccScreenBlit) 919 flags |= HW_ACC_COPY_REGION; 920 if (fAccFillRect) 921 flags |= HW_ACC_FILL_REGION; 922 if (fAccInvertRect) 923 flags |= HW_ACC_INVERT_REGION; 924 } 925 926 return flags; 927} 928 929 930void 931DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList, 932 uint32 count, int32 xOffset, int32 yOffset) 933{ 934 if (fAccScreenBlit && fAccAcquireEngine) { 935 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 936 &fEngineToken) >= B_OK) { 937 // make sure the blit_params cache is large enough 938 if (fBlitParamsCount < count) { 939 fBlitParamsCount = (count / kDefaultParamsCount + 1) 940 * kDefaultParamsCount; 941 // NOTE: realloc() could be used instead... 942 blit_params* params 943 = new(std::nothrow) blit_params[fBlitParamsCount]; 944 if (params) { 945 delete[] fBlitParams; 946 fBlitParams = params; 947 } else { 948 count = fBlitParamsCount; 949 } 950 } 951 // convert the rects 952 for (uint32 i = 0; i < count; i++) { 953 fBlitParams[i].src_left 954 = (uint16)sortedRectList[i].left + fXOffset; 955 fBlitParams[i].src_top 956 = (uint16)sortedRectList[i].top + fYOffset; 957 958 fBlitParams[i].dest_left 959 = (uint16)sortedRectList[i].left + xOffset + fXOffset; 960 fBlitParams[i].dest_top 961 = (uint16)sortedRectList[i].top + yOffset + fYOffset; 962 963 // NOTE: width and height are expressed as distance, not count! 964 fBlitParams[i].width = (uint16)(sortedRectList[i].right 965 - sortedRectList[i].left); 966 fBlitParams[i].height = (uint16)(sortedRectList[i].bottom 967 - sortedRectList[i].top); 968 } 969 970 // go 971 fAccScreenBlit(fEngineToken, fBlitParams, count); 972 973 // done 974 if (fAccReleaseEngine) 975 fAccReleaseEngine(fEngineToken, &fSyncToken); 976 977 // sync 978 if (fAccSyncToToken) 979 fAccSyncToToken(&fSyncToken); 980 } 981 } 982} 983 984 985void 986DWindowHWInterface::FillRegion(/*const*/ BRegion& region, 987 const rgb_color& color, bool autoSync) 988{ 989 if (fAccFillRect && fAccAcquireEngine) { 990 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 991 &fEngineToken) >= B_OK) { 992 // convert the region 993 uint32 count; 994 _RegionToRectParams(®ion, &count); 995 996 // go 997 fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count); 998 999 // done 1000 if (fAccReleaseEngine) 1001 fAccReleaseEngine(fEngineToken, &fSyncToken); 1002 1003 // sync 1004 if (autoSync && fAccSyncToToken) 1005 fAccSyncToToken(&fSyncToken); 1006 } 1007 } 1008} 1009 1010 1011void 1012DWindowHWInterface::InvertRegion(/*const*/ BRegion& region) 1013{ 1014 if (fAccInvertRect && fAccAcquireEngine) { 1015 if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, 1016 &fEngineToken) >= B_OK) { 1017 // convert the region 1018 uint32 count; 1019 _RegionToRectParams(®ion, &count); 1020 1021 // go 1022 fAccInvertRect(fEngineToken, fRectParams, count); 1023 1024 // done 1025 if (fAccReleaseEngine) 1026 fAccReleaseEngine(fEngineToken, &fSyncToken); 1027 1028 // sync 1029 if (fAccSyncToToken) 1030 fAccSyncToToken(&fSyncToken); 1031 1032 } else { 1033 fprintf(stderr, "AcquireEngine failed!\n"); 1034 } 1035 } else { 1036 fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but " 1037 "hook not available!\n"); 1038 } 1039} 1040 1041 1042void 1043DWindowHWInterface::Sync() 1044{ 1045 if (fAccSyncToToken) 1046 fAccSyncToToken(&fSyncToken); 1047} 1048 1049 1050RenderingBuffer* 1051DWindowHWInterface::FrontBuffer() const 1052{ 1053 return fFrontBuffer; 1054} 1055 1056 1057RenderingBuffer* 1058DWindowHWInterface::BackBuffer() const 1059{ 1060 return fFrontBuffer; 1061} 1062 1063 1064bool 1065DWindowHWInterface::IsDoubleBuffered() const 1066{ 1067 return false; 1068} 1069 1070 1071status_t 1072DWindowHWInterface::Invalidate(const BRect& frame) 1073{ 1074 return HWInterface::Invalidate(frame); 1075} 1076 1077 1078void 1079DWindowHWInterface::SetOffset(int32 left, int32 top) 1080{ 1081 if (!WriteLock()) 1082 return; 1083 1084 fXOffset = left; 1085 fYOffset = top; 1086 1087 _UpdateFrameBufferConfig(); 1088 1089 // TODO: someone would have to call DrawingEngine::Update() now! 1090 1091 WriteUnlock(); 1092} 1093 1094 1095void 1096DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region, 1097 uint32* count) const 1098{ 1099 *count = region->CountRects(); 1100 if (fRectParamsCount < *count) { 1101 fRectParamsCount = (*count / kDefaultParamsCount + 1) 1102 * kDefaultParamsCount; 1103 // NOTE: realloc() could be used instead... 1104 fill_rect_params* params 1105 = new(std::nothrow) fill_rect_params[fRectParamsCount]; 1106 if (params) { 1107 delete[] fRectParams; 1108 fRectParams = params; 1109 } else { 1110 *count = fRectParamsCount; 1111 } 1112 } 1113 1114 for (uint32 i = 0; i < *count; i++) { 1115 clipping_rect r = region->RectAtInt(i); 1116 fRectParams[i].left = (uint16)r.left + fXOffset; 1117 fRectParams[i].top = (uint16)r.top + fYOffset; 1118 fRectParams[i].right = (uint16)r.right + fXOffset; 1119 fRectParams[i].bottom = (uint16)r.bottom + fYOffset; 1120 } 1121} 1122 1123 1124uint32 1125DWindowHWInterface::_NativeColor(const rgb_color& color) const 1126{ 1127 // NOTE: This functions looks somehow suspicios to me. 1128 // It assumes that all graphics cards have the same native endianess, no? 1129 switch (fDisplayMode.space) { 1130 case B_CMAP8: 1131 case B_GRAY8: 1132 return RGBColor(color).GetColor8(); 1133 1134 case B_RGB15_BIG: 1135 case B_RGBA15_BIG: 1136 case B_RGB15_LITTLE: 1137 case B_RGBA15_LITTLE: 1138 return RGBColor(color).GetColor15(); 1139 1140 case B_RGB16_BIG: 1141 case B_RGB16_LITTLE: 1142 return RGBColor(color).GetColor16(); 1143 1144 case B_RGB32_BIG: 1145 case B_RGBA32_BIG: 1146 case B_RGB32_LITTLE: 1147 case B_RGBA32_LITTLE: { 1148 uint32 native = (color.alpha << 24) | (color.red << 16) 1149 | (color.green << 8) | (color.blue); 1150 return native; 1151 } 1152 } 1153 return 0; 1154} 1155