From 3294d07b156f3329d8c5839d297089ae84d5ffa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 26 Mar 2005 22:16:29 +0000 Subject: [PATCH] abstract base class and implementation using BView and BWindow of an interface to a graphics card, UpdateQueue doesn't work yet, it was going to be used to decouple frame buffer transfers to the front buffer from the drawing in the back buffer git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12056 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/drawing/HWInterface.cpp | 13 + src/servers/app/drawing/HWInterface.h | 51 + src/servers/app/drawing/UpdateQueue.cpp | 112 ++ src/servers/app/drawing/UpdateQueue.h | 36 + src/servers/app/drawing/ViewHWInterface.cpp | 1116 +++++++++++++++++++ src/servers/app/drawing/ViewHWInterface.h | 63 ++ 6 files changed, 1391 insertions(+) create mode 100644 src/servers/app/drawing/HWInterface.cpp create mode 100644 src/servers/app/drawing/HWInterface.h create mode 100644 src/servers/app/drawing/UpdateQueue.cpp create mode 100644 src/servers/app/drawing/UpdateQueue.h create mode 100644 src/servers/app/drawing/ViewHWInterface.cpp create mode 100644 src/servers/app/drawing/ViewHWInterface.h diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp new file mode 100644 index 0000000000..b58f35ced9 --- /dev/null +++ b/src/servers/app/drawing/HWInterface.cpp @@ -0,0 +1,13 @@ +// HWInterface.cpp + +#include "HWInterface.h" + +// constructor +HWInterface::HWInterface() +{ +} + +// destructor +HWInterface::~HWInterface() +{ +} diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h new file mode 100644 index 0000000000..f9207e0a99 --- /dev/null +++ b/src/servers/app/drawing/HWInterface.h @@ -0,0 +1,51 @@ +// +// Copyright 2005, Stephan Aßmus +// Distributed under the terms of the MIT License. +// +// Contains an abstract base class HWInterface that provides the +// basic functionality for frame buffer acces in the DisplayDriverPainter +// implementation. + +#ifndef HW_INTERFACE_H +#define HW_INTERFACE_H + +#include +#include +#include + +class RenderingBuffer; +class BRect; + +class HWInterface { + public: + HWInterface(); + virtual ~HWInterface(); + + virtual status_t SetMode(const display_mode &mode) = 0; +// virtual void GetMode(display_mode *mode) = 0; + + + virtual status_t GetDeviceInfo(accelerant_device_info *info) = 0; + virtual status_t GetModeList(display_mode **mode_list, + uint32 *count) = 0; + virtual status_t GetPixelClockLimits(display_mode *mode, + uint32 *low, + uint32 *high) = 0; + virtual status_t GetTimingConstraints(display_timing_constraints *dtc) = 0; + virtual status_t ProposeMode(display_mode *candidate, + const display_mode *low, + const display_mode *high) = 0; + + virtual status_t WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT) = 0; + + // frame buffer access + virtual RenderingBuffer* FrontBuffer() const = 0; + virtual RenderingBuffer* BackBuffer() const = 0; + + // Invalidate is planned to be used for scheduling an area for updating + virtual status_t Invalidate(const BRect& frame) = 0; + // while as CopyBackToFront() actually performs the operation + virtual status_t CopyBackToFront(const BRect& frame) = 0; +}; + +#endif // HW_INTERFACE_H diff --git a/src/servers/app/drawing/UpdateQueue.cpp b/src/servers/app/drawing/UpdateQueue.cpp new file mode 100644 index 0000000000..b1bd3e4d0f --- /dev/null +++ b/src/servers/app/drawing/UpdateQueue.cpp @@ -0,0 +1,112 @@ +// UpdateQueue.cpp + +#include +#include + +#include "HWInterface.h" + +#include "UpdateQueue.h" + +// constructor +UpdateQueue::UpdateQueue(HWInterface* interface) + : fInterface(interface), + fUpdateRegion(), + fUpdateExecutor(-1), + fThreadControl(-1), + fStatus(B_ERROR) + +{ + fThreadControl = create_sem(0, "update queue control"); + if (fThreadControl >= B_OK) + fStatus = B_OK; + else + fStatus = fThreadControl; + if (fStatus == B_OK) { + fUpdateExecutor = spawn_thread(_execute_updates_, "update queue runner", + B_NORMAL_PRIORITY, this); + if (fUpdateExecutor >= B_OK) { + fStatus = B_OK; + resume_thread(fUpdateExecutor); + } else + fStatus = fUpdateExecutor; + } +} + +// destructor +UpdateQueue::~UpdateQueue() +{ + if (delete_sem(fThreadControl) == B_OK) + wait_for_thread(fUpdateExecutor, &fUpdateExecutor); +} + +// InitCheck +status_t +UpdateQueue::InitCheck() +{ + return fStatus; +} + +// AddRect +void +UpdateQueue::AddRect(const BRect& rect) +{ + Lock(); + fUpdateRegion.Include(rect); + _Reschedule(); + Unlock(); +} + +// _execute_updates_ +int32 +UpdateQueue::_execute_updates_(void* cookie) +{ + UpdateQueue *gc = (UpdateQueue*)cookie; + return gc->_ExecuteUpdates(); +} + +// _ExecuteUpdates +int32 +UpdateQueue::_ExecuteUpdates() +{ + bool running = true; + while (running) { + status_t err = acquire_sem_etc(fThreadControl, 1, B_RELATIVE_TIMEOUT, + 40000); + switch (err) { + case B_OK: + case B_TIMED_OUT: + // execute updates + if (Lock()) { +// if (fInterface->Lock()) { + int32 count = fUpdateRegion.CountRects(); + for (int32 i = 0; i < count; i++) { + fInterface->CopyBackToFront(fUpdateRegion.RectAt(i)); + } +// fInterface->Unlock(); + fUpdateRegion.MakeEmpty(); +// } + Unlock(); + } + break; + case B_BAD_SEM_ID: + running = false; + break; + default: + break; + } + } + return 0; +} + +// _Reschedule +// +// PRE: The object must be locked. +void +UpdateQueue::_Reschedule() +{ + if (fStatus == B_OK) { + if (fUpdateRegion.Frame().IsValid()) + release_sem(fThreadControl); + } +} + diff --git a/src/servers/app/drawing/UpdateQueue.h b/src/servers/app/drawing/UpdateQueue.h new file mode 100644 index 0000000000..bb86edeaba --- /dev/null +++ b/src/servers/app/drawing/UpdateQueue.h @@ -0,0 +1,36 @@ +// UpdateQueue.h + +#ifndef EVENT_QUEUE_H +#define EVENT_QUEUE_H + +#include +#include +#include +#include + +class HWInterface; + +class UpdateQueue : public BLocker { + public: + UpdateQueue(HWInterface* interface); + virtual ~UpdateQueue(); + + status_t InitCheck(); + + void AddRect(const BRect& rect); + + private: + static int32 _execute_updates_(void *cookie); + int32 _ExecuteUpdates(); + + void _Reschedule(); + + HWInterface* fInterface; + + BRegion fUpdateRegion; + thread_id fUpdateExecutor; + sem_id fThreadControl; + status_t fStatus; +}; + +#endif // EVENT_QUEUE_H diff --git a/src/servers/app/drawing/ViewHWInterface.cpp b/src/servers/app/drawing/ViewHWInterface.cpp new file mode 100644 index 0000000000..6c9531f7af --- /dev/null +++ b/src/servers/app/drawing/ViewHWInterface.cpp @@ -0,0 +1,1116 @@ +//------------------------------------------------------------------------------ +// +// Copyright 2002-2005, Haiku, Inc. +// Distributed under the terms of the MIT License. +// +// +// File Name: ViewHWInterface.cpp +// Authors: DarkWyrm +// Stephan Aßmus +// Description: BView/BWindow combination HWInterface implementation +// +//------------------------------------------------------------------------------ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BitmapBuffer.h" +#include "PortLink.h" +#include "ServerConfig.h" +#include "ServerProtocol.h" +#include "UpdateQueue.h" + +#include "ViewHWInterface.h" + +#ifdef DEBUG_DRIVER_MODULE +# include +# define STRACE(x) printf x +#else +# define STRACE(x) ; +#endif + +const unsigned char kEmptyCursor[] = { 16, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +enum { + MSG_UPDATE = 'updt', +}; + +class CardView : public BView { + public: + CardView(BRect bounds); + virtual ~CardView(); + + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + virtual void MouseUp(BPoint where); + virtual void MessageReceived(BMessage* message); + + // CardView + void SetBitmap(const BBitmap* bimtap); + + inline BPortLink* ServerLink() const + { return fServerLink; } + +private: + BPortLink* fServerLink; + const BBitmap* fBitmap; + +/* int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor;*/ +}; + +class CardWindow : public BWindow { + public: + CardWindow(BRect frame); + virtual ~CardWindow(); + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + // CardWindow + void SetBitmap(const BBitmap* bitmap); + void Invalidate(const BRect& area); + + private: + CardView* fView; + BMessageRunner* fUpdateRunner; + BRegion fUpdateRegion; + BLocker fUpdateLock; +}; + + +//extern RGBColor workspace_default_color; + +CardView::CardView(BRect bounds) + : BView(bounds, "graphics card view", B_FOLLOW_ALL, B_WILL_DRAW), + fServerLink(NULL), + fBitmap(NULL) +{ + SetViewColor(B_TRANSPARENT_32_BIT); + + // This link for sending mouse messages to the Haiku app_server. + // This is only to take the place of the input_server. + port_id serverInputPort = create_port(200, SERVER_INPUT_PORT); + if (serverInputPort == B_NO_MORE_PORTS) { + debugger("ViewHWInterface: out of ports\n"); + return; + } + fServerLink = new BPortLink(serverInputPort); + + // Create a cursor which isn't just a box +/* cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + hide_cursor=0; + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds();*/ +} + +CardView::~CardView() +{ + delete fServerLink; +/* delete cursor;*/ +} + +// AttachedToWindow +void +CardView::AttachedToWindow() +{ +} + +// Draw +void +CardView::Draw(BRect updateRect) +{ + if (fBitmap) { + DrawBitmapAsync(fBitmap, updateRect, updateRect); + } +/* if (viewbmp) { + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if (hide_cursor == 0 && obscure_cursor == false) { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(), cursorframe); + SetDrawingMode(B_OP_COPY); + } + }*/ +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +// MouseDown +void +CardView::MouseDown(BPoint pt) +{ +#ifdef ENABLE_INPUT_SERVER_EMULATION + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + + if (BMessage* message = Window()->CurrentMessage()) { + uint32 buttons, mod, clicks = 1; + int64 time=(int64)real_time_clock(); + + message->FindPoint("where", &pt); + message->FindInt32("modifiers", (int32*)&mod); + message->FindInt32("buttons", (int32*)&buttons); + message->FindInt32("clicks", (int32*)&clicks); + + fServerLink->StartMessage(B_MOUSE_DOWN); + fServerLink->Attach(&time, sizeof(int64)); + fServerLink->Attach(&pt.x, sizeof(float)); + fServerLink->Attach(&pt.y, sizeof(float)); + fServerLink->Attach(&mod, sizeof(uint32)); + fServerLink->Attach(&buttons, sizeof(uint32)); + fServerLink->Attach(&clicks, sizeof(uint32)); + fServerLink->Flush(); + } +#endif +} + +// MouseMoved +void +CardView::MouseMoved(BPoint pt, uint32 transit, const BMessage* dragMessage) +{ + if (!Bounds().Contains(pt)) + return; +// TODO: no cursor support yet + + // A bug in R5 prevents this call from having an effect if + // called elsewhere, and calling it here works, if we're lucky :-) +// BCursor cursor(kEmptyCursor); +// SetViewCursor(&cursor, true); + +#ifdef ENABLE_INPUT_SERVER_EMULATION + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + if (BMessage* message = Window()->CurrentMessage()) { + uint32 buttons; + int64 time=(int64)real_time_clock(); + + message->FindInt32("buttons",(int32*)&buttons); + + fServerLink->StartMessage(B_MOUSE_MOVED); + fServerLink->Attach(&time, sizeof(int64)); + fServerLink->Attach(&pt.x, sizeof(float)); + fServerLink->Attach(&pt.y, sizeof(float)); + fServerLink->Attach(&buttons, sizeof(int32)); + fServerLink->Flush(); + } +#endif +} + +// MouseUp +void +CardView::MouseUp(BPoint pt) +{ +#ifdef ENABLE_INPUT_SERVER_EMULATION + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + + int64 time=(int64)real_time_clock(); + uint32 mod = modifiers(); + + fServerLink->StartMessage(B_MOUSE_UP); + fServerLink->Attach(&time, sizeof(int64)); + fServerLink->Attach(&pt.x, sizeof(float)); + fServerLink->Attach(&pt.y, sizeof(float)); + fServerLink->Attach(&mod, sizeof(uint32)); + fServerLink->Flush(); +#endif +} + +// MessageReceived +void +CardView::MessageReceived(BMessage* message) +{ + switch(message->what) { + default: + BView::MessageReceived(message); + break; + } +} + +// SetBitmap +void +CardView::SetBitmap(const BBitmap* bitmap) +{ + if (bitmap != fBitmap) { + fBitmap = bitmap; + + if (Parent()) + Invalidate(); + } +} + +// constructor +CardWindow::CardWindow(BRect frame) + : BWindow(frame, "Haiku App Server", B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE), + fUpdateRunner(NULL), + fUpdateRegion(), + fUpdateLock("update lock") +{ + fView = new CardView(Bounds()); + AddChild(fView); +} + +// destructor +CardWindow::~CardWindow() +{ + delete fUpdateRunner; +} + +void CardWindow::MessageReceived(BMessage *msg) +{ + BPortLink* serverLink = fView->ServerLink(); + switch(msg->what) + { + case MSG_UPDATE: + // invalidate all areas in the view that need redrawing + if (fUpdateLock.LockWithTimeout(0LL) >= B_OK) { +/* int32 count = fUpdateRegion.CountRects(); + for (int32 i = 0; i < count; i++) { + fView->Invalidate(fUpdateRegion.RectAt(i)); + }*/ + BRect frame = fUpdateRegion.Frame(); + if (frame.IsValid()) { + fView->Invalidate(frame); + fUpdateRegion.MakeEmpty(); + } + fUpdateLock.Unlock(); + } else { + // see you next time + } + break; +#ifdef ENABLE_INPUT_SERVER_EMULATION + case B_MOUSE_WHEEL_CHANGED: + { + float x,y; + msg->FindFloat("be:wheel_delta_x",&x); + msg->FindFloat("be:wheel_delta_y",&y); + int64 time=real_time_clock(); + serverLink->StartMessage(B_MOUSE_WHEEL_CHANGED); + serverLink->Attach(&time,sizeof(int64)); + serverLink->Attach(x); + serverLink->Attach(y); + serverLink->Flush(); + break; + } +#endif + case B_KEY_DOWN: + { + // Attached Data: + // 1) int64 bigtime_t object of when the message was sent + // 2) int32 raw key code (scancode) + // 3) int32 modifier-independent ASCII code for the character + // 4) int32 repeat count + // 5) int32 modifiers + // 6) int8[3] UTF-8 data generated + // 7) int8 number of bytes to follow containing the + // generated string + // 8) Character string generated by the keystroke + // 10) int8[16] state of all keys + bigtime_t systime; + int32 scancode, asciicode,repeatcount,modifiers; + int8 utf8data[4]; + BString string; + int8 keyarray[16]; + + systime=(int64)real_time_clock(); + msg->FindInt32("key",&scancode); + if(msg->FindInt32("be:key_repeat",&repeatcount)!=B_OK) + { + // TODO: see if repeatcount should be 0 or 1 when not repeating in ViewDriver + repeatcount=1; + } + msg->FindInt32("modifiers",&modifiers); + msg->FindInt32("raw_char",&asciicode); + + msg->FindInt8("byte",0,utf8data); + if(msg->FindInt8("byte",1,utf8data+1)!=B_OK) + utf8data[1]=0; + if(msg->FindInt8("byte",2,utf8data+2)!=B_OK) + utf8data[2]=0; + if(msg->FindInt8("byte",3,utf8data+3)!=B_OK) + utf8data[3]=0; + msg->FindString("bytes",&string); + for(int8 i=0;i<15;i++) + msg->FindInt8("states",i,&keyarray[i]); + serverLink->StartMessage(B_KEY_DOWN); + serverLink->Attach(&systime,sizeof(bigtime_t)); + serverLink->Attach(scancode); + serverLink->Attach(asciicode); + serverLink->Attach(repeatcount); + serverLink->Attach(modifiers); + serverLink->Attach(utf8data,sizeof(int8)*3); + serverLink->AttachString(string.String()); + serverLink->Attach(keyarray,sizeof(int8)*16); + serverLink->Flush(); + break; + } + case B_KEY_UP: + { + // Attached Data: + // 1) int64 bigtime_t object of when the message was sent + // 2) int32 raw key code (scancode) + // 3) int32 modifier-independent ASCII code for the character + // 4) int32 modifiers + // 5) int8[3] UTF-8 data generated + // 6) int8 number of bytes to follow containing the + // generated string + // 7) Character string generated by the keystroke + // 8) int8[16] state of all keys + bigtime_t systime; + int32 scancode, asciicode,modifiers; + int8 utf8data[3]; + BString string; + int8 keyarray[16]; + + systime=(int64)real_time_clock(); + msg->FindInt32("key",&scancode); + msg->FindInt32("raw_char",&asciicode); + msg->FindInt32("modifiers",&modifiers); + msg->FindInt8("byte",0,utf8data); + if(msg->FindInt8("byte",1,utf8data+1)!=B_OK) + utf8data[1]=0; + if(msg->FindInt8("byte",1,utf8data+2)!=B_OK) + utf8data[2]=0; + if(msg->FindInt8("byte",1,utf8data+3)!=B_OK) + utf8data[3]=0; + msg->FindString("bytes",&string); + for(int8 i=0;i<15;i++) + msg->FindInt8("states",i,&keyarray[i]); + serverLink->StartMessage(B_KEY_UP); + serverLink->Attach(&systime,sizeof(bigtime_t)); + serverLink->Attach(scancode); + serverLink->Attach(asciicode); + serverLink->Attach(modifiers); + serverLink->Attach(utf8data,sizeof(int8)*3); + serverLink->AttachString(string.String()); + serverLink->Attach(keyarray,sizeof(int8)*16); + serverLink->Flush(); + break; + } + case B_UNMAPPED_KEY_DOWN: + { + // Attached Data: + // 1) int64 bigtime_t object of when the message was sent + // 2) int32 raw key code (scancode) + // 3) int32 modifiers + // 4) int8[16] state of all keys + bigtime_t systime; + int32 scancode,modifiers; + int8 keyarray[16]; + + systime=(int64)real_time_clock(); + msg->FindInt32("key",&scancode); + msg->FindInt32("modifiers",&modifiers); + for(int8 i=0;i<15;i++) + msg->FindInt8("states",i,&keyarray[i]); + serverLink->StartMessage(B_UNMAPPED_KEY_DOWN); + serverLink->Attach(&systime,sizeof(bigtime_t)); + serverLink->Attach(scancode); + serverLink->Attach(modifiers); + serverLink->Attach(keyarray,sizeof(int8)*16); + serverLink->Flush(); + break; + } + case B_UNMAPPED_KEY_UP: + { + // Attached Data: + // 1) int64 bigtime_t object of when the message was sent + // 2) int32 raw key code (scancode) + // 3) int32 modifiers + // 4) int8[16] state of all keys + bigtime_t systime; + int32 scancode,modifiers; + int8 keyarray[16]; + + systime=(int64)real_time_clock(); + msg->FindInt32("key",&scancode); + msg->FindInt32("modifiers",&modifiers); + for(int8 i=0;i<15;i++) + msg->FindInt8("states",i,&keyarray[i]); + serverLink->StartMessage(B_UNMAPPED_KEY_UP); + serverLink->Attach(&systime,sizeof(bigtime_t)); + serverLink->Attach(scancode); + serverLink->Attach(modifiers); + serverLink->Attach(keyarray,sizeof(int8)*16); + serverLink->Flush(); + break; + } + case B_MODIFIERS_CHANGED: + { + // Attached Data: + // 1) int64 bigtime_t object of when the message was sent + // 2) int32 modifiers + // 3) int32 old modifiers + // 4) int8 state of all keys + bigtime_t systime; + int32 scancode,modifiers,oldmodifiers; + int8 keyarray[16]; + + systime=(int64)real_time_clock(); + msg->FindInt32("key",&scancode); + msg->FindInt32("modifiers",&modifiers); + msg->FindInt32("be:old_modifiers",&oldmodifiers); + for(int8 i=0;i<15;i++) + msg->FindInt8("states",i,&keyarray[i]); + + serverLink->StartMessage(B_MODIFIERS_CHANGED); + serverLink->Attach(&systime,sizeof(bigtime_t)); + serverLink->Attach(scancode); + serverLink->Attach(modifiers); + serverLink->Attach(oldmodifiers); + serverLink->Attach(keyarray,sizeof(int8)*16); + serverLink->Flush(); + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +// QuitRequested +bool +CardWindow::QuitRequested() +{ + port_id serverport = find_port(SERVER_PORT_NAME); + + if (serverport >= 0) { + BPortLink link(serverport); + link.StartMessage(B_QUIT_REQUESTED); + link.Flush(); + } else + printf("ERROR: couldn't find the app_server's main port!"); + + // we don't quit on ourself, we let us be Quit()! + return false; +} + +// MessageReceived +void +CardWindow::SetBitmap(const BBitmap* bitmap) +{ + fView->SetBitmap(bitmap); +} + +// Invalidate +void +CardWindow::Invalidate(const BRect& frame) +{ + if (fUpdateLock.Lock()) { + if (!fUpdateRunner) { + BMessage message(MSG_UPDATE); + fUpdateRunner = new BMessageRunner(BMessenger(this, this), &message, 20000); + } + fUpdateRegion.Include(frame); + fUpdateLock.Unlock(); + } +} + + +// constructor +ViewHWInterface::ViewHWInterface() + : HWInterface(), + fBackBuffer(NULL), + fFrontBuffer(NULL), + fWindow(NULL), + fUpdateExecutor(new UpdateQueue(this)) +{ + fDisplayMode.virtual_width = 640; + fDisplayMode.virtual_height = 480; + fDisplayMode.space = B_RGBA32; +} + +// destructor +ViewHWInterface::~ViewHWInterface() +{ + fWindow->Lock(); + fWindow->Quit(); + + delete fBackBuffer; + delete fFrontBuffer; +} +/* +bool +ViewHWInterface::Initialize() +{ + Lock(); + + // the screen should start black + framebuffer->Lock(); + rgb_color c; c.red = 0; c.blue = 0; c.green = 0; c.alpha = 255; + drawview->SetHighColor(c); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + framebuffer->Unlock(); + + hide_cursor=0; + obscure_cursor=false; + + is_initialized=true; + + // We can afford to call the above functions without locking + // because the window is locked until Show() is first called + screenwin->Show(); + Unlock(); + + return DisplayDriver::Initialize(); +} + +void ViewHWInterface::Shutdown() +{ + DisplayDriver::Shutdown(); + + Lock(); + is_initialized=false; + Unlock(); +}*/ + +// SetMode +status_t +ViewHWInterface::SetMode(const display_mode &mode) +{ + status_t ret = B_OK; + // prevent from doing the unnecessary + if (fDisplayMode.virtual_width == mode.virtual_width && + fDisplayMode.virtual_height == mode.virtual_height && + fDisplayMode.space == mode.space) { + return ret; + } + // TODO: check if the mode is valid even (ie complies to the modes we said we would support) + // or else ret = B_BAD_VALUE + + // take on settings + fDisplayMode.virtual_width = mode.virtual_width; + fDisplayMode.virtual_height = mode.virtual_height; + fDisplayMode.space = mode.space; + +// left over code +// hide_cursor=0; + + BRect frame(0.0, 0.0, + fDisplayMode.virtual_width - 1, + fDisplayMode.virtual_height - 1); + + // create the window if we don't have one already + if (!fWindow) { + fWindow = new CardWindow(frame.OffsetToCopy(BPoint(50.0, 50.0))); + + // fire up the window thread but don't show it on screen yet + fWindow->Hide(); + fWindow->Show(); + } + + if (fWindow->Lock()) { + // just to be save + fWindow->SetBitmap(NULL); + + // free and reallocate the bitmaps while the window is locked, + // so that the view does not accidentally draw a freed bitmap + delete fBackBuffer; + delete fFrontBuffer; + + BBitmap* backBitmap = new BBitmap(frame, 0, (color_space)fDisplayMode.space); + BBitmap* frontBitmap = new BBitmap(frame, 0, (color_space)fDisplayMode.space); + + fBackBuffer = new BitmapBuffer(backBitmap); + fFrontBuffer = new BitmapBuffer(frontBitmap); + + status_t err = fBackBuffer->InitCheck(); + if (err < B_OK) { + delete fBackBuffer; + fBackBuffer = NULL; + ret = err; + } + + err = fFrontBuffer->InitCheck(); + if (err < B_OK) { + delete fFrontBuffer; + fFrontBuffer = NULL; + ret = err; + } + + if (ret >= B_OK) { + // clear out buffers, alpha is 255 this way + // TODO: maybe this should handle different color spaces in different ways + memset(backBitmap->Bits(), 255, backBitmap->BitsLength()); + memset(frontBitmap->Bits(), 255, frontBitmap->BitsLength()); + + // change the window size and update the bitmap used for drawing + fWindow->ResizeTo(frame.Width(), frame.Height()); + fWindow->SetBitmap(fFrontBuffer->Bitmap()); + } + + // window is hidden when this function is called the first time + if (fWindow->IsHidden()) + fWindow->Show(); + + fWindow->Unlock(); + } else { + ret = B_ERROR; + } + return ret; +} + +/* +status_t ViewHWInterface::SetDPMSMode(const uint32 &state) +{ + if(!is_initialized) + return B_ERROR; + + // NOTE: Originally, this was a to-do item to implement software DPMS, + // but this driver will not be the official testing driver, so implementing + // this stuff the way it was intended -- blanking the server's screen but not + // the physical monitor -- is moot, but we will support blanking the + // actual monitor if it is supported. + return BScreen().SetDPMS(state); +} + +uint32 ViewHWInterface::DPMSMode() const +{ + // See note for SetDPMSMode if there are questions + return BScreen().DPMSState(); +} + +uint32 ViewHWInterface::DPMSCapabilities() const +{ + // See note for SetDPMSMode if there are questions + return BScreen().DPMSCapabilites(); +} +*/ +status_t ViewHWInterface::GetDeviceInfo(accelerant_device_info *info) +{ +// if(!info || !is_initialized) +// return B_ERROR; + + // We really don't have to provide anything here because this is strictly + // a software-only driver, but we'll have some fun, anyway. + + info->version=100; + sprintf(info->name,"Haiku, Inc. ViewHWInterface"); + sprintf(info->chipset,"Haiku, Inc. Chipset"); + sprintf(info->serial_no,"3.14159265358979323846"); + info->memory=134217728; // 128 MB, not that we really have that much. :) + info->dac_speed=0xFFFFFFFF; // *heh* + + return B_OK; +} + +status_t ViewHWInterface::GetModeList(display_mode **modes, uint32 *count) +{ +// if(!count || !is_initialized) +// return B_ERROR; + +// screenwin->Lock(); + + // DEPRECATED: + // NOTE: Originally, I was going to figure out good timing values to be + // returned in each of the modes supported, but I won't bother, being this + // won't be used much longer anyway. + + *modes=new display_mode[13]; + *count=13; + + modes[0]->virtual_width=640; + modes[0]->virtual_width=480; + modes[0]->space=B_CMAP8; + modes[1]->virtual_width=640; + modes[1]->virtual_width=480; + modes[1]->space=B_RGB16; + modes[2]->virtual_width=640; + modes[2]->virtual_width=480; + modes[2]->space=B_RGB32; + modes[3]->virtual_width=640; + modes[3]->virtual_width=480; + modes[3]->space=B_RGBA32; + + modes[4]->virtual_width=800; + modes[4]->virtual_width=600; + modes[4]->space=B_CMAP8; + modes[5]->virtual_width=800; + modes[5]->virtual_width=600; + modes[5]->space=B_RGB16; + modes[6]->virtual_width=800; + modes[6]->virtual_width=600; + modes[6]->space=B_RGB32; + + modes[7]->virtual_width=1024; + modes[7]->virtual_width=768; + modes[7]->space=B_CMAP8;; + modes[8]->virtual_width=1024; + modes[8]->virtual_width=768; + modes[8]->space=B_RGB16; + modes[9]->virtual_width=1024; + modes[9]->virtual_width=768; + modes[9]->space=B_RGB32; + + modes[10]->virtual_width=1152; + modes[10]->virtual_width=864; + modes[10]->space=B_CMAP8; + modes[11]->virtual_width=1152; + modes[11]->virtual_width=864; + modes[11]->space=B_RGB16; + modes[12]->virtual_width=1152; + modes[12]->virtual_width=864; + modes[12]->space=B_RGB32; + + for(int32 i=0; i<13; i++) + { + modes[i]->h_display_start=0; + modes[i]->v_display_start=0; + modes[i]->flags=B_PARALLEL_ACCESS; + } +// screenwin->Unlock(); + + return B_OK; +} + +status_t ViewHWInterface::GetPixelClockLimits(display_mode *mode, uint32 *low, uint32 *high) +{ +// if(!is_initialized) +// return B_ERROR; + + return B_ERROR; +} + +status_t ViewHWInterface::GetTimingConstraints(display_timing_constraints *dtc) +{ +// if(!is_initialized) +// return B_ERROR; + + return B_ERROR; +} + +status_t ViewHWInterface::ProposeMode(display_mode *candidate, const display_mode *low, const display_mode *high) +{ +// if(!is_initialized) +// return B_ERROR; + + // We should be able to get away with this because we're not dealing with any + // specific hardware. This is a Good Thing(TM) because we can support any hardware + // we wish within reasonable expectaions and programmer laziness. :P + return B_OK; +} + +// WaitForRetrace +status_t +ViewHWInterface::WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT) +{ +// if(!is_initialized) +// return B_ERROR; + + // Locking shouldn't be necessary here - R5 should handle this for us. :) + BScreen screen; + return screen.WaitForRetrace(timeout); +} + +// FrontBuffer +RenderingBuffer* +ViewHWInterface::FrontBuffer() const +{ + return fFrontBuffer; +} + +// BackBuffer +RenderingBuffer* +ViewHWInterface::BackBuffer() const +{ + return fBackBuffer; +} + +// Invalidate +status_t +ViewHWInterface::Invalidate(const BRect& frame) +{ +// TODO: get this working, figure out semaphores... +// fUpdateExecutor->AddRect(frame); +// return B_OK; + return CopyBackToFront(frame); +} + +// CopyBackToFront +status_t +ViewHWInterface::CopyBackToFront(const BRect& frame) +{ + if (!fBackBuffer || !fFrontBuffer) + return B_NO_INIT; + + // we need to mess with the area, but it is const + BRect area(frame); + + if (area.IsValid() && area.Intersects(fFrontBuffer->Bitmap()->Bounds())) { +// if we couldn't be sure the bitmaps had the same size: +// && area.Intersects(fBackBuffer->Bitmap()->Bounds())) { + + const BBitmap* from = fBackBuffer->Bitmap(); + const BBitmap* into = fFrontBuffer->Bitmap(); + + // make sure we don't copy out of bounds + area = from->Bounds() & area; +// area = into->Bounds() & area; + + uint32 srcBPR = from->BytesPerRow(); + uint32 dstBPR = into->BytesPerRow(); + uint8* dst = (uint8*)into->Bits(); + uint8* src = (uint8*)from->Bits(); + + // convert to integer coordinates + int32 x = (int32)floorf(area.left); + int32 y = (int32)floorf(area.top); + int32 right = (int32)ceilf(area.right); + int32 bottom = (int32)ceilf(area.bottom); + + int32 pixelSize = 0; + color_space dstFormat = into->ColorSpace(); + // NOTE: there is no check if the bitmaps + // are of the same format, because they are + if (dstFormat == B_RGBA32 || dstFormat == B_RGB32) { + pixelSize = 4; + } else if (dstFormat == B_RGB24) { + pixelSize = 3; + } else if (dstFormat == B_RGB15 || dstFormat == B_RGB16) { + pixelSize = 2; + } else if (dstFormat == B_GRAY8 || dstFormat == B_CMAP8) { + pixelSize = 1; + } + int32 bytes = (right - x + 1) * pixelSize; + + if (bytes > 0) { + // offset pointers to left top of area + dst += y * dstBPR + x * pixelSize; + src += y * srcBPR + x * pixelSize; + // copy + for (; y <= bottom; y++) { + memcpy(dst, src, bytes); + dst += dstBPR; + src += srcBPR; + } + } + } + // update the region on screen + fWindow->Invalidate(area); + + return B_OK; +} + + +/*void ViewHWInterface::CopyBitmap(ServerBitmap *bitmap, const BRect &source, const BRect &dest, const DrawData *d) +{ + if(!is_initialized || !bitmap || !d) + { + printf("CopyBitmap returned - not init or NULL bitmap\n"); + return; + } + + // DON't set draw data here! your existing clipping region will be deleted +// SetDrawData(d); + + // Oh, wow, is this going to be slow. Then again, ViewHWInterface was never meant to be very fast. It could + // be made significantly faster by directly copying from the source to the destination, but that would + // require implementing a lot of code. Eventually, this should be replaced, but for now, using + // DrawBitmap will at least work with a minimum of effort. + + BBitmap *mediator=new BBitmap(bitmap->Bounds(),bitmap->ColorSpace()); + memcpy(mediator->Bits(),bitmap->Bits(),bitmap->BitsLength()); + + screenwin->Lock(); + framebuffer->Lock(); + + drawview->DrawBitmap(mediator,source,dest); + drawview->Sync(); + screenwin->view->Invalidate(dest); + + framebuffer->Unlock(); + screenwin->Unlock(); + delete mediator; +} + +void ViewHWInterface::CopyToBitmap(ServerBitmap *destbmp, const BRect &sourcerect) +{ + if(!is_initialized || !destbmp) + { + printf("CopyToBitmap returned - not init or NULL bitmap\n"); + return; + } + + if(((uint32)destbmp->ColorSpace() & 0x000F) != (fDisplayMode.space & 0x000F)) + { + printf("CopyToBitmap returned - unequal buffer pixel depth\n"); + return; + } + + BRect destrect(destbmp->Bounds()), source(sourcerect); + + uint8 colorspace_size=destbmp->BitsPerPixel()/8; + + // First, clip source rect to destination + if(source.Width() > destrect.Width()) + source.right=source.left+destrect.Width(); + + if(source.Height() > destrect.Height()) + source.bottom=source.top+destrect.Height(); + + + // Second, check rectangle bounds against their own bitmaps + BRect work_rect(destbmp->Bounds()); + + if( !(work_rect.Contains(destrect)) ) + { + // something in selection must be clipped + if(destrect.left < 0) + destrect.left = 0; + if(destrect.right > work_rect.right) + destrect.right = work_rect.right; + if(destrect.top < 0) + destrect.top = 0; + if(destrect.bottom > work_rect.bottom) + destrect.bottom = work_rect.bottom; + } + + work_rect.Set(0,0,fDisplayMode.virtual_width-1,fDisplayMode.virtual_height-1); + + if(!work_rect.Contains(sourcerect)) + return; + + if( !(work_rect.Contains(source)) ) + { + // something in selection must be clipped + if(source.left < 0) + source.left = 0; + if(source.right > work_rect.right) + source.right = work_rect.right; + if(source.top < 0) + source.top = 0; + if(source.bottom > work_rect.bottom) + source.bottom = work_rect.bottom; + } + + // Set pointers to the actual data + uint8 *dest_bits = (uint8*) destbmp->Bits(); + uint8 *src_bits = (uint8*) framebuffer->Bits(); + + // Get row widths for offset looping + uint32 dest_width = uint32 (destbmp->BytesPerRow()); + uint32 src_width = uint32 (framebuffer->BytesPerRow()); + + // Offset bitmap pointers to proper spot in each bitmap + src_bits += uint32 ( (source.top * src_width) + (source.left * colorspace_size) ); + dest_bits += uint32 ( (destrect.top * dest_width) + (destrect.left * colorspace_size) ); + + + uint32 line_length = uint32 ((destrect.right - destrect.left+1)*colorspace_size); + uint32 lines = uint32 (source.bottom-source.top+1); + + for (uint32 pos_y=0; pos_yLock(); + framebuffer->Lock(); + +// screenwin->view->ConstrainClippingRegion(reg); + drawview->ConstrainClippingRegion(reg); + + framebuffer->Unlock(); + screenwin->Unlock(); +} + +bool ViewHWInterface::AcquireBuffer(FBBitmap *bmp) +{ + if(!bmp || !is_initialized) + return false; + + screenwin->Lock(); + framebuffer->Lock(); + + bmp->SetBytesPerRow(framebuffer->BytesPerRow()); + bmp->SetSpace(framebuffer->ColorSpace()); + bmp->SetSize(framebuffer->Bounds().IntegerWidth(), framebuffer->Bounds().IntegerHeight()); + bmp->SetBuffer(framebuffer->Bits()); + bmp->SetBitsPerPixel(framebuffer->ColorSpace(),framebuffer->BytesPerRow()); + + return true; +} + +void ViewHWInterface::ReleaseBuffer() +{ + if(!is_initialized) + return; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewHWInterface::Invalidate(const BRect &r) +{ + if(!is_initialized) + return; + + screenwin->Lock(); + screenwin->view->Draw(r); + screenwin->Unlock(); +} +*/ diff --git a/src/servers/app/drawing/ViewHWInterface.h b/src/servers/app/drawing/ViewHWInterface.h new file mode 100644 index 0000000000..b837b2a85a --- /dev/null +++ b/src/servers/app/drawing/ViewHWInterface.h @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Copyright 2005, Haiku, Inc. +// Distributed under the terms of the MIT License. +// +// +// File Name: ViewHWInterface.h +// Author: Stephan Aßmus +// Description: BView/BWindow combination HWInterface implementation +// +//------------------------------------------------------------------------------ +#ifndef VIEW_GRAPHICS_CARD_H +#define VIEW_GRAPHICS_CARD_H + +#include "HWInterface.h" + +class BBitmap; +class BitmapBuffer; +class CardWindow; +class UpdateQueue; + + +class ViewHWInterface : public HWInterface { + public: + ViewHWInterface(); + virtual ~ViewHWInterface(); + + virtual status_t SetMode(const display_mode &mode); +// virtual void GetMode(display_mode *mode); + + + virtual status_t GetDeviceInfo(accelerant_device_info *info); + virtual status_t GetModeList(display_mode **mode_list, + uint32 *count); + virtual status_t GetPixelClockLimits(display_mode *mode, + uint32 *low, + uint32 *high); + virtual status_t GetTimingConstraints(display_timing_constraints *dtc); + virtual status_t ProposeMode(display_mode *candidate, + const display_mode *low, + const display_mode *high); + + virtual status_t WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT); + + // frame buffer access + virtual RenderingBuffer* FrontBuffer() const; + virtual RenderingBuffer* BackBuffer() const; + + virtual status_t Invalidate(const BRect& frame); + virtual status_t CopyBackToFront(const BRect& area); + +private: + BitmapBuffer* fBackBuffer; + BitmapBuffer* fFrontBuffer; + + CardWindow* fWindow; + + display_mode fDisplayMode; + + UpdateQueue* fUpdateExecutor; +}; + +#endif // VIEW_GRAPHICS_CARD_H