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