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; |
} |
} |