OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/command_buffer/service/query_manager.h" | 5 #include "gpu/command_buffer/service/query_manager.h" |
6 #include "base/atomicops.h" | 6 #include "base/atomicops.h" |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/time.h" |
8 #include "gpu/command_buffer/common/gles2_cmd_format.h" | 9 #include "gpu/command_buffer/common/gles2_cmd_format.h" |
9 #include "gpu/command_buffer/service/common_decoder.h" | 10 #include "gpu/command_buffer/service/common_decoder.h" |
10 | 11 |
11 namespace gpu { | 12 namespace gpu { |
12 namespace gles2 { | 13 namespace gles2 { |
13 | 14 |
14 QueryManager::QueryManager() | 15 class AllSamplesPassedQuery : public QueryManager::Query { |
15 : query_count_(0) { | 16 public: |
| 17 AllSamplesPassedQuery( |
| 18 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, |
| 19 GLuint service_id); |
| 20 virtual ~AllSamplesPassedQuery(); |
| 21 virtual bool Begin() OVERRIDE; |
| 22 virtual bool End(uint32 submit_count) OVERRIDE; |
| 23 virtual bool Process() OVERRIDE; |
| 24 virtual void Destroy(bool have_context) OVERRIDE; |
| 25 |
| 26 private: |
| 27 // Service side query id. |
| 28 GLuint service_id_; |
| 29 }; |
| 30 |
| 31 AllSamplesPassedQuery::AllSamplesPassedQuery( |
| 32 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, |
| 33 GLuint service_id) |
| 34 : Query(manager, target, shm_id, shm_offset), |
| 35 service_id_(service_id) { |
| 36 } |
| 37 |
| 38 AllSamplesPassedQuery::~AllSamplesPassedQuery() { |
| 39 } |
| 40 |
| 41 void AllSamplesPassedQuery::Destroy(bool have_context) { |
| 42 if (have_context && !IsDeleted()) { |
| 43 glDeleteQueriesARB(1, &service_id_); |
| 44 MarkAsDeleted(); |
| 45 } |
| 46 } |
| 47 |
| 48 bool AllSamplesPassedQuery::Begin() { |
| 49 BeginQueryHelper(target(), service_id_); |
| 50 return true; |
| 51 } |
| 52 |
| 53 bool AllSamplesPassedQuery::End(uint32 submit_count) { |
| 54 EndQueryHelper(target()); |
| 55 return AddToPendingQueue(submit_count); |
| 56 } |
| 57 |
| 58 bool AllSamplesPassedQuery::Process() { |
| 59 GLuint available = 0; |
| 60 glGetQueryObjectuivARB( |
| 61 service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); |
| 62 if (!available) { |
| 63 return true; |
| 64 } |
| 65 GLuint result = 0; |
| 66 glGetQueryObjectuivARB( |
| 67 service_id_, GL_QUERY_RESULT_EXT, &result); |
| 68 |
| 69 return MarkAsCompleted(result); |
| 70 } |
| 71 |
| 72 class CommandsIssuedQuery : public QueryManager::Query { |
| 73 public: |
| 74 CommandsIssuedQuery( |
| 75 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset); |
| 76 virtual ~CommandsIssuedQuery(); |
| 77 |
| 78 virtual bool Begin() OVERRIDE; |
| 79 virtual bool End(uint32 submit_count) OVERRIDE; |
| 80 virtual bool Process() OVERRIDE; |
| 81 virtual void Destroy(bool have_context) OVERRIDE; |
| 82 |
| 83 private: |
| 84 base::TimeTicks begin_time_; |
| 85 }; |
| 86 |
| 87 CommandsIssuedQuery::CommandsIssuedQuery( |
| 88 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) |
| 89 : Query(manager, target, shm_id, shm_offset) { |
| 90 } |
| 91 |
| 92 CommandsIssuedQuery::~CommandsIssuedQuery() { |
| 93 } |
| 94 |
| 95 bool CommandsIssuedQuery::Process() { |
| 96 NOTREACHED(); |
| 97 return true; |
| 98 } |
| 99 |
| 100 bool CommandsIssuedQuery::Begin() { |
| 101 begin_time_ = base::TimeTicks::HighResNow(); |
| 102 return true; |
| 103 } |
| 104 |
| 105 bool CommandsIssuedQuery::End(uint32 submit_count) { |
| 106 base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_; |
| 107 MarkAsPending(submit_count); |
| 108 return MarkAsCompleted( |
| 109 std::min(elapsed.InMicroseconds(), static_cast<int64>(0xFFFFFFFFL))); |
| 110 } |
| 111 |
| 112 void CommandsIssuedQuery::Destroy(bool /* have_context */) { |
| 113 if (!IsDeleted()) { |
| 114 MarkAsDeleted(); |
| 115 } |
| 116 } |
| 117 |
| 118 QueryManager::QueryManager( |
| 119 CommonDecoder* decoder, |
| 120 bool use_arb_occlusion_query2_for_occlusion_query_boolean) |
| 121 : decoder_(decoder), |
| 122 use_arb_occlusion_query2_for_occlusion_query_boolean_( |
| 123 use_arb_occlusion_query2_for_occlusion_query_boolean), |
| 124 query_count_(0) { |
16 } | 125 } |
17 | 126 |
18 QueryManager::~QueryManager() { | 127 QueryManager::~QueryManager() { |
19 DCHECK(queries_.empty()); | 128 DCHECK(queries_.empty()); |
20 | 129 |
21 // If this triggers, that means something is keeping a reference to | 130 // If this triggers, that means something is keeping a reference to |
22 // a Query belonging to this. | 131 // a Query belonging to this. |
23 CHECK_EQ(query_count_, 0u); | 132 CHECK_EQ(query_count_, 0u); |
24 } | 133 } |
25 | 134 |
26 void QueryManager::Destroy(bool have_context) { | 135 void QueryManager::Destroy(bool have_context) { |
27 pending_queries_.clear(); | 136 pending_queries_.clear(); |
28 while (!queries_.empty()) { | 137 while (!queries_.empty()) { |
29 Query* query = queries_.begin()->second; | 138 Query* query = queries_.begin()->second; |
30 if (have_context) { | 139 query->Destroy(have_context); |
31 if (!query->IsDeleted()) { | |
32 GLuint service_id = query->service_id(); | |
33 glDeleteQueriesARB(1, &service_id); | |
34 query->MarkAsDeleted(); | |
35 } | |
36 } | |
37 queries_.erase(queries_.begin()); | 140 queries_.erase(queries_.begin()); |
38 } | 141 } |
39 } | 142 } |
40 | 143 |
41 QueryManager::Query* QueryManager::CreateQuery( | 144 QueryManager::Query* QueryManager::CreateQuery( |
42 GLuint client_id, | 145 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) { |
43 GLuint service_id) { | 146 Query::Ref query; |
44 Query::Ref query(new Query(this, service_id)); | 147 switch (target) { |
| 148 case GL_COMMANDS_ISSUED_CHROMIUM: |
| 149 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset); |
| 150 break; |
| 151 default: { |
| 152 GLuint service_id = 0; |
| 153 glGenQueriesARB(1, &service_id); |
| 154 DCHECK_NE(0u, service_id); |
| 155 query = new AllSamplesPassedQuery( |
| 156 this, target, shm_id, shm_offset, service_id); |
| 157 break; |
| 158 } |
| 159 } |
45 std::pair<QueryMap::iterator, bool> result = | 160 std::pair<QueryMap::iterator, bool> result = |
46 queries_.insert(std::make_pair(client_id, query)); | 161 queries_.insert(std::make_pair(client_id, query)); |
47 DCHECK(result.second); | 162 DCHECK(result.second); |
48 return query.get(); | 163 return query.get(); |
49 } | 164 } |
50 | 165 |
51 QueryManager::Query* QueryManager::GetQuery( | 166 QueryManager::Query* QueryManager::GetQuery( |
52 GLuint client_id) { | 167 GLuint client_id) { |
53 QueryMap::iterator it = queries_.find(client_id); | 168 QueryMap::iterator it = queries_.find(client_id); |
54 return it != queries_.end() ? it->second : NULL; | 169 return it != queries_.end() ? it->second : NULL; |
(...skipping 10 matching lines...) Expand all Loading... |
65 } | 180 } |
66 | 181 |
67 void QueryManager::StartTracking(QueryManager::Query* /* query */) { | 182 void QueryManager::StartTracking(QueryManager::Query* /* query */) { |
68 ++query_count_; | 183 ++query_count_; |
69 } | 184 } |
70 | 185 |
71 void QueryManager::StopTracking(QueryManager::Query* /* query */) { | 186 void QueryManager::StopTracking(QueryManager::Query* /* query */) { |
72 --query_count_; | 187 --query_count_; |
73 } | 188 } |
74 | 189 |
| 190 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) { |
| 191 // ARB_occlusion_query2 does not have a GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT |
| 192 // target. |
| 193 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) { |
| 194 target = GL_ANY_SAMPLES_PASSED_EXT; |
| 195 } |
| 196 glBeginQueryARB(target, id); |
| 197 } |
| 198 |
| 199 void QueryManager::EndQueryHelper(GLenum target) { |
| 200 // ARB_occlusion_query2 does not have a GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT |
| 201 // target. |
| 202 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) { |
| 203 target = GL_ANY_SAMPLES_PASSED_EXT; |
| 204 } |
| 205 glEndQueryARB(target); |
| 206 } |
| 207 |
75 QueryManager::Query::Query( | 208 QueryManager::Query::Query( |
76 QueryManager* manager, | 209 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) |
77 GLuint service_id) | |
78 : manager_(manager), | 210 : manager_(manager), |
79 service_id_(service_id), | 211 target_(target), |
80 target_(0), | 212 shm_id_(shm_id), |
81 shm_id_(0), | 213 shm_offset_(shm_offset), |
82 shm_offset_(0), | |
83 submit_count_(0), | 214 submit_count_(0), |
84 pending_(false) { | 215 pending_(false), |
| 216 deleted_(false) { |
85 DCHECK(manager); | 217 DCHECK(manager); |
86 manager_->StartTracking(this); | 218 manager_->StartTracking(this); |
87 } | 219 } |
88 | 220 |
89 QueryManager::Query::~Query() { | 221 QueryManager::Query::~Query() { |
90 if (manager_) { | 222 if (manager_) { |
91 manager_->StopTracking(this); | 223 manager_->StopTracking(this); |
92 manager_ = NULL; | 224 manager_ = NULL; |
93 } | 225 } |
94 } | 226 } |
95 | 227 |
96 void QueryManager::Query::Initialize( | 228 bool QueryManager::Query::MarkAsCompleted(GLuint result) { |
97 GLenum target, int32 shm_id, uint32 shm_offset) { | 229 DCHECK(pending_); |
98 DCHECK(!IsInitialized()); | 230 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>( |
99 target_ = target; | 231 shm_id_, shm_offset_, sizeof(*sync)); |
100 shm_id_ = shm_id; | 232 if (!sync) { |
101 shm_offset_ = shm_offset; | 233 return false; |
| 234 } |
| 235 |
| 236 pending_ = false; |
| 237 sync->result = result; |
| 238 // Need a MemoryBarrier here so that sync->result is written before |
| 239 // sync->process_count. |
| 240 base::subtle::MemoryBarrier(); |
| 241 sync->process_count = submit_count_; |
| 242 |
| 243 return true; |
102 } | 244 } |
103 | 245 |
104 bool QueryManager::GetClientId(GLuint service_id, GLuint* client_id) const { | 246 bool QueryManager::ProcessPendingQueries() { |
105 DCHECK(client_id); | 247 while (!pending_queries_.empty()) { |
106 // This doesn't need to be fast. It's only used during slow queries. | 248 Query* query = pending_queries_.front().get(); |
107 for (QueryMap::const_iterator it = queries_.begin(); | 249 if (!query->Process()) { |
108 it != queries_.end(); ++it) { | 250 return false; |
109 if (it->second->service_id() == service_id) { | 251 } |
110 *client_id = it->first; | 252 if (query->pending()) { |
111 return true; | 253 return true; |
112 } | 254 } |
113 } | |
114 return false; | |
115 } | |
116 | |
117 bool QueryManager::ProcessPendingQueries(CommonDecoder* decoder) { | |
118 DCHECK(decoder); | |
119 while (!pending_queries_.empty()) { | |
120 Query* query = pending_queries_.front().get(); | |
121 GLuint available = 0; | |
122 glGetQueryObjectuivARB( | |
123 query->service_id(), GL_QUERY_RESULT_AVAILABLE_EXT, &available); | |
124 if (!available) { | |
125 return true; | |
126 } | |
127 GLuint result = 0; | |
128 glGetQueryObjectuivARB( | |
129 query->service_id(), GL_QUERY_RESULT_EXT, &result); | |
130 QuerySync* sync = decoder->GetSharedMemoryAs<QuerySync*>( | |
131 query->shm_id(), query->shm_offset(), sizeof(*sync)); | |
132 if (!sync) { | |
133 return false; | |
134 } | |
135 | |
136 sync->result = result; | |
137 // Need a MemoryBarrier here so that sync->result is written before | |
138 // sync->process_count. | |
139 base::subtle::MemoryBarrier(); | |
140 sync->process_count = query->submit_count(); | |
141 | |
142 query->MarkAsCompleted(); | |
143 pending_queries_.pop_front(); | 255 pending_queries_.pop_front(); |
144 } | 256 } |
145 | 257 |
146 return true; | 258 return true; |
147 } | 259 } |
148 | 260 |
149 bool QueryManager::HavePendingQueries() { | 261 bool QueryManager::HavePendingQueries() { |
150 return !pending_queries_.empty(); | 262 return !pending_queries_.empty(); |
151 } | 263 } |
152 | 264 |
153 void QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { | 265 bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { |
154 DCHECK(query); | 266 DCHECK(query); |
155 DCHECK(query->IsInitialized()); | |
156 DCHECK(!query->IsDeleted()); | 267 DCHECK(!query->IsDeleted()); |
157 RemovePendingQuery(query); | 268 if (!RemovePendingQuery(query)) { |
| 269 return false; |
| 270 } |
158 query->MarkAsPending(submit_count); | 271 query->MarkAsPending(submit_count); |
159 pending_queries_.push_back(query); | 272 pending_queries_.push_back(query); |
| 273 return true; |
160 } | 274 } |
161 | 275 |
162 void QueryManager::RemovePendingQuery(Query* query) { | 276 bool QueryManager::RemovePendingQuery(Query* query) { |
163 DCHECK(query); | 277 DCHECK(query); |
164 if (query->pending()) { | 278 if (query->pending()) { |
165 // TODO(gman): Speed this up if this is a common operation. This would only | 279 // TODO(gman): Speed this up if this is a common operation. This would only |
166 // happen if you do being/end begin/end on the same query without waiting | 280 // happen if you do being/end begin/end on the same query without waiting |
167 // for the first one to finish. | 281 // for the first one to finish. |
168 for (QueryQueue::iterator it = pending_queries_.begin(); | 282 for (QueryQueue::iterator it = pending_queries_.begin(); |
169 it != pending_queries_.end(); ++it) { | 283 it != pending_queries_.end(); ++it) { |
170 if (it->get() == query) { | 284 if (it->get() == query) { |
171 pending_queries_.erase(it); | 285 pending_queries_.erase(it); |
172 break; | 286 break; |
173 } | 287 } |
174 } | 288 } |
175 query->MarkAsCompleted(); | 289 if (!query->MarkAsCompleted(0)) { |
| 290 return false; |
| 291 } |
176 } | 292 } |
| 293 return true; |
| 294 } |
| 295 |
| 296 bool QueryManager::BeginQuery(Query* query) { |
| 297 DCHECK(query); |
| 298 if (!RemovePendingQuery(query)) { |
| 299 return false; |
| 300 } |
| 301 return query->Begin(); |
| 302 } |
| 303 |
| 304 bool QueryManager::EndQuery(Query* query, uint32 submit_count) { |
| 305 DCHECK(query); |
| 306 if (!RemovePendingQuery(query)) { |
| 307 return false; |
| 308 } |
| 309 return query->End(submit_count); |
177 } | 310 } |
178 | 311 |
179 } // namespace gles2 | 312 } // namespace gles2 |
180 } // namespace gpu | 313 } // namespace gpu |
181 | 314 |
182 | 315 |
OLD | NEW |