diff --git a/headers/private/servers/app/RenderingBuffer.h b/headers/private/servers/app/RenderingBuffer.h index c51c3ebbda..0ef31400b4 100644 --- a/headers/private/servers/app/RenderingBuffer.h +++ b/headers/private/servers/app/RenderingBuffer.h @@ -7,16 +7,21 @@ class RenderingBuffer { public: - RenderingBuffer() {}; - virtual ~RenderingBuffer() {}; + RenderingBuffer() {} + virtual ~RenderingBuffer() {} virtual status_t InitCheck() const = 0; virtual color_space ColorSpace() const = 0; virtual void* Bits() const = 0; virtual uint32 BytesPerRow() const = 0; + // the *count* of the pixels per line virtual uint32 Width() const = 0; + // the *count* of lines virtual uint32 Height() const = 0; + + inline uint32 BitsLength() const + { return Height() * BytesPerRow(); } }; #endif // RENDERING_BUFFER_H diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index 9c1647dc80..ff42cc776e 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -329,23 +329,33 @@ AccelerantHWInterface::SetMode(const display_mode &mode) // NOTE: backbuffer is always B_RGBA32, this simplifies the // drawing backend implementation tremendously for the time // being. The color space conversion is handled in CopyBackToFront() - + delete fBackBuffer; - fBackBuffer = new MallocBuffer(fDisplayMode.virtual_width, - fDisplayMode.virtual_height); + + // TODO: Above not true anymore for single buffered mode!!! + // -> fall back to double buffer for fDisplayMode.space != B_RGB32 + // as intermediate solution... + bool doubleBuffered = HWInterface::IsDoubleBuffered(); + if ((color_space)fDisplayMode.space != B_RGB32 && + (color_space)fDisplayMode.space != B_RGBA32) + doubleBuffered = true; - status_t ret = fBackBuffer->InitCheck(); - if (ret < B_OK) { - delete fBackBuffer; - fBackBuffer = NULL; - return ret; + if (doubleBuffered) { + fBackBuffer = new MallocBuffer(fDisplayMode.virtual_width, + fDisplayMode.virtual_height); + + status_t ret = fBackBuffer->InitCheck(); + if (ret < B_OK) { + delete fBackBuffer; + fBackBuffer = NULL; + return ret; + } } // clear out backbuffer, alpha is 255 this way // TODO: maybe this should handle different color spaces in different // ways - memset(fBackBuffer->Bits(), 255, - fBackBuffer->BytesPerRow() * fBackBuffer->Height()); + memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength()); } return B_OK; @@ -454,6 +464,21 @@ AccelerantHWInterface::ProposeMode(display_mode *candidate, const display_mode * return fAccProposeDisplayMode(candidate, &this_low, &this_high); } +// WaitForRetrace +status_t +AccelerantHWInterface::WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT) +{ + accelerant_retrace_semaphore AccelerantRetraceSemaphore = (accelerant_retrace_semaphore)fAccelerantHook(B_ACCELERANT_RETRACE_SEMAPHORE, NULL); + if (!AccelerantRetraceSemaphore) + return B_UNSUPPORTED; + + sem_id sem = AccelerantRetraceSemaphore(); + if (sem < 0) + return B_ERROR; + + return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout); +} + // SetDPMSMode status_t AccelerantHWInterface::SetDPMSMode(const uint32 &state) @@ -484,19 +509,41 @@ AccelerantHWInterface::DPMSCapabilities() const return fAccDPMSCapabilities(); } -// WaitForRetrace -status_t -AccelerantHWInterface::WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT) +// SetCursor +void +AccelerantHWInterface::SetCursor(ServerCursor* cursor) { - accelerant_retrace_semaphore AccelerantRetraceSemaphore = (accelerant_retrace_semaphore)fAccelerantHook(B_ACCELERANT_RETRACE_SEMAPHORE, NULL); - if (!AccelerantRetraceSemaphore) - return B_UNSUPPORTED; - - sem_id sem = AccelerantRetraceSemaphore(); - if (sem < 0) - return B_ERROR; - - return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout); + if (Lock()) { + HWInterface::SetCursor(cursor); + // TODO: implement setting the hard ware cursor + // NOTE: cursor should be always B_RGBA32 + // NOTE: The HWInterface implementation should + // still be called, since it takes ownership of + // the cursor. + Unlock(); + } +} + +// SetCursorVisible +void +AccelerantHWInterface::SetCursorVisible(bool visible) +{ + if (Lock()) { + HWInterface::SetCursorVisible(visible); + // TODO: update graphics hardware + Unlock(); + } +} + +// MoveCursorTo +void +AccelerantHWInterface::MoveCursorTo(const float& x, const float& y) +{ + if (Lock()) { + HWInterface::MoveCursorTo(x, y); + // TODO: update graphics hardware + Unlock(); + } } // FrontBuffer @@ -526,5 +573,7 @@ AccelerantHWInterface::_DrawCursor(BRect area) const // use the default implementation for now, // until we have a hardware cursor HWInterface::_DrawCursor(area); + // TODO: this would only be called, if we don't have + // a hardware cursor for some reason } diff --git a/src/servers/app/drawing/AccelerantHWInterface.h b/src/servers/app/drawing/AccelerantHWInterface.h index 018d010080..b46d1a472b 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.h +++ b/src/servers/app/drawing/AccelerantHWInterface.h @@ -49,6 +49,12 @@ virtual status_t SetDPMSMode(const uint32 &state); virtual uint32 DPMSMode() const; virtual uint32 DPMSCapabilities() const; + // cursor handling +virtual void SetCursor(ServerCursor* cursor); +virtual void SetCursorVisible(bool visible); +virtual void MoveCursorTo(const float& x, + const float& y); + // frame buffer access virtual RenderingBuffer *FrontBuffer() const; virtual RenderingBuffer *BackBuffer() const; diff --git a/src/servers/app/drawing/DisplayDriverPainter.cpp b/src/servers/app/drawing/DisplayDriverPainter.cpp index 82db81c2db..1d736c7162 100644 --- a/src/servers/app/drawing/DisplayDriverPainter.cpp +++ b/src/servers/app/drawing/DisplayDriverPainter.cpp @@ -96,7 +96,7 @@ DisplayDriverPainter::CopyBits(const BRect &src, const BRect &dst, if (Lock()) { // TODO: handle clipping to d->clipreg here? - RenderingBuffer* backBuffer = fGraphicsCard->BackBuffer(); + RenderingBuffer* backBuffer = fGraphicsCard->DrawingBuffer(); BRect valid(0, 0, backBuffer->Width() - 1, backBuffer->Height() - 1); if (valid.Intersects(src) && valid.Intersects(dst)) { @@ -288,7 +288,7 @@ DisplayDriverPainter::CopyRegionList(BList* list, BList* pList, BRect updateRect; - RenderingBuffer* backBuffer = fGraphicsCard->BackBuffer(); + RenderingBuffer* backBuffer = fGraphicsCard->DrawingBuffer(); uint8* bits = (uint8*)backBuffer->Bits(); uint32 bpr = backBuffer->BytesPerRow(); @@ -355,7 +355,7 @@ printf("region: %ld, rect: %ld, offset(%ld, %ld)\n", i, j, xOffset, yOffset); } */ - RenderingBuffer* bmp = fGraphicsCard->BackBuffer(); + RenderingBuffer* bmp = fGraphicsCard->DrawingBuffer(); uint32 bytesPerPixel = bmp->BytesPerRow() / bmp->Width(); BList rectList; @@ -1081,7 +1081,7 @@ DisplayDriverPainter::SetMode(const display_mode &mode) { if (Lock()) { if (fGraphicsCard->SetMode(mode) >= B_OK) { - fPainter->AttachToBuffer(fGraphicsCard->BackBuffer()); + fPainter->AttachToBuffer(fGraphicsCard->DrawingBuffer()); DisplayDriver::SetMode(mode); } else { fprintf(stderr, "DisplayDriverPainter::SetMode() - unsupported " @@ -1113,10 +1113,10 @@ DisplayDriverPainter::DumpToFile(const char *path) if (!output) return false; - RenderingBuffer *back_buffer = fGraphicsCard->BackBuffer(); - uint32 row = back_buffer->BytesPerRow() / 4; + RenderingBuffer *backBuffer = fGraphicsCard->DrawingBuffer(); + uint32 row = backBuffer->BytesPerRow() / 4; for (int i = 0; i < fDisplayMode.virtual_height; i++) { - fwrite((uint32 *)back_buffer->Bits() + i * row, 4, row, output); + fwrite((uint32 *)backBuffer->Bits() + i * row, 4, row, output); sync(); } fclose(output); @@ -1300,7 +1300,7 @@ void DisplayDriverPainter::ConstrainClippingRegion(BRegion *region) if (!region) { // BRegion empty; // fPainter->ConstrainClipping(empty); - if (RenderingBuffer* buffer = fGraphicsCard->BackBuffer()) { + if (RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer()) { BRegion all; all.Include(BRect(0, 0, buffer->Width() - 1, buffer->Height() - 1)); diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index f10be3de2b..48cf933ddc 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -14,11 +14,12 @@ #include "HWInterface.h" // constructor -HWInterface::HWInterface() +HWInterface::HWInterface(bool doubleBuffered) : BLocker("hw interface lock"), fCursor(NULL), fCursorVisible(true), fCursorLocation(0, 0), + fDoubleBuffered(doubleBuffered), // fUpdateExecutor(new UpdateQueue(this)) fUpdateExecutor(NULL) { @@ -100,23 +101,44 @@ HWInterface::GetCursorPosition() return location; } +// DrawingBuffer +RenderingBuffer* +HWInterface::DrawingBuffer() const +{ + if (IsDoubleBuffered()) + return BackBuffer(); + return FrontBuffer(); +} + +// IsDoubleBuffered +bool +HWInterface::IsDoubleBuffered() const +{ + return fDoubleBuffered; +} + // Invalidate // * the object needs to be already locked! status_t HWInterface::Invalidate(const BRect& frame) { - return CopyBackToFront(frame); + if (IsDoubleBuffered()) { + return CopyBackToFront(frame); // TODO: the remaining problem is the immediate wake up of the // thread carrying out the updates, when I enable it, there // seems to be a deadlock, but I didn't figure it out yet. // Maybe the same bug is there without the wakeup, only, triggered // less often.... scarry, huh? -/* if (frame.IsValid()) { - fUpdateExecutor->AddRect(frame); - return B_OK; +/* if (frame.IsValid()) { + fUpdateExecutor->AddRect(frame); + return B_OK; + } + return B_BAD_VALUE;*/ + } else { + _DrawCursor(frame); } - return B_BAD_VALUE;*/ + return B_OK; } // CopyBackToFront @@ -162,12 +184,22 @@ HWInterface::CopyBackToFront(const BRect& frame) // _DrawCursor // * default implementation, can be used as fallback or for // software cursor +// * area is where we potentially draw the cursor, the cursor +// might be somewhere else, in which case this function does nothing void HWInterface::_DrawCursor(BRect area) const { + RenderingBuffer* backBuffer = DrawingBuffer(); + if (!backBuffer) + return; + BRect cf = _CursorFrame(); - RenderingBuffer* backBuffer = BackBuffer(); - if (backBuffer && cf.IsValid() && area.Intersects(cf)) { + + // make sure we don't copy out of bounds + BRect bufferClip(0.0, 0.0, backBuffer->Width() - 1, backBuffer->Height() - 1); + area = bufferClip & area; + + if (cf.IsValid() && area.Intersects(cf)) { // clip to common area area = area & cf; diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index c70a58a46a..bcfb177af9 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -21,7 +21,7 @@ class UpdateQueue; class HWInterface : public BLocker { public: - HWInterface(); + HWInterface(bool doubleBuffered = true); virtual ~HWInterface(); virtual status_t Initialize() = 0; @@ -51,19 +51,21 @@ class HWInterface : public BLocker { // cursor handling virtual void SetCursor(ServerCursor* cursor); virtual void SetCursorVisible(bool visible); - virtual bool IsCursorVisible(); + bool IsCursorVisible(); virtual void MoveCursorTo(const float& x, const float& y); BPoint GetCursorPosition(); // frame buffer access + RenderingBuffer* DrawingBuffer() const; virtual RenderingBuffer* FrontBuffer() const = 0; virtual RenderingBuffer* BackBuffer() const = 0; + virtual bool IsDoubleBuffered() const; // Invalidate is planned to be used for scheduling an area for updating - status_t Invalidate(const BRect& frame); + virtual status_t Invalidate(const BRect& frame); // while as CopyBackToFront() actually performs the operation - virtual status_t CopyBackToFront(const BRect& frame); + status_t CopyBackToFront(const BRect& frame); protected: // implement this in derived classes @@ -79,6 +81,7 @@ class HWInterface : public BLocker { ServerCursor* fCursor; bool fCursorVisible; BPoint fCursorLocation; + bool fDoubleBuffered; private: UpdateQueue* fUpdateExecutor; diff --git a/src/servers/app/drawing/ViewHWInterface.cpp b/src/servers/app/drawing/ViewHWInterface.cpp index 8a95b5b2a6..efc5f98f53 100644 --- a/src/servers/app/drawing/ViewHWInterface.cpp +++ b/src/servers/app/drawing/ViewHWInterface.cpp @@ -403,31 +403,46 @@ ViewHWInterface::SetMode(const display_mode &mode) // NOTE: backbuffer is always B_RGBA32, this simplifies the // drawing backend implementation tremendously for the time // being. The color space conversion is handled in CopyBackToFront() - BBitmap* backBitmap = new BBitmap(frame, 0, B_RGBA32); - BBitmap* frontBitmap = new BBitmap(frame, 0, (color_space)fDisplayMode.space); - fBackBuffer = new BitmapBuffer(backBitmap); + // TODO: Above not true anymore for single buffered mode!!! + // -> fall back to double buffer for fDisplayMode.space != B_RGB32 + // as intermediate solution... + bool doubleBuffered = HWInterface::IsDoubleBuffered(); + if ((color_space)fDisplayMode.space != B_RGB32 && + (color_space)fDisplayMode.space != B_RGBA32) + doubleBuffered = true; + + BBitmap* frontBitmap = new BBitmap(frame, 0, (color_space)fDisplayMode.space); fFrontBuffer = new BitmapBuffer(frontBitmap); - status_t err = fBackBuffer->InitCheck(); - if (err < B_OK) { - delete fBackBuffer; - fBackBuffer = NULL; - ret = err; - } - - err = fFrontBuffer->InitCheck(); + status_t err = fFrontBuffer->InitCheck(); if (err < B_OK) { delete fFrontBuffer; fFrontBuffer = NULL; ret = err; } + if (err >= B_OK && doubleBuffered) { + // backbuffer is always B_RGBA32 + // since we override IsDoubleBuffered(), the drawing buffer + // is in effect also always B_RGBA32. + BBitmap* backBitmap = new BBitmap(frame, 0, B_RGBA32); + fBackBuffer = new BitmapBuffer(backBitmap); + + err = fBackBuffer->InitCheck(); + if (err < B_OK) { + delete fBackBuffer; + fBackBuffer = 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()); + if (fBackBuffer) + memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength()); + memset(fFrontBuffer->Bits(), 255, fFrontBuffer->BitsLength()); // change the window size and update the bitmap used for drawing fWindow->ResizeTo(frame.Width(), frame.Height()); @@ -600,13 +615,23 @@ ViewHWInterface::BackBuffer() const return fBackBuffer; } -// CopyBackToFront -status_t -ViewHWInterface::CopyBackToFront(const BRect& frame) +// IsDoubleBuffered +bool +ViewHWInterface::IsDoubleBuffered() const { - status_t ret = HWInterface::CopyBackToFront(frame); -// TODO: investigate why this function is called before SetMode() was called! - if (fWindow) + if (fFrontBuffer) + return fBackBuffer != NULL; + + return HWInterface::IsDoubleBuffered(); +} + +// Invalidate +status_t +ViewHWInterface::Invalidate(const BRect& frame) +{ + status_t ret = HWInterface::Invalidate(frame); + + if (ret >= B_OK && fWindow) fWindow->Invalidate(frame); return ret; } diff --git a/src/servers/app/drawing/ViewHWInterface.h b/src/servers/app/drawing/ViewHWInterface.h index 15676410e8..509bd9ceb0 100644 --- a/src/servers/app/drawing/ViewHWInterface.h +++ b/src/servers/app/drawing/ViewHWInterface.h @@ -52,8 +52,9 @@ class ViewHWInterface : public HWInterface { // frame buffer access virtual RenderingBuffer* FrontBuffer() const; virtual RenderingBuffer* BackBuffer() const; + virtual bool IsDoubleBuffered() const; - virtual status_t CopyBackToFront(const BRect& frame); + virtual status_t Invalidate(const BRect& frame); private: BitmapBuffer* fBackBuffer;