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
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/client/query_tracker.h"
8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h>
11 #include "base/atomicops.h"
12 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
13 #include "gpu/command_buffer/client/gles2_implementation.h"
14 #include "gpu/command_buffer/client/mapped_memory.h"
15 #include "gpu/command_buffer/common/time.h"
20 QuerySyncManager::QuerySyncManager(MappedMemoryManager
* manager
)
21 : mapped_memory_(manager
) {
25 QuerySyncManager::~QuerySyncManager() {
26 while (!buckets_
.empty()) {
27 mapped_memory_
->Free(buckets_
.front()->syncs
);
28 delete buckets_
.front();
33 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo
* info
) {
35 if (free_queries_
.empty()) {
37 unsigned int shm_offset
;
38 void* mem
= mapped_memory_
->Alloc(
39 kSyncsPerBucket
* sizeof(QuerySync
), &shm_id
, &shm_offset
);
43 QuerySync
* syncs
= static_cast<QuerySync
*>(mem
);
44 Bucket
* bucket
= new Bucket(syncs
);
45 buckets_
.push_back(bucket
);
46 for (size_t ii
= 0; ii
< kSyncsPerBucket
; ++ii
) {
47 free_queries_
.push_back(QueryInfo(bucket
, shm_id
, shm_offset
, syncs
));
49 shm_offset
+= sizeof(*syncs
);
52 *info
= free_queries_
.front();
53 ++(info
->bucket
->used_query_count
);
55 free_queries_
.pop_front();
59 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo
& info
) {
60 DCHECK_GT(info
.bucket
->used_query_count
, 0u);
61 --(info
.bucket
->used_query_count
);
62 free_queries_
.push_back(info
);
65 void QuerySyncManager::Shrink() {
66 std::deque
<QueryInfo
> new_queue
;
67 while (!free_queries_
.empty()) {
68 if (free_queries_
.front().bucket
->used_query_count
)
69 new_queue
.push_back(free_queries_
.front());
70 free_queries_
.pop_front();
72 free_queries_
.swap(new_queue
);
74 std::deque
<Bucket
*> new_buckets
;
75 while (!buckets_
.empty()) {
76 Bucket
* bucket
= buckets_
.front();
77 if (bucket
->used_query_count
) {
78 new_buckets
.push_back(bucket
);
80 mapped_memory_
->Free(bucket
->syncs
);
85 buckets_
.swap(new_buckets
);
88 QueryTracker::Query::Query(GLuint id
, GLenum target
,
89 const QuerySyncManager::QueryInfo
& info
)
93 state_(kUninitialized
),
97 client_begin_time_us_(0),
102 void QueryTracker::Query::Begin(GLES2Implementation
* gl
) {
103 // init memory, inc count
107 case GL_GET_ERROR_QUERY_CHROMIUM
:
108 // To nothing on begin for error queries.
110 case GL_LATENCY_QUERY_CHROMIUM
:
111 client_begin_time_us_
= MicrosecondsSinceOriginOfTime();
112 // tell service about id, shared memory and count
113 gl
->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
115 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM
:
116 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
118 // tell service about id, shared memory and count
119 gl
->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
124 void QueryTracker::Query::End(GLES2Implementation
* gl
) {
126 case GL_GET_ERROR_QUERY_CHROMIUM
: {
127 GLenum error
= gl
->GetClientSideGLError();
128 if (error
== GL_NO_ERROR
) {
129 // There was no error so start the query on the service.
130 // it will end immediately.
131 gl
->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
133 // There's an error on the client, no need to bother the service. Just
134 // set the query as completed and return the error.
135 if (error
!= GL_NO_ERROR
) {
143 flush_count_
= gl
->helper()->flush_generation();
144 gl
->helper()->EndQueryEXT(target(), submit_count());
145 MarkAsPending(gl
->helper()->InsertToken());
148 bool QueryTracker::Query::CheckResultsAvailable(
149 CommandBufferHelper
* helper
) {
151 if (base::subtle::Acquire_Load(&info_
.sync
->process_count
) ==
153 helper
->IsContextLost()) {
155 case GL_COMMANDS_ISSUED_CHROMIUM
:
156 result_
= std::min(info_
.sync
->result
,
157 static_cast<uint64
>(0xFFFFFFFFL
));
159 case GL_LATENCY_QUERY_CHROMIUM
:
160 DCHECK(info_
.sync
->result
>= client_begin_time_us_
);
161 result_
= std::min(info_
.sync
->result
- client_begin_time_us_
,
162 static_cast<uint64
>(0xFFFFFFFFL
));
164 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM
:
165 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
167 result_
= info_
.sync
->result
;
172 if ((helper
->flush_generation() - flush_count_
- 1) >= 0x80000000) {
175 // Insert no-ops so that eventually the GPU process will see more work.
180 return state_
== kComplete
;
183 uint32
QueryTracker::Query::GetResult() const {
184 DCHECK(state_
== kComplete
|| state_
== kUninitialized
);
188 QueryTracker::QueryTracker(MappedMemoryManager
* manager
)
189 : query_sync_manager_(manager
) {
192 QueryTracker::~QueryTracker() {
193 while (!queries_
.empty()) {
194 delete queries_
.begin()->second
;
195 queries_
.erase(queries_
.begin());
197 while (!removed_queries_
.empty()) {
198 delete removed_queries_
.front();
199 removed_queries_
.pop_front();
203 QueryTracker::Query
* QueryTracker::CreateQuery(GLuint id
, GLenum target
) {
205 FreeCompletedQueries();
206 QuerySyncManager::QueryInfo info
;
207 if (!query_sync_manager_
.Alloc(&info
)) {
210 Query
* query
= new Query(id
, target
, info
);
211 std::pair
<QueryMap::iterator
, bool> result
=
212 queries_
.insert(std::make_pair(id
, query
));
213 DCHECK(result
.second
);
217 QueryTracker::Query
* QueryTracker::GetQuery(
219 QueryMap::iterator it
= queries_
.find(client_id
);
220 return it
!= queries_
.end() ? it
->second
: NULL
;
223 void QueryTracker::RemoveQuery(GLuint client_id
) {
224 QueryMap::iterator it
= queries_
.find(client_id
);
225 if (it
!= queries_
.end()) {
226 Query
* query
= it
->second
;
227 // When you delete a query you can't mark its memory as unused until it's
229 // Note: If you don't do this you won't mess up the service but you will
231 removed_queries_
.push_back(query
);
233 FreeCompletedQueries();
237 void QueryTracker::Shrink() {
238 FreeCompletedQueries();
239 query_sync_manager_
.Shrink();
242 void QueryTracker::FreeCompletedQueries() {
243 QueryList::iterator it
= removed_queries_
.begin();
244 while (it
!= removed_queries_
.end()) {
246 if (query
->Pending() &&
247 base::subtle::Acquire_Load(&query
->info_
.sync
->process_count
) !=
248 query
->submit_count()) {
253 query_sync_manager_
.Free(query
->info_
);
254 it
= removed_queries_
.erase(it
);