| 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..93c54341dfe201fa5b5525bb7808a76fe95b865e 100644
 | 
| --- a/gpu/command_buffer/service/gpu_tracer.cc
 | 
| +++ b/gpu/command_buffer/service/gpu_tracer.cc
 | 
| @@ -59,45 +59,68 @@ 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),
 | 
| -      end_requested_(false),
 | 
| -      enabled_(true) {
 | 
| -  glGenQueries(2, queries_);
 | 
| +      tracer_type_(tracer_type),
 | 
| +      end_requested_(false) {
 | 
| +  memset(queries_, 0, sizeof(queries_));
 | 
| +  switch (tracer_type_) {
 | 
| +    case kTracerTypeARBTimer:
 | 
| +    case kTracerTypeDisjointTimer:
 | 
| +      glGenQueriesARB(2, queries_);
 | 
| +      break;
 | 
| +
 | 
| +    default:
 | 
| +      tracer_type_ = kTracerTypeInvalid;
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  GPUTrace::~GPUTrace() {
 | 
| -  if (enabled_)
 | 
| -    glDeleteQueries(2, queries_);
 | 
| +  switch (tracer_type_) {
 | 
| +    case kTracerTypeInvalid:
 | 
| +      break;
 | 
| +
 | 
| +    case kTracerTypeARBTimer:
 | 
| +    case kTracerTypeDisjointTimer:
 | 
| +      glDeleteQueriesARB(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:
 | 
| +    case kTracerTypeDisjointTimer:
 | 
| +      // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
 | 
| +      glQueryCounter(queries_[0], GL_TIMESTAMP);
 | 
| +      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:
 | 
| +    case kTracerTypeDisjointTimer:
 | 
| +      // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
 | 
| +      glQueryCounter(queries_[1], GL_TIMESTAMP);
 | 
| +      break;
 | 
|    }
 | 
|  
 | 
|    TRACE_EVENT_COPY_ASYNC_END0(
 | 
| @@ -105,34 +128,36 @@ 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;
 | 
|  
 | 
| -  GLint done = 0;
 | 
| -  glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
 | 
| -  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 begin_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_;
 | 
| +  glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
 | 
| +  glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
 | 
|  
 | 
| -  glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp);
 | 
| -  end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
 | 
| -
 | 
| -  glDeleteQueries(2, queries_);
 | 
| +  start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) +
 | 
| +                offset_;
 | 
| +  end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
 | 
|    outputter_->Trace(name(), start_time_, end_time_);
 | 
|  }
 | 
|  
 | 
| @@ -144,13 +169,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 +186,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;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
|    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 +294,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,11 +307,8 @@ void GPUTracer::Process() {
 | 
|  }
 | 
|  
 | 
|  void GPUTracer::ProcessTraces() {
 | 
| -  if (!enabled_) {
 | 
| -    while (!traces_.empty() && traces_.front()->IsAvailable()) {
 | 
| -      traces_.front()->Process();
 | 
| -      traces_.pop_front();
 | 
| -    }
 | 
| +  if (tracer_type_ == kTracerTypeInvalid) {
 | 
| +    traces_.clear();
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| @@ -302,6 +321,14 @@ 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)
 | 
| +      traces_.clear();
 | 
| +  }
 | 
| +
 | 
|    while (!traces_.empty() && traces_.front()->IsAvailable()) {
 | 
|      traces_.front()->Process();
 | 
|      traces_.pop_front();
 | 
| @@ -314,23 +341,48 @@ void GPUTracer::ProcessTraces() {
 | 
|  }
 | 
|  
 | 
|  void GPUTracer::CalculateTimerOffset() {
 | 
| -  if (enabled_) {
 | 
| +  if (tracer_type_ != kTracerTypeInvalid) {
 | 
| +    // If GPU device category is off, invalidate timing sync.
 | 
| +    if (*gpu_trace_dev_category == '\0') {
 | 
| +      gpu_timing_synced_ = false;
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    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;
 | 
| +    GLint disjoint_value = 0;
 | 
| +
 | 
| +    if (tracer_type_ == kTracerTypeDisjointTimer) {
 | 
| +      // Clear the disjoint bit before we do any queries.
 | 
| +      glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
 | 
| +    }
 | 
| +
 | 
|      glFinish();
 | 
| -    glGenQueries(1, &query);
 | 
| +    glGenQueriesARB(1, &query);
 | 
|      glQueryCounter(query, GL_TIMESTAMP);
 | 
|      glFinish();
 | 
| +
 | 
|      glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
 | 
| +    glDeleteQueriesARB(1, &query);
 | 
| +
 | 
| +    if (tracer_type_ == kTracerTypeDisjointTimer) {
 | 
| +      glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
 | 
| +      if (disjoint_value)
 | 
| +        return;
 | 
| +    }
 | 
| +
 | 
|      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;
 | 
|    }
 | 
|  }
 | 
|  
 | 
| 
 |