Don't add an aura tooltip to bubble close buttons on Windows.
[chromium-blink-merge.git] / gpu / command_buffer / service / gpu_tracer.cc
bloba633959f385d11f9ff0ad72f543bc3bd5d2b8543
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/gpu_tracer.h"
7 #include <deque>
9 #include "base/bind.h"
10 #include "base/strings/string_util.h"
11 #include "base/time/time.h"
12 #include "base/trace_event/trace_event.h"
13 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
14 #include "gpu/command_buffer/service/context_group.h"
15 #include "ui/gl/gl_bindings.h"
16 #include "ui/gl/gl_version_info.h"
17 #include "ui/gl/gpu_timing.h"
19 namespace gpu {
20 namespace gles2 {
22 static const unsigned int kProcessInterval = 16;
23 static TraceOutputter* g_outputter_thread = NULL;
25 TraceMarker::TraceMarker(const std::string& category, const std::string& name)
26 : category_(category),
27 name_(name),
28 trace_(NULL) {
31 TraceMarker::~TraceMarker() {
34 scoped_refptr<TraceOutputter> TraceOutputter::Create(const std::string& name) {
35 if (!g_outputter_thread) {
36 g_outputter_thread = new TraceOutputter(name);
38 return g_outputter_thread;
41 TraceOutputter::TraceOutputter(const std::string& name)
42 : named_thread_(name.c_str()), local_trace_id_(0) {
43 named_thread_.Start();
44 named_thread_.Stop();
47 TraceOutputter::~TraceOutputter() { g_outputter_thread = NULL; }
49 void TraceOutputter::TraceDevice(const std::string& category,
50 const std::string& name,
51 int64 start_time,
52 int64 end_time) {
53 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1(
54 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
55 name.c_str(),
56 local_trace_id_,
57 named_thread_.thread_id(),
58 start_time,
59 "gl_category",
60 category.c_str());
61 TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1(
62 TRACE_DISABLED_BY_DEFAULT("gpu.device"),
63 name.c_str(),
64 local_trace_id_,
65 named_thread_.thread_id(),
66 end_time,
67 "gl_category",
68 category.c_str());
69 ++local_trace_id_;
72 void TraceOutputter::TraceServiceBegin(const std::string& category,
73 const std::string& name) {
74 TRACE_EVENT_COPY_BEGIN1(TRACE_DISABLED_BY_DEFAULT("gpu.service"),
75 name.c_str(), "gl_category", category.c_str());
78 void TraceOutputter::TraceServiceEnd(const std::string& category,
79 const std::string& name) {
80 TRACE_EVENT_COPY_END1(TRACE_DISABLED_BY_DEFAULT("gpu.service"),
81 name.c_str(), "gl_category", category.c_str());
84 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter,
85 gfx::GPUTimingClient* gpu_timing_client,
86 const std::string& category,
87 const std::string& name,
88 const bool enabled)
89 : category_(category),
90 name_(name),
91 outputter_(outputter),
92 enabled_(enabled) {
93 if (gpu_timing_client->IsAvailable() &&
94 gpu_timing_client->IsTimerOffsetAvailable()) {
95 gpu_timer_ = gpu_timing_client->CreateGPUTimer();
99 GPUTrace::~GPUTrace() {
102 void GPUTrace::Destroy(bool have_context) {
103 if (gpu_timer_.get()) {
104 gpu_timer_->Destroy(have_context);
108 void GPUTrace::Start(bool trace_service) {
109 if (trace_service) {
110 outputter_->TraceServiceBegin(category_, name_);
112 if (gpu_timer_.get()) {
113 gpu_timer_->Start();
117 void GPUTrace::End(bool tracing_service) {
118 if (gpu_timer_.get()) {
119 gpu_timer_->End();
121 if (tracing_service) {
122 outputter_->TraceServiceEnd(category_, name_);
126 bool GPUTrace::IsAvailable() {
127 return !gpu_timer_.get() || gpu_timer_->IsAvailable();
130 void GPUTrace::Process() {
131 if (gpu_timer_.get()) {
132 DCHECK(IsAvailable());
134 int64 start = 0;
135 int64 end = 0;
136 gpu_timer_->GetStartEndTimestamps(&start, &end);
137 outputter_->TraceDevice(category_, name_, start, end);
141 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder)
142 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
143 TRACE_DISABLED_BY_DEFAULT("gpu.service"))),
144 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
145 TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
146 decoder_(decoder),
147 gpu_executing_(false),
148 process_posted_(false) {
149 DCHECK(decoder_);
150 gfx::GLContext* context = decoder_->GetGLContext();
151 if (context) {
152 gpu_timing_client_ = context->CreateGPUTimingClient();
153 } else {
154 gpu_timing_client_ = new gfx::GPUTimingClient();
158 GPUTracer::~GPUTracer() {
161 void GPUTracer::Destroy(bool have_context) {
162 for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
163 for (size_t i = 0; i < markers_[n].size(); i++) {
164 TraceMarker& marker = markers_[n][i];
165 if (marker.trace_.get()) {
166 marker.trace_->Destroy(have_context);
167 marker.trace_ = 0;
172 ClearFinishedTraces(have_context);
175 bool GPUTracer::BeginDecoding() {
176 if (gpu_executing_)
177 return false;
179 if (!outputter_) {
180 outputter_ = CreateOutputter(gpu_timing_client_->GetTimerTypeName());
183 if (*gpu_trace_dev_category == '\0') {
184 // If GPU device category is off, invalidate timing sync.
185 gpu_timing_client_->InvalidateTimerOffset();
188 gpu_executing_ = true;
189 if (IsTracing()) {
190 gpu_timing_client_->CheckAndResetTimerErrors();
191 // Begin a Trace for all active markers
192 for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
193 for (size_t i = 0; i < markers_[n].size(); i++) {
194 TraceMarker& trace_marker = markers_[n][i];
195 trace_marker.trace_ =
196 new GPUTrace(outputter_, gpu_timing_client_.get(),
197 trace_marker.category_, trace_marker.name_,
198 *gpu_trace_dev_category != 0);
199 trace_marker.trace_->Start(*gpu_trace_srv_category != 0);
203 return true;
206 bool GPUTracer::EndDecoding() {
207 if (!gpu_executing_)
208 return false;
210 // End Trace for all active markers
211 if (IsTracing()) {
212 for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
213 for (size_t i = 0; i < markers_[n].size(); i++) {
214 TraceMarker& marker = markers_[n][i];
215 if (marker.trace_.get()) {
216 marker.trace_->End(*gpu_trace_srv_category != 0);
218 finished_traces_.push_back(marker.trace_);
219 marker.trace_ = 0;
223 IssueProcessTask();
226 gpu_executing_ = false;
228 // NOTE(vmiura): glFlush() here can help give better trace results,
229 // but it distorts the normal device behavior.
230 return true;
233 bool GPUTracer::Begin(const std::string& category, const std::string& name,
234 GpuTracerSource source) {
235 if (!gpu_executing_)
236 return false;
238 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES);
240 // Push new marker from given 'source'
241 markers_[source].push_back(TraceMarker(category, name));
243 // Create trace
244 if (IsTracing()) {
245 scoped_refptr<GPUTrace> trace = new GPUTrace(
246 outputter_, gpu_timing_client_.get(), category, name,
247 *gpu_trace_dev_category != 0);
248 trace->Start(*gpu_trace_srv_category != 0);
249 markers_[source].back().trace_ = trace;
252 return true;
255 bool GPUTracer::End(GpuTracerSource source) {
256 if (!gpu_executing_)
257 return false;
259 DCHECK(source >= 0 && source < NUM_TRACER_SOURCES);
261 // Pop last marker with matching 'source'
262 if (!markers_[source].empty()) {
263 scoped_refptr<GPUTrace> trace = markers_[source].back().trace_;
264 if (trace.get()) {
265 if (IsTracing()) {
266 trace->End(*gpu_trace_srv_category != 0);
269 finished_traces_.push_back(trace);
270 IssueProcessTask();
273 markers_[source].pop_back();
274 return true;
276 return false;
279 bool GPUTracer::IsTracing() {
280 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0);
283 const std::string& GPUTracer::CurrentCategory(GpuTracerSource source) const {
284 if (source >= 0 &&
285 source < NUM_TRACER_SOURCES &&
286 !markers_[source].empty()) {
287 return markers_[source].back().category_;
289 return base::EmptyString();
292 const std::string& GPUTracer::CurrentName(GpuTracerSource source) const {
293 if (source >= 0 &&
294 source < NUM_TRACER_SOURCES &&
295 !markers_[source].empty()) {
296 return markers_[source].back().name_;
298 return base::EmptyString();
301 scoped_refptr<Outputter> GPUTracer::CreateOutputter(const std::string& name) {
302 return TraceOutputter::Create(name);
305 void GPUTracer::PostTask() {
306 base::MessageLoop::current()->PostDelayedTask(
307 FROM_HERE,
308 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)),
309 base::TimeDelta::FromMilliseconds(kProcessInterval));
312 void GPUTracer::Process() {
313 process_posted_ = false;
314 ProcessTraces();
315 IssueProcessTask();
318 void GPUTracer::ProcessTraces() {
319 if (!gpu_timing_client_->IsAvailable()) {
320 ClearFinishedTraces(false);
321 return;
324 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces");
326 // Make owning decoder's GL context current
327 if (!decoder_->MakeCurrent()) {
328 // Skip subsequent GL calls if MakeCurrent fails
329 ClearFinishedTraces(false);
330 return;
333 // Check if timers are still valid (e.g: a disjoint operation
334 // might have occurred.)
335 if (gpu_timing_client_->CheckAndResetTimerErrors()) {
336 ClearFinishedTraces(true);
339 while (!finished_traces_.empty()) {
340 scoped_refptr<GPUTrace>& trace = finished_traces_.front();
341 if (trace->IsEnabled()) {
342 if (!finished_traces_.front()->IsAvailable())
343 break;
344 finished_traces_.front()->Process();
346 finished_traces_.front()->Destroy(true);
347 finished_traces_.pop_front();
350 // Clear pending traces if there were are any errors
351 GLenum err = glGetError();
352 if (err != GL_NO_ERROR)
353 ClearFinishedTraces(true);
356 void GPUTracer::ClearFinishedTraces(bool have_context) {
357 while (!finished_traces_.empty()) {
358 finished_traces_.front()->Destroy(have_context);
359 finished_traces_.pop_front();
363 void GPUTracer::IssueProcessTask() {
364 if (finished_traces_.empty() || process_posted_)
365 return;
367 process_posted_ = true;
368 PostTask();
371 } // namespace gles2
372 } // namespace gpu