#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
#include "base/debug/trace_event_synthetic_delay.h"
-#include "base/metrics/histogram.h"
#include "cc/base/swap_promise.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/gfx/frame_time.h"
+namespace cc {
+
namespace {
// Measured in seconds.
const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
+unsigned int nextBeginFrameId = 0;
+
class SwapPromiseChecker {
public:
- explicit SwapPromiseChecker(cc::LayerTreeHost* layer_tree_host)
+ explicit SwapPromiseChecker(LayerTreeHost* layer_tree_host)
: layer_tree_host_(layer_tree_host) {}
~SwapPromiseChecker() {
- layer_tree_host_->BreakSwapPromises(cc::SwapPromise::COMMIT_FAILS);
+ layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_FAILS);
}
private:
- cc::LayerTreeHost* layer_tree_host_;
+ LayerTreeHost* layer_tree_host_;
};
} // namespace
-namespace cc {
-
-struct ThreadProxy::CommitPendingRequest {
- CompletionEvent completion;
- bool commit_pending;
-};
-
struct ThreadProxy::SchedulerStateRequest {
CompletionEvent completion;
scoped_ptr<base::Value> state;
scoped_ptr<Proxy> ThreadProxy::Create(
LayerTreeHost* layer_tree_host,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return make_scoped_ptr(new ThreadProxy(layer_tree_host, impl_task_runner))
- .PassAs<Proxy>();
+ return make_scoped_ptr(new ThreadProxy(layer_tree_host,
+ main_task_runner,
+ impl_task_runner)).PassAs<Proxy>();
}
ThreadProxy::ThreadProxy(
LayerTreeHost* layer_tree_host,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
- : Proxy(impl_task_runner),
+ : Proxy(main_task_runner, impl_task_runner),
main_thread_only_vars_unsafe_(this, layer_tree_host->id()),
main_thread_or_blocked_vars_unsafe_(layer_tree_host),
- compositor_thread_vars_unsafe_(this, layer_tree_host->id()) {
+ compositor_thread_vars_unsafe_(
+ this,
+ layer_tree_host->id(),
+ layer_tree_host->rendering_stats_instrumentation()) {
TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
DCHECK(IsMainThread());
DCHECK(this->layer_tree_host());
return layer_tree_host->contents_texture_manager();
}
-ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(ThreadProxy* proxy,
- int layer_tree_host_id)
+ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
+ ThreadProxy* proxy,
+ int layer_tree_host_id,
+ RenderingStatsInstrumentation* rendering_stats_instrumentation)
: layer_tree_host_id(layer_tree_host_id),
contents_texture_manager(NULL),
commit_completion_event(NULL),
base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)),
base::TimeDelta::FromMilliseconds(
kSmoothnessTakesPriorityExpirationDelay * 1000)),
+ timing_history(rendering_stats_instrumentation),
weak_factory(proxy) {
}
void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread");
DCHECK(IsImplThread());
- CheckOutputSurfaceStatusOnImplThread();
-}
-
-void ThreadProxy::CheckOutputSurfaceStatusOnImplThread() {
- TRACE_EVENT0("cc", "ThreadProxy::CheckOutputSurfaceStatusOnImplThread");
- DCHECK(IsImplThread());
- if (!impl().layer_tree_host_impl->IsContextLost())
- return;
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::DidLoseOutputSurface, main_thread_weak_ptr_));
else
TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this);
- if (!main().defer_commits && main().pending_deferred_commit)
+ if (!main().defer_commits && main().pending_deferred_commit) {
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrame,
main_thread_weak_ptr_,
base::Passed(&main().pending_deferred_commit)));
+ }
}
bool ThreadProxy::CommitRequested() const {
completion->Signal();
}
+bool ThreadProxy::SupportsImplScrolling() const {
+ return true;
+}
+
void ThreadProxy::SetDebugState(const LayerTreeDebugState& debug_state) {
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
}
void ThreadProxy::ScheduledActionSendBeginMainFrame() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginMainFrame");
+ unsigned int begin_frame_id = nextBeginFrameId++;
+ benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
+ benchmark_instrumentation::kSendBeginFrame, begin_frame_id);
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
new BeginMainFrameAndCommitState);
+ begin_main_frame_state->begin_frame_id = begin_frame_id;
begin_main_frame_state->monotonic_frame_begin_time =
impl().layer_tree_host_impl->CurrentFrameTimeTicks();
begin_main_frame_state->scroll_info =
void ThreadProxy::BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
- TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame");
+ benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
+ benchmark_instrumentation::kDoBeginFrame,
+ begin_main_frame_state->begin_frame_id);
TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
DCHECK(IsMainThread());
main().commit_requested = true;
main().commit_request_sent_to_impl_thread = true;
- layer_tree_host()->ApplyScrollAndScale(*begin_main_frame_state->scroll_info);
+ layer_tree_host()->ApplyScrollAndScale(
+ begin_main_frame_state->scroll_info.get());
layer_tree_host()->WillBeginMainFrame();
// went through, and input should no longer be throttled, etc.
layer_tree_host()->CommitComplete();
layer_tree_host()->DidBeginMainFrame();
+ layer_tree_host()->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE);
return;
}
RenderingStatsInstrumentation* stats_instrumentation =
layer_tree_host()->rendering_stats_instrumentation();
- BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
+ benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
stats_instrumentation->main_thread_rendering_stats());
stats_instrumentation->AccumulateAndClearMainThreadStats();
}
if (hold_commit) {
// For some layer types in impl-side painting, the commit is held until
- // the pending tree is activated. It's also possible that the
- // pending tree has already activated if there was no work to be done.
+ // the sync tree is activated. It's also possible that the
+ // sync tree has already activated if there was no work to be done.
TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
impl().completion_event_for_commit_held_on_tree_activation =
impl().commit_completion_event;
impl().layer_tree_host_impl->UpdateVisibleTiles();
}
-void ThreadProxy::ScheduledActionActivatePendingTree() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivatePendingTree");
+void ThreadProxy::ScheduledActionActivateSyncTree() {
+ TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree");
DCHECK(IsImplThread());
- impl().layer_tree_host_impl->ActivatePendingTree();
+ impl().layer_tree_host_impl->ActivateSyncTree();
}
void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
DCHECK(impl().layer_tree_host_impl.get());
impl().timing_history.DidStartDrawing();
- base::TimeDelta draw_duration_estimate = DrawDurationEstimate();
base::AutoReset<bool> mark_inside(&impl().inside_draw, true);
if (impl().did_commit_after_animating) {
base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_));
}
- if (draw_frame)
- CheckOutputSurfaceStatusOnImplThread();
-
- if (result == DRAW_SUCCESS) {
- base::TimeDelta draw_duration = impl().timing_history.DidFinishDrawing();
-
- base::TimeDelta draw_duration_overestimate;
- base::TimeDelta draw_duration_underestimate;
- if (draw_duration > draw_duration_estimate)
- draw_duration_underestimate = draw_duration - draw_duration_estimate;
- else
- draw_duration_overestimate = draw_duration_estimate - draw_duration;
- UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDuration",
- draw_duration,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(100),
- 50);
- UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationUnderestimate",
- draw_duration_underestimate,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(100),
- 50);
- UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationOverestimate",
- draw_duration_overestimate,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(100),
- 50);
- }
+ if (result == DRAW_SUCCESS)
+ impl().timing_history.DidFinishDrawing();
DCHECK_NE(INVALID_RESULT, result);
return result;
void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) {
TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread");
DCHECK(IsImplThread());
- if (impl().layer_tree_host_impl->resource_provider())
- impl().layer_tree_host_impl->resource_provider()->Finish();
+ if (impl().layer_tree_host_impl->output_surface()) {
+ ContextProvider* context_provider =
+ impl().layer_tree_host_impl->output_surface()->context_provider();
+ if (context_provider)
+ context_provider->ContextGL()->Finish();
+ }
completion->Signal();
}
ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {}
-scoped_ptr<base::Value> ThreadProxy::AsValue() const {
- scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
-
+void ThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
CompletionEvent completion;
{
DebugScopedSetMainThreadBlocked main_thread_blocked(
const_cast<ThreadProxy*>(this));
+ scoped_refptr<base::debug::TracedValue> state_refptr(state);
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::AsValueOnImplThread,
impl_thread_weak_ptr_,
&completion,
- state.get()));
+ state_refptr));
completion.Wait();
}
- return state.PassAs<base::Value>();
}
void ThreadProxy::AsValueOnImplThread(CompletionEvent* completion,
- base::DictionaryValue* state) const {
- state->Set("layer_tree_host_impl",
- impl().layer_tree_host_impl->AsValue().release());
+ base::debug::TracedValue* state) const {
+ state->BeginDictionary("layer_tree_host_impl");
+ impl().layer_tree_host_impl->AsValueInto(state);
+ state->EndDictionary();
completion->Signal();
}
-bool ThreadProxy::CommitPendingForTesting() {
+bool ThreadProxy::MainFrameWillHappenForTesting() {
DCHECK(IsMainThread());
- CommitPendingRequest commit_pending_request;
+ CompletionEvent completion;
+ bool main_frame_will_happen = false;
{
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(&ThreadProxy::CommitPendingOnImplThreadForTesting,
+ base::Bind(&ThreadProxy::MainFrameWillHappenOnImplThreadForTesting,
impl_thread_weak_ptr_,
- &commit_pending_request));
- commit_pending_request.completion.Wait();
+ &completion,
+ &main_frame_will_happen));
+ completion.Wait();
}
- return commit_pending_request.commit_pending;
+ return main_frame_will_happen;
}
-void ThreadProxy::CommitPendingOnImplThreadForTesting(
- CommitPendingRequest* request) {
+void ThreadProxy::MainFrameWillHappenOnImplThreadForTesting(
+ CompletionEvent* completion,
+ bool* main_frame_will_happen) {
DCHECK(IsImplThread());
- if (impl().layer_tree_host_impl->output_surface())
- request->commit_pending = impl().scheduler->CommitPending();
- else
- request->commit_pending = false;
- request->completion.Signal();
-}
-
-scoped_ptr<base::Value> ThreadProxy::SchedulerAsValueForTesting() {
- if (IsImplThread())
- return impl().scheduler->AsValue().Pass();
-
- SchedulerStateRequest scheduler_state_request;
- {
- DebugScopedSetMainThreadBlocked main_thread_blocked(this);
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::SchedulerAsValueOnImplThreadForTesting,
- impl_thread_weak_ptr_,
- &scheduler_state_request));
- scheduler_state_request.completion.Wait();
+ if (impl().layer_tree_host_impl->output_surface()) {
+ *main_frame_will_happen = impl().scheduler->MainFrameForTestingWillHappen();
+ } else {
+ *main_frame_will_happen = false;
}
- return scheduler_state_request.state.Pass();
-}
-
-void ThreadProxy::SchedulerAsValueOnImplThreadForTesting(
- SchedulerStateRequest* request) {
- DCHECK(IsImplThread());
- request->state = impl().scheduler->AsValue();
- request->completion.Signal();
+ completion->Signal();
}
void ThreadProxy::RenewTreePriority() {
Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, start_fade, delay);
}
-void ThreadProxy::DidActivatePendingTree() {
- TRACE_EVENT0("cc", "ThreadProxy::DidActivatePendingTreeOnImplThread");
+void ThreadProxy::DidActivateSyncTree() {
+ TRACE_EVENT0("cc", "ThreadProxy::DidActivateSyncTreeOnImplThread");
DCHECK(IsImplThread());
- DCHECK(!impl().layer_tree_host_impl->pending_tree());
if (impl().completion_event_for_commit_held_on_tree_activation) {
TRACE_EVENT_INSTANT0(
UpdateBackgroundAnimateTicking();
- impl().timing_history.DidActivatePendingTree();
+ impl().timing_history.DidActivateSyncTree();
}
void ThreadProxy::DidManageTiles() {