OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_tracer.h" | 5 #include "gpu/command_buffer/service/gpu_tracer.h" |
6 | 6 |
7 #include <deque> | 7 #include <deque> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 virtual bool IsAvailable() OVERRIDE { return true; } | 67 virtual bool IsAvailable() OVERRIDE { return true; } |
68 virtual bool IsProcessable() OVERRIDE { return false; } | 68 virtual bool IsProcessable() OVERRIDE { return false; } |
69 virtual void Process() OVERRIDE {} | 69 virtual void Process() OVERRIDE {} |
70 | 70 |
71 private: | 71 private: |
72 virtual ~NoopTrace() {} | 72 virtual ~NoopTrace() {} |
73 | 73 |
74 DISALLOW_COPY_AND_ASSIGN(NoopTrace); | 74 DISALLOW_COPY_AND_ASSIGN(NoopTrace); |
75 }; | 75 }; |
76 | 76 |
77 struct TraceMarker { | 77 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder) |
78 TraceMarker(const std::string& name, GpuTracerSource source) | 78 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
79 : name_(name), source_(source) {} | 79 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), |
80 | 80 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
81 std::string name_; | 81 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), |
82 GpuTracerSource source_; | 82 decoder_(decoder), |
83 scoped_refptr<Trace> trace_; | 83 timer_offset_(0), |
84 }; | 84 last_tracer_source_(kTraceGroupInvalid), |
85 | 85 enabled_(false), |
86 class GPUTracerImpl | 86 gpu_timing_synced_(false), |
87 : public GPUTracer, | 87 gpu_executing_(false), |
88 public base::SupportsWeakPtr<GPUTracerImpl> { | 88 process_posted_(false) { |
89 public: | 89 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { |
90 GPUTracerImpl() | 90 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); |
91 : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | 91 enabled_ = true; |
92 TRACE_DISABLED_BY_DEFAULT("gpu.service"))), | |
93 gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( | |
94 TRACE_DISABLED_BY_DEFAULT("gpu.device"))), | |
95 gpu_executing_(false), | |
96 process_posted_(false) {} | |
97 virtual ~GPUTracerImpl() {} | |
98 | |
99 // Implementation of gpu::gles2::GPUTracer | |
100 virtual bool BeginDecoding() OVERRIDE; | |
101 virtual bool EndDecoding() OVERRIDE; | |
102 virtual bool Begin(const std::string& name, GpuTracerSource source) OVERRIDE; | |
103 virtual bool End(GpuTracerSource source) OVERRIDE; | |
104 virtual const std::string& CurrentName() const OVERRIDE; | |
105 virtual bool IsTracing() OVERRIDE { | |
106 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); | |
107 } | 92 } |
108 virtual void CalculateTimerOffset() {} | |
109 | |
110 // Process any completed traces. | |
111 virtual void Process(); | |
112 virtual void ProcessTraces(); | |
113 | |
114 protected: | |
115 // Create a new trace. | |
116 virtual scoped_refptr<Trace> CreateTrace(const std::string& name); | |
117 | |
118 const unsigned char* gpu_trace_srv_category; | |
119 const unsigned char* gpu_trace_dev_category; | |
120 | |
121 protected: | |
122 void IssueProcessTask(); | |
123 | |
124 std::vector<TraceMarker> markers_; | |
125 std::deque<scoped_refptr<Trace> > traces_; | |
126 | |
127 bool gpu_executing_; | |
128 bool process_posted_; | |
129 | |
130 DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl); | |
131 }; | |
132 | |
133 class GPUTracerARBTimerQuery : public GPUTracerImpl { | |
134 public: | |
135 explicit GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder); | |
136 virtual ~GPUTracerARBTimerQuery(); | |
137 | |
138 // Implementation of GPUTracerImpl | |
139 virtual void ProcessTraces() OVERRIDE; | |
140 | |
141 protected: | |
142 // Implementation of GPUTracerImpl. | |
143 virtual bool BeginDecoding() OVERRIDE; | |
144 virtual bool EndDecoding() OVERRIDE; | |
145 virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE; | |
146 virtual void CalculateTimerOffset() OVERRIDE; | |
147 | |
148 scoped_refptr<Outputter> outputter_; | |
149 | |
150 bool gpu_timing_synced_; | |
151 int64 timer_offset_; | |
152 | |
153 gles2::GLES2Decoder* decoder_; | |
154 | |
155 DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery); | |
156 }; | |
157 | |
158 bool Trace::IsProcessable() { return true; } | |
159 | |
160 const std::string& Trace::name() { return name_; } | |
161 | |
162 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, | |
163 const std::string& name, | |
164 int64 offset) | |
165 : Trace(name), | |
166 outputter_(outputter), | |
167 offset_(offset), | |
168 start_time_(0), | |
169 end_time_(0), | |
170 end_requested_(false) { | |
171 glGenQueries(2, queries_); | |
172 } | 93 } |
173 | 94 |
174 GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); } | 95 GPUTracer::~GPUTracer() { |
175 | |
176 void GLARBTimerTrace::Start() { | |
177 TRACE_EVENT_COPY_ASYNC_BEGIN0( | |
178 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | |
179 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
180 } | 96 } |
181 | 97 |
182 void GLARBTimerTrace::End() { | 98 bool GPUTracer::BeginDecoding() { |
183 glQueryCounter(queries_[1], GL_TIMESTAMP); | 99 if (enabled_) { |
184 end_requested_ = true; | 100 if (*gpu_trace_dev_category) { |
185 TRACE_EVENT_COPY_ASYNC_END0( | 101 // Make sure timing is synced before tracing |
186 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | 102 if (!gpu_timing_synced_) { |
187 } | 103 CalculateTimerOffset(); |
104 gpu_timing_synced_ = true; | |
105 } | |
106 } else { | |
107 // If GPU device category is off, invalidate timing sync | |
108 gpu_timing_synced_ = false; | |
109 } | |
110 } | |
188 | 111 |
189 bool GLARBTimerTrace::IsAvailable() { | |
190 if (!end_requested_) | |
191 return false; | |
192 | |
193 GLint done = 0; | |
194 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
195 return !!done; | |
196 } | |
197 | |
198 void GLARBTimerTrace::Process() { | |
199 DCHECK(IsAvailable()); | |
200 | |
201 GLuint64 timestamp; | |
202 | |
203 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | |
204 // We need to detect if the end is less then the start and correct for the | |
205 // wrapping. | |
206 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); | |
207 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
208 | |
209 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); | |
210 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
211 | |
212 glDeleteQueries(2, queries_); | |
213 outputter_->Trace(name(), start_time_, end_time_); | |
214 } | |
215 | |
216 bool GPUTracerImpl::BeginDecoding() { | |
217 if (gpu_executing_) | 112 if (gpu_executing_) |
218 return false; | 113 return false; |
219 | 114 |
220 gpu_executing_ = true; | 115 gpu_executing_ = true; |
221 | 116 |
222 if (IsTracing()) { | 117 if (IsTracing()) { |
223 // Begin a Trace for all active markers | 118 // Begin a Trace for all active markers |
224 for (size_t i = 0; i < markers_.size(); i++) { | 119 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
225 markers_[i].trace_ = CreateTrace(markers_[i].name_); | 120 for (size_t i = 0; i < markers_[n].size(); i++) { |
226 markers_[i].trace_->Start(); | 121 markers_[n][i].trace_ = CreateTrace(markers_[n][i].name_); |
122 markers_[n][i].trace_->Start(); | |
123 } | |
227 } | 124 } |
228 } | 125 } |
229 return true; | 126 return true; |
230 } | 127 } |
231 | 128 |
232 bool GPUTracerImpl::EndDecoding() { | 129 bool GPUTracer::EndDecoding() { |
233 if (!gpu_executing_) | 130 if (!gpu_executing_) |
234 return false; | 131 return false; |
235 | 132 |
236 // End Trace for all active markers | 133 // End Trace for all active markers |
237 if (IsTracing()) { | 134 if (IsTracing()) { |
238 for (size_t i = 0; i < markers_.size(); i++) { | 135 for (int n = 0; n < NUM_TRACER_SOURCES; n++) { |
239 if (markers_[i].trace_) { | 136 for (size_t i = 0; i < markers_[n].size(); i++) { |
240 markers_[i].trace_->End(); | 137 if (markers_[n][i].trace_) { |
241 if (markers_[i].trace_->IsProcessable()) | 138 markers_[n][i].trace_->End(); |
242 traces_.push_back(markers_[i].trace_); | 139 if (markers_[n][i].trace_->IsProcessable()) |
243 markers_[i].trace_ = 0; | 140 traces_.push_back(markers_[n][i].trace_); |
141 markers_[n][i].trace_ = 0; | |
142 } | |
244 } | 143 } |
245 } | 144 } |
246 IssueProcessTask(); | 145 IssueProcessTask(); |
247 } | 146 } |
248 | 147 |
249 gpu_executing_ = false; | 148 gpu_executing_ = false; |
149 | |
150 // NOTE(vmiura_: glFlush() here can help give better trace results, | |
vmiura
2014/07/29 23:45:30
nit: NOTE(vmiura)
David Yen
2014/08/04 22:20:05
Done.
| |
151 // but it distorts the normal device behavior. | |
250 return true; | 152 return true; |
251 } | 153 } |
252 | 154 |
253 bool GPUTracerImpl::Begin(const std::string& name, GpuTracerSource source) { | 155 bool GPUTracer::Begin(const std::string& name, GpuTracerSource source) { |
254 if (!gpu_executing_) | 156 if (!gpu_executing_) |
255 return false; | 157 return false; |
256 | 158 |
159 assert(source >= 0 && source < NUM_TRACER_SOURCES); | |
vmiura
2014/07/29 23:45:30
Please use DCHECK instead of assert here and below
David Yen
2014/08/04 22:20:05
Done.
| |
160 | |
257 // Push new marker from given 'source' | 161 // Push new marker from given 'source' |
258 markers_.push_back(TraceMarker(name, source)); | 162 last_tracer_source_ = source; |
163 markers_[source].push_back(TraceMarker(name)); | |
259 | 164 |
260 // Create trace | 165 // Create trace |
261 if (IsTracing()) { | 166 if (IsTracing()) { |
262 scoped_refptr<Trace> trace = CreateTrace(name); | 167 scoped_refptr<Trace> trace = CreateTrace(name); |
263 trace->Start(); | 168 trace->Start(); |
264 markers_.back().trace_ = trace; | 169 markers_[source].back().trace_ = trace; |
265 } | 170 } |
171 | |
266 return true; | 172 return true; |
267 } | 173 } |
268 | 174 |
269 bool GPUTracerImpl::End(GpuTracerSource source) { | 175 bool GPUTracer::End(GpuTracerSource source) { |
270 if (!gpu_executing_) | 176 if (!gpu_executing_) |
271 return false; | 177 return false; |
272 | 178 |
179 assert(source >= 0 && source < NUM_TRACER_SOURCES); | |
180 | |
273 // Pop last marker with matching 'source' | 181 // Pop last marker with matching 'source' |
274 for (int i = markers_.size() - 1; i >= 0; i--) { | 182 if (!markers_[source].empty()) { |
275 if (markers_[i].source_ == source) { | 183 if (IsTracing()) { |
276 // End trace | 184 scoped_refptr<Trace> trace = markers_[source].back().trace_; |
277 if (IsTracing()) { | 185 if (trace) { |
278 scoped_refptr<Trace> trace = markers_[i].trace_; | 186 trace->End(); |
279 if (trace) { | 187 if (trace->IsProcessable()) |
280 trace->End(); | 188 traces_.push_back(trace); |
281 if (trace->IsProcessable()) | 189 IssueProcessTask(); |
282 traces_.push_back(trace); | |
283 IssueProcessTask(); | |
284 } | |
285 } | 190 } |
191 } | |
286 | 192 |
287 markers_.erase(markers_.begin() + i); | 193 markers_[source].pop_back(); |
288 return true; | 194 return true; |
289 } | |
290 } | 195 } |
291 return false; | 196 return false; |
292 } | 197 } |
293 | 198 |
294 void GPUTracerImpl::Process() { | 199 bool GPUTracer::IsTracing() { |
200 return (*gpu_trace_srv_category != 0) || (*gpu_trace_dev_category != 0); | |
201 } | |
202 | |
203 const std::string& GPUTracer::CurrentName() const { | |
204 if (last_tracer_source_ >= 0 && | |
205 last_tracer_source_ < NUM_TRACER_SOURCES && | |
206 !markers_[last_tracer_source_].empty()) { | |
207 return markers_[last_tracer_source_].back().name_; | |
208 } | |
209 return base::EmptyString(); | |
210 } | |
211 | |
212 void GPUTracer::CalculateTimerOffset() { | |
213 if (enabled_) { | |
214 TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset"); | |
215 | |
216 // NOTE(vmiura): It would be better to use glGetInteger64v, however | |
217 // it's not available everywhere. | |
218 GLuint64 gl_now = 0; | |
219 GLuint query; | |
220 glFinish(); | |
221 glGenQueries(1, &query); | |
222 glQueryCounter(query, GL_TIMESTAMP); | |
223 glFinish(); | |
224 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | |
225 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | |
226 | |
227 gl_now /= base::Time::kNanosecondsPerMicrosecond; | |
228 timer_offset_ = system_now.ToInternalValue() - gl_now; | |
229 glDeleteQueries(1, &query); | |
230 } | |
231 } | |
232 | |
233 scoped_refptr<Trace> GPUTracer::CreateTrace(const std::string& name) { | |
234 if (enabled_) { | |
235 if (*gpu_trace_dev_category) | |
236 return new GLARBTimerTrace(outputter_, name, timer_offset_); | |
237 } | |
238 return new NoopTrace(name); | |
239 } | |
240 | |
241 void GPUTracer::Process() { | |
295 process_posted_ = false; | 242 process_posted_ = false; |
296 ProcessTraces(); | 243 ProcessTraces(); |
297 IssueProcessTask(); | 244 IssueProcessTask(); |
298 } | 245 } |
299 | 246 |
300 void GPUTracerImpl::ProcessTraces() { | 247 void GPUTracer::ProcessTraces() { |
301 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 248 if (!enabled_) { |
302 traces_.front()->Process(); | 249 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
303 traces_.pop_front(); | 250 traces_.front()->Process(); |
304 } | 251 traces_.pop_front(); |
305 } | 252 } |
306 | |
307 const std::string& GPUTracerImpl::CurrentName() const { | |
308 if (markers_.empty()) | |
309 return base::EmptyString(); | |
310 return markers_.back().name_; | |
311 } | |
312 | |
313 scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) { | |
314 return new NoopTrace(name); | |
315 } | |
316 | |
317 void GPUTracerImpl::IssueProcessTask() { | |
318 if (traces_.empty() || process_posted_) | |
319 return; | 253 return; |
320 | |
321 process_posted_ = true; | |
322 base::MessageLoop::current()->PostDelayedTask( | |
323 FROM_HERE, | |
324 base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)), | |
325 base::TimeDelta::FromMilliseconds(kProcessInterval)); | |
326 } | |
327 | |
328 GPUTracerARBTimerQuery::GPUTracerARBTimerQuery(gles2::GLES2Decoder* decoder) | |
329 : timer_offset_(0), decoder_(decoder) { | |
330 outputter_ = TraceOutputter::Create("GL_ARB_timer_query"); | |
331 } | |
332 | |
333 GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() { | |
334 } | |
335 | |
336 scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace( | |
337 const std::string& name) { | |
338 if (*gpu_trace_dev_category) | |
339 return new GLARBTimerTrace(outputter_, name, timer_offset_); | |
340 return GPUTracerImpl::CreateTrace(name); | |
341 } | |
342 | |
343 bool GPUTracerARBTimerQuery::BeginDecoding() { | |
344 if (*gpu_trace_dev_category) { | |
345 // Make sure timing is synced before tracing | |
346 if (!gpu_timing_synced_) { | |
347 CalculateTimerOffset(); | |
348 gpu_timing_synced_ = true; | |
349 } | |
350 } else { | |
351 // If GPU device category is off, invalidate timing sync | |
352 gpu_timing_synced_ = false; | |
353 } | 254 } |
354 | 255 |
355 return GPUTracerImpl::BeginDecoding(); | 256 TRACE_EVENT0("gpu", "GPUTracer::ProcessTraces"); |
356 } | |
357 | |
358 bool GPUTracerARBTimerQuery::EndDecoding() { | |
359 bool ret = GPUTracerImpl::EndDecoding(); | |
360 | |
361 // NOTE(vmiura_: glFlush() here can help give better trace results, | |
362 // but it distorts the normal device behavior. | |
363 return ret; | |
364 } | |
365 | |
366 void GPUTracerARBTimerQuery::ProcessTraces() { | |
367 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::ProcessTraces"); | |
368 | 257 |
369 // Make owning decoder's GL context current | 258 // Make owning decoder's GL context current |
370 if (!decoder_->MakeCurrent()) { | 259 if (!decoder_->MakeCurrent()) { |
371 // Skip subsequent GL calls if MakeCurrent fails | 260 // Skip subsequent GL calls if MakeCurrent fails |
372 traces_.clear(); | 261 traces_.clear(); |
373 return; | 262 return; |
374 } | 263 } |
375 | 264 |
376 while (!traces_.empty() && traces_.front()->IsAvailable()) { | 265 while (!traces_.empty() && traces_.front()->IsAvailable()) { |
377 traces_.front()->Process(); | 266 traces_.front()->Process(); |
378 traces_.pop_front(); | 267 traces_.pop_front(); |
379 } | 268 } |
380 | 269 |
381 // Clear pending traces if there were are any errors | 270 // Clear pending traces if there were are any errors |
382 GLenum err = glGetError(); | 271 GLenum err = glGetError(); |
383 if (err != GL_NO_ERROR) | 272 if (err != GL_NO_ERROR) |
384 traces_.clear(); | 273 traces_.clear(); |
385 } | 274 } |
386 | 275 |
387 void GPUTracerARBTimerQuery::CalculateTimerOffset() { | 276 void GPUTracer::IssueProcessTask() { |
388 TRACE_EVENT0("gpu", "GPUTracerARBTimerQuery::CalculateTimerOffset"); | 277 if (traces_.empty() || process_posted_) |
278 return; | |
389 | 279 |
390 // NOTE(vmiura): It would be better to use glGetInteger64v, however | 280 process_posted_ = true; |
391 // it's not available everywhere. | 281 base::MessageLoop::current()->PostDelayedTask( |
392 GLuint64 gl_now = 0; | 282 FROM_HERE, |
393 GLuint query; | 283 base::Bind(&GPUTracer::Process, base::AsWeakPtr(this)), |
394 glFinish(); | 284 base::TimeDelta::FromMilliseconds(kProcessInterval)); |
395 glGenQueries(1, &query); | |
396 glQueryCounter(query, GL_TIMESTAMP); | |
397 glFinish(); | |
398 glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now); | |
399 base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime(); | |
400 | |
401 gl_now /= base::Time::kNanosecondsPerMicrosecond; | |
402 timer_offset_ = system_now.ToInternalValue() - gl_now; | |
403 glDeleteQueries(1, &query); | |
404 } | 285 } |
405 | 286 |
406 GPUTracer::GPUTracer() {} | 287 bool Trace::IsProcessable() { return true; } |
407 | 288 |
408 GPUTracer::~GPUTracer() {} | 289 const std::string& Trace::name() { return name_; } |
409 | 290 |
410 scoped_ptr<GPUTracer> GPUTracer::Create(gles2::GLES2Decoder* decoder) { | 291 GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter, |
411 if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) { | 292 const std::string& name, |
412 return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery(decoder)); | 293 int64 offset) |
413 } | 294 : Trace(name), |
414 return scoped_ptr<GPUTracer>(new GPUTracerImpl()); | 295 outputter_(outputter), |
296 offset_(offset), | |
297 start_time_(0), | |
298 end_time_(0), | |
299 end_requested_(false) { | |
300 glGenQueries(2, queries_); | |
301 } | |
302 | |
303 GLARBTimerTrace::~GLARBTimerTrace() { glDeleteQueries(2, queries_); } | |
304 | |
305 void GLARBTimerTrace::Start() { | |
306 TRACE_EVENT_COPY_ASYNC_BEGIN0( | |
307 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | |
308 glQueryCounter(queries_[0], GL_TIMESTAMP); | |
309 } | |
310 | |
311 void GLARBTimerTrace::End() { | |
312 glQueryCounter(queries_[1], GL_TIMESTAMP); | |
313 end_requested_ = true; | |
314 TRACE_EVENT_COPY_ASYNC_END0( | |
315 TRACE_DISABLED_BY_DEFAULT("gpu.service"), name().c_str(), this); | |
316 } | |
317 | |
318 bool GLARBTimerTrace::IsAvailable() { | |
319 if (!end_requested_) | |
320 return false; | |
321 | |
322 GLint done = 0; | |
323 glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done); | |
324 return !!done; | |
325 } | |
326 | |
327 void GLARBTimerTrace::Process() { | |
328 DCHECK(IsAvailable()); | |
329 | |
330 GLuint64 timestamp; | |
331 | |
332 // TODO(dsinclair): It's possible for the timer to wrap during the start/end. | |
333 // We need to detect if the end is less then the start and correct for the | |
334 // wrapping. | |
335 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, ×tamp); | |
336 start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
337 | |
338 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, ×tamp); | |
339 end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_; | |
340 | |
341 glDeleteQueries(2, queries_); | |
342 outputter_->Trace(name(), start_time_, end_time_); | |
415 } | 343 } |
416 | 344 |
417 } // namespace gles2 | 345 } // namespace gles2 |
418 } // namespace gpu | 346 } // namespace gpu |
OLD | NEW |