1*2469a6f4SStephan Aßmus /*
2*2469a6f4SStephan Aßmus * Copyright 2005-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3*2469a6f4SStephan Aßmus * Distributed under the terms of the MIT License.
4*2469a6f4SStephan Aßmus */
5*2469a6f4SStephan Aßmus #include "UpdateQueue.h"
63294d07bSStephan Aßmus
73294d07bSStephan Aßmus #include <new>
83294d07bSStephan Aßmus #include <stdio.h>
9f6939eb1SStephan Aßmus #include <string.h>
103294d07bSStephan Aßmus
113294d07bSStephan Aßmus
12*2469a6f4SStephan Aßmus //#define TRACE_UPDATE_QUEUE
13*2469a6f4SStephan Aßmus #ifdef TRACE_UPDATE_QUEUE
14*2469a6f4SStephan Aßmus # include <FunctionTracer.h>
15*2469a6f4SStephan Aßmus # include <String.h>
16*2469a6f4SStephan Aßmus
17*2469a6f4SStephan Aßmus static int32 sFunctionDepth = -1;
18*2469a6f4SStephan Aßmus # define CALLED(x...) FunctionTracer _ft("UpdateQueue", __FUNCTION__, \
19*2469a6f4SStephan Aßmus sFunctionDepth)
20*2469a6f4SStephan Aßmus # define TRACE(x...) { BString _to; \
21*2469a6f4SStephan Aßmus _to.Append(' ', (sFunctionDepth + 1) * 2); \
22*2469a6f4SStephan Aßmus printf("%s", _to.String()); printf(x); }
23*2469a6f4SStephan Aßmus #else
24*2469a6f4SStephan Aßmus # define CALLED(x...)
25*2469a6f4SStephan Aßmus # define TRACE(x...)
26*2469a6f4SStephan Aßmus #endif
27*2469a6f4SStephan Aßmus
283294d07bSStephan Aßmus
293294d07bSStephan Aßmus // constructor
UpdateQueue(HWInterface * interface)303294d07bSStephan Aßmus UpdateQueue::UpdateQueue(HWInterface* interface)
31*2469a6f4SStephan Aßmus :
32*2469a6f4SStephan Aßmus BLocker("AppServer_UpdateQueue"),
33*2469a6f4SStephan Aßmus fQuitting(false),
34f38c001eSMarcus Overhagen fInterface(interface),
353294d07bSStephan Aßmus fUpdateRegion(),
36*2469a6f4SStephan Aßmus fUpdateExecutor(B_BAD_THREAD_ID),
37*2469a6f4SStephan Aßmus fRetraceSem(B_BAD_SEM_ID),
38*2469a6f4SStephan Aßmus fRefreshDuration(1000000 / 60)
393294d07bSStephan Aßmus {
40*2469a6f4SStephan Aßmus CALLED();
41*2469a6f4SStephan Aßmus TRACE("this: %p\n", this);
42*2469a6f4SStephan Aßmus TRACE("fInterface: %p\n", fInterface);
433294d07bSStephan Aßmus }
443294d07bSStephan Aßmus
453294d07bSStephan Aßmus // destructor
~UpdateQueue()463294d07bSStephan Aßmus UpdateQueue::~UpdateQueue()
473294d07bSStephan Aßmus {
48*2469a6f4SStephan Aßmus CALLED();
49*2469a6f4SStephan Aßmus
50*2469a6f4SStephan Aßmus Shutdown();
513294d07bSStephan Aßmus }
523294d07bSStephan Aßmus
53*2469a6f4SStephan Aßmus // FrameBufferChanged
54*2469a6f4SStephan Aßmus void
FrameBufferChanged()55*2469a6f4SStephan Aßmus UpdateQueue::FrameBufferChanged()
563294d07bSStephan Aßmus {
57*2469a6f4SStephan Aßmus CALLED();
58*2469a6f4SStephan Aßmus
59*2469a6f4SStephan Aßmus Init();
60*2469a6f4SStephan Aßmus }
61*2469a6f4SStephan Aßmus
62*2469a6f4SStephan Aßmus // Init
63*2469a6f4SStephan Aßmus status_t
Init()64*2469a6f4SStephan Aßmus UpdateQueue::Init()
65*2469a6f4SStephan Aßmus {
66*2469a6f4SStephan Aßmus CALLED();
67*2469a6f4SStephan Aßmus
68*2469a6f4SStephan Aßmus Shutdown();
69*2469a6f4SStephan Aßmus
70*2469a6f4SStephan Aßmus fRetraceSem = fInterface->RetraceSemaphore();
71*2469a6f4SStephan Aßmus // fRefreshDuration = fInterface->...
72*2469a6f4SStephan Aßmus
73*2469a6f4SStephan Aßmus TRACE("fRetraceSem: %ld, fRefreshDuration: %lld\n",
74*2469a6f4SStephan Aßmus fRetraceSem, fRefreshDuration);
75*2469a6f4SStephan Aßmus
76*2469a6f4SStephan Aßmus fQuitting = false;
77*2469a6f4SStephan Aßmus fUpdateExecutor = spawn_thread(_ExecuteUpdatesEntry, "update queue runner",
78*2469a6f4SStephan Aßmus B_REAL_TIME_PRIORITY, this);
79*2469a6f4SStephan Aßmus if (fUpdateExecutor < B_OK)
80*2469a6f4SStephan Aßmus return fUpdateExecutor;
81*2469a6f4SStephan Aßmus
82*2469a6f4SStephan Aßmus return resume_thread(fUpdateExecutor);
83*2469a6f4SStephan Aßmus }
84*2469a6f4SStephan Aßmus
85*2469a6f4SStephan Aßmus // Shutdown
86*2469a6f4SStephan Aßmus void
Shutdown()87*2469a6f4SStephan Aßmus UpdateQueue::Shutdown()
88*2469a6f4SStephan Aßmus {
89*2469a6f4SStephan Aßmus CALLED();
90*2469a6f4SStephan Aßmus
91*2469a6f4SStephan Aßmus if (fUpdateExecutor < B_OK)
92*2469a6f4SStephan Aßmus return;
93*2469a6f4SStephan Aßmus fQuitting = true;
94*2469a6f4SStephan Aßmus status_t exitValue;
95*2469a6f4SStephan Aßmus wait_for_thread(fUpdateExecutor, &exitValue);
96*2469a6f4SStephan Aßmus fUpdateExecutor = B_BAD_THREAD_ID;
973294d07bSStephan Aßmus }
983294d07bSStephan Aßmus
993294d07bSStephan Aßmus // AddRect
1003294d07bSStephan Aßmus void
AddRect(const BRect & rect)1013294d07bSStephan Aßmus UpdateQueue::AddRect(const BRect& rect)
1023294d07bSStephan Aßmus {
103*2469a6f4SStephan Aßmus if (!rect.IsValid())
104*2469a6f4SStephan Aßmus return;
105*2469a6f4SStephan Aßmus
106*2469a6f4SStephan Aßmus CALLED();
107*2469a6f4SStephan Aßmus
108*2469a6f4SStephan Aßmus if (Lock()) {
1093294d07bSStephan Aßmus fUpdateRegion.Include(rect);
110*2469a6f4SStephan Aßmus Unlock();
111*2469a6f4SStephan Aßmus }
1123294d07bSStephan Aßmus }
1133294d07bSStephan Aßmus
114*2469a6f4SStephan Aßmus // _ExecuteUpdatesEntry
1153294d07bSStephan Aßmus int32
_ExecuteUpdatesEntry(void * cookie)116*2469a6f4SStephan Aßmus UpdateQueue::_ExecuteUpdatesEntry(void* cookie)
1173294d07bSStephan Aßmus {
1183294d07bSStephan Aßmus UpdateQueue *gc = (UpdateQueue*)cookie;
1193294d07bSStephan Aßmus return gc->_ExecuteUpdates();
1203294d07bSStephan Aßmus }
1213294d07bSStephan Aßmus
1223294d07bSStephan Aßmus // _ExecuteUpdates
1233294d07bSStephan Aßmus int32
_ExecuteUpdates()1243294d07bSStephan Aßmus UpdateQueue::_ExecuteUpdates()
1253294d07bSStephan Aßmus {
126*2469a6f4SStephan Aßmus while (!fQuitting) {
127*2469a6f4SStephan Aßmus status_t err;
128*2469a6f4SStephan Aßmus if (fRetraceSem >= 0) {
129*2469a6f4SStephan Aßmus bigtime_t timeout = system_time() + fRefreshDuration * 2;
130*2469a6f4SStephan Aßmus // TRACE("acquire_sem_etc(%lld)\n", timeout);
131*2469a6f4SStephan Aßmus do {
132*2469a6f4SStephan Aßmus err = acquire_sem_etc(fRetraceSem, 1,
133*2469a6f4SStephan Aßmus B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
134*2469a6f4SStephan Aßmus } while (err == B_INTERRUPTED && !fQuitting);
135*2469a6f4SStephan Aßmus } else {
136*2469a6f4SStephan Aßmus bigtime_t timeout = system_time() + fRefreshDuration;
137*2469a6f4SStephan Aßmus // TRACE("snooze_until(%lld)\n", timeout);
138*2469a6f4SStephan Aßmus do {
139*2469a6f4SStephan Aßmus err = snooze_until(timeout, B_SYSTEM_TIMEBASE);
140*2469a6f4SStephan Aßmus } while (err == B_INTERRUPTED && !fQuitting);
141*2469a6f4SStephan Aßmus }
142*2469a6f4SStephan Aßmus if (fQuitting)
143*2469a6f4SStephan Aßmus return B_OK;
1443294d07bSStephan Aßmus switch (err) {
1453294d07bSStephan Aßmus case B_OK:
1463294d07bSStephan Aßmus case B_TIMED_OUT:
1473294d07bSStephan Aßmus // execute updates
1482cfe93e7SStephan Aßmus if (fInterface->LockParallelAccess()) {
149*2469a6f4SStephan Aßmus if (Lock()) {
1503294d07bSStephan Aßmus int32 count = fUpdateRegion.CountRects();
151f6939eb1SStephan Aßmus if (count > 0) {
152*2469a6f4SStephan Aßmus TRACE("CopyBackToFront() - rects: %ld\n", count);
153*2469a6f4SStephan Aßmus // NOTE: not using the BRegion version, since that
154*2469a6f4SStephan Aßmus // doesn't take care of leaving out and compositing
155*2469a6f4SStephan Aßmus // the cursor.
156*2469a6f4SStephan Aßmus for (int32 i = 0; i < count; i++)
157*2469a6f4SStephan Aßmus fInterface->CopyBackToFront(
158*2469a6f4SStephan Aßmus fUpdateRegion.RectAt(i));
1593294d07bSStephan Aßmus fUpdateRegion.MakeEmpty();
160f6939eb1SStephan Aßmus }
161*2469a6f4SStephan Aßmus Unlock();
162*2469a6f4SStephan Aßmus }
1632cfe93e7SStephan Aßmus fInterface->UnlockParallelAccess();
1643294d07bSStephan Aßmus }
1653294d07bSStephan Aßmus break;
1663294d07bSStephan Aßmus default:
167*2469a6f4SStephan Aßmus return err;
1683294d07bSStephan Aßmus }
1693294d07bSStephan Aßmus }
170*2469a6f4SStephan Aßmus return B_OK;
1713294d07bSStephan Aßmus }
1723294d07bSStephan Aßmus
173