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_bindings.h" | |
9 #include "ui/gl/gl_context.h" | |
10 #include "ui/gl/gl_version_info.h" | |
11 | |
12 namespace gpu { | |
13 | |
14 GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) { | |
15 DCHECK(gpu_timing_); | |
16 memset(queries_, 0, sizeof(queries_)); | |
17 glGenQueriesARB(2, queries_); | |
18 } | |
19 | |
20 GPUTimer::~GPUTimer() { | |
21 glDeleteQueriesARB(2, queries_); | |
22 } | |
23 | |
24 void GPUTimer::Start() { | |
25 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | |
26 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
27 } | |
28 | |
29 void GPUTimer::End() { | |
30 end_requested_ = true; | |
31 offset_ = gpu_timing_->CalculateTimerOffset(); | |
32 glQueryCounter(queries_[1], GL_TIMESTAMP); | |
33 } | |
34 | |
35 bool GPUTimer::IsAvailable() { | |
36 if (!gpu_timing_->IsAvailable() || !end_requested_) { | |
37 return false; | |
38 } | |
39 GLint done = 0; | |
40 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
41 return done != 0; | |
42 } | |
43 | |
44 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { | |
45 DCHECK(start && end); | |
46 DCHECK(IsAvailable()); | |
47 GLuint64 begin_stamp = 0; | |
48 GLuint64 end_stamp = 0; | |
49 // 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 | |
51 // wrapping. | |
52 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | |
53 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | |
54 | |
55 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
56 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
57 } | |
58 | |
59 int64 GPUTimer::GetDeltaElapsed() { | |
60 int64 start = 0; | |
61 int64 end = 0; | |
62 GetStartEndTimestamps(&start, &end); | |
63 return end - start; | |
64 } | |
65 | |
66 GPUTiming::GPUTiming() : cpu_time_for_testing_() { | |
67 } | |
68 | |
69 GPUTiming::~GPUTiming() { | |
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_) { | |
95 case kTimerTypeDisjoint: | |
96 return "GL_EXT_disjoint_timer_query"; | |
97 case kTimerTypeARB: | |
98 return "GL_ARB_timer_query"; | |
99 default: | |
100 return "Unknown"; | |
101 } | |
102 } | |
103 | |
104 bool GPUTiming::CheckAndResetTimerErrors() { | |
105 if (timer_type_ == kTimerTypeDisjoint) { | |
106 GLint disjoint_value = 0; | |
107 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
108 return disjoint_value != 0; | |
109 } else { | |
110 return false; | |
111 } | |
112 } | |
113 | |
114 int64 GPUTiming::CalculateTimerOffset() { | |
115 if (!offset_valid_) { | |
116 GLint64 gl_now = 0; | |
117 glGetInteger64v(GL_TIMESTAMP, &gl_now); | |
118 int64 now = | |
119 cpu_time_for_testing_.is_null() | |
120 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() | |
121 : cpu_time_for_testing_.Run(); | |
122 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; | |
123 offset_valid_ = timer_type_ == kTimerTypeARB; | |
124 } | |
125 return offset_; | |
126 } | |
127 | |
128 void GPUTiming::InvalidateTimerOffset() { | |
129 offset_valid_ = false; | |
130 } | |
131 | |
132 void GPUTiming::SetCpuTimeForTesting( | |
133 const base::Callback<int64(void)>& cpu_time) { | |
134 cpu_time_for_testing_ = cpu_time; | |
135 } | |
136 | |
137 void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) { | |
138 offset_ = offset; | |
139 offset_valid_ = cache_it; | |
140 } | |
141 | |
142 void GPUTiming::SetTimerTypeForTesting(TimerType type) { | |
143 timer_type_ = type; | |
144 } | |
145 | |
146 } // namespace gpu | |
OLD | NEW |