blob: a3b697fe306b0afaaac1c48787e8049c76276163 [file] [log] [blame]
Etienne Membrives386015a2015-02-19 17:27:12 +01001// 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
Benjamin Lerman507bb1a2015-02-26 13:15:17 +01005#include "ui/gl/gpu_timing.h"
Etienne Membrives386015a2015-02-19 17:27:12 +01006
7#include "base/time/time.h"
Benjamin Lermane8ca9b72015-02-24 16:42:13 +01008#include "ui/gl/gl_bindings.h"
Etienne Membrives386015a2015-02-19 17:27:12 +01009#include "ui/gl/gl_context.h"
10#include "ui/gl/gl_version_info.h"
11
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010012namespace gfx {
Etienne Membrives386015a2015-02-19 17:27:12 +010013
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010014GPUTiming::GPUTiming(GLContextReal* context) {
15 DCHECK(context);
16 const GLVersionInfo* version_info = context->GetVersionInfo();
17 DCHECK(version_info);
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;
23 }
24}
25
26GPUTiming::~GPUTiming() {
27}
28
29scoped_refptr<GPUTimingClient> GPUTiming::CreateGPUTimingClient() {
30 return new GPUTimingClient(this);
Etienne Membrives386015a2015-02-19 17:27:12 +010031}
32
Dave Moorecc0e4f92015-03-10 15:23:04 -070033uint32_t GPUTiming::GetDisjointCount() {
34 if (timer_type_ == kTimerTypeDisjoint) {
35 GLint disjoint_value = 0;
36 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
37 if (disjoint_value) {
38 disjoint_counter_++;
39 }
40 }
41 return disjoint_counter_;
42}
43
Etienne Membrives386015a2015-02-19 17:27:12 +010044GPUTimer::~GPUTimer() {
45 glDeleteQueriesARB(2, queries_);
46}
47
48void GPUTimer::Start() {
49 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
50 glQueryCounter(queries_[0], GL_TIMESTAMP);
Etienne Membrives386015a2015-02-19 17:27:12 +010051}
52
53void GPUTimer::End() {
54 end_requested_ = true;
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010055 offset_ = gpu_timing_client_->CalculateTimerOffset();
Etienne Membrives386015a2015-02-19 17:27:12 +010056 glQueryCounter(queries_[1], GL_TIMESTAMP);
57}
58
59bool GPUTimer::IsAvailable() {
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010060 if (!gpu_timing_client_->IsAvailable() || !end_requested_) {
Etienne Membrives386015a2015-02-19 17:27:12 +010061 return false;
62 }
63 GLint done = 0;
64 glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
65 return done != 0;
66}
67
68void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) {
69 DCHECK(start && 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
75 // wrapping.
76 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
77 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
78
79 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
80 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
81}
82
83int64 GPUTimer::GetDeltaElapsed() {
84 int64 start = 0;
85 int64 end = 0;
86 GetStartEndTimestamps(&start, &end);
87 return end - start;
88}
89
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010090GPUTimer::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_);
Etienne Membrives386015a2015-02-19 17:27:12 +010095}
96
Benjamin Lerman507bb1a2015-02-26 13:15:17 +010097GPUTimingClient::GPUTimingClient(GPUTiming* gpu_timing)
98 : gpu_timing_(gpu_timing) {
99 if (gpu_timing) {
100 timer_type_ = gpu_timing->GetTimerType();
Dave Moorecc0e4f92015-03-10 15:23:04 -0700101 disjoint_counter_ = gpu_timing_->GetDisjointCount();
Etienne Membrives386015a2015-02-19 17:27:12 +0100102 }
Etienne Membrives386015a2015-02-19 17:27:12 +0100103}
104
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100105scoped_ptr<GPUTimer> GPUTimingClient::CreateGPUTimer() {
106 return make_scoped_ptr(new GPUTimer(this));
Etienne Membrives386015a2015-02-19 17:27:12 +0100107}
108
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100109bool GPUTimingClient::IsAvailable() {
110 return timer_type_ != GPUTiming::kTimerTypeInvalid;
111}
112
113const char* GPUTimingClient::GetTimerTypeName() const {
Etienne Membrives386015a2015-02-19 17:27:12 +0100114 switch (timer_type_) {
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100115 case GPUTiming::kTimerTypeDisjoint:
Etienne Membrives386015a2015-02-19 17:27:12 +0100116 return "GL_EXT_disjoint_timer_query";
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100117 case GPUTiming::kTimerTypeARB:
Etienne Membrives386015a2015-02-19 17:27:12 +0100118 return "GL_ARB_timer_query";
119 default:
120 return "Unknown";
121 }
122}
123
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100124bool GPUTimingClient::CheckAndResetTimerErrors() {
125 if (timer_type_ == GPUTiming::kTimerTypeDisjoint) {
Dave Moorecc0e4f92015-03-10 15:23:04 -0700126 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;
Etienne Membrives386015a2015-02-19 17:27:12 +0100131 }
Dave Moorecc0e4f92015-03-10 15:23:04 -0700132 return false;
Etienne Membrives386015a2015-02-19 17:27:12 +0100133}
134
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100135int64 GPUTimingClient::CalculateTimerOffset() {
Etienne Membrives386015a2015-02-19 17:27:12 +0100136 if (!offset_valid_) {
137 GLint64 gl_now = 0;
138 glGetInteger64v(GL_TIMESTAMP, &gl_now);
139 int64 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;
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100144 offset_valid_ = timer_type_ == GPUTiming::kTimerTypeARB;
Etienne Membrives386015a2015-02-19 17:27:12 +0100145 }
146 return offset_;
147}
148
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100149void GPUTimingClient::InvalidateTimerOffset() {
Etienne Membrives386015a2015-02-19 17:27:12 +0100150 offset_valid_ = false;
151}
152
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100153void GPUTimingClient::SetCpuTimeForTesting(
Etienne Membrives386015a2015-02-19 17:27:12 +0100154 const base::Callback<int64(void)>& cpu_time) {
155 cpu_time_for_testing_ = cpu_time;
156}
157
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100158GPUTimingClient::~GPUTimingClient() {
Etienne Membrives386015a2015-02-19 17:27:12 +0100159}
160
Benjamin Lerman507bb1a2015-02-26 13:15:17 +0100161} // namespace gfx