From 727653f7ab76ecb76d377ae83c0a319f67ab8abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Thu, 1 Dec 2005 19:04:37 +0000 Subject: [PATCH] implemented invalidation triggered from the client side. 20 clients each displaying an animation in one view at 25 fps leaves the new clipping unimpressed, everything is fluent, also during moving and resizing windows git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15275 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../app/newerClipping/ClientLooper.cpp | 111 +++++++++++++++- .../servers/app/newerClipping/ClientLooper.h | 16 +++ .../servers/app/newerClipping/WindowLayer.cpp | 119 +++++++++++++++++- .../servers/app/newerClipping/WindowLayer.h | 15 ++- src/tests/servers/app/newerClipping/main.cpp | 2 + 5 files changed, 251 insertions(+), 12 deletions(-) diff --git a/src/tests/servers/app/newerClipping/ClientLooper.cpp b/src/tests/servers/app/newerClipping/ClientLooper.cpp index eb6e2356e0..7cba05937c 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.cpp +++ b/src/tests/servers/app/newerClipping/ClientLooper.cpp @@ -1,8 +1,13 @@ +#include #include +#include #include #include +#include +#include +#include #include #include "WindowLayer.h" @@ -11,6 +16,71 @@ #define SLOW_DRAWING 0 +#define SPEED 2.0 + +// random_number_between +static float +random_number_between(float v1, float v2) +{ + if (v1 < v2) + return v1 + fmod(rand() / 1000.0, (v2 - v1)); + else if (v2 < v1) + return v2 + fmod(rand() / 1000.0, (v1 - v2)); + return v1; +} + +// init_polygon +static void +init_polygon(const BRect& b, point* polygon) +{ + polygon[0].x = b.left; + polygon[0].y = b.top; + polygon[0].direction_x = random_number_between(-SPEED, SPEED); + polygon[0].direction_y = random_number_between(-SPEED, SPEED); + polygon[1].x = b.right; + polygon[1].y = b.top; + polygon[1].direction_x = random_number_between(-SPEED, SPEED); + polygon[1].direction_y = random_number_between(-SPEED, SPEED); + polygon[2].x = b.right; + polygon[2].y = b.bottom; + polygon[2].direction_x = random_number_between(-SPEED, SPEED); + polygon[2].direction_y = random_number_between(-SPEED, SPEED); + polygon[3].x = b.left; + polygon[3].y = b.bottom; + polygon[3].direction_x = random_number_between(-SPEED, SPEED); + polygon[3].direction_y = random_number_between(-SPEED, SPEED); +} + +// morph +static inline void +morph(double* value, double* direction, double min, double max) +{ + *value += *direction; + if (*value < min) { + *value = min; + *direction = -*direction; + } else if (*value > max) { + *value = max; + *direction = -*direction; + } +} + +// morph_polygon +static inline void +morph_polygon(const BRect& b, point* polygon) +{ + morph(&polygon[0].x, &polygon[0].direction_x, b.left, b.right); + morph(&polygon[1].x, &polygon[1].direction_x, b.left, b.right); + morph(&polygon[2].x, &polygon[2].direction_x, b.left, b.right); + morph(&polygon[3].x, &polygon[3].direction_x, b.left, b.right); + morph(&polygon[0].y, &polygon[0].direction_y, b.top, b.bottom); + morph(&polygon[1].y, &polygon[1].direction_y, b.top, b.bottom); + morph(&polygon[2].y, &polygon[2].direction_y, b.top, b.bottom); + morph(&polygon[3].y, &polygon[3].direction_y, b.top, b.bottom); +} + + + // constructor ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) : BLooper("", B_DISPLAY_PRIORITY), @@ -20,11 +90,17 @@ ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) BString clientName(name); clientName << " client"; SetName(clientName.String()); + + BMessenger messenger(this); + fTicker = new BMessageRunner(messenger, new BMessage(MSG_TICK), 40000); + + init_polygon(BRect(0, 0, 100, 100), fPolygon); } // destructor ClientLooper::~ClientLooper() { + delete fTicker; } // MessageReceived @@ -40,9 +116,13 @@ ClientLooper::MessageReceived(BMessage* message) // the client is slow // snooze(40000L); // send the command to redraw a view - BMessage command(MSG_DRAWING_COMMAND); - command.AddInt32("token", i); - fServerWindow->PostMessage(&command); + if (i == 5) { + _DrawAnimatedLayer(i); + } else { + BMessage command(MSG_DRAWING_COMMAND); + command.AddInt32("token", i); + fServerWindow->PostMessage(&command); + } } fServerWindow->PostMessage(MSG_END_UPDATE); @@ -69,8 +149,33 @@ ClientLooper::MessageReceived(BMessage* message) fServerWindow->PostMessage(MSG_SHOW); break; + case MSG_TICK: { + BMessage invalidate(MSG_INVALIDATE_VIEW); + invalidate.AddInt32("token", 5); + fServerWindow->PostMessage(&invalidate); + + morph_polygon(BRect(0, 0, 100, 100), fPolygon); + break; + } + default: BLooper::MessageReceived(message); break; } } + +// _DrawAnimatedLayer +void +ClientLooper::_DrawAnimatedLayer(int32 token) +{ + BMessage message(MSG_DRAW_POLYGON); + message.AddInt32("token", token); + + message.AddPoint("point", BPoint(fPolygon[0].x, fPolygon[0].y)); + message.AddPoint("point", BPoint(fPolygon[1].x, fPolygon[1].y)); + message.AddPoint("point", BPoint(fPolygon[2].x, fPolygon[2].y)); + message.AddPoint("point", BPoint(fPolygon[3].x, fPolygon[3].y)); + + fServerWindow->PostMessage(&message); +} + diff --git a/src/tests/servers/app/newerClipping/ClientLooper.h b/src/tests/servers/app/newerClipping/ClientLooper.h index 425ee851c4..6d16477313 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.h +++ b/src/tests/servers/app/newerClipping/ClientLooper.h @@ -12,6 +12,15 @@ enum { MSG_VIEWS_REMOVED = 'vwrm', MSG_WINDOW_HIDDEN = 'whdn', + + MSG_TICK = 'tick', +}; + +struct point { + double x; + double y; + double direction_x; + double direction_y; }; class ClientLooper : public BLooper { @@ -25,6 +34,13 @@ class ClientLooper : public BLooper { private: WindowLayer* fServerWindow; int32 fViewCount; + + BMessageRunner* fTicker; + + + void _DrawAnimatedLayer(int32 token); + + point fPolygon[4]; }; #endif // CLIENT_LOOPER_H diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 8c03dd2b4c..5c4ac7d414 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -22,6 +22,9 @@ // the update session, which tells us the cause of the update #define DELAYED_BACKGROUND_CLEARING 1 +// IMPORTANT: nested ReadLockClipping()s are not supported (by MultiLocker) + + // constructor WindowLayer::WindowLayer(BRect frame, const char* name, DrawingEngine* drawingEngine, Desktop* desktop) @@ -75,6 +78,9 @@ WindowLayer::WindowLayer(BRect frame, const char* name, // destructor WindowLayer::~WindowLayer() { + fClient->Lock(); + fClient->Quit(); + delete fTopLayer; } @@ -117,6 +123,27 @@ WindowLayer::MessageReceived(BMessage* message) _DrawClient(token); break; } + case MSG_DRAW_POLYGON: { + int32 token; + BPoint polygon[4]; + if (message->FindInt32("token", &token) >= B_OK && + message->FindPoint("point", 0, &polygon[0]) >= B_OK && + message->FindPoint("point", 1, &polygon[1]) >= B_OK && + message->FindPoint("point", 2, &polygon[2]) >= B_OK && + message->FindPoint("point", 3, &polygon[3]) >= B_OK) { + + _DrawClientPolygon(token, polygon); + } + break; + + } + + case MSG_INVALIDATE_VIEW: { + int32 token; + if (message->FindInt32("token", &token) >= B_OK) + InvalidateView(token); + break; + } case MSG_SHOW: if (IsHidden()) { @@ -386,6 +413,26 @@ WindowLayer::MarkContentDirty(BRegion* regionOnScreen) } } +// InvalidateView +void +WindowLayer::InvalidateView(int32 token) +{ + if (fDesktop && fDesktop->ReadLockClipping()) { + + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + if (!fContentRegionValid) + _UpdateContentRegion(); + + _MarkContentDirty(&layer->ScreenClipping(&fContentRegion)); + + fDesktop->ReadUnlockClipping(); + } +} + //# pragma mark - // CopyContents @@ -507,12 +554,14 @@ WindowLayer::_DrawClient(int32 token) // We have to be sure that the clipping is up to date. // If true readlocking would work correctly, this would // not be an issue - ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); - if (!layer || !layer->IsVisible()) - return; - if (fDesktop->ReadLockClipping()) { + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + if (!fEffectiveDrawingRegionValid) { fEffectiveDrawingRegion = VisibleContentRegion(); if (fInUpdate) { @@ -551,6 +600,68 @@ WindowLayer::_DrawClient(int32 token) } } +// _DrawClientPolygon +void +WindowLayer::_DrawClientPolygon(int32 token, BPoint polygon[4]) +{ + if (fDesktop->ReadLockClipping()) { + + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + + if (!fEffectiveDrawingRegionValid) { + fEffectiveDrawingRegion = VisibleContentRegion(); + if (fInUpdate) { + // enforce the dirty region of the update session + fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession.DirtyRegion()); + } else { + printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token); + } + fEffectiveDrawingRegionValid = true; + } + + BRegion effectiveClipping(fEffectiveDrawingRegion); + if (!fContentRegionValid) + _UpdateContentRegion(); + effectiveClipping.IntersectWith(&layer->ScreenClipping(&fContentRegion)); + + if (effectiveClipping.CountRects() > 0) { +#if DELAYED_BACKGROUND_CLEARING + layer->Draw(fDrawingEngine, &effectiveClipping, + &fContentRegion, false); +#endif + + if (fDrawingEngine->Lock()) { + + fDrawingEngine->PushState(); + fDrawingEngine->ConstrainClippingRegion(&effectiveClipping); + fDrawingEngine->SetPenSize(3); +// fDrawingEngine->SetDrawingMode(B_OP_BLEND); + layer->ConvertToTop(&polygon[0]); + layer->ConvertToTop(&polygon[1]); + layer->ConvertToTop(&polygon[2]); + layer->ConvertToTop(&polygon[3]); + fDrawingEngine->BeginLineArray(4); + fDrawingEngine->AddLine(polygon[0], polygon[1], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[1], polygon[2], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[2], polygon[3], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[3], polygon[0], layer->ViewColor()); + fDrawingEngine->EndLineArray(); + + fDrawingEngine->PopState(); + fDrawingEngine->MarkDirty(&effectiveClipping); + fDrawingEngine->Unlock(); + } + } + + fDesktop->ReadUnlockClipping(); + } +} + + // _DrawBorder void WindowLayer::_DrawBorder() diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 8943a033f0..15e78af13d 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -14,14 +14,17 @@ class Desktop; class DrawingEngine; enum { - MSG_REDRAW = 'rdrw', + MSG_REDRAW = 'rdrw', // client messages - MSG_BEGIN_UPDATE = 'bgud', - MSG_END_UPDATE = 'edud', - MSG_DRAWING_COMMAND = 'draw', + MSG_BEGIN_UPDATE = 'bgud', + MSG_END_UPDATE = 'edud', + MSG_DRAWING_COMMAND = 'draw', - MSG_SHOW = 'show', + MSG_SHOW = 'show', + + MSG_INVALIDATE_VIEW = 'invl', + MSG_DRAW_POLYGON = 'drwp', }; class UpdateSession { @@ -82,6 +85,7 @@ class WindowLayer : public BLooper { void MarkDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen); + void InvalidateView(int32 token); void ProcessDirtyRegion(BRegion* region); @@ -98,6 +102,7 @@ class WindowLayer : public BLooper { // different types of drawing void _TriggerContentRedraw(); void _DrawClient(int32 token); + void _DrawClientPolygon(int32 token, BPoint polygon[4]); void _DrawBorder(); // handling update sessions diff --git a/src/tests/servers/app/newerClipping/main.cpp b/src/tests/servers/app/newerClipping/main.cpp index cb6221bbc2..8f2b3f0f1e 100644 --- a/src/tests/servers/app/newerClipping/main.cpp +++ b/src/tests/servers/app/newerClipping/main.cpp @@ -220,6 +220,8 @@ Window::Test() int main(int argc, const char* argv[]) { + srand((long int)system_time()); + App app; app.Run(); return 0;