Chromium Code Reviews| Index: gpu/command_buffer/service/gpu_tracer.cc |
| diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc |
| index b1c9f23e4858f5a68ac1c1e3b161c956c02d56ee..bd9bde0db41926eaaa60ca2f74ae21904d426c31 100644 |
| --- a/gpu/command_buffer/service/gpu_tracer.cc |
| +++ b/gpu/command_buffer/service/gpu_tracer.cc |
| @@ -59,45 +59,75 @@ void TraceOutputter::Trace(const std::string& name, |
| ++local_trace_id_; |
| } |
| -GPUTrace::GPUTrace(const std::string& name) |
| - : name_(name), |
| - outputter_(NULL), |
| - offset_(0), |
| - end_time_(0), |
| - end_requested_(false), |
| - enabled_(false) { |
| -} |
| - |
| GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter, |
| const std::string& name, |
| - int64 offset) |
| + int64 offset, |
| + GpuTracerType tracer_type) |
| : name_(name), |
| outputter_(outputter), |
| offset_(offset), |
| start_time_(0), |
| end_time_(0), |
| + tracer_type_(tracer_type), |
| end_requested_(false), |
| - enabled_(true) { |
| - glGenQueries(2, queries_); |
| + discard_trace_(false) { |
| + memset(queries_, 0, sizeof(queries_)); |
| + switch (tracer_type_) { |
| + case kTracerTypeARBTimer: |
| + glGenQueries(2, queries_); |
| + break; |
| + case kTracerTypeDisjointTimer: |
| + glGenQueriesEXT(2, queries_); |
| + break; |
| + |
| + default: |
| + tracer_type_ = kTracerTypeInvalid; |
| + } |
| } |
| GPUTrace::~GPUTrace() { |
| - if (enabled_) |
| - glDeleteQueries(2, queries_); |
| + switch (tracer_type_) { |
| + case kTracerTypeInvalid: |
| + break; |
| + |
| + case kTracerTypeARBTimer: |
| + glDeleteQueries(2, queries_); |
| + break; |
| + case kTracerTypeDisjointTimer: |
| + glDeleteQueriesEXT(2, queries_); |
| + break; |
| + } |
| } |
| void GPUTrace::Start() { |
| TRACE_EVENT_COPY_ASYNC_BEGIN0( |
| TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); |
| - if (enabled_) { |
| - glQueryCounter(queries_[0], GL_TIMESTAMP); |
| + |
| + switch (tracer_type_) { |
| + case kTracerTypeInvalid: |
| + break; |
| + |
| + case kTracerTypeARBTimer: |
| + glQueryCounter(queries_[0], GL_TIMESTAMP); |
| + break; |
| + case kTracerTypeDisjointTimer: |
| + glQueryCounterEXT(queries_[0], GL_TIMESTAMP_EXT); |
| + break; |
| } |
| } |
| void GPUTrace::End() { |
| - if (enabled_) { |
| - glQueryCounter(queries_[1], GL_TIMESTAMP); |
| - end_requested_ = true; |
| + end_requested_ = true; |
| + switch (tracer_type_) { |
| + case kTracerTypeInvalid: |
| + break; |
| + |
| + case kTracerTypeARBTimer: |
| + glQueryCounter(queries_[1], GL_TIMESTAMP); |
| + break; |
| + case kTracerTypeDisjointTimer: |
| + glQueryCounterEXT(queries_[1], GL_TIMESTAMP_EXT); |
| + break; |
| } |
| TRACE_EVENT_COPY_ASYNC_END0( |
| @@ -105,37 +135,75 @@ void GPUTrace::End() { |
| } |
| bool GPUTrace::IsAvailable() { |
| - if (!enabled_) |
| - return true; |
| - else if (!end_requested_) |
| - return false; |
| + if (tracer_type_ != kTracerTypeInvalid) { |
| + if (!end_requested_) |
| + return false; |
| + else if (discard_trace_) |
| + return true; |
| + |
| + GLint done = 0; |
| + |
| + switch (tracer_type_) { |
| + case kTracerTypeARBTimer: |
| + glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| + break; |
| + |
| + case kTracerTypeDisjointTimer: |
| + glGetQueryObjectivEXT(queries_[1], GL_QUERY_RESULT_AVAILABLE_EXT, |
| + &done); |
| + break; |
| + |
| + default: |
| + done = 1; |
| + break; |
| + } |
| + |
| + return !!done; |
| + } |
| - GLint done = 0; |
| - glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| - return !!done; |
| + return true; |
| } |
| void GPUTrace::Process() { |
| - if (!enabled_) |
| + if (tracer_type_ == kTracerTypeInvalid) |
| return; |
| DCHECK(IsAvailable()); |
| - GLuint64 timestamp; |
| + GLuint64 beg_stamp = 0; |
| + GLuint64 end_stamp = 0; |
| // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| // We need to detect if the end is less then the start and correct for the |
| // wrapping. |
| - glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); |
| - start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| + switch (tracer_type_) { |
| + case kTracerTypeARBTimer: |
| + glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &beg_stamp); |
| + glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
| + glDeleteQueries(2, queries_); |
|
vmiura
2014/08/26 23:47:26
~GPUTrace deletes the queries too so perhaps we sh
David Yen
2014/08/27 19:47:45
Done.
|
| + break; |
| + case kTracerTypeDisjointTimer: |
| + glGetQueryObjectui64vEXT(queries_[0], GL_QUERY_RESULT_EXT, &beg_stamp); |
| + glGetQueryObjectui64vEXT(queries_[1], GL_QUERY_RESULT_EXT, &end_stamp); |
| + glDeleteQueriesEXT(2, queries_); |
| + break; |
| + |
| + default: |
| + return; |
| + } |
| - glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); |
| - end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| + if (discard_trace_) |
| + return; |
| - glDeleteQueries(2, queries_); |
| + start_time_ = (beg_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| + end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| outputter_->Trace(name(), start_time_, end_time_); |
| } |
| +void GPUTrace::DiscardTrace() { |
| + discard_trace_ = true; |
| +} |
| + |
| GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
| : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
| TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
| @@ -144,13 +212,16 @@ GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
| decoder_(decoder), |
| timer_offset_(0), |
| last_tracer_source_(kTraceGroupInvalid), |
| - enabled_(false), |
| + tracer_type_(kTracerTypeInvalid), |
| gpu_timing_synced_(false), |
| gpu_executing_(false), |
| process_posted_(false) { |
| - if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| + if (gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { |
| + tracer_type_ = kTracerTypeDisjointTimer; |
| + outputter_ = TraceOutputter::Create("GL_EXT_disjoint_timer_query"); |
| + } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| + tracer_type_ = kTracerTypeARBTimer; |
| outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
| - enabled_ = true; |
| } |
| } |
| @@ -158,25 +229,19 @@ GPUTracer::~GPUTracer() { |
| } |
| bool GPUTracer::BeginDecoding() { |
| - if (enabled_) { |
| - if (*gpu_trace_dev_category) { |
| - // Make sure timing is synced before tracing |
| - if (!gpu_timing_synced_) { |
| - CalculateTimerOffset(); |
| - gpu_timing_synced_ = true; |
| - } |
| - } else { |
| - // If GPU device category is off, invalidate timing sync |
| - gpu_timing_synced_ = false; |
|
vmiura
2014/08/26 23:47:26
I think we still need this part, so that we sync t
David Yen
2014/08/27 19:47:45
Okay good point. I've moved this to the CalculateT
|
| - } |
| - } |
| - |
| if (gpu_executing_) |
| return false; |
| + CalculateTimerOffset(); |
| gpu_executing_ = true; |
| if (IsTracing()) { |
| + // Reset disjoint bit for the disjoint timer. |
| + if (tracer_type_ == kTracerTypeDisjointTimer) { |
| + GLint disjoint_value = 0; |
| + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| + } |
| + |
| // Begin a Trace for all active markers |
| for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
| for (size_t i = 0; i < markers_[n].size(); i++) { |
| @@ -272,10 +337,10 @@ const std::string& GPUTracer::CurrentName() const { |
| } |
| scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& name) { |
| - if (enabled_ && *gpu_trace_dev_category) |
| - return new GPUTrace(outputter_, name, timer_offset_); |
| - else |
| - return new GPUTrace(name); |
| + GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ : |
| + kTracerTypeInvalid; |
| + |
| + return new GPUTrace(outputter_, name, timer_offset_, tracer_type); |
| } |
| void GPUTracer::Process() { |
| @@ -285,7 +350,7 @@ void GPUTracer::Process() { |
| } |
| void GPUTracer::ProcessTraces() { |
| - if (!enabled_) { |
| + if (tracer_type_ == kTracerTypeInvalid) { |
| while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| traces_.front()->Process(); |
| traces_.pop_front(); |
| @@ -302,6 +367,19 @@ void GPUTracer::ProcessTraces() { |
| return; |
| } |
| + // Check if disjoint operation has occurred, discard ongoing traces if so. |
| + if (tracer_type_ == kTracerTypeDisjointTimer) { |
| + GLint disjoint_value = 0; |
| + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| + if (disjoint_value) { |
| + while (!traces_.empty()) { |
| + traces_.front()->DiscardTrace(); |
| + traces_.front()->Process(); |
| + traces_.pop_front(); |
|
vmiura
2014/08/26 23:47:26
Can we completely remove DiscardTrace() & Process(
David Yen
2014/08/27 19:47:45
Yes you are right, I think I was thrown off by how
|
| + } |
| + } |
| + } |
| + |
| while (!traces_.empty() && traces_.front()->IsAvailable()) { |
| traces_.front()->Process(); |
| traces_.pop_front(); |
| @@ -314,23 +392,57 @@ void GPUTracer::ProcessTraces() { |
| } |
| void GPUTracer::CalculateTimerOffset() { |
| - if (enabled_) { |
| + if (*gpu_trace_dev_category && tracer_type_ != kTracerTypeInvalid) { |
| + if (gpu_timing_synced_) |
| + return; |
| + |
| TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); |
| // NOTE(vmiura): It would be better to use glGetInteger64v, however |
| // it's not available everywhere. |
| GLuint64 gl_now = 0; |
| GLuint query; |
| - glFinish(); |
| - glGenQueries(1, &query); |
| - glQueryCounter(query, GL_TIMESTAMP); |
| - glFinish(); |
| - glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
| + GLint disjoint_value = 0; |
| + |
| + switch (tracer_type_) { |
| + case kTracerTypeARBTimer: |
| + glFinish(); |
| + glGenQueries(1, &query); |
| + glQueryCounter(query, GL_TIMESTAMP); |
| + glFinish(); |
| + |
| + glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); |
| + glDeleteQueries(1, &query); |
| + break; |
| + |
| + case kTracerTypeDisjointTimer: |
| + // Clear the disjoint bit before we do any queries. |
| + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| + |
| + glFinish(); |
| + glGenQueriesEXT(1, &query); |
| + glQueryCounterEXT(query, GL_TIMESTAMP_EXT); |
| + glFinish(); |
| + |
| + glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT_EXT, &gl_now); |
| + glDeleteQueriesEXT(1, &query); |
| + |
| + // Discard results if disjoint operation has occurred. |
| + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| + if (disjoint_value) |
| + return; |
| + |
| + break; |
| + |
| + default: |
| + break; |
| + } |
| + |
| base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); |
| gl_now /= base::Time::kNanosecondsPerMicrosecond; |
| timer_offset_ = system_now.ToInternalValue() - gl_now; |
| - glDeleteQueries(1, &query); |
| + gpu_timing_synced_ = true; |
| } |
| } |