Chromium Code Reviews| Index: gpu/command_buffer/service/gpu_timing.cc |
| diff --git a/gpu/command_buffer/service/gpu_timing.cc b/gpu/command_buffer/service/gpu_timing.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..95f67ab3ebadac4b37db387f2319b176a62b9964 |
| --- /dev/null |
| +++ b/gpu/command_buffer/service/gpu_timing.cc |
| @@ -0,0 +1,147 @@ |
| +// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "gpu/command_buffer/service/gpu_timing.h" |
| + |
| +#include "base/time/time.h" |
| +#include "ui/gl/gl_context.h" |
| +#include "ui/gl/gl_version_info.h" |
| + |
| +namespace gpu { |
| + |
| +GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) { |
| + DCHECK(gpu_timing_); |
| + memset(queries_, 0, sizeof(queries_)); |
| + glGenQueriesARB(2, queries_); |
| +} |
| + |
| +GPUTimer::~GPUTimer() { |
| + glDeleteQueriesARB(2, queries_); |
| +} |
| + |
| +void GPUTimer::Start() { |
| + // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
| + offset_ = gpu_timing_->CalculateTimerOffset(); |
| + glQueryCounter(queries_[0], GL_TIMESTAMP); |
| +} |
| + |
| +void GPUTimer::End() { |
| + end_requested_ = true; |
| + glQueryCounter(queries_[1], GL_TIMESTAMP); |
| +} |
| + |
| +bool GPUTimer::IsAvailable() { |
| + if (!gpu_timing_->IsAvailable() || !end_requested_) { |
| + return false; |
| + } |
| + GLint done = 0; |
| + glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| + return done != 0; |
| +} |
| + |
| +void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { |
| + DCHECK(start && end); |
| + DCHECK(IsAvailable()); |
| + 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, &begin_stamp); |
| + *start = begin_stamp / base::Time::kNanosecondsPerMicrosecond + offset_; |
| + glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
| + *end = end_stamp / base::Time::kNanosecondsPerMicrosecond + offset_; |
| +} |
| + |
| +int64 GPUTimer::GetDeltaElapsed() { |
| + int64 start = 0; |
| + int64 end = 0; |
| + GetStartEndTimestamps(&start, &end); |
| + return end - start; |
| +} |
| + |
| +GPUTiming::GPUTiming() : cpu_time_for_testing_() { |
| +} |
| + |
| +GPUTiming::~GPUTiming() { |
| +} |
| + |
| +bool GPUTiming::Initialize(gfx::GLContext* gl_context) { |
| + DCHECK(gl_context); |
| + DCHECK_EQ(kTimerTypeInvalid, timer_type_); |
| + |
| + const gfx::GLVersionInfo* version_info = gl_context->GetVersionInfo(); |
| + DCHECK(version_info); |
| + if (version_info->is_es3 && // glGetInteger64v is supported under ES3. |
| + gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { |
| + timer_type_ = kTimerTypeDisjoint; |
| + CheckAndResetTimerErrors(); |
|
David Yen
2015/02/06 22:47:01
The ResetTimerErrors() needs to be called everytim
Daniele Castagna
2015/02/10 04:49:33
Done.
|
| + return true; |
| + } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| + timer_type_ = kTimerTypeARB; |
| + offset_ = CalculateTimerOffset(); |
|
David Yen
2015/02/06 22:47:01
I think we don't need to call CalculateTimerOffset
Daniele Castagna
2015/02/10 04:49:33
Done.
|
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool GPUTiming::IsAvailable() { |
| + return timer_type_ != kTimerTypeInvalid; |
| +} |
| + |
| +const char* GPUTiming::GetTimerTypeName() const { |
| + switch (timer_type_) { |
| + case kTimerTypeDisjoint: |
| + return "GL_EXT_disjoint_timer_query"; |
| + case kTimerTypeARB: |
| + return "GL_ARB_timer_query"; |
| + default: |
| + return "Unknown"; |
| + } |
| +} |
| + |
| +bool GPUTiming::CheckAndResetTimerErrors() { |
| + if (timer_type_ == kTimerTypeDisjoint) { |
| + DCHECK_EQ(kTimerTypeDisjoint, timer_type_); |
|
David Yen
2015/02/06 22:47:01
This DCHECK seems unnecessary, was it from old cod
Daniele Castagna
2015/02/10 04:49:32
Done.
|
| + GLint disjoint_value = 0; |
| + glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| + return disjoint_value != 0; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +int64 GPUTiming::CalculateTimerOffset() { |
| + if (!offset_valid_) { |
| + GLint64 gl_now = 0; |
| + glGetInteger64v(GL_TIMESTAMP, &gl_now); |
| + int64 now = |
| + cpu_time_for_testing_.is_null() |
| + ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() |
| + : cpu_time_for_testing_.Run(); |
| + offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; |
| + offset_valid_ = timer_type_ == kTimerTypeARB; |
| + } |
| + return offset_; |
| +} |
| + |
| +void GPUTiming::InvalidateTimerOffset() { |
| + offset_valid_ = false; |
| +} |
| + |
| +void GPUTiming::SetCpuTimeForTesting( |
| + const base::Callback<int64(void)>& cpu_time) { |
| + cpu_time_for_testing_ = cpu_time; |
| +} |
| + |
| +void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) { |
| + offset_ = offset; |
| + offset_valid_ = cache_it; |
| +} |
| + |
| +void GPUTiming::SetTimerTypeForTesting(TimerType type) { |
| + timer_type_ = type; |
| +} |
| + |
| +} // namespace gpu |