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
This commit is contained in:
Stephan Aßmus
2005-12-01 19:04:37 +00:00
parent 755ae3a961
commit 727653f7ab
5 changed files with 251 additions and 12 deletions
@@ -1,8 +1,13 @@
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <Message.h> #include <Message.h>
#include <MessageQueue.h> #include <MessageQueue.h>
#include <MessageRunner.h>
#include <Messenger.h>
#include <Rect.h>
#include <String.h> #include <String.h>
#include "WindowLayer.h" #include "WindowLayer.h"
@@ -11,6 +16,71 @@
#define SLOW_DRAWING 0 #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 // constructor
ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow)
: BLooper("", B_DISPLAY_PRIORITY), : BLooper("", B_DISPLAY_PRIORITY),
@@ -20,11 +90,17 @@ ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow)
BString clientName(name); BString clientName(name);
clientName << " client"; clientName << " client";
SetName(clientName.String()); SetName(clientName.String());
BMessenger messenger(this);
fTicker = new BMessageRunner(messenger, new BMessage(MSG_TICK), 40000);
init_polygon(BRect(0, 0, 100, 100), fPolygon);
} }
// destructor // destructor
ClientLooper::~ClientLooper() ClientLooper::~ClientLooper()
{ {
delete fTicker;
} }
// MessageReceived // MessageReceived
@@ -40,9 +116,13 @@ ClientLooper::MessageReceived(BMessage* message)
// the client is slow // the client is slow
// snooze(40000L); // snooze(40000L);
// send the command to redraw a view // send the command to redraw a view
BMessage command(MSG_DRAWING_COMMAND); if (i == 5) {
command.AddInt32("token", i); _DrawAnimatedLayer(i);
fServerWindow->PostMessage(&command); } else {
BMessage command(MSG_DRAWING_COMMAND);
command.AddInt32("token", i);
fServerWindow->PostMessage(&command);
}
} }
fServerWindow->PostMessage(MSG_END_UPDATE); fServerWindow->PostMessage(MSG_END_UPDATE);
@@ -69,8 +149,33 @@ ClientLooper::MessageReceived(BMessage* message)
fServerWindow->PostMessage(MSG_SHOW); fServerWindow->PostMessage(MSG_SHOW);
break; 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: default:
BLooper::MessageReceived(message); BLooper::MessageReceived(message);
break; 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);
}
@@ -12,6 +12,15 @@ enum {
MSG_VIEWS_REMOVED = 'vwrm', MSG_VIEWS_REMOVED = 'vwrm',
MSG_WINDOW_HIDDEN = 'whdn', MSG_WINDOW_HIDDEN = 'whdn',
MSG_TICK = 'tick',
};
struct point {
double x;
double y;
double direction_x;
double direction_y;
}; };
class ClientLooper : public BLooper { class ClientLooper : public BLooper {
@@ -25,6 +34,13 @@ class ClientLooper : public BLooper {
private: private:
WindowLayer* fServerWindow; WindowLayer* fServerWindow;
int32 fViewCount; int32 fViewCount;
BMessageRunner* fTicker;
void _DrawAnimatedLayer(int32 token);
point fPolygon[4];
}; };
#endif // CLIENT_LOOPER_H #endif // CLIENT_LOOPER_H
@@ -22,6 +22,9 @@
// the update session, which tells us the cause of the update // the update session, which tells us the cause of the update
#define DELAYED_BACKGROUND_CLEARING 1 #define DELAYED_BACKGROUND_CLEARING 1
// IMPORTANT: nested ReadLockClipping()s are not supported (by MultiLocker)
// constructor // constructor
WindowLayer::WindowLayer(BRect frame, const char* name, WindowLayer::WindowLayer(BRect frame, const char* name,
DrawingEngine* drawingEngine, Desktop* desktop) DrawingEngine* drawingEngine, Desktop* desktop)
@@ -75,6 +78,9 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
// destructor // destructor
WindowLayer::~WindowLayer() WindowLayer::~WindowLayer()
{ {
fClient->Lock();
fClient->Quit();
delete fTopLayer; delete fTopLayer;
} }
@@ -117,6 +123,27 @@ WindowLayer::MessageReceived(BMessage* message)
_DrawClient(token); _DrawClient(token);
break; 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: case MSG_SHOW:
if (IsHidden()) { 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 - //# pragma mark -
// CopyContents // CopyContents
@@ -507,12 +554,14 @@ WindowLayer::_DrawClient(int32 token)
// We have to be sure that the clipping is up to date. // We have to be sure that the clipping is up to date.
// If true readlocking would work correctly, this would // If true readlocking would work correctly, this would
// not be an issue // not be an issue
ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token);
if (!layer || !layer->IsVisible())
return;
if (fDesktop->ReadLockClipping()) { if (fDesktop->ReadLockClipping()) {
ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token);
if (!layer || !layer->IsVisible()) {
fDesktop->ReadUnlockClipping();
return;
}
if (!fEffectiveDrawingRegionValid) { if (!fEffectiveDrawingRegionValid) {
fEffectiveDrawingRegion = VisibleContentRegion(); fEffectiveDrawingRegion = VisibleContentRegion();
if (fInUpdate) { 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 // _DrawBorder
void void
WindowLayer::_DrawBorder() WindowLayer::_DrawBorder()
@@ -14,14 +14,17 @@ class Desktop;
class DrawingEngine; class DrawingEngine;
enum { enum {
MSG_REDRAW = 'rdrw', MSG_REDRAW = 'rdrw',
// client messages // client messages
MSG_BEGIN_UPDATE = 'bgud', MSG_BEGIN_UPDATE = 'bgud',
MSG_END_UPDATE = 'edud', MSG_END_UPDATE = 'edud',
MSG_DRAWING_COMMAND = 'draw', MSG_DRAWING_COMMAND = 'draw',
MSG_SHOW = 'show', MSG_SHOW = 'show',
MSG_INVALIDATE_VIEW = 'invl',
MSG_DRAW_POLYGON = 'drwp',
}; };
class UpdateSession { class UpdateSession {
@@ -82,6 +85,7 @@ class WindowLayer : public BLooper {
void MarkDirty(BRegion* regionOnScreen); void MarkDirty(BRegion* regionOnScreen);
void MarkContentDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen);
void InvalidateView(int32 token);
void ProcessDirtyRegion(BRegion* region); void ProcessDirtyRegion(BRegion* region);
@@ -98,6 +102,7 @@ class WindowLayer : public BLooper {
// different types of drawing // different types of drawing
void _TriggerContentRedraw(); void _TriggerContentRedraw();
void _DrawClient(int32 token); void _DrawClient(int32 token);
void _DrawClientPolygon(int32 token, BPoint polygon[4]);
void _DrawBorder(); void _DrawBorder();
// handling update sessions // handling update sessions
@@ -220,6 +220,8 @@ Window::Test()
int int
main(int argc, const char* argv[]) main(int argc, const char* argv[])
{ {
srand((long int)system_time());
App app; App app;
app.Run(); app.Run();
return 0; return 0;