Skip to content

Commit

Permalink
gpu: Extract the gpu timing code from gpu_tracer.
Browse files Browse the repository at this point in the history
This commit introduces two new classes: GPUTiming and GPUTimer. The first one takes care of checking which timing GL extension to use, and the second one measures the amount of time it takes to complete a set of opengl commands.
GPUTracer and GPUTrace have been modified accordingly to use the two new classes.

BUG=

Review URL: https://codereview.chromium.org/904743002

Cr-Commit-Position: refs/heads/master@{#316020}
  • Loading branch information
DCastagna authored and Commit bot committed Feb 12, 2015
1 parent d84033d commit 82922f8
Show file tree
Hide file tree
Showing 9 changed files with 397 additions and 380 deletions.
2 changes: 2 additions & 0 deletions gpu/command_buffer/service/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ source_set("service") {
"gpu_switches.h",
"gpu_tracer.cc",
"gpu_tracer.h",
"gpu_timing.cc",
"gpu_timing.h",
"id_manager.h",
"id_manager.cc",
"image_factory.cc",
Expand Down
3 changes: 3 additions & 0 deletions gpu/command_buffer/service/gpu_service_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,8 @@ void GpuServiceTest::TearDown() {
testing::Test::TearDown();
}

gfx::GLContext* GpuServiceTest::GetGLContext() {
return context_.get();
}
} // namespace gles2
} // namespace gpu
3 changes: 2 additions & 1 deletion gpu/command_buffer/service/gpu_service_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class GpuServiceTest : public testing::Test {
void SetUpWithGLVersion(const char* gl_version, const char* gl_extensions);
void SetUp() override;
void TearDown() override;
gfx::GLContext* GetGLContext();

scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;

Expand All @@ -40,4 +41,4 @@ class GpuServiceTest : public testing::Test {
} // namespace gles2
} // namespace gpu

#endif // GPU_COMMAND_BUFFER_SERVICE_MAILBOX_SYNCHRONIZER_H_
#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SERVICE_TEST_H_
145 changes: 145 additions & 0 deletions gpu/command_buffer/service/gpu_timing.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/gpu_timing.h"

#include "base/time/time.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_version_info.h"

namespace gpu {

GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) {
DCHECK(gpu_timing_);
memset(queries_, 0, sizeof(queries_));
glGenQueriesARB(2, queries_);
}

GPUTimer::~GPUTimer() {
glDeleteQueriesARB(2, queries_);
}

void GPUTimer::Start() {
// GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
offset_ = gpu_timing_->CalculateTimerOffset();
glQueryCounter(queries_[0], GL_TIMESTAMP);
}

void GPUTimer::End() {
end_requested_ = true;
glQueryCounter(queries_[1], GL_TIMESTAMP);
}

bool GPUTimer::IsAvailable() {
if (!gpu_timing_->IsAvailable() || !end_requested_) {
return false;
}
GLint done = 0;
glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
return done != 0;
}

void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) {
DCHECK(start && end);
DCHECK(IsAvailable());
GLuint64 begin_stamp = 0;
GLuint64 end_stamp = 0;
// TODO(dsinclair): It's possible for the timer to wrap during the start/end.
// We need to detect if the end is less then the start and correct for the
// wrapping.
glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);

*start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
*end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
}

int64 GPUTimer::GetDeltaElapsed() {
int64 start = 0;
int64 end = 0;
GetStartEndTimestamps(&start, &end);
return end - start;
}

GPUTiming::GPUTiming() : cpu_time_for_testing_() {
}

GPUTiming::~GPUTiming() {
}

bool GPUTiming::Initialize(gfx::GLContext* gl_context) {
DCHECK(gl_context);
DCHECK_EQ(kTimerTypeInvalid, timer_type_);

const gfx::GLVersionInfo* version_info = gl_context->GetVersionInfo();
DCHECK(version_info);
if (version_info->is_es3 && // glGetInteger64v is supported under ES3.
gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) {
timer_type_ = kTimerTypeDisjoint;
return true;
} else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) {
timer_type_ = kTimerTypeARB;
return true;
}
return false;
}

