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