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 49const 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 55static const bool kDefaultDoubleBuffered = true; 56 57enum { 58 MSG_UPDATE = 'updt' 59}; 60 61 62const char* 63string_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 113static int32 114run_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 128class CardView : public BView { 129public: 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 142private: 143 port_id fInputPort; 144 const BBitmap* fBitmap; 145}; 146 147class CardWindow : public BWindow { 148public: 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 159private: 160 CardView* fView; 161 BRegion fUpdateRegion; 162 BLocker fUpdateLock; 163}; 164 165class CardMessageFilter : public BMessageFilter { 166public: 167 CardMessageFilter(CardView* view); 168 169 virtual filter_result Filter(BMessage* message, BHandler** _target); 170 171private: 172 CardView* fView; 173}; 174 175 176// #pragma mark - 177 178 179CardView::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 198CardView::~CardView() 199{ 200} 201 202 203void 204CardView::AttachedToWindow() 205{ 206} 207 208 209void 210CardView::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*/ 221void 222CardView::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 245void 246CardView::MessageReceived(BMessage* message) 247{ 248 switch (message->what) { 249 default: 250 BView::MessageReceived(message); 251 break; 252 } 253} 254 255 256void 257CardView::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 271CardMessageFilter::CardMessageFilter(CardView* view) 272 : 273 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 274 fView(view) 275{ 276} 277 278 279filter_result 280CardMessageFilter::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 318CardWindow::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 332CardWindow::~CardWindow() 333{ 334} 335 336 337void 338CardWindow::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 369bool 370CardWindow::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 386void 387CardWindow::SetBitmap(const BBitmap* bitmap) 388{ 389 fView->SetBitmap(bitmap); 390} 391 392 393void 394CardWindow::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 406ViewHWInterface::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 421ViewHWInterface::~ViewHWInterface() 422{ 423 if (fWindow) { 424 fWindow->Lock(); 425 fWindow->Quit(); 426 } 427 428 be_app->Lock(); 429 be_app->Quit(); 430} 431 432 433status_t 434ViewHWInterface::Initialize() 435{ 436 return B_OK; 437} 438 439 440status_t 441ViewHWInterface::Shutdown() 442{ 443 return B_OK; 444} 445 446 447status_t 448ViewHWInterface::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 587void 588ViewHWInterface::GetMode(display_mode* mode) 589{ 590 if (mode && ReadLock()) { 591 *mode = fDisplayMode; 592 ReadUnlock(); 593 } 594} 595 596 597status_t 598ViewHWInterface::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 617status_t 618ViewHWInterface::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 631status_t 632ViewHWInterface::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 689status_t 690ViewHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, 691 uint32* high) 692{ 693 return B_ERROR; 694} 695 696 697status_t 698ViewHWInterface::GetTimingConstraints(display_timing_constraints* constraints) 699{ 700 return B_ERROR; 701} 702 703 704status_t 705ViewHWInterface::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 716status_t 717ViewHWInterface::SetDPMSMode(uint32 state) 718{ 719 AutoWriteLocker _(this); 720 721 return BScreen().SetDPMS(state); 722} 723 724 725uint32 726ViewHWInterface::DPMSMode() 727{ 728 AutoReadLocker _(this); 729 730 return BScreen().DPMSState(); 731} 732 733 734uint32 735ViewHWInterface::DPMSCapabilities() 736{ 737 AutoReadLocker _(this); 738 739 return BScreen().DPMSCapabilites(); 740} 741 742 743status_t 744ViewHWInterface::SetBrightness(float brightness) 745{ 746 AutoReadLocker _(this); 747 748 return BScreen().SetBrightness(brightness); 749} 750 751 752status_t 753ViewHWInterface::GetBrightness(float* brightness) 754{ 755 AutoReadLocker _(this); 756 757 return BScreen().GetBrightness(brightness); 758} 759 760 761sem_id 762ViewHWInterface::RetraceSemaphore() 763{ 764 return -1; 765} 766 767 768status_t 769ViewHWInterface::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 777RenderingBuffer* 778ViewHWInterface::FrontBuffer() const 779{ 780 return fFrontBuffer.Get(); 781} 782 783 784RenderingBuffer* 785ViewHWInterface::BackBuffer() const 786{ 787 return fBackBuffer.Get(); 788} 789 790 791bool 792ViewHWInterface::IsDoubleBuffered() const 793{ 794 if (fFrontBuffer.IsSet()) 795 return fBackBuffer.IsSet(); 796 797 return false; 798} 799 800 801status_t 802ViewHWInterface::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 812status_t 813ViewHWInterface::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