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.
5 #include "ui/gl/gpu_timing.h"
7 #include "base/time/time.h"
8 #include "ui/gl/gl_bindings.h"
9 #include "ui/gl/gl_context.h"
10 #include "ui/gl/gl_version_info.h"
14 GPUTiming::GPUTiming(GLContextReal
* context
) {
16 const GLVersionInfo
* version_info
= context
->GetVersionInfo();
18 if (version_info
->is_es3
&& // glGetInteger64v is supported under ES3.
19 context
->HasExtension("GL_EXT_disjoint_timer_query")) {
20 timer_type_
= kTimerTypeDisjoint
;
21 } else if (context
->HasExtension("GL_ARB_timer_query")) {
22 timer_type_
= kTimerTypeARB
;
26 GPUTiming::~GPUTiming() {
29 scoped_refptr
<GPUTimingClient
> GPUTiming::CreateGPUTimingClient() {
30 return new GPUTimingClient(this);
33 uint32_t GPUTiming::GetDisjointCount() {
34 if (timer_type_
== kTimerTypeDisjoint
) {
35 GLint disjoint_value
= 0;
36 glGetIntegerv(GL_GPU_DISJOINT_EXT
, &disjoint_value
);
41 return disjoint_counter_
;
44 GPUTimer::~GPUTimer() {
45 glDeleteQueriesARB(2, queries_
);
48 void GPUTimer::Start() {
49 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
50 glQueryCounter(queries_
[0], GL_TIMESTAMP
);
53 void GPUTimer::End() {
54 end_requested_
= true;
55 offset_
= gpu_timing_client_
->CalculateTimerOffset();
56 glQueryCounter(queries_
[1], GL_TIMESTAMP
);
59 bool GPUTimer::IsAvailable() {
60 if (!gpu_timing_client_
->IsAvailable() || !end_requested_
) {
64 glGetQueryObjectivARB(queries_
[1], GL_QUERY_RESULT_AVAILABLE
, &done
);
68 void GPUTimer::GetStartEndTimestamps(int64
* start
, int64
* end
) {
70 DCHECK(IsAvailable());
71 GLuint64 begin_stamp
= 0;
72 GLuint64 end_stamp
= 0;
73 // 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
76 glGetQueryObjectui64v(queries_
[0], GL_QUERY_RESULT
, &begin_stamp
);
77 glGetQueryObjectui64v(queries_
[1], GL_QUERY_RESULT
, &end_stamp
);
79 *start
= (begin_stamp
/ base::Time::kNanosecondsPerMicrosecond
) + offset_
;
80 *end
= (end_stamp
/ base::Time::kNanosecondsPerMicrosecond
) + offset_
;
83 int64
GPUTimer::GetDeltaElapsed() {
86 GetStartEndTimestamps(&start
, &end
);
90 GPUTimer::GPUTimer(scoped_refptr
<GPUTimingClient
> gpu_timing_client
)
91 : gpu_timing_client_(gpu_timing_client
) {
92 DCHECK(gpu_timing_client_
);
93 memset(queries_
, 0, sizeof(queries_
));
94 glGenQueriesARB(2, queries_
);
97 GPUTimingClient::GPUTimingClient(GPUTiming
* gpu_timing
)
98 : gpu_timing_(gpu_timing
) {
100 timer_type_
= gpu_timing
->GetTimerType();
101 disjoint_counter_
= gpu_timing_
->GetDisjointCount();
105 scoped_ptr
<GPUTimer
> GPUTimingClient::CreateGPUTimer() {
106 return make_scoped_ptr(new GPUTimer(this));
109 bool GPUTimingClient::IsAvailable() {
110 return timer_type_
!= GPUTiming::kTimerTypeInvalid
;
113 const char* GPUTimingClient::GetTimerTypeName() const {
114 switch (timer_type_
) {
115 case GPUTiming::kTimerTypeDisjoint
:
116 return "GL_EXT_disjoint_timer_query";
117 case GPUTiming::kTimerTypeARB
:
118 return "GL_ARB_timer_query";
124 bool GPUTimingClient::CheckAndResetTimerErrors() {
125 if (timer_type_
== GPUTiming::kTimerTypeDisjoint
) {
126 DCHECK(gpu_timing_
!= nullptr);
127 const uint32_t total_disjoint_count
= gpu_timing_
->GetDisjointCount();
128 const bool disjoint_triggered
= total_disjoint_count
!= disjoint_counter_
;
129 disjoint_counter_
= total_disjoint_count
;
130 return disjoint_triggered
;
135 int64
GPUTimingClient::CalculateTimerOffset() {
136 if (!offset_valid_
) {
138 glGetInteger64v(GL_TIMESTAMP
, &gl_now
);
140 cpu_time_for_testing_
.is_null()
141 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()
142 : cpu_time_for_testing_
.Run();
143 offset_
= now
- gl_now
/ base::Time::kNanosecondsPerMicrosecond
;
144 offset_valid_
= timer_type_
== GPUTiming::kTimerTypeARB
;
149 void GPUTimingClient::InvalidateTimerOffset() {
150 offset_valid_
= false;
153 void GPUTimingClient::SetCpuTimeForTesting(
154 const base::Callback
<int64(void)>& cpu_time
) {
155 cpu_time_for_testing_
= cpu_time
;
158 GPUTimingClient::~GPUTimingClient() {