bool GPUTiming::IsAvailable() {
return timer_type_ != kTimerTypeInvalid;
}

const char* GPUTiming::GetTimerTypeName() const {
switch (timer_type_) {
case kTimerTypeDisjoint:
return "GL_EXT_disjoint_timer_query";
case kTimerTypeARB:
return "GL_ARB_timer_query";
default:
return "Unknown";
}
}

bool GPUTiming::CheckAndResetTimerErrors() {
if (timer_type_ == kTimerTypeDisjoint) {
GLint disjoint_value = 0;
glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
return disjoint_value != 0;
} else {
return false;
}
}

int64 GPUTiming::CalculateTimerOffset() {
if (!offset_valid_) {
GLint64 gl_now = 0;
glGetInteger64v(GL_TIMESTAMP, &gl_now);
int64 now =
cpu_time_for_testing_.is_null()
? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()
: cpu_time_for_testing_.Run();
offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond;
offset_valid_ = timer_type_ == kTimerTypeARB;
}
return offset_;
}

void GPUTiming::InvalidateTimerOffset() {
offset_valid_ = false;
}

void GPUTiming::SetCpuTimeForTesting(
const base::Callback<int64(void)>& cpu_time) {
cpu_time_for_testing_ = cpu_time;
}

void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) {
offset_ = offset;
offset_valid_ = cache_it;
}

void GPUTiming::SetTimerTypeForTesting(TimerType type) {
timer_type_ = type;
}

} // namespace gpu
85 changes: 85 additions & 0 deletions gpu/command_buffer/service/gpu_timing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_
#define GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_

#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/gpu_export.h"
#include "ui/gl/gl_bindings.h"

namespace gpu {

class GPUTiming;

// Class to compute the amount of time it takes to fully
// complete a set of GL commands
class GPU_EXPORT GPUTimer {
public:
// gpu_timing must outlive GPUTimer instance we're creating.
explicit GPUTimer(GPUTiming* gpu_timing);
~GPUTimer();

void Start();
void End();
bool IsAvailable();

void GetStartEndTimestamps(int64* start, int64* end);
int64 GetDeltaElapsed();

private:
GLuint queries_[2];
int64 offset_ = 0;
bool end_requested_ = false;
GPUTiming* gpu_timing_;

DISALLOW_COPY_AND_ASSIGN(GPUTimer);
};

// GPUTiming contains all the gl timing logic that is not specific
// to a single GPUTimer.
class GPU_EXPORT GPUTiming {
public:
enum TimerType {
kTimerTypeInvalid = -1,

kTimerTypeARB, // ARB_timer_query
kTimerTypeDisjoint // EXT_disjoint_timer_query
};

GPUTiming();
virtual ~GPUTiming();

bool Initialize(gfx::GLContext* context);
bool IsAvailable();

// CheckAndResetTimerErrors has to be called before reading timestamps
// from GPUTimers instances and after making sure all the timers
// were available.
// If the returned value is false, all the previous timers should be
// discarded.
bool CheckAndResetTimerErrors();

const char* GetTimerTypeName() const;

// Returns the offset between the current gpu time and the cpu time.
int64 CalculateTimerOffset();
void InvalidateTimerOffset();

void SetCpuTimeForTesting(const base::Callback<int64(void)>& cpu_time);
void SetOffsetForTesting(int64 offset, bool cache_it);
void SetTimerTypeForTesting(TimerType type);

private:
TimerType timer_type_ = kTimerTypeInvalid;
int64 offset_ = 0; // offset cache when timer_type_ == kTimerTypeARB
bool offset_valid_ = false;
base::Callback<int64(void)> cpu_time_for_testing_;
friend class GPUTimer;
DISALLOW_COPY_AND_ASSIGN(GPUTiming);
};
} // namespace gpu

#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_
Loading

0 comments on commit 82922f8

Please sign in to comment.