/* * Copyright 2005-2008 Stephan Aßmus . All rights reserved. * Distributed under the terms of the MIT License. */ #include "UpdateQueue.h" #include #include #include //#define TRACE_UPDATE_QUEUE #ifdef TRACE_UPDATE_QUEUE # include # include 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 // constructor 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); } // destructor UpdateQueue::~UpdateQueue() { CALLED(); Shutdown(); } // FrameBufferChanged void UpdateQueue::FrameBufferChanged() { CALLED(); Init(); } // Init status_t UpdateQueue::Init() { CALLED(); Shutdown(); fRetraceSem = fInterface->RetraceSemaphore(); // fRefreshDuration = fInterface->... 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); } // Shutdown void UpdateQueue::Shutdown() { CALLED(); if (fUpdateExecutor < B_OK) return; fQuitting = true; status_t exitValue; wait_for_thread(fUpdateExecutor, &exitValue); fUpdateExecutor = B_BAD_THREAD_ID; } // AddRect void UpdateQueue::AddRect(const BRect& rect) { if (!rect.IsValid()) return; CALLED(); if (Lock()) { fUpdateRegion.Include(rect); Unlock(); } } // _ExecuteUpdatesEntry int32 UpdateQueue::_ExecuteUpdatesEntry(void* cookie) { UpdateQueue *gc = (UpdateQueue*)cookie; return gc->_ExecuteUpdates(); } // _ExecuteUpdates int32 UpdateQueue::_ExecuteUpdates() { while (!fQuitting) { status_t err; if (fRetraceSem >= 0) { bigtime_t timeout = system_time() + fRefreshDuration * 2; // TRACE("acquire_sem_etc(%lld)\n", timeout); 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; // TRACE("snooze_until(%lld)\n", timeout); 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: // execute updates if (fInterface->LockParallelAccess()) { if (Lock()) { int32 count = fUpdateRegion.CountRects(); if (count > 0) { TRACE("CopyBackToFront() - rects: %ld\n", count); // NOTE: not using the BRegion version, since that // doesn't take care of leaving out and compositing // the cursor. for (int32 i = 0; i < count; i++) fInterface->CopyBackToFront( fUpdateRegion.RectAt(i)); fUpdateRegion.MakeEmpty(); } Unlock(); } fInterface->UnlockParallelAccess(); } break; default: return err; } } return B_OK; }