1/*
2 * Copyright 2005-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5#include "UpdateQueue.h"
6
7#include <new>
8#include <stdio.h>
9#include <string.h>
10
11
12//#define TRACE_UPDATE_QUEUE
13#ifdef TRACE_UPDATE_QUEUE
14#	include <FunctionTracer.h>
15#	include <String.h>
16
17	static int32 sFunctionDepth = -1;
18#	define CALLED(x...)	FunctionTracer _ft("UpdateQueue", __FUNCTION__, \
19							sFunctionDepth)
20#	define TRACE(x...)	{ BString _to; \
21							_to.Append(' ', (sFunctionDepth + 1) * 2); \
22							printf("%s", _to.String()); printf(x); }
23#else
24#	define CALLED(x...)
25#	define TRACE(x...)
26#endif
27
28
29// constructor
30UpdateQueue::UpdateQueue(HWInterface* interface)
31	:
32	BLocker("AppServer_UpdateQueue"),
33	fQuitting(false),
34 	fInterface(interface),
35	fUpdateRegion(),
36	fUpdateExecutor(B_BAD_THREAD_ID),
37	fRetraceSem(B_BAD_SEM_ID),
38	fRefreshDuration(1000000 / 60)
39{
40	CALLED();
41	TRACE("this: %p\n", this);
42	TRACE("fInterface: %p\n", fInterface);
43}
44
45// destructor
46UpdateQueue::~UpdateQueue()
47{
48	CALLED();
49
50	Shutdown();
51}
52
53// FrameBufferChanged
54void
55UpdateQueue::FrameBufferChanged()
56{
57	CALLED();
58
59	Init();
60}
61
62// Init
63status_t
64UpdateQueue::Init()
65{
66	CALLED();
67
68	Shutdown();
69
70	fRetraceSem = fInterface->RetraceSemaphore();
71//	fRefreshDuration = fInterface->...
72
73	TRACE("fRetraceSem: %ld, fRefreshDuration: %lld\n",
74		fRetraceSem, fRefreshDuration);
75
76	fQuitting = false;
77	fUpdateExecutor = spawn_thread(_ExecuteUpdatesEntry, "update queue runner",
78		B_REAL_TIME_PRIORITY, this);
79	if (fUpdateExecutor < B_OK)
80		return fUpdateExecutor;
81
82	return resume_thread(fUpdateExecutor);
83}
84
85// Shutdown
86void
87UpdateQueue::Shutdown()
88{
89	CALLED();
90
91	if (fUpdateExecutor < B_OK)
92		return;
93	fQuitting = true;
94	status_t exitValue;
95	wait_for_thread(fUpdateExecutor, &exitValue);
96	fUpdateExecutor = B_BAD_THREAD_ID;
97}
98
99// AddRect
100void
101UpdateQueue::AddRect(const BRect& rect)
102{
103	if (!rect.IsValid())
104		return;
105
106	CALLED();
107
108	if (Lock()) {
109		fUpdateRegion.Include(rect);
110		Unlock();
111	}
112}
113
114// _ExecuteUpdatesEntry
115int32
116UpdateQueue::_ExecuteUpdatesEntry(void* cookie)
117{
118	UpdateQueue *gc = (UpdateQueue*)cookie;
119	return gc->_ExecuteUpdates();
120}
121
122// _ExecuteUpdates
123int32
124UpdateQueue::_ExecuteUpdates()
125{
126	while (!fQuitting) {
127		status_t err;
128		if (fRetraceSem >= 0) {
129			bigtime_t timeout = system_time() + fRefreshDuration * 2;
130//			TRACE("acquire_sem_etc(%lld)\n", timeout);
131			do {
132				err = acquire_sem_etc(fRetraceSem, 1,
133					B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
134			} while (err == B_INTERRUPTED && !fQuitting);
135		} else {
136			bigtime_t timeout = system_time() + fRefreshDuration;
137//			TRACE("snooze_until(%lld)\n", timeout);
138			do {
139				err = snooze_until(timeout, B_SYSTEM_TIMEBASE);
140			} while (err == B_INTERRUPTED && !fQuitting);
141		}
142		if (fQuitting)
143			return B_OK;
144		switch (err) {
145			case B_OK:
146			case B_TIMED_OUT:
147				// execute updates
148				if (fInterface->LockParallelAccess()) {
149					if (Lock()) {
150						int32 count = fUpdateRegion.CountRects();
151						if (count > 0) {
152							TRACE("CopyBackToFront() - rects: %ld\n", count);
153							// NOTE: not using the BRegion version, since that
154							// doesn't take care of leaving out and compositing
155							// the cursor.
156							for (int32 i = 0; i < count; i++)
157								fInterface->CopyBackToFront(
158									fUpdateRegion.RectAt(i));
159							fUpdateRegion.MakeEmpty();
160						}
161						Unlock();
162					}
163					fInterface->UnlockParallelAccess();
164				}
165				break;
166			default:
167				return err;
168		}
169	}
170	return B_OK;
171}
172
173