From 74b3612ac3f32d32a9f2aa97d0a50746e088d3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 18 Apr 2005 16:09:43 +0000 Subject: [PATCH] refactoring, speedup by decoupling back to front transferes from drawing and usage of special memcpy routine, minor speedups in Painter git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12437 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../app/drawing/AccelerantHWInterface.cpp | 66 +------ src/servers/app/drawing/HWInterface.cpp | 176 +++++++++++++++++- src/servers/app/drawing/HWInterface.h | 2 +- src/servers/app/drawing/Painter/Painter.cpp | 36 ++-- src/servers/app/drawing/UpdateQueue.cpp | 18 +- src/servers/app/drawing/ViewHWInterface.cpp | 68 ------- src/servers/app/drawing/ViewHWInterface.h | 3 - 7 files changed, 210 insertions(+), 159 deletions(-) diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index 20158f6ea3..9c1647dc80 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -523,68 +523,8 @@ AccelerantHWInterface::BackBuffer() const void AccelerantHWInterface::_DrawCursor(BRect area) const { - - BRect cf = _CursorFrame(); - if (cf.IsValid() && area.Intersects(cf)) { - // clip to common area - area = area & cf; - - int32 left = (int32)floorf(area.left); - int32 top = (int32)floorf(area.top); - int32 right = (int32)ceilf(area.right); - int32 bottom = (int32)ceilf(area.bottom); - int32 width = right - left + 1; - int32 height = bottom - top + 1; - - // make a bitmap from the backbuffer - // that has the cursor blended on top of it - - // blending buffer - uint8* buffer = new uint8[width * height * 4]; - - // offset into back buffer - uint8* src = (uint8*)fBackBuffer->Bits(); - uint32 srcBPR = fBackBuffer->BytesPerRow(); - src += top * srcBPR + left * 4; - - // offset into cursor bitmap - uint8* crs = (uint8*)fCursor->Bits(); - uint32 crsBPR = fCursor->BytesPerRow(); - // since area is clipped to cf, - // the diff between top and cf.top is always positive, - // same for diff between left and cf.left - crs += (top - (int32)floorf(cf.top)) * crsBPR - + (left - (int32)floorf(cf.left)) * 4; - - uint8* dst = buffer; - - // blending - for (int32 y = top; y <= bottom; y++) { - uint8* s = src; - uint8* c = crs; - uint8* d = dst; - for (int32 x = left; x <= right; x++) { - // assume backbuffer alpha = 255 - // TODO: it appears alpha in cursor us upside down - uint8 a = 255 - c[3]; - d[0] = (((s[0] - c[0]) * a) + (c[0] << 8)) >> 8; - d[1] = (((s[1] - c[1]) * a) + (c[1] << 8)) >> 8; - d[2] = (((s[2] - c[2]) * a) + (c[2] << 8)) >> 8; - d[3] = 255; - s += 4; - c += 4; - d += 4; - } - crs += crsBPR; - src += srcBPR; - dst += width * 4; - } - - // copy result to front buffer - _CopyToFront(buffer, width * 4, left, top, right, bottom); - - delete[] buffer; - } - + // use the default implementation for now, + // until we have a hardware cursor + HWInterface::_DrawCursor(area); } diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index c483d43ecf..b50c646596 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -19,8 +19,8 @@ HWInterface::HWInterface() fCursor(NULL), fCursorVisible(true), fCursorLocation(0, 0), -// fUpdateExecutor(new UpdateQueue(this)) - fUpdateExecutor(NULL) + fUpdateExecutor(new UpdateQueue(this)) +// fUpdateExecutor(NULL) { } @@ -105,14 +105,18 @@ HWInterface::GetCursorPosition() status_t HWInterface::Invalidate(const BRect& frame) { - return CopyBackToFront(frame);; +// return CopyBackToFront(frame); -// TODO: get this working, the locking in the DisplayDriverPainter needs -// to be based on locking this object, which essentially means the access -// to the back buffer is locked, or more precise the access to the invalid -// region scheduled to be copied to the front buffer -// fUpdateExecutor->AddRect(frame); -// return B_OK; +// 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; + } + return B_BAD_VALUE; } // CopyBackToFront @@ -155,6 +159,155 @@ HWInterface::CopyBackToFront(const BRect& frame) return B_BAD_VALUE; } +// _DrawCursor +// * default implementation, can be used as fallback or for +// software cursor +void +HWInterface::_DrawCursor(BRect area) const +{ + BRect cf = _CursorFrame(); + RenderingBuffer* backBuffer = BackBuffer(); + if (backBuffer && cf.IsValid() && area.Intersects(cf)) { + // clip to common area + area = area & cf; + + int32 left = (int32)area.left; + int32 top = (int32)area.top; + int32 right = (int32)area.right; + int32 bottom = (int32)area.bottom; + int32 width = right - left + 1; + int32 height = bottom - top + 1; + + // make a bitmap from the backbuffer + // that has the cursor blended on top of it + + // blending buffer + uint8* buffer = new uint8[width * height * 4]; + + // offset into back buffer + uint8* src = (uint8*)backBuffer->Bits(); + uint32 srcBPR = backBuffer->BytesPerRow(); + src += top * srcBPR + left * 4; + + // offset into cursor bitmap + uint8* crs = (uint8*)fCursor->Bits(); + uint32 crsBPR = fCursor->BytesPerRow(); + // since area is clipped to cf, + // the diff between top and cf.top is always positive, + // same for diff between left and cf.left + crs += (top - (int32)floorf(cf.top)) * crsBPR + + (left - (int32)floorf(cf.left)) * 4; + + uint8* dst = buffer; + + // blending + for (int32 y = top; y <= bottom; y++) { + uint8* s = src; + uint8* c = crs; + uint8* d = dst; + for (int32 x = left; x <= right; x++) { + // assume backbuffer alpha = 255 + // TODO: it appears alpha in cursor is upside down + uint8 a = 255 - c[3]; + d[0] = (((s[0] - c[0]) * a) + (c[0] << 8)) >> 8; + d[1] = (((s[1] - c[1]) * a) + (c[1] << 8)) >> 8; + d[2] = (((s[2] - c[2]) * a) + (c[2] << 8)) >> 8; + d[3] = 255; + s += 4; + c += 4; + d += 4; + } + crs += crsBPR; + src += srcBPR; + dst += width * 4; + } + + // copy result to front buffer + _CopyToFront(buffer, width * 4, left, top, right, bottom); + + delete[] buffer; + } +} + +/* +// gfxcpy +inline +void +gfxcpy(uint8* dst, uint8* src, int32 numBytes) +{ + uint64* d64 = (uint64*)dst; + uint64* s64 = (uint64*)src; + int32 numBytesBegin = numBytes; + while (numBytes >= 32) { + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 32; + } + while (numBytes >= 16) { + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 16; + } + while (numBytes >= 8) { + *d64++ = *s64++; + numBytes -= 8; + } + if (numBytes > 0) { + // update original pointers + dst += numBytesBegin - numBytes; + src += numBytesBegin - numBytes; + numBytesBegin = numBytes; + + uint32* d32 = (uint32*)dst; + uint32* s32 = (uint32*)src; + while (numBytes >= 4) { + *d32++ = *s32++; + numBytes -= 4; + } + // update original pointers + dst += numBytesBegin - numBytes; + src += numBytesBegin - numBytes; + + while (numBytes > 0) { + *dst++ = *src++; + numBytes--; + } + } +}*/ + +// gfxcpy32 +// * numBytes is expected to be a multiple of 4 +inline +void +gfxcpy32(uint8* dst, uint8* src, int32 numBytes) +{ + uint64* d64 = (uint64*)dst; + uint64* s64 = (uint64*)src; + int32 numBytesStart = numBytes; + while (numBytes >= 32) { + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 32; + } + if (numBytes >= 16) { + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 16; + } + if (numBytes >= 8) { + *d64++ = *s64++; + numBytes -= 8; + } + if (numBytes == 4) { + uint32* d32 = (uint32*)(dst + numBytesStart - numBytes); + uint32* s32 = (uint32*)(src + numBytesStart - numBytes); + *d32 = *s32; + } +} // _CopyToFront // @@ -183,7 +336,12 @@ HWInterface::_CopyToFront(uint8* src, uint32 srcBPR, dst += y * dstBPR + x * 4; // copy for (; y <= bottom; y++) { +#ifndef __HAIKU__ memcpy(dst, src, bytes); +#else + // bytes is guaranteed to be multiple of 4 + gfxcpy32(dst, src, bytes); +#endif // __HAIKU__ dst += dstBPR; src += srcBPR; } diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index e67b479fd1..c70a58a46a 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -67,7 +67,7 @@ class HWInterface : public BLocker { protected: // implement this in derived classes - virtual void _DrawCursor(BRect area) const = 0; + virtual void _DrawCursor(BRect area) const; // does the actual transfer and handles color space conversion void _CopyToFront(uint8* src, uint32 srcBPR, diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 1b2e4fb664..676935c3fa 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -363,6 +363,11 @@ Painter::StrokeLine(BPoint b, DrawData* context) return StrokeLine(context->penlocation, b, context); } +typedef union { + uint32 data32; + int8 data[4]; +} color32; + // StraightLine bool Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const @@ -376,6 +381,11 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const dst += x * 4; int32 y1 = (int32)min_c(a.y, b.y); int32 y2 = (int32)max_c(a.y, b.y); + color32 color; + color.data[0] = c.blue; + color.data[1] = c.green; + color.data[2] = c.red; + color.data[3] = 255; // draw a line, iterate over clipping boxes fBaseRenderer->first_clip_box(); do { @@ -385,9 +395,7 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const int32 end = min_c(fBaseRenderer->ymax(), y2); uint8* handle = dst + i * bpr; for (; i <= end; i++) { - handle[0] = c.blue; - handle[1] = c.green; - handle[2] = c.red; + *(uint32*)handle = color.data32; handle += bpr; } } @@ -403,6 +411,11 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const dst += y * bpr; int32 x1 = (int32)min_c(a.x, b.x); int32 x2 = (int32)max_c(a.x, b.x); + color32 color; + color.data[0] = c.blue; + color.data[1] = c.green; + color.data[2] = c.red; + color.data[3] = 255; // draw a line, iterate over clipping boxes fBaseRenderer->first_clip_box(); do { @@ -412,9 +425,7 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const int32 end = min_c(fBaseRenderer->xmax(), x2); uint8* handle = dst + i * 4; for (; i <= end; i++) { - handle[0] = c.blue; - handle[1] = c.green; - handle[2] = c.red; + *(uint32*)handle = color.data32; handle += 4; } } @@ -626,6 +637,12 @@ Painter::FillRect(const BRect& r, const rgb_color& c) const int32 top = (int32)r.top; int32 right = (int32)r.right; int32 bottom = (int32)r.bottom; + // get a 32 bit pixel ready with the color + color32 color; + color.data[0] = c.blue; + color.data[1] = c.green; + color.data[2] = c.red; + color.data[3] = 255; // fill rects, iterate over clipping boxes fBaseRenderer->first_clip_box(); do { @@ -636,12 +653,9 @@ Painter::FillRect(const BRect& r, const rgb_color& c) const int32 y2 = min_c(fBaseRenderer->ymax(), bottom); uint8* offset = dst + x1 * 4; for (; y1 <= y2; y1++) { - uint8* handle = offset + y1 * bpr; + uint32* handle = (uint32*)(offset + y1 * bpr); for (int32 x = x1; x <= x2; x++) { - handle[0] = c.blue; - handle[1] = c.green; - handle[2] = c.red; - handle += 4; + *handle++ = color.data32; } } } diff --git a/src/servers/app/drawing/UpdateQueue.cpp b/src/servers/app/drawing/UpdateQueue.cpp index 21f5789a64..639e67bf7d 100644 --- a/src/servers/app/drawing/UpdateQueue.cpp +++ b/src/servers/app/drawing/UpdateQueue.cpp @@ -53,8 +53,15 @@ UpdateQueue::AddRect(const BRect& rect) { // Lock(); //printf("UpdateQueue::AddRect()\n"); + // NOTE: The access to fUpdateRegion + // is protected by the HWInterface lock. + // When trying to access the fUpdateRegion, + // our thread will first try to lock the + // HWInterface, while on the other hand + // HWInterface will always be locked when + // it calls AddRect(). fUpdateRegion.Include(rect); - _Reschedule(); +// _Reschedule(); // Unlock(); } @@ -80,9 +87,7 @@ UpdateQueue::_ExecuteUpdates() // execute updates if (fInterface->LockWithTimeout(5000) >= B_OK) { int32 count = fUpdateRegion.CountRects(); -//printf("%ld copy dirty region\n", find_thread(NULL)); if (count > 0) { -printf("%ld rects\n", count); for (int32 i = 0; i < count; i++) { fInterface->CopyBackToFront(fUpdateRegion.RectAt(i)); } @@ -96,7 +101,7 @@ printf("%ld rects\n", count); break; default: printf("other error: %s\n", strerror(err)); -running = false; +//running = false; snooze(20000); break; } @@ -110,6 +115,11 @@ running = false; void UpdateQueue::_Reschedule() { + // TODO: _Reschedule() is supposed to cause the + // immediate wake up of the update thread, but + // the HWInterface is still locked when we get here. + // Somehow this causes a deadlock, but I don't + // see why yet... if (fStatus == B_OK) { release_sem(fThreadControl); } diff --git a/src/servers/app/drawing/ViewHWInterface.cpp b/src/servers/app/drawing/ViewHWInterface.cpp index 33a75ea8fa..8a95b5b2a6 100644 --- a/src/servers/app/drawing/ViewHWInterface.cpp +++ b/src/servers/app/drawing/ViewHWInterface.cpp @@ -611,74 +611,6 @@ ViewHWInterface::CopyBackToFront(const BRect& frame) return ret; } -// _DrawCursor -void -ViewHWInterface::_DrawCursor(BRect area) const -{ - BRect cf = _CursorFrame(); - if (cf.IsValid() && area.Intersects(cf)) { - // clip to common area - area = area & cf; - - int32 left = (int32)floorf(area.left); - int32 top = (int32)floorf(area.top); - int32 right = (int32)ceilf(area.right); - int32 bottom = (int32)ceilf(area.bottom); - int32 width = right - left + 1; - int32 height = bottom - top + 1; - - // make a bitmap from the backbuffer - // that has the cursor blended on top of it - - // blending buffer - uint8* buffer = new uint8[width * height * 4]; - - // offset into back buffer - uint8* src = (uint8*)fBackBuffer->Bits(); - uint32 srcBPR = fBackBuffer->BytesPerRow(); - src += top * srcBPR + left * 4; - - // offset into cursor bitmap - uint8* crs = (uint8*)fCursor->Bits(); - uint32 crsBPR = fCursor->BytesPerRow(); - // since area is clipped to cf, - // the diff between top and cf.top is always positive, - // same for diff between left and cf.left - crs += (top - (int32)floorf(cf.top)) * crsBPR - + (left - (int32)floorf(cf.left)) * 4; - - uint8* dst = buffer; - - // blending - for (int32 y = top; y <= bottom; y++) { - uint8* s = src; - uint8* c = crs; - uint8* d = dst; - for (int32 x = left; x <= right; x++) { - // assume backbuffer alpha = 255 - // TODO: it appears alpha in cursor us upside down - uint8 a = 255 - c[3]; - d[0] = (((s[0] - c[0]) * a) + (c[0] << 8)) >> 8; - d[1] = (((s[1] - c[1]) * a) + (c[1] << 8)) >> 8; - d[2] = (((s[2] - c[2]) * a) + (c[2] << 8)) >> 8; - d[3] = 255; - s += 4; - c += 4; - d += 4; - } - crs += crsBPR; - src += srcBPR; - dst += width * 4; - } - - // copy result to front buffer - _CopyToFront(buffer, width * 4, left, top, right, bottom); - - delete[] buffer; - } -} - - /*void ViewHWInterface::CopyBitmap(ServerBitmap *bitmap, const BRect &source, const BRect &dest, const DrawData *d) { diff --git a/src/servers/app/drawing/ViewHWInterface.h b/src/servers/app/drawing/ViewHWInterface.h index deb5a49afa..15676410e8 100644 --- a/src/servers/app/drawing/ViewHWInterface.h +++ b/src/servers/app/drawing/ViewHWInterface.h @@ -55,9 +55,6 @@ class ViewHWInterface : public HWInterface { virtual status_t CopyBackToFront(const BRect& frame); - protected: - virtual void _DrawCursor(BRect area) const; - private: BitmapBuffer* fBackBuffer; BitmapBuffer* fFrontBuffer;