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_context.h" | |
9 #include "ui/gl/gl_version_info.h" | |
10 | |
11 namespace gpu { | |
12 | |
13 GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) { | |
14 DCHECK(gpu_timing_); | |
15 memset(queries_, 0, sizeof(queries_)); | |
16 glGenQueriesARB(2, queries_); | |
17 } | |
18 | |
19 GPUTimer::~GPUTimer() { | |
20 glDeleteQueriesARB(2, queries_); | |
21 } | |
22 | |
23 void GPUTimer::Start() { | |
24 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value. | |
25 offset_ = gpu_timing_->CalculateTimerOffset(); | |
26 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
27 } | |
28 | |
29 void GPUTimer::End() { | |
30 end_requested_ = true; | |
31 glQueryCounter(queries_[1], GL_TIMESTAMP); | |
32 } | |
33 | |
34 bool GPUTimer::IsAvailable() { | |
35 if (!gpu_timing_->IsAvailable() || !end_requested_) { | |
36 return false; | |
37 } | |
38 GLint done = 0; | |
39 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
40 return done != 0; | |
41 } | |
42 | |
43 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) { | |
44 DCHECK(start && end); | |
45 DCHECK(IsAvailable()); | |
46 GLuint64 begin_stamp = 0; | |
47 GLuint64 end_stamp = 0; | |
48 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | |
49 // We need to detect if the end is less then the start and correct for the | |
50 // wrapping. | |
51 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp); | |
52 *start = begin_stamp / base::Time::kNanosecondsPerMicrosecond + offset_; | |
53 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp); | |
54 *end = end_stamp / base::Time::kNanosecondsPerMicrosecond + offset_; | |
55 } | |
56 | |
57 int64 GPUTimer::GetDeltaElapsed() { | |
58 int64 start = 0; | |
59 int64 end = 0; | |
60 GetStartEndTimestamps(&start, &end); | |
61 return end - start; | |
62 } | |
63 | |
64 GPUTiming::GPUTiming() : cpu_time_for_testing_() { | |
65 } | |
66 | |
67 GPUTiming::~GPUTiming() { | |
68 } | |
69 | |
70 bool GPUTiming::Initialize(gfx::GLContext* gl_context) { | |
71 DCHECK(gl_context); | |
72 DCHECK_EQ(kTimerTypeInvalid, timer_type_); | |
73 | |
74 const gfx::GLVersionInfo* version_info = gl_context->GetVersionInfo(); | |
75 DCHECK(version_info); | |
76 if (version_info->is_es3 && // glGetInteger64v is supported under ES3. | |
77 gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) { | |
78 timer_type_ = kTimerTypeDisjoint; | |
79 CheckAndResetTimerErrors(); | |
David Yen
2015/02/06 22:47:01
The ResetTimerErrors() needs to be called everytim
Daniele Castagna
2015/02/10 04:49:33
Done.
| |
80 return true; | |
81 } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | |
82 timer_type_ = kTimerTypeARB; | |
83 offset_ = CalculateTimerOffset(); | |
David Yen
2015/02/06 22:47:01
I think we don't need to call CalculateTimerOffset
Daniele Castagna
2015/02/10 04:49:33
Done.
| |
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 DCHECK_EQ(kTimerTypeDisjoint, timer_type_); | |
David Yen
2015/02/06 22:47:01
This DCHECK seems unnecessary, was it from old cod
Daniele Castagna
2015/02/10 04:49:32
Done.
| |
107 GLint disjoint_value = 0; | |
108 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value); | |
109 return disjoint_value != 0; | |
110 } else { | |
111 return false; | |
112 } | |
113 } | |
114 | |
115 int64 GPUTiming::CalculateTimerOffset() { | |
116 if (!offset_valid_) { | |
117 GLint64 gl_now = 0; | |
118 glGetInteger64v(GL_TIMESTAMP, &gl_now); | |
119 int64 now = | |
120 cpu_time_for_testing_.is_null() | |
121 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue() | |
122 : cpu_time_for_testing_.Run(); | |
123 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond; | |
124 offset_valid_ = timer_type_ == kTimerTypeARB; | |
125 } | |
126 return offset_; | |
127 } | |
128 | |
129 void GPUTiming::InvalidateTimerOffset() { | |
130 offset_valid_ = false; | |
131 } | |
132 | |
133 void GPUTiming::SetCpuTimeForTesting( | |
134 const base::Callback<int64(void)>& cpu_time) { | |
135 cpu_time_for_testing_ = cpu_time; | |
136 } | |
137 | |
138 void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) { | |
139 offset_ = offset; | |
140 offset_valid_ = cache_it; | |
141 } | |
142 | |
143 void GPUTiming::SetTimerTypeForTesting(TimerType type) { | |
144 timer_type_ = type; | |
145 } | |
146 | |
147 } // namespace gpu | |
OLD | NEW |