Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / client / query_tracker.cc
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.
4
5 #include "gpu/command_buffer/client/query_tracker.h"
6
7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h>
10
11 #include "base/atomicops.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
14 #include "gpu/command_buffer/client/gles2_implementation.h"
15 #include "gpu/command_buffer/client/mapped_memory.h"
16 #include "gpu/command_buffer/common/time.h"
17
18 namespace gpu {
19 namespace gles2 {
20
21 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
22     : mapped_memory_(manager) {
23   DCHECK(manager);
24 }
25
26 QuerySyncManager::~QuerySyncManager() {
27   while (!buckets_.empty()) {
28     mapped_memory_->Free(buckets_.front()->syncs);
29     delete buckets_.front();
30     buckets_.pop_front();
31   }
32 }
33
34 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
35   DCHECK(info);
36   if (free_queries_.empty()) {
37     int32 shm_id;
38     unsigned int shm_offset;
39     void* mem = mapped_memory_->Alloc(
40         kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
41     if (!mem) {
42       return false;
43     }
44     QuerySync* syncs = static_cast<QuerySync*>(mem);
45     Bucket* bucket = new Bucket(syncs);
46     buckets_.push_back(bucket);
47     for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
48       free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
49       ++syncs;
50       shm_offset += sizeof(*syncs);
51     }
52   }
53   *info = free_queries_.front();
54   ++(info->bucket->used_query_count);
55   info->sync->Reset();
56   free_queries_.pop_front();
57   return true;
58 }
59
60 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
61   DCHECK_GT(info.bucket->used_query_count, 0u);
62   --(info.bucket->used_query_count);
63   free_queries_.push_back(info);
64 }
65
66 void QuerySyncManager::Shrink() {
67   std::deque<QueryInfo> new_queue;
68   while (!free_queries_.empty()) {
69     if (free_queries_.front().bucket->used_query_count)
70       new_queue.push_back(free_queries_.front());
71     free_queries_.pop_front();
72   }
73   free_queries_.swap(new_queue);
74
75   std::deque<Bucket*> new_buckets;
76   while (!buckets_.empty()) {
77     Bucket* bucket = buckets_.front();
78     if (bucket->used_query_count) {
79       new_buckets.push_back(bucket);
80     } else {
81       mapped_memory_->Free(bucket->syncs);
82       delete bucket;
83     }
84     buckets_.pop_front();
85   }
86   buckets_.swap(new_buckets);
87 }
88
89 QueryTracker::Query::Query(GLuint id, GLenum target,
90                            const QuerySyncManager::QueryInfo& info)
91     : id_(id),
92       target_(target),
93       info_(info),
94       state_(kUninitialized),
95       submit_count_(0),
96       token_(0),
97       flush_count_(0),
98       client_begin_time_us_(0),
99       result_(0) {
100     }
101
102
103 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
104   // init memory, inc count
105   MarkAsActive();
106
107   switch (target()) {
108     case GL_GET_ERROR_QUERY_CHROMIUM:
109       // To nothing on begin for error queries.
110       break;
111     case GL_LATENCY_QUERY_CHROMIUM:
112       client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
113       // tell service about id, shared memory and count
114       gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
115       break;
116     case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
117     case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
118     default:
119       // tell service about id, shared memory and count
120       gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
121       break;
122   }
123 }
124
125 void QueryTracker::Query::End(GLES2Implementation* gl) {
126   switch (target()) {
127     case GL_GET_ERROR_QUERY_CHROMIUM: {
128       GLenum error = gl->GetClientSideGLError();
129       if (error == GL_NO_ERROR) {
130         // There was no error so start the query on the service.
131         // it will end immediately.
132         gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
133       } else {
134         // There's an error on the client, no need to bother the service. Just
135         // set the query as completed and return the error.
136         if (error != GL_NO_ERROR) {
137           state_ = kComplete;
138           result_ = error;
139           return;
140         }
141       }
142     }
143   }
144   flush_count_ = gl->helper()->flush_generation();
145   gl->helper()->EndQueryEXT(target(), submit_count());
146   MarkAsPending(gl->helper()->InsertToken());
147 }
148
149 bool QueryTracker::Query::CheckResultsAvailable(
150     CommandBufferHelper* helper) {
151   if (Pending()) {
152     if (base::subtle::Acquire_Load(&info_.sync->process_count) ==
153             submit_count_ ||
154         helper->IsContextLost()) {
155       switch (target()) {
156         case GL_COMMANDS_ISSUED_CHROMIUM:
157           result_ = base::saturated_cast<uint32>(info_.sync->result);
158           break;
159         case GL_LATENCY_QUERY_CHROMIUM:
160           // Disabled DCHECK because of http://crbug.com/419236.
161           //DCHECK(info_.sync->result >= client_begin_time_us_);
162           result_ = base::saturated_cast<uint32>(
163               info_.sync->result - client_begin_time_us_);
164           break;
165         case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
166         case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
167         default:
168           result_ = static_cast<uint32>(info_.sync->result);
169           break;
170       }
171       state_ = kComplete;
172     } else {
173       if ((helper->flush_generation() - flush_count_ - 1) >= 0x80000000) {
174         helper->Flush();
175       } else {
176         // Insert no-ops so that eventually the GPU process will see more work.
177         helper->Noop(1);
178       }
179     }
180   }
181   return state_ == kComplete;
182 }
183
184 uint32 QueryTracker::Query::GetResult() const {
185   DCHECK(state_ == kComplete || state_ == kUninitialized);
186   return result_;
187 }
188
189 QueryTracker::QueryTracker(MappedMemoryManager* manager)
190     : query_sync_manager_(manager) {
191 }
192
193 QueryTracker::~QueryTracker() {
194   while (!queries_.empty()) {
195     delete queries_.begin()->second;
196     queries_.erase(queries_.begin());
197   }
198   while (!removed_queries_.empty()) {
199     delete removed_queries_.front();
200     removed_queries_.pop_front();
201   }
202 }
203
204 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
205   DCHECK_NE(0u, id);
206   FreeCompletedQueries();
207   QuerySyncManager::QueryInfo info;
208   if (!query_sync_manager_.Alloc(&info)) {
209     return NULL;
210   }
211   Query* query = new Query(id, target, info);
212   std::pair<QueryMap::iterator, bool> result =
213       queries_.insert(std::make_pair(id, query));
214   DCHECK(result.second);
215   return query;
216 }
217
218 QueryTracker::Query* QueryTracker::GetQuery(
219     GLuint client_id) {
220   QueryMap::iterator it = queries_.find(client_id);
221   return it != queries_.end() ? it->second : NULL;
222 }
223
224 void QueryTracker::RemoveQuery(GLuint client_id) {
225   QueryMap::iterator it = queries_.find(client_id);
226   if (it != queries_.end()) {
227     Query* query = it->second;
228     // When you delete a query you can't mark its memory as unused until it's
229     // completed.
230     // Note: If you don't do this you won't mess up the service but you will
231     // mess up yourself.
232     removed_queries_.push_back(query);
233     queries_.erase(it);
234     FreeCompletedQueries();
235   }
236 }
237
238 void QueryTracker::Shrink() {
239   FreeCompletedQueries();
240   query_sync_manager_.Shrink();
241 }
242
243 void QueryTracker::FreeCompletedQueries() {
244   QueryList::iterator it = removed_queries_.begin();
245   while (it != removed_queries_.end()) {
246     Query* query = *it;
247     if (query->Pending() &&
248         base::subtle::Acquire_Load(&query->info_.sync->process_count) !=
249             query->submit_count()) {
250       ++it;
251       continue;
252     }
253
254     query_sync_manager_.Free(query->info_);
255     it = removed_queries_.erase(it);
256     delete query;
257   }
258 }
259
260 }  // namespace gles2
261 }  // namespace gpu