Commit 71c79ec0 authored by ewell's avatar ewell Committed by Commit bot

Force time elapsed queries on certain drivers.

Certain drivers, particularly Mac drivers and ANGLE when running on the
D3D11 backend do not support timestamp queries despite implementing an
extension that has them in the specification (ARB_timer_query and
EXT_disjoint_timer_query). To indicate this, the driver returns 0 when
queried for the size of the timestamps they return using glGetQueryiv.
Additional logic was added to the GPUTimingImpl class to check for that
when using those extensions and to fall back to the time elapsed query
implementation of timestamps if the driver does not have native support.

BUG=587173
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel

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

Cr-Commit-Position: refs/heads/master@{#376049}
parent 8728e6c1
......@@ -704,10 +704,9 @@ static void CheckBeginEndQueryBadMemoryFails(GLES2DecoderTestBase* test,
error::Error error1 = error::kNoError;
error::Error error2 = error::kNoError;
if (query_type.is_counter) {
error1 = ExecuteQueryCounterCmd(test, gl, &gpu_timing_queries,
query_type.type,
client_id, service_id,
shm_id, shm_offset, 1);
error1 =
ExecuteQueryCounterCmd(test, gl, &gpu_timing_queries, query_type.type,
client_id, service_id, shm_id, shm_offset, 1);
} else {
error1 = ExecuteBeginQueryCmd(test, gl, &gpu_timing_queries,
query_type.type,
......@@ -777,14 +776,11 @@ TEST_P(GLES2DecoderManualInitTest, QueryReuseTest) {
// Query once.
if (query_type.is_counter) {
EXPECT_EQ(error::kNoError, ExecuteQueryCounterCmd(this, gl,
&gpu_timing_queries,
query_type.type,
kNewClientId,
kNewServiceId,
kSharedMemoryId,
kSharedMemoryOffset,
1));
EXPECT_EQ(
error::kNoError,
ExecuteQueryCounterCmd(this, gl, &gpu_timing_queries, query_type.type,
kNewClientId, kNewServiceId, kSharedMemoryId,
kSharedMemoryOffset, 1));
} else {
EXPECT_EQ(error::kNoError, ExecuteBeginQueryCmd(this, gl,
&gpu_timing_queries,
......@@ -801,14 +797,11 @@ TEST_P(GLES2DecoderManualInitTest, QueryReuseTest) {
// Reuse query.
if (query_type.is_counter) {
EXPECT_EQ(error::kNoError, ExecuteQueryCounterCmd(this, gl,
&gpu_timing_queries,
query_type.type,
kNewClientId,
kNewServiceId,
kSharedMemoryId,
kSharedMemoryOffset,
2));
EXPECT_EQ(
error::kNoError,
ExecuteQueryCounterCmd(this, gl, &gpu_timing_queries, query_type.type,
kNewClientId, kNewServiceId, kSharedMemoryId,
kSharedMemoryOffset, 2));
} else {
EXPECT_EQ(error::kNoError, ExecuteBeginQueryCmd(this, gl,
&gpu_timing_queries,
......@@ -1029,6 +1022,9 @@ TEST_P(GLES2DecoderManualInitTest, QueryCounterEXTTimeStamp) {
EXPECT_CALL(*gl_, GenQueries(1, _))
.WillOnce(SetArgPointee<1>(kNewServiceId))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, _))
.WillOnce(SetArgPointee<2>(64))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, QueryCounter(kNewServiceId, GL_TIMESTAMP))
.Times(1)
.RetiresOnSaturation();
......
......@@ -274,7 +274,7 @@ class BaseGpuTraceTest : public BaseGpuTest {
g_fakeCPUTime = expect_end_time;
EXPECT_TRUE(trace->IsAvailable());
// Proces should output expected Trace results to MockOutputter
// Process should output expected Trace results to MockOutputter
trace->Process();
// Destroy trace after we are done.
......
......@@ -20,6 +20,12 @@ int64_t NanoToMicro(uint64_t nano_seconds) {
return static_cast<int64_t>(up / base::Time::kNanosecondsPerMicrosecond);
}
int32_t QueryTimestampBits() {
GLint timestamp_bits;
glGetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, &timestamp_bits);
return static_cast<int32_t>(timestamp_bits);
}
class GPUTimingImpl : public GPUTiming {
public:
GPUTimingImpl(GLContextReal* context);
......@@ -73,6 +79,7 @@ class GPUTimingImpl : public GPUTiming {
int64_t offset_ = 0; // offset cache when timer_type_ == kTimerTypeARB
bool offset_valid_ = false;
bool force_time_elapsed_query_ = false;
int32_t timestamp_bit_count_gl_ = -1; // gl implementation timestamp bits
uint32_t next_timer_query_id_ = 0;
uint32_t next_good_timer_query_id_ = 0; // identify bad ids for disjoints.
......@@ -318,6 +325,7 @@ GPUTimingImpl::GPUTimingImpl(GLContextReal* context) {
} else if (context->HasExtension("GL_EXT_timer_query")) {
timer_type_ = GPUTiming::kTimerTypeEXT;
force_time_elapsed_query_ = true;
timestamp_bit_count_gl_ = 0;
}
}
......@@ -392,6 +400,15 @@ void GPUTimingImpl::EndElapsedTimeQuery(scoped_refptr<QueryResult> result) {
scoped_refptr<QueryResult> GPUTimingImpl::DoTimeStampQuery() {
DCHECK(timer_type_ != GPUTiming::kTimerTypeInvalid);
// Certain GL drivers have timestamp bit count set to 0 which means timestamps
// aren't supported. Emulate them with time elapsed queries if that is the
// case.
if (timestamp_bit_count_gl_ == -1) {
DCHECK(timer_type_ != GPUTiming::kTimerTypeEXT);
timestamp_bit_count_gl_ = QueryTimestampBits();
force_time_elapsed_query_ = (timestamp_bit_count_gl_ == 0);
}
if (force_time_elapsed_query_) {
// Replace with elapsed timer queries instead.
scoped_refptr<QueryResult> result = BeginElapsedTimeQuery();
......
......@@ -16,6 +16,9 @@ using ::testing::AtMost;
using ::testing::Exactly;
using ::testing::Invoke;
using ::testing::NotNull;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
int64_t GPUTimingFake::fake_cpu_time_ = 0;
......@@ -75,11 +78,13 @@ void GPUTimingFake::ExpectNoDisjointCalls(MockGLInterface& gl) {
EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0));
}
void GPUTimingFake::ExpectGPUTimeStampQuery(
MockGLInterface& gl, bool elapsed_query) {
void GPUTimingFake::ExpectGPUTimeStampQuery(MockGLInterface& gl,
bool elapsed_query) {
EXPECT_CALL(gl, GenQueries(1, NotNull())).Times(Exactly(1))
.WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries));
EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull()))
.WillRepeatedly(DoAll(SetArgPointee<2>(64), Return()));
if (!elapsed_query) {
// Time Stamp based queries.
EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _))
......@@ -121,6 +126,9 @@ void GPUTimingFake::ExpectGPUTimerQuery(
if (!elapsed_query) {
// Time Stamp based queries.
EXPECT_CALL(gl, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull()))
.WillRepeatedly(DoAll(SetArgPointee<2>(64), Return()));
EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _))
.WillRepeatedly(
Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
......
......@@ -17,6 +17,12 @@
namespace gfx {
using ::testing::Exactly;
using ::testing::NotNull;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
class GPUTimingTest : public testing::Test {
public:
void SetUp() override {
......@@ -163,4 +169,41 @@ TEST_F(GPUTimingTest, QueryTimeStampUsingElapsedTest) {
EXPECT_EQ(begin_cpu_time, end);
}
TEST_F(GPUTimingTest, QueryTimestampUsingElapsedARBTest) {
// Test timestamp queries on platforms with GL_ARB_timer_query but still lack
// support for timestamp queries
SetupGLContext("3.2", "GL_ARB_timer_query");
scoped_refptr<GPUTimingClient> client = CreateGPUTimingClient();
scoped_ptr<GPUTimer> gpu_timer = client->CreateGPUTimer(false);
const int64_t begin_cpu_time = 123;
const int64_t begin_gl_time = 10 * base::Time::kNanosecondsPerMicrosecond;
const int64_t cpu_gl_offset = begin_gl_time - begin_cpu_time;
gpu_timing_fake_queries_.SetCPUGLOffset(cpu_gl_offset);
gpu_timing_fake_queries_.SetCurrentCPUTime(begin_cpu_time);
gpu_timing_fake_queries_.ExpectGPUTimeStampQuery(*gl_, true);
// Custom mock override to ensure the timestamp bits are 0
EXPECT_CALL(*gl_, GetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, NotNull()))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<2>(0), Return()));
gpu_timer->QueryTimeStamp();
gpu_timing_fake_queries_.SetCurrentCPUTime(begin_cpu_time - 1);
EXPECT_FALSE(gpu_timer->IsAvailable());
gpu_timing_fake_queries_.SetCurrentCPUTime(begin_cpu_time + 1);
EXPECT_TRUE(gpu_timer->IsAvailable());
EXPECT_EQ(0, gpu_timer->GetDeltaElapsed());
int64_t start, end;
gpu_timer->GetStartEndTimestamps(&start, &end);
// Force time elapsed won't be set until a query is actually attempted
ASSERT_TRUE(client->IsForceTimeElapsedQuery());
EXPECT_EQ(begin_cpu_time, start);
EXPECT_EQ(begin_cpu_time, end);
}
} // namespace gpu
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment