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 * Stephan Aßmus <superstippi@gmx.de> 8 */ 9 10 11 /*! BView/BWindow combination HWInterface implementation */ 12 13 14 #include "ViewHWInterface.h" 15 16 #include <new> 17 #include <stdio.h> 18 19 #include <Application.h> 20 #include <Bitmap.h> 21 #include <Cursor.h> 22 #include <Locker.h> 23 #include <Message.h> 24 #include <MessageFilter.h> 25 #include <MessageRunner.h> 26 #include <Region.h> 27 #include <Screen.h> 28 #include <String.h> 29 #include <View.h> 30 #include <Window.h> 31 32 #include <ServerProtocol.h> 33 34 #include "BBitmapBuffer.h" 35 #include "PortLink.h" 36 #include "ServerConfig.h" 37 #include "ServerCursor.h" 38 #include "UpdateQueue.h" 39 40 41 #ifdef DEBUG_DRIVER_MODULE 42 # include <stdio.h> 43 # define STRACE(x) printf x 44 #else 45 # define STRACE(x) ; 46 #endif 47 48 49 const unsigned char kEmptyCursor[] = { 16, 1, 0, 0, 50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 54 55 static const bool kDefaultDoubleBuffered = true; 56 57 enum { 58 MSG_UPDATE = 'updt' 59 }; 60 61 62 const char* 63 string_for_color_space(color_space format) 64 { 65 const char* name = "<unkown format>"; 66 switch (format) { 67 case B_RGBA64: 68 name = "B_RGBA64"; 69 break; 70 case B_RGBA64_BIG: 71 name = "B_RGBA64_BIG"; 72 break; 73 case B_RGB48: 74 name = "B_RGB48"; 75 break; 76 case B_RGB48_BIG: 77 name = "B_RGB48_BIG"; 78 break; 79 case B_RGB32: 80 name = "B_RGB32"; 81 break; 82 case B_RGBA32: 83 name = "B_RGBA32"; 84 break; 85 case B_RGB32_BIG: 86 name = "B_RGB32_BIG"; 87 break; 88 case B_RGBA32_BIG: 89 name = "B_RGBA32_BIG"; 90 break; 91 case B_RGB24: 92 name = "B_RGB24"; 93 break; 94 case B_RGB24_BIG: 95 name = "B_RGB24_BIG"; 96 break; 97 case B_CMAP8: 98 name = "B_CMAP8"; 99 break; 100 case B_GRAY8: 101 name = "B_GRAY8"; 102 break; 103 case B_GRAY1: 104 name = "B_GRAY1"; 105 break; 106 default: 107 break; 108 } 109 return name; 110 } 111 112 113 static int32 114 run_app_thread(void* cookie) 115 { 116 if (BApplication* app = (BApplication*)cookie) { 117 app->Lock(); 118 app->Run(); 119 delete app; 120 } 121 return 0; 122 } 123 124 125 //#define INPUTSERVER_TEST_MODE 1 126 127 128 class CardView : public BView { 129 public: 130 CardView(BRect bounds); 131 virtual ~CardView(); 132 133 virtual void AttachedToWindow(); 134 virtual void Draw(BRect updateRect); 135 virtual void MessageReceived(BMessage* message); 136 137 // CardView 138 void SetBitmap(const BBitmap* bitmap); 139 140 void ForwardMessage(BMessage* message = NULL); 141 142 private: 143 port_id fInputPort; 144 const BBitmap* fBitmap; 145 }; 146 147 class CardWindow : public BWindow { 148 public: 149 CardWindow(BRect frame); 150 virtual ~CardWindow(); 151 152 virtual void MessageReceived(BMessage* message); 153 virtual bool QuitRequested(); 154 155 // CardWindow 156 void SetBitmap(const BBitmap* bitmap); 157 void Invalidate(const BRect& area); 158 159 private: 160 CardView* fView; 161 BRegion fUpdateRegion; 162 BLocker fUpdateLock; 163 }; 164 165 class CardMessageFilter : public BMessageFilter { 166 public: 167 CardMessageFilter(CardView* view); 168 169 virtual filter_result Filter(BMessage* message, BHandler** _target); 170 171 private: 172 CardView* fView; 173 }; 174 175 176 // #pragma mark - 177 178 179 CardView::CardView(BRect bounds) 180 : 181 BView(bounds, "graphics card view", B_FOLLOW_ALL, B_WILL_DRAW), 182 fBitmap(NULL) 183 { 184 SetViewColor(B_TRANSPARENT_32_BIT); 185 186 #ifndef INPUTSERVER_TEST_MODE 187 fInputPort = create_port(200, SERVER_INPUT_PORT); 188 #else 189 fInputPort = create_port(100, "ViewInputDevice"); 190 #endif 191 192 #ifdef ENABLE_INPUT_SERVER_EMULATION 193 AddFilter(new CardMessageFilter(this)); 194 #endif 195 } 196 197 198 CardView::~CardView() 199 { 200 } 201 202 203 void 204 CardView::AttachedToWindow() 205 { 206 } 207 208 209 void 210 CardView::Draw(BRect updateRect) 211 { 212 if (fBitmap != NULL) 213 DrawBitmapAsync(fBitmap, updateRect, updateRect); 214 } 215 216 217 /*! These functions emulate the Input Server by sending the *exact* same kind of 218 messages to the server's port. Being we're using a regular window, it would 219 make little sense to do anything else. 220 */ 221 void 222 CardView::ForwardMessage(BMessage* message) 223 { 224 if (message == NULL) 225 message = Window()->CurrentMessage(); 226 if (message == NULL) 227 return; 228 229 // remove some fields that potentially mess up our own message processing 230 BMessage copy = *message; 231 copy.RemoveName("screen_where"); 232 copy.RemoveName("be:transit"); 233 copy.RemoveName("be:view_where"); 234 copy.RemoveName("be:cursor_needed"); 235 copy.RemoveName("_view_token"); 236 237 size_t length = copy.FlattenedSize(); 238 char stream[length]; 239 240 if (copy.Flatten(stream, length) == B_OK) 241 write_port(fInputPort, 0, stream, length); 242 } 243 244 245 void 246 CardView::MessageReceived(BMessage* message) 247 { 248 switch (message->what) { 249 default: 250 BView::MessageReceived(message); 251 break; 252 } 253 } 254 255 256 void 257 CardView::SetBitmap(const BBitmap* bitmap) 258 { 259 if (bitmap != fBitmap) { 260 fBitmap = bitmap; 261 262 if (Parent()) 263 Invalidate(); 264 } 265 } 266 267 268 // #pragma mark - 269 270 271 CardMessageFilter::CardMessageFilter(CardView* view) 272 : 273 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 274 fView(view) 275 { 276 } 277 278 279 filter_result 280 CardMessageFilter::Filter(BMessage* message, BHandler** target) 281 { 282 switch (message->what) { 283 case B_KEY_DOWN: 284 case B_UNMAPPED_KEY_DOWN: 285 case B_KEY_UP: 286 case B_UNMAPPED_KEY_UP: 287 case B_MOUSE_DOWN: 288 case B_MOUSE_UP: 289 case B_MOUSE_WHEEL_CHANGED: 290 if (message->what == B_MOUSE_DOWN) 291 fView->SetMouseEventMask(B_POINTER_EVENTS); 292 293 fView->ForwardMessage(message); 294 return B_SKIP_MESSAGE; 295 296 case B_MOUSE_MOVED: 297 { 298 int32 transit; 299 if (message->FindInt32("be:transit", &transit) == B_OK 300 && transit == B_ENTERED_VIEW) { 301 // A bug in R5 prevents this call from having an effect if 302 // called elsewhere, and calling it here works, if we're lucky :-) 303 BCursor cursor(kEmptyCursor); 304 fView->SetViewCursor(&cursor, true); 305 } 306 fView->ForwardMessage(message); 307 return B_SKIP_MESSAGE; 308 } 309 } 310 311 return B_DISPATCH_MESSAGE; 312 } 313 314 315 // #pragma mark - 316 317 318 CardWindow::CardWindow(BRect frame) 319 : 320 BWindow(frame, "Haiku App Server", B_TITLED_WINDOW, 321 B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NO_SERVER_SIDE_WINDOW_MODIFIERS), 322 fUpdateRegion(), 323 fUpdateLock("update lock") 324 { 325 fView = new CardView(Bounds()); 326 AddChild(fView); 327 fView->MakeFocus(); 328 // make it receive key events 329 } 330 331 332 CardWindow::~CardWindow() 333 { 334 } 335 336 337 void 338 CardWindow::MessageReceived(BMessage* msg) 339 { 340 STRACE("CardWindow::MessageReceived()\n"); 341 switch (msg->what) { 342 case MSG_UPDATE: 343 STRACE("MSG_UPDATE\n"); 344 // invalidate all areas in the view that need redrawing 345 if (fUpdateLock.LockWithTimeout(2000LL) >= B_OK) { 346 /* int32 count = fUpdateRegion.CountRects(); 347 for (int32 i = 0; i < count; i++) { 348 fView->Invalidate(fUpdateRegion.RectAt(i)); 349 }*/ 350 BRect frame = fUpdateRegion.Frame(); 351 if (frame.IsValid()) { 352 fView->Invalidate(frame); 353 // fView->Invalidate(); 354 } 355 fUpdateRegion.MakeEmpty(); 356 fUpdateLock.Unlock(); 357 } else { 358 // see you next time 359 } 360 break; 361 default: 362 BWindow::MessageReceived(msg); 363 break; 364 } 365 STRACE("CardWindow::MessageReceived() - exit\n"); 366 } 367 368 369 bool 370 CardWindow::QuitRequested() 371 { 372 port_id serverport = find_port(SERVER_PORT_NAME); 373 374 if (serverport >= 0) { 375 BPrivate::PortLink link(serverport); 376 link.StartMessage(B_QUIT_REQUESTED); 377 link.Flush(); 378 } else 379 printf("ERROR: couldn't find the app_server's main port!"); 380 381 // we don't quit on ourself, we let us be Quit()! 382 return false; 383 } 384 385 386 void 387 CardWindow::SetBitmap(const BBitmap* bitmap) 388 { 389 fView->SetBitmap(bitmap); 390 } 391 392 393 void 394 CardWindow::Invalidate(const BRect& frame) 395 { 396 if (LockWithTimeout(1000000) >= B_OK) { 397 fView->Invalidate(frame); 398 Unlock(); 399 } 400 } 401 402 403 // #pragma mark - 404 405 406 ViewHWInterface::ViewHWInterface() 407 : 408 HWInterface(), 409 fBackBuffer(NULL), 410 fFrontBuffer(NULL), 411 fWindow(NULL) 412 { 413 SetAsyncDoubleBuffered(kDefaultDoubleBuffered); 414 415 fDisplayMode.virtual_width = 640; 416 fDisplayMode.virtual_height = 480; 417 fDisplayMode.space = B_RGBA32; 418 } 419 420 421 ViewHWInterface::~ViewHWInterface() 422 { 423 if (fWindow) { 424 fWindow->Lock(); 425 fWindow->Quit(); 426 } 427 428 be_app->Lock(); 429 be_app->Quit(); 430 } 431 432 433 status_t 434 ViewHWInterface::Initialize() 435 { 436 return B_OK; 437 } 438 439 440 status_t 441 ViewHWInterface::Shutdown() 442 { 443 return B_OK; 444 } 445 446 447 status_t 448 ViewHWInterface::SetMode(const display_mode& mode) 449 { 450 AutoWriteLocker _(this); 451 452 status_t ret = B_OK; 453 // prevent from doing the unnecessary 454 if (fBackBuffer.IsSet() && fFrontBuffer.IsSet() 455 && fDisplayMode.virtual_width == mode.virtual_width 456 && fDisplayMode.virtual_height == mode.virtual_height 457 && fDisplayMode.space == mode.space) 458 return ret; 459 460 // check if we support the mode 461 462 display_mode* modes; 463 uint32 modeCount, i; 464 if (GetModeList(&modes, &modeCount) != B_OK) 465 return B_NO_MEMORY; 466 467 for (i = 0; i < modeCount; i++) { 468 // we only care for the bare minimum 469 if (modes[i].virtual_width == mode.virtual_width 470 && modes[i].virtual_height == mode.virtual_height 471 && modes[i].space == mode.space) { 472 // take over settings 473 fDisplayMode = modes[i]; 474 break; 475 } 476 } 477 478 delete[] modes; 479 480 if (i == modeCount) 481 return B_BAD_VALUE; 482 483 BRect frame(0.0, 0.0, fDisplayMode.virtual_width - 1, 484 fDisplayMode.virtual_height - 1); 485 486 // create the window if we don't have one already 487 if (!fWindow) { 488 // if the window has not been created yet, the BApplication 489 // has not been created either, but we need one to display 490 // a real BWindow in the test environment. 491 // be_app->Run() needs to be called in another thread 492 493 if (be_app == NULL) { 494 BApplication* app = new BApplication( 495 "application/x-vnd.Haiku-test-app_server"); 496 app->Unlock(); 497 498 thread_id appThread = spawn_thread(run_app_thread, "app thread", 499 B_NORMAL_PRIORITY, app); 500 if (appThread >= B_OK) 501 ret = resume_thread(appThread); 502 else 503 ret = appThread; 504 505 if (ret < B_OK) 506 return ret; 507 } 508 509 fWindow = new CardWindow(frame.OffsetToCopy(BPoint(50.0, 50.0))); 510 511 // fire up the window thread but don't show it on screen yet 512 fWindow->Hide(); 513 fWindow->Show(); 514 } 515 516 if (fWindow->Lock()) { 517 // just to be save 518 fWindow->SetBitmap(NULL); 519 520 // free and reallocate the bitmaps while the window is locked, 521 // so that the view does not accidentally draw a freed bitmap 522 fBackBuffer.Unset(); 523 fFrontBuffer.Unset(); 524 525 // NOTE: backbuffer is always B_RGBA32, this simplifies the 526 // drawing backend implementation tremendously for the time 527 // being. The color space conversion is handled in CopyBackToFront() 528 529 // TODO: Above not true anymore for single buffered mode!!! 530 // -> fall back to double buffer for fDisplayMode.space != B_RGB32 531 // as intermediate solution... 532 bool doubleBuffered = true; 533 if ((color_space)fDisplayMode.space != B_RGB32 534 && (color_space)fDisplayMode.space != B_RGBA32) 535 doubleBuffered = true; 536 537 BBitmap* frontBitmap 538 = new BBitmap(frame, 0, (color_space)fDisplayMode.space); 539 fFrontBuffer.SetTo(new BBitmapBuffer(frontBitmap)); 540 541 status_t err = fFrontBuffer->InitCheck(); 542 if (err < B_OK) { 543 fFrontBuffer.Unset(); 544 ret = err; 545 } 546 547 if (err >= B_OK && doubleBuffered) { 548 // backbuffer is always B_RGBA32 549 // since we override IsDoubleBuffered(), the drawing buffer 550 // is in effect also always B_RGBA32. 551 BBitmap* backBitmap = new BBitmap(frame, 0, B_RGBA32); 552 fBackBuffer.SetTo(new BBitmapBuffer(backBitmap)); 553 554 err = fBackBuffer->InitCheck(); 555 if (err < B_OK) { 556 fBackBuffer.Unset(); 557 ret = err; 558 } 559 } 560 561 _NotifyFrameBufferChanged(); 562 563 if (ret >= B_OK) { 564 // clear out buffers, alpha is 255 this way 565 // TODO: maybe this should handle different color spaces in different ways 566 if (fBackBuffer.IsSet()) 567 memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength()); 568 memset(fFrontBuffer->Bits(), 255, fFrontBuffer->BitsLength()); 569 570 // change the window size and update the bitmap used for drawing 571 fWindow->ResizeTo(frame.Width(), frame.Height()); 572 fWindow->SetBitmap(fFrontBuffer->Bitmap()); 573 } 574 575 // window is hidden when this function is called the first time 576 if (fWindow->IsHidden()) 577 fWindow->Show(); 578 579 fWindow->Unlock(); 580 } else { 581 ret = B_ERROR; 582 } 583 return ret; 584 } 585 586 587 void 588 ViewHWInterface::GetMode(display_mode* mode) 589 { 590 if (mode && ReadLock()) { 591 *mode = fDisplayMode; 592 ReadUnlock(); 593 } 594 } 595 596 597 status_t 598 ViewHWInterface::GetDeviceInfo(accelerant_device_info* info) 599 { 600 // We really don't have to provide anything here because this is strictly 601 // a software-only driver, but we'll have some fun, anyway. 602 if (ReadLock()) { 603 info->version = 100; 604 sprintf(info->name, "Haiku, Inc. ViewHWInterface"); 605 sprintf(info->chipset, "Haiku, Inc. Chipset"); 606 sprintf(info->serial_no, "3.14159265358979323846"); 607 info->memory = 134217728; // 128 MB, not that we really have that much. :) 608 info->dac_speed = 0xFFFFFFFF; // *heh* 609 610 ReadUnlock(); 611 } 612 613 return B_OK; 614 } 615 616 617 status_t 618 ViewHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 619 { 620 if (!fFrontBuffer.IsSet()) 621 return B_ERROR; 622 623 config.frame_buffer = fFrontBuffer->Bits(); 624 config.frame_buffer_dma = NULL; 625 config.bytes_per_row = fFrontBuffer->BytesPerRow(); 626 627 return B_OK; 628 } 629 630 631 status_t 632 ViewHWInterface::GetModeList(display_mode** _modes, uint32* _count) 633 { 634 AutoReadLocker _(this); 635 636 #if 1 637 // setup a whole bunch of different modes 638 const struct resolution { int32 width, height; } resolutions[] = { 639 {640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960}, 640 {1280, 1024}, {1400, 1050}, {1600, 1200} 641 }; 642 uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]); 643 const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32}; 644 uint32 count = resolutionCount * 4; 645 646 display_mode* modes = new(std::nothrow) display_mode[count]; 647 if (modes == NULL) 648 return B_NO_MEMORY; 649 650 *_modes = modes; 651 *_count = count; 652 653 int32 index = 0; 654 for (uint32 i = 0; i < resolutionCount; i++) { 655 for (uint32 c = 0; c < 4; c++) { 656 modes[index].virtual_width = resolutions[i].width; 657 modes[index].virtual_height = resolutions[i].height; 658 modes[index].space = colors[c]; 659 660 modes[index].h_display_start = 0; 661 modes[index].v_display_start = 0; 662 modes[index].timing.h_display = resolutions[i].width; 663 modes[index].timing.v_display = resolutions[i].height; 664 modes[index].timing.h_total = 22000; 665 modes[index].timing.v_total = 22000; 666 modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total 667 * modes[index].timing.v_total * 60) / 1000; 668 modes[index].flags = B_PARALLEL_ACCESS; 669 670 index++; 671 } 672 } 673 #else 674 // support only a single mode, useful 675 // for testing a specific mode 676 display_mode *modes = new(nothrow) display_mode[1]; 677 modes[0].virtual_width = 640; 678 modes[0].virtual_height = 480; 679 modes[0].space = B_CMAP8; 680 681 *_modes = modes; 682 *_count = 1; 683 #endif 684 685 return B_OK; 686 } 687 688 689 status_t 690 ViewHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 691 uint32* high) 692 { 693 return B_ERROR; 694 } 695 696 697 status_t 698 ViewHWInterface::GetTimingConstraints(display_timing_constraints* constraints) 699 { 700 return B_ERROR; 701 } 702 703 704 status_t 705 ViewHWInterface::ProposeMode(display_mode* candidate, const display_mode* low, 706 const display_mode* high) 707 { 708 // We should be able to get away with this because we're not dealing with 709 // any specific hardware. This is a Good Thing(TM) because we can support 710 // any hardware we wish within reasonable expectaions and programmer 711 // laziness. :P 712 return B_OK; 713 } 714 715 716 status_t 717 ViewHWInterface::SetDPMSMode(uint32 state) 718 { 719 AutoWriteLocker _(this); 720 721 return BScreen().SetDPMS(state); 722 } 723 724 725 uint32 726 ViewHWInterface::DPMSMode() 727 { 728 AutoReadLocker _(this); 729 730 return BScreen().DPMSState(); 731 } 732 733 734 uint32 735 ViewHWInterface::DPMSCapabilities() 736 { 737 AutoReadLocker _(this); 738 739 return BScreen().DPMSCapabilites(); 740 } 741 742 743 status_t 744 ViewHWInterface::SetBrightness(float brightness) 745 { 746 AutoReadLocker _(this); 747 748 return BScreen().SetBrightness(brightness); 749 } 750 751 752 status_t 753 ViewHWInterface::GetBrightness(float* brightness) 754 { 755 AutoReadLocker _(this); 756 757 return BScreen().GetBrightness(brightness); 758 } 759 760 761 sem_id 762 ViewHWInterface::RetraceSemaphore() 763 { 764 return -1; 765 } 766 767 768 status_t 769 ViewHWInterface::WaitForRetrace(bigtime_t timeout) 770 { 771 // Locking shouldn't be necessary here - R5 should handle this for us. :) 772 BScreen screen; 773 return screen.WaitForRetrace(timeout); 774 } 775 776 777 RenderingBuffer* 778 ViewHWInterface::FrontBuffer() const 779 { 780 return fFrontBuffer.Get(); 781 } 782 783 784 RenderingBuffer* 785 ViewHWInterface::BackBuffer() const 786 { 787 return fBackBuffer.Get(); 788 } 789 790 791 bool 792 ViewHWInterface::IsDoubleBuffered() const 793 { 794 if (fFrontBuffer.IsSet()) 795 return fBackBuffer.IsSet(); 796 797 return false; 798 } 799 800 801 status_t 802 ViewHWInterface::Invalidate(const BRect& frame) 803 { 804 status_t ret = HWInterface::Invalidate(frame); 805 806 if (ret >= B_OK && fWindow && !IsDoubleBuffered()) 807 fWindow->Invalidate(frame); 808 return ret; 809 } 810 811 812 status_t 813 ViewHWInterface::CopyBackToFront(const BRect& frame) 814 { 815 status_t ret = HWInterface::CopyBackToFront(frame); 816 817 if (ret >= B_OK && fWindow) 818 fWindow->Invalidate(frame); 819 return ret; 820 } 821