OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015 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. |
| 4 |
| 5 #include "gpu/command_buffer/service/gpu_timing.h" |
| 6 |
| 7 #include "base/time/time.h" |
| 8 #include "ui/gl/gl_context.h" |
| 9 #include "ui/gl/gl_version_info.h" |
| 10 |
| 11 namespace gpu { |
| 12 |
| 13 GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) { |
| 14 DCHECK(gpu_timing_); |
| 15 memset(queries_, 0, sizeof(queries_)); |
| 16 glGenQueriesARB(2, queries_); |
| 17 } |
| 18 |
| 19 GPUTimer::~GPUTimer() { |
| 20 glDeleteQueriesARB(2, queries_); |
| 21 } |
| 22 |
| 23 void GPUTimer::Start() { |
| 24 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
| 25 glQueryCounter(queries_[0], GL_TIMESTAMP); |
| 26 offset_ = gpu_timing_->CalculateTimerOffset(); |
| 27 } |
| 28 |
| 29 void GPUTimer::End() { |
| 30 end_requested_ = true; |
| 31 glQueryCounter(queries_[1], GL_TIMESTAMP); |
| 32 } |
| 33 |
| 34 bool GPUTimer::IsAvailable() { |
| 35 if (!gpu_timing_->IsAvailable() || !end_requested_) { |
| 36 return false; |
| 37 } |
| 38 GLint done = 0; |
| 39 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); |
| 40 return done != 0; |
| 41 } |
| 42 |
| 43 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { |
| 44 DCHECK(start && end); |
| 45 DCHECK(IsAvailable()); |
| 46 GLuint64 begin_stamp = 0; |
| 47 GLuint64 end_stamp = 0; |
| 48 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| 49 // We need to detect if the end is less then the start and correct for the |
| 50 // wrapping. |
| 51 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); |
| 52 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
| 53 |
| 54 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 55 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 56 } |
| 57 |
| 58 int64 GPUTimer::GetDeltaElapsed() { |
| 59 int64 start = 0; |
| 60 int64 end = 0; |
| 61 GetStartEndTimestamps(&start, &end); |
| 62 return end - start; |
| 63 } |
| 64 |
| 65 GPUTiming::GPUTiming() : cpu_time_for_testing_() { |
| 66 } |
| 67 |
| 68 GPUTiming::~GPUTiming() { |
| 69 } |
| 70 |
| 71 bool GPUTiming::Initialize(gfx::GLContext* gl_context) { |
| 72 DCHECK(gl_context); |
| 73 DCHECK_EQ(kTimerTypeInvalid, timer_type_); |
| 74 |
| 75 const gfx::GLVersionInfo* version_info = gl_context->GetVersionInfo(); |
| 76 DCHECK(version_info); |
| 77 if (version_info->is_es3 && // glGetInteger64v is supported under ES3. |
| 78 gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { |
| 79 timer_type_ = kTimerTypeDisjoint; |
| 80 return true; |
| 81 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
| 82 timer_type_ = kTimerTypeARB; |
| 83 return true; |
| 84 } |
| 85 return false; |
| 86 } |
| 87 |
| 88 bool GPUTiming::IsAvailable() { |
| 89 return timer_type_ != kTimerTypeInvalid; |
| 90 } |
| 91 |
| 92 const char* GPUTiming::GetTimerTypeName() const { |
| 93 switch (timer_type_) { |
| 94 case kTimerTypeDisjoint: |
| 95 return "GL_EXT_disjoint_timer_query"; |
| 96 case kTimerTypeARB: |
| 97 return "GL_ARB_timer_query"; |
| 98 default: |
| 99 return "Unknown"; |
| 100 } |
| 101 } |
| 102 |
| 103 bool GPUTiming::CheckAndResetTimerErrors() { |
| 104 if (timer_type_ == kTimerTypeDisjoint) { |
| 105 GLint disjoint_value = 0; |
| 106 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| 107 return disjoint_value != 0; |
| 108 } else { |
| 109 return false; |
| 110 } |
| 111 } |
| 112 |
| 113 int64 GPUTiming::CalculateTimerOffset() { |
| 114 if (!offset_valid_) { |
| 115 GLint64 gl_now = 0; |
| 116 glGetInteger64v(GL_TIMESTAMP, &gl_now); |
| 117 int64 now = |
| 118 cpu_time_for_testing_.is_null() |
| 119 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() |
| 120 : cpu_time_for_testing_.Run(); |
| 121 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; |
| 122 offset_valid_ = timer_type_ == kTimerTypeARB; |
| 123 } |
| 124 return offset_; |
| 125 } |
| 126 |
| 127 void GPUTiming::InvalidateTimerOffset() { |
| 128 offset_valid_ = false; |
| 129 } |
| 130 |
| 131 void GPUTiming::SetCpuTimeForTesting( |
| 132 const base::Callback<int64(void)>& cpu_time) { |
| 133 cpu_time_for_testing_ = cpu_time; |
| 134 } |
| 135 |
| 136 void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) { |
| 137 offset_ = offset; |
| 138 offset_valid_ = cache_it; |
| 139 } |
| 140 |
| 141 void GPUTiming::SetTimerTypeForTesting(TimerType type) { |
| 142 timer_type_ = type; |
| 143 } |
| 144 |
| 145 } // namespace gpu |
OLD | NEW |