| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/gpu_timing.h" | 5 #include "ui/gl/gpu_timing.h" |
| 6 | 6 |
| 7 #include "base/time/time.h" | 7 #include "base/time/time.h" |
| 8 #include "ui/gl/gl_bindings.h" | 8 #include "ui/gl/gl_bindings.h" |
| 9 #include "ui/gl/gl_context.h" | 9 #include "ui/gl/gl_context.h" |
| 10 #include "ui/gl/gl_version_info.h" | 10 #include "ui/gl/gl_version_info.h" |
| 11 | 11 |
| 12 namespace gfx { | 12 namespace gfx { |
| 13 | 13 |
| 14 GPUTiming::GPUTiming(GLContextReal* context) { | 14 GPUTiming::GPUTiming(GLContextReal* context) { |
| 15 DCHECK(context); | 15 DCHECK(context); |
| 16 const GLVersionInfo* version_info = context->GetVersionInfo(); | 16 const GLVersionInfo* version_info = context->GetVersionInfo(); |
| 17 DCHECK(version_info); | 17 DCHECK(version_info); |
| 18 if (version_info->is_es3 && // glGetInteger64v is supported under ES3. | 18 if (version_info->is_es3 && // glGetInteger64v is supported under ES3. |
| 19 context->HasExtension("GL_EXT_disjoint_timer_query")) { | 19 context->HasExtension("GL_EXT_disjoint_timer_query")) { |
| 20 timer_type_ = kTimerTypeDisjoint; | 20 timer_type_ = kTimerTypeDisjoint; |
| 21 } else if (context->HasExtension("GL_ARB_timer_query")) { | 21 } else if (context->HasExtension("GL_ARB_timer_query")) { |
| 22 timer_type_ = kTimerTypeARB; | 22 timer_type_ = kTimerTypeARB; |
| 23 } else if (context->HasExtension("GL_EXT_timer_query")) { |
| 24 timer_type_ = kTimerTypeEXT; |
| 23 } | 25 } |
| 24 } | 26 } |
| 25 | 27 |
| 26 GPUTiming::~GPUTiming() { | 28 GPUTiming::~GPUTiming() { |
| 27 } | 29 } |
| 28 | 30 |
| 29 scoped_refptr<GPUTimingClient> GPUTiming::CreateGPUTimingClient() { | 31 scoped_refptr<GPUTimingClient> GPUTiming::CreateGPUTimingClient() { |
| 30 return new GPUTimingClient(this); | 32 return new GPUTimingClient(this); |
| 31 } | 33 } |
| 32 | 34 |
| 33 uint32_t GPUTiming::GetDisjointCount() { | 35 uint32_t GPUTiming::GetDisjointCount() { |
| 34 if (timer_type_ == kTimerTypeDisjoint) { | 36 if (timer_type_ == kTimerTypeDisjoint) { |
| 35 GLint disjoint_value = 0; | 37 GLint disjoint_value = 0; |
| 36 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | 38 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); |
| 37 if (disjoint_value) { | 39 if (disjoint_value) { |
| 38 disjoint_counter_++; | 40 disjoint_counter_++; |
| 39 } | 41 } |
| 40 } | 42 } |
| 41 return disjoint_counter_; | 43 return disjoint_counter_; |
| 42 } | 44 } |
| 43 | 45 |
| 44 GPUTimer::~GPUTimer() { | 46 GPUTimer::~GPUTimer() { |
| 45 glDeleteQueriesARB(2, queries_); | 47 glDeleteQueriesARB(2, queries_); |
| 46 } | 48 } |
| 47 | 49 |
| 48 void GPUTimer::Start() { | 50 void GPUTimer::Start() { |
| 49 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | 51 switch (gpu_timing_client_->gpu_timing_->timer_type_) { |
| 50 glQueryCounter(queries_[0], GL_TIMESTAMP); | 52 case GPUTiming::kTimerTypeARB: |
| 53 case GPUTiming::kTimerTypeDisjoint: |
| 54 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. |
| 55 glQueryCounter(queries_[0], GL_TIMESTAMP); |
| 56 break; |
| 57 case GPUTiming::kTimerTypeEXT: |
| 58 glBeginQuery(GL_TIME_ELAPSED_EXT, queries_[0]); |
| 59 break; |
| 60 default: |
| 61 NOTREACHED(); |
| 62 } |
| 51 } | 63 } |
| 52 | 64 |
| 53 void GPUTimer::End() { | 65 void GPUTimer::End() { |
| 54 end_requested_ = true; | 66 end_requested_ = true; |
| 55 offset_ = gpu_timing_client_->CalculateTimerOffset(); | 67 DCHECK(gpu_timing_client_->gpu_timing_); |
| 56 glQueryCounter(queries_[1], GL_TIMESTAMP); | 68 switch (gpu_timing_client_->gpu_timing_->timer_type_) { |
| 69 case GPUTiming::kTimerTypeARB: |
| 70 case GPUTiming::kTimerTypeDisjoint: |
| 71 offset_ = gpu_timing_client_->CalculateTimerOffset(); |
| 72 glQueryCounter(queries_[1], GL_TIMESTAMP); |
| 73 break; |
| 74 case GPUTiming::kTimerTypeEXT: |
| 75 glEndQuery(GL_TIME_ELAPSED_EXT); |
| 76 break; |
| 77 default: |
| 78 NOTREACHED(); |
| 79 } |
| 57 } | 80 } |
| 58 | 81 |
| 59 bool GPUTimer::IsAvailable() { | 82 bool GPUTimer::IsAvailable() { |
| 60 if (!gpu_timing_client_->IsAvailable() || !end_requested_) { | 83 if (!gpu_timing_client_->IsAvailable() || !end_requested_) { |
| 61 return false; | 84 return false; |
| 62 } | 85 } |
| 63 GLint done = 0; | 86 GLint done = 0; |
| 64 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | 87 glGetQueryObjectivARB(queries_[1] ? queries_[1] : queries_[0], |
| 88 GL_QUERY_RESULT_AVAILABLE, &done); |
| 65 return done != 0; | 89 return done != 0; |
| 66 } | 90 } |
| 67 | 91 |
| 68 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { | 92 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { |
| 69 DCHECK(start && end); | 93 DCHECK(start && end); |
| 70 DCHECK(IsAvailable()); | 94 DCHECK(IsAvailable()); |
| 95 DCHECK(gpu_timing_client_->gpu_timing_); |
| 96 DCHECK(gpu_timing_client_->gpu_timing_->timer_type_ != |
| 97 GPUTiming::kTimerTypeEXT); |
| 71 GLuint64 begin_stamp = 0; | 98 GLuint64 begin_stamp = 0; |
| 72 GLuint64 end_stamp = 0; | 99 GLuint64 end_stamp = 0; |
| 73 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | 100 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. |
| 74 // We need to detect if the end is less then the start and correct for the | 101 // We need to detect if the end is less then the start and correct for the |
| 75 // wrapping. | 102 // wrapping. |
| 76 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | 103 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); |
| 77 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | 104 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); |
| 78 | 105 |
| 79 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 106 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 80 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | 107 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; |
| 81 } | 108 } |
| 82 | 109 |
| 83 int64 GPUTimer::GetDeltaElapsed() { | 110 int64 GPUTimer::GetDeltaElapsed() { |
| 84 int64 start = 0; | 111 DCHECK(gpu_timing_client_->gpu_timing_); |
| 85 int64 end = 0; | 112 switch (gpu_timing_client_->gpu_timing_->timer_type_) { |
| 86 GetStartEndTimestamps(&start, &end); | 113 case GPUTiming::kTimerTypeARB: |
| 87 return end - start; | 114 case GPUTiming::kTimerTypeDisjoint: { |
| 115 int64 start = 0; |
| 116 int64 end = 0; |
| 117 GetStartEndTimestamps(&start, &end); |
| 118 return end - start; |
| 119 } break; |
| 120 case GPUTiming::kTimerTypeEXT: { |
| 121 GLuint64 delta = 0; |
| 122 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &delta); |
| 123 return static_cast<int64>(delta / base::Time::kNanosecondsPerMicrosecond); |
| 124 } break; |
| 125 default: |
| 126 NOTREACHED(); |
| 127 } |
| 128 return 0; |
| 88 } | 129 } |
| 89 | 130 |
| 90 GPUTimer::GPUTimer(scoped_refptr<GPUTimingClient> gpu_timing_client) | 131 GPUTimer::GPUTimer(scoped_refptr<GPUTimingClient> gpu_timing_client) |
| 91 : gpu_timing_client_(gpu_timing_client) { | 132 : gpu_timing_client_(gpu_timing_client) { |
| 92 DCHECK(gpu_timing_client_); | 133 DCHECK(gpu_timing_client_); |
| 93 memset(queries_, 0, sizeof(queries_)); | 134 memset(queries_, 0, sizeof(queries_)); |
| 94 glGenQueriesARB(2, queries_); | 135 int queries = 0; |
| 136 DCHECK(gpu_timing_client_->gpu_timing_); |
| 137 switch (gpu_timing_client_->gpu_timing_->timer_type_) { |
| 138 case GPUTiming::kTimerTypeARB: |
| 139 case GPUTiming::kTimerTypeDisjoint: |
| 140 queries = 2; |
| 141 break; |
| 142 case GPUTiming::kTimerTypeEXT: |
| 143 queries = 1; |
| 144 break; |
| 145 default: |
| 146 NOTREACHED(); |
| 147 } |
| 148 glGenQueriesARB(queries, queries_); |
| 95 } | 149 } |
| 96 | 150 |
| 97 GPUTimingClient::GPUTimingClient(GPUTiming* gpu_timing) | 151 GPUTimingClient::GPUTimingClient(GPUTiming* gpu_timing) |
| 98 : gpu_timing_(gpu_timing) { | 152 : gpu_timing_(gpu_timing) { |
| 99 if (gpu_timing) { | 153 if (gpu_timing) { |
| 100 timer_type_ = gpu_timing->GetTimerType(); | 154 timer_type_ = gpu_timing->GetTimerType(); |
| 101 disjoint_counter_ = gpu_timing_->GetDisjointCount(); | 155 disjoint_counter_ = gpu_timing_->GetDisjointCount(); |
| 102 } | 156 } |
| 103 } | 157 } |
| 104 | 158 |
| 105 scoped_ptr<GPUTimer> GPUTimingClient::CreateGPUTimer() { | 159 scoped_ptr<GPUTimer> GPUTimingClient::CreateGPUTimer() { |
| 106 return make_scoped_ptr(new GPUTimer(this)); | 160 return make_scoped_ptr(new GPUTimer(this)); |
| 107 } | 161 } |
| 108 | 162 |
| 109 bool GPUTimingClient::IsAvailable() { | 163 bool GPUTimingClient::IsAvailable() { |
| 110 return timer_type_ != GPUTiming::kTimerTypeInvalid; | 164 return timer_type_ != GPUTiming::kTimerTypeInvalid; |
| 111 } | 165 } |
| 112 | 166 |
| 167 bool GPUTimingClient::IsTimerOffsetAvailable() { |
| 168 return timer_type_ == GPUTiming::kTimerTypeARB || |
| 169 timer_type_ == GPUTiming::kTimerTypeDisjoint; |
| 170 } |
| 171 |
| 113 const char* GPUTimingClient::GetTimerTypeName() const { | 172 const char* GPUTimingClient::GetTimerTypeName() const { |
| 114 switch (timer_type_) { | 173 switch (timer_type_) { |
| 115 case GPUTiming::kTimerTypeDisjoint: | 174 case GPUTiming::kTimerTypeDisjoint: |
| 116 return "GL_EXT_disjoint_timer_query"; | 175 return "GL_EXT_disjoint_timer_query"; |
| 117 case GPUTiming::kTimerTypeARB: | 176 case GPUTiming::kTimerTypeARB: |
| 118 return "GL_ARB_timer_query"; | 177 return "GL_ARB_timer_query"; |
| 178 case GPUTiming::kTimerTypeEXT: |
| 179 return "GL_EXT_timer_query"; |
| 119 default: | 180 default: |
| 120 return "Unknown"; | 181 return "Unknown"; |
| 121 } | 182 } |
| 122 } | 183 } |
| 123 | 184 |
| 124 bool GPUTimingClient::CheckAndResetTimerErrors() { | 185 bool GPUTimingClient::CheckAndResetTimerErrors() { |
| 125 if (timer_type_ == GPUTiming::kTimerTypeDisjoint) { | 186 if (timer_type_ == GPUTiming::kTimerTypeDisjoint) { |
| 126 DCHECK(gpu_timing_ != nullptr); | 187 DCHECK(gpu_timing_ != nullptr); |
| 127 const uint32_t total_disjoint_count = gpu_timing_->GetDisjointCount(); | 188 const uint32_t total_disjoint_count = gpu_timing_->GetDisjointCount(); |
| 128 const bool disjoint_triggered = total_disjoint_count != disjoint_counter_; | 189 const bool disjoint_triggered = total_disjoint_count != disjoint_counter_; |
| 129 disjoint_counter_ = total_disjoint_count; | 190 disjoint_counter_ = total_disjoint_count; |
| 130 return disjoint_triggered; | 191 return disjoint_triggered; |
| 131 } | 192 } |
| 132 return false; | 193 return false; |
| 133 } | 194 } |
| 134 | 195 |
| 135 int64 GPUTimingClient::CalculateTimerOffset() { | 196 int64 GPUTimingClient::CalculateTimerOffset() { |
| 197 DCHECK(IsTimerOffsetAvailable()); |
| 136 if (!offset_valid_) { | 198 if (!offset_valid_) { |
| 137 GLint64 gl_now = 0; | 199 GLint64 gl_now = 0; |
| 138 glGetInteger64v(GL_TIMESTAMP, &gl_now); | 200 glGetInteger64v(GL_TIMESTAMP, &gl_now); |
| 139 int64 now = | 201 int64 now = |
| 140 cpu_time_for_testing_.is_null() | 202 cpu_time_for_testing_.is_null() |
| 141 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() | 203 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() |
| 142 : cpu_time_for_testing_.Run(); | 204 : cpu_time_for_testing_.Run(); |
| 143 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; | 205 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; |
| 144 offset_valid_ = timer_type_ == GPUTiming::kTimerTypeARB; | 206 offset_valid_ = timer_type_ == GPUTiming::kTimerTypeARB; |
| 145 } | 207 } |
| 146 return offset_; | 208 return offset_; |
| 147 } | 209 } |
| 148 | 210 |
| 149 void GPUTimingClient::InvalidateTimerOffset() { | 211 void GPUTimingClient::InvalidateTimerOffset() { |
| 150 offset_valid_ = false; | 212 offset_valid_ = false; |
| 151 } | 213 } |
| 152 | 214 |
| 153 void GPUTimingClient::SetCpuTimeForTesting( | 215 void GPUTimingClient::SetCpuTimeForTesting( |
| 154 const base::Callback<int64(void)>& cpu_time) { | 216 const base::Callback<int64(void)>& cpu_time) { |
| 155 cpu_time_for_testing_ = cpu_time; | 217 cpu_time_for_testing_ = cpu_time; |
| 156 } | 218 } |
| 157 | 219 |
| 158 GPUTimingClient::~GPUTimingClient() { | 220 GPUTimingClient::~GPUTimingClient() { |
| 159 } | 221 } |
| 160 | 222 |
| 161 } // namespace gfx | 223 } // namespace gfx |
| OLD | NEW |