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

View File

@ -1,8 +1,13 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <Message.h>
#include <MessageQueue.h>
#include <MessageRunner.h>
#include <Messenger.h>
#include <Rect.h>
#include <String.h>
#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);
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -220,6 +220,8 @@ Window::Test()
int
main(int argc, const char* argv[])
{
srand((long int)system_time());
App app;
app.Run();
return 0;