0

gpu: Fix removal of pending queries.

This moves all queries to a "removed queries" list at removal
time. The memory used by the queries is not freed until the
query has completed.

BUG=253488
TEST=gpu_unittests --gtest_filter=QueryTrackerTest.Remove
NOTRY=true

Review URL: https://chromiumcodereview.appspot.com/18340003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209977 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
reveman@chromium.org
2013-07-03 14:24:41 +00:00
parent 526de35d10
commit 1414635fba
4 changed files with 79 additions and 36 deletions

@ -3174,36 +3174,10 @@ void GLES2Implementation::DeleteQueriesEXTHelper(
"glDeleteTextures", "id not created by this context.");
return;
}
// When you delete a query you can't mark its memory as unused until it's
// completed.
// Note: If you don't do this you won't mess up the service but you will mess
// up yourself.
// TODO(gman): Consider making this faster by putting pending quereies
// on some queue to be removed when they are finished.
bool query_pending = false;
for (GLsizei ii = 0; ii < n; ++ii) {
QueryTracker::Query* query = query_tracker_->GetQuery(queries[ii]);
if (query && query->Pending()) {
query_pending = true;
break;
}
}
for (GLsizei ii = 0; ii < n; ++ii)
query_tracker_->RemoveQuery(queries[ii]);
if (query_pending) {
WaitForCmd();
}
for (GLsizei ii = 0; ii < n; ++ii) {
QueryTracker::Query* query = query_tracker_->GetQuery(queries[ii]);
if (query && query->Pending()) {
if (!query->CheckResultsAvailable(helper_)) {
// Should only get here on context lost.
MustBeContextLost();
}
}
query_tracker_->RemoveQuery(queries[ii], helper_->IsContextLost());
}
helper_->DeleteQueriesEXTImmediate(n, queries);
}

@ -199,11 +199,19 @@ QueryTracker::QueryTracker(MappedMemoryManager* manager)
}
QueryTracker::~QueryTracker() {
queries_.clear();
while (!queries_.empty()) {
delete queries_.begin()->second;
queries_.erase(queries_.begin());
}
while (!removed_queries_.empty()) {
delete removed_queries_.front();
removed_queries_.pop_front();
}
}
QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
GPU_DCHECK_NE(0u, id);
FreeCompletedQueries();
QuerySyncManager::QueryInfo info;
if (!query_sync_manager_.Alloc(&info)) {
return NULL;
@ -221,21 +229,40 @@ QueryTracker::Query* QueryTracker::GetQuery(
return it != queries_.end() ? it->second : NULL;
}
void QueryTracker::RemoveQuery(GLuint client_id, bool context_lost) {
(void)context_lost; // stop unused warning
void QueryTracker::RemoveQuery(GLuint client_id) {
QueryMap::iterator it = queries_.find(client_id);
if (it != queries_.end()) {
Query* query = it->second;
GPU_DCHECK(context_lost || !query->Pending());
query_sync_manager_.Free(query->info_);
// When you delete a query you can't mark its memory as unused until it's
// completed.
// Note: If you don't do this you won't mess up the service but you will
// mess up yourself.
removed_queries_.push_back(query);
queries_.erase(it);
delete query;
FreeCompletedQueries();
}
}
void QueryTracker::Shrink() {
FreeCompletedQueries();
query_sync_manager_.Shrink();
}
void QueryTracker::FreeCompletedQueries() {
QueryList::iterator it = removed_queries_.begin();
while (it != removed_queries_.end()) {
Query* query = *it;
if (query->Pending() &&
query->info_.sync->process_count != query->submit_count()) {
++it;
continue;
}
query_sync_manager_.Free(query->info_);
it = removed_queries_.erase(it);
delete query;
}
}
} // namespace gles2
} // namespace gpu

@ -8,6 +8,8 @@
#include <GLES2/gl2.h>
#include <deque>
#include <list>
#include "gles2_impl_export.h"
#include "gpu/command_buffer/client/hash_tables.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
@ -154,13 +156,16 @@ class GLES2_IMPL_EXPORT QueryTracker {
Query* CreateQuery(GLuint id, GLenum target);
Query* GetQuery(GLuint id);
void RemoveQuery(GLuint id, bool context_lost);
void RemoveQuery(GLuint id);
void Shrink();
void FreeCompletedQueries();
private:
typedef gpu::hash_map<GLuint, Query*> QueryMap;
typedef std::list<Query*> QueryList;
QueryMap queries_;
QueryList removed_queries_;
QuerySyncManager query_sync_manager_;
DISALLOW_COPY_AND_ASSIGN(QueryTracker);

@ -96,6 +96,10 @@ class QueryTrackerTest : public testing::Test {
return query->info_.sync;
}
QuerySyncManager::Bucket* GetBucket(QueryTracker::Query* query) {
return query->info_.bucket;
}
scoped_ptr<CommandBuffer> command_buffer_;
scoped_ptr<GLES2CmdHelper> helper_;
scoped_ptr<MappedMemoryManager> mapped_memory_;
@ -115,7 +119,7 @@ TEST_F(QueryTrackerTest, Basic) {
// Check we get nothing for a non-existent query.
EXPECT_TRUE(query_tracker_->GetQuery(kId2) == NULL);
// Check we can delete the query.
query_tracker_->RemoveQuery(kId1, false);
query_tracker_->RemoveQuery(kId1);
// Check we get nothing for a non-existent query.
EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
}
@ -165,6 +169,39 @@ TEST_F(QueryTrackerTest, Query) {
EXPECT_FALSE(query->Pending());
}
TEST_F(QueryTrackerTest, Remove) {
const GLuint kId1 = 123;
const int32 kToken = 46;
const uint32 kResult = 456;
// Create a Query.
QueryTracker::Query* query = query_tracker_->CreateQuery(
kId1, GL_ANY_SAMPLES_PASSED_EXT);
ASSERT_TRUE(query != NULL);
QuerySyncManager::Bucket* bucket = GetBucket(query);
EXPECT_EQ(1u, bucket->used_query_count);
query->MarkAsActive();
query->MarkAsPending(kToken);
query_tracker_->RemoveQuery(kId1);
// Check we get nothing for a non-existent query.
EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
// Check that memory was not freed.
EXPECT_EQ(1u, bucket->used_query_count);
// Simulate GPU process marking it as available.
QuerySync* sync = GetSync(query);
sync->process_count = query->submit_count();
sync->result = kResult;
// Check FreeCompletedQueries.
query_tracker_->FreeCompletedQueries();
EXPECT_EQ(0u, bucket->used_query_count);
}
} // namespace gles2
} // namespace gpu