* Copyright 2005-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "UpdateQueue.h"
#include <new>
#include <stdio.h>
#include <string.h>
#ifdef TRACE_UPDATE_QUEUE
# include <FunctionTracer.h>
# include <String.h>
static int32 sFunctionDepth = -1;
# define CALLED(x...) FunctionTracer _ft("UpdateQueue", __FUNCTION__, \
sFunctionDepth)
# define TRACE(x...) { BString _to; \
_to.Append(' ', (sFunctionDepth + 1) * 2); \
printf("%s", _to.String()); printf(x); }
#else
# define CALLED(x...)
# define TRACE(x...)
#endif
UpdateQueue::UpdateQueue(HWInterface* interface)
:
BLocker("AppServer_UpdateQueue"),
fQuitting(false),
fInterface(interface),
fUpdateRegion(),
fUpdateExecutor(B_BAD_THREAD_ID),
fRetraceSem(B_BAD_SEM_ID),
fRefreshDuration(1000000 / 60)
{
CALLED();
TRACE("this: %p\n", this);
TRACE("fInterface: %p\n", fInterface);
}
UpdateQueue::~UpdateQueue()
{
CALLED();
Shutdown();
}
void
UpdateQueue::FrameBufferChanged()
{
CALLED();
Init();
}
status_t
UpdateQueue::Init()
{
CALLED();
Shutdown();
fRetraceSem = fInterface->RetraceSemaphore();
TRACE("fRetraceSem: %ld, fRefreshDuration: %lld\n",
fRetraceSem, fRefreshDuration);
fQuitting = false;
fUpdateExecutor = spawn_thread(_ExecuteUpdatesEntry, "update queue runner",
B_REAL_TIME_PRIORITY, this);
if (fUpdateExecutor < B_OK)
return fUpdateExecutor;
return resume_thread(fUpdateExecutor);
}
void
UpdateQueue::Shutdown()
{
CALLED();
if (fUpdateExecutor < B_OK)
return;
fQuitting = true;
status_t exitValue;
wait_for_thread(fUpdateExecutor, &exitValue);
fUpdateExecutor = B_BAD_THREAD_ID;
}
void
UpdateQueue::AddRect(const BRect& rect)
{
if (!rect.IsValid())
return;
CALLED();
if (Lock()) {
fUpdateRegion.Include(rect);
Unlock();
}
}
int32
UpdateQueue::_ExecuteUpdatesEntry(void* cookie)
{
UpdateQueue *gc = (UpdateQueue*)cookie;
return gc->_ExecuteUpdates();
}
int32
UpdateQueue::_ExecuteUpdates()
{
while (!fQuitting) {
status_t err;
if (fRetraceSem >= 0) {
bigtime_t timeout = system_time() + fRefreshDuration * 2;
do {
err = acquire_sem_etc(fRetraceSem, 1,
B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
} while (err == B_INTERRUPTED && !fQuitting);
} else {
bigtime_t timeout = system_time() + fRefreshDuration;
do {
err = snooze_until(timeout, B_SYSTEM_TIMEBASE);
} while (err == B_INTERRUPTED && !fQuitting);
}
if (fQuitting)
return B_OK;
switch (err) {
case B_OK:
case B_TIMED_OUT:
if (fInterface->LockParallelAccess()) {
if (Lock()) {
int32 count = fUpdateRegion.CountRects();
if (count > 0) {
TRACE("CopyBackToFront() - rects: %ld\n", count);
for (int32 i = 0; i < count; i++)
fInterface->CopyBackToFront(
fUpdateRegion.RectAt(i));
fUpdateRegion.MakeEmpty();
}
Unlock();
}
fInterface->UnlockParallelAccess();
}
break;
default:
return err;
}
}
return B_OK;
}