| 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 |