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