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 |
6 #include "base/atomicops.h" | 7 #include "base/atomicops.h" |
7 #include "base/bind.h" | 8 #include "base/bind.h" |
8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/shared_memory.h" |
9 #include "base/time.h" | 11 #include "base/time.h" |
10 #include "gpu/command_buffer/common/gles2_cmd_format.h" | 12 #include "gpu/command_buffer/common/gles2_cmd_format.h" |
| 13 #include "gpu/command_buffer/service/feature_info.h" |
11 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
12 #include "gpu/command_buffer/service/feature_info.h" | |
13 #include "ui/gl/async_pixel_transfer_delegate.h" | 15 #include "ui/gl/async_pixel_transfer_delegate.h" |
14 | 16 |
15 namespace gpu { | 17 namespace gpu { |
16 namespace gles2 { | 18 namespace gles2 { |
17 | 19 |
18 class AllSamplesPassedQuery : public QueryManager::Query { | 20 class AllSamplesPassedQuery : public QueryManager::Query { |
19 public: | 21 public: |
20 AllSamplesPassedQuery( | 22 AllSamplesPassedQuery( |
21 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, | 23 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, |
22 GLuint service_id); | 24 GLuint service_id); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 , public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> { | 171 , public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> { |
170 public: | 172 public: |
171 AsyncPixelTransfersCompletedQuery( | 173 AsyncPixelTransfersCompletedQuery( |
172 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset); | 174 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset); |
173 | 175 |
174 virtual bool Begin() OVERRIDE; | 176 virtual bool Begin() OVERRIDE; |
175 virtual bool End(uint32 submit_count) OVERRIDE; | 177 virtual bool End(uint32 submit_count) OVERRIDE; |
176 virtual bool Process() OVERRIDE; | 178 virtual bool Process() OVERRIDE; |
177 virtual void Destroy(bool have_context) OVERRIDE; | 179 virtual void Destroy(bool have_context) OVERRIDE; |
178 | 180 |
179 void MarkAsCompletedCallback() { MarkAsCompleted(1); } | |
180 | |
181 protected: | 181 protected: |
182 virtual ~AsyncPixelTransfersCompletedQuery(); | 182 virtual ~AsyncPixelTransfersCompletedQuery(); |
| 183 |
| 184 static void MarkAsCompletedThreadSafe( |
| 185 uint32 submit_count, const gfx::AsyncMemoryParams& mem_params) { |
| 186 DCHECK(mem_params.shared_memory); |
| 187 DCHECK(mem_params.shared_memory->memory()); |
| 188 void *data = static_cast<int8*>(mem_params.shared_memory->memory()) + |
| 189 mem_params.shm_data_offset; |
| 190 QuerySync* sync = static_cast<QuerySync*>(data); |
| 191 |
| 192 // No need for a MemoryBarrier here as sync->result is not written. |
| 193 sync->process_count = submit_count; |
| 194 } |
183 }; | 195 }; |
184 | 196 |
185 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery( | 197 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery( |
186 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) | 198 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) |
187 : Query(manager, target, shm_id, shm_offset) { | 199 : Query(manager, target, shm_id, shm_offset) { |
188 } | 200 } |
189 | 201 |
190 bool AsyncPixelTransfersCompletedQuery::Begin() { | 202 bool AsyncPixelTransfersCompletedQuery::Begin() { |
191 return true; | 203 return true; |
192 } | 204 } |
193 | 205 |
194 bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) { | 206 bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) { |
195 MarkAsPending(submit_count); | 207 gfx::AsyncMemoryParams mem_params; |
| 208 // Get the real shared memory since it might need to be duped to prevent |
| 209 // use-after-free of the memory. |
| 210 Buffer buffer = manager()->decoder()->GetSharedMemoryBuffer(shm_id()); |
| 211 if (!buffer.shared_memory) |
| 212 return false; |
| 213 mem_params.shared_memory = buffer.shared_memory; |
| 214 mem_params.shm_size = buffer.size; |
| 215 mem_params.shm_data_offset = shm_offset(); |
| 216 mem_params.shm_data_size = sizeof(QuerySync); |
196 | 217 |
197 // This will call MarkAsCompleted(1) as a reply to a task on | 218 // Ask AsyncPixelTransferDelegate to run completion callback after all |
198 // the async upload thread, such that it occurs after all previous | 219 // previous async transfers are done. No guarantee that callback is run |
199 // async transfers have completed. | 220 // on the current thread. |
200 manager()->decoder()->GetAsyncPixelTransferDelegate()->AsyncNotifyCompletion( | 221 manager()->decoder()->GetAsyncPixelTransferDelegate()->AsyncNotifyCompletion( |
201 base::Bind( | 222 mem_params, |
202 &AsyncPixelTransfersCompletedQuery::MarkAsCompletedCallback, | 223 base::Bind(AsyncPixelTransfersCompletedQuery::MarkAsCompletedThreadSafe, |
203 AsWeakPtr())); | 224 submit_count)); |
204 | 225 |
205 // TODO(epenner): The async task occurs outside the normal | 226 return AddToPendingTransferQueue(submit_count); |
206 // flow, via a callback on this thread. Is there anything | 227 } |
207 // missing or wrong with that? | |
208 | 228 |
209 // TODO(epenner): Could we possibly trigger the completion on | 229 bool AsyncPixelTransfersCompletedQuery::Process() { |
210 // the upload thread by writing to the query shared memory | 230 QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>( |
211 // directly? | 231 shm_id(), shm_offset(), sizeof(*sync)); |
| 232 if (!sync) |
| 233 return false; |
| 234 |
| 235 // Check if completion callback has been run. sync->process_count atomicity |
| 236 // is guaranteed as this is already used to notify client of a completed |
| 237 // query. |
| 238 if (sync->process_count != submit_count()) |
| 239 return true; |
| 240 |
| 241 UnmarkAsPending(); |
212 return true; | 242 return true; |
213 } | 243 } |
214 | 244 |
215 bool AsyncPixelTransfersCompletedQuery::Process() { | |
216 NOTREACHED(); | |
217 return true; | |
218 } | |
219 | |
220 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) { | 245 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) { |
221 if (!IsDeleted()) { | 246 if (!IsDeleted()) { |
222 MarkAsDeleted(); | 247 MarkAsDeleted(); |
223 } | 248 } |
224 } | 249 } |
225 | 250 |
226 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() { | 251 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() { |
227 } | 252 } |
228 | 253 |
229 class GetErrorQuery : public QueryManager::Query { | 254 class GetErrorQuery : public QueryManager::Query { |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 return true; | 453 return true; |
429 } | 454 } |
430 | 455 |
431 bool QueryManager::ProcessPendingQueries() { | 456 bool QueryManager::ProcessPendingQueries() { |
432 while (!pending_queries_.empty()) { | 457 while (!pending_queries_.empty()) { |
433 Query* query = pending_queries_.front().get(); | 458 Query* query = pending_queries_.front().get(); |
434 if (!query->Process()) { | 459 if (!query->Process()) { |
435 return false; | 460 return false; |
436 } | 461 } |
437 if (query->pending()) { | 462 if (query->pending()) { |
438 return true; | 463 break; |
439 } | 464 } |
440 pending_queries_.pop_front(); | 465 pending_queries_.pop_front(); |
441 } | 466 } |
442 | 467 |
443 return true; | 468 return true; |
444 } | 469 } |
445 | 470 |
446 bool QueryManager::HavePendingQueries() { | 471 bool QueryManager::HavePendingQueries() { |
447 return !pending_queries_.empty(); | 472 return !pending_queries_.empty(); |
448 } | 473 } |
449 | 474 |
| 475 bool QueryManager::ProcessPendingTransferQueries() { |
| 476 while (!pending_transfer_queries_.empty()) { |
| 477 Query* query = pending_transfer_queries_.front().get(); |
| 478 if (!query->Process()) { |
| 479 return false; |
| 480 } |
| 481 if (query->pending()) { |
| 482 break; |
| 483 } |
| 484 pending_transfer_queries_.pop_front(); |
| 485 } |
| 486 |
| 487 return true; |
| 488 } |
| 489 |
| 490 bool QueryManager::HavePendingTransferQueries() { |
| 491 return !pending_transfer_queries_.empty(); |
| 492 } |
| 493 |
450 bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { | 494 bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { |
451 DCHECK(query); | 495 DCHECK(query); |
452 DCHECK(!query->IsDeleted()); | 496 DCHECK(!query->IsDeleted()); |
453 if (!RemovePendingQuery(query)) { | 497 if (!RemovePendingQuery(query)) { |
454 return false; | 498 return false; |
455 } | 499 } |
456 query->MarkAsPending(submit_count); | 500 query->MarkAsPending(submit_count); |
457 pending_queries_.push_back(query); | 501 pending_queries_.push_back(query); |
458 return true; | 502 return true; |
459 } | 503 } |
460 | 504 |
| 505 bool QueryManager::AddPendingTransferQuery(Query* query, uint32 submit_count) { |
| 506 DCHECK(query); |
| 507 DCHECK(!query->IsDeleted()); |
| 508 if (!RemovePendingQuery(query)) { |
| 509 return false; |
| 510 } |
| 511 query->MarkAsPending(submit_count); |
| 512 pending_transfer_queries_.push_back(query); |
| 513 return true; |
| 514 } |
| 515 |
461 bool QueryManager::RemovePendingQuery(Query* query) { | 516 bool QueryManager::RemovePendingQuery(Query* query) { |
462 DCHECK(query); | 517 DCHECK(query); |
463 if (query->pending()) { | 518 if (query->pending()) { |
464 // TODO(gman): Speed this up if this is a common operation. This would only | 519 // TODO(gman): Speed this up if this is a common operation. This would only |
465 // happen if you do being/end begin/end on the same query without waiting | 520 // happen if you do being/end begin/end on the same query without waiting |
466 // for the first one to finish. | 521 // for the first one to finish. |
467 for (QueryQueue::iterator it = pending_queries_.begin(); | 522 for (QueryQueue::iterator it = pending_queries_.begin(); |
468 it != pending_queries_.end(); ++it) { | 523 it != pending_queries_.end(); ++it) { |
469 if (it->get() == query) { | 524 if (it->get() == query) { |
470 pending_queries_.erase(it); | 525 pending_queries_.erase(it); |
471 break; | 526 break; |
472 } | 527 } |
473 } | 528 } |
| 529 for (QueryQueue::iterator it = pending_transfer_queries_.begin(); |
| 530 it != pending_transfer_queries_.end(); ++it) { |
| 531 if (it->get() == query) { |
| 532 pending_transfer_queries_.erase(it); |
| 533 break; |
| 534 } |
| 535 } |
474 if (!query->MarkAsCompleted(0)) { | 536 if (!query->MarkAsCompleted(0)) { |
475 return false; | 537 return false; |
476 } | 538 } |
477 } | 539 } |
478 return true; | 540 return true; |
479 } | 541 } |
480 | 542 |
481 bool QueryManager::BeginQuery(Query* query) { | 543 bool QueryManager::BeginQuery(Query* query) { |
482 DCHECK(query); | 544 DCHECK(query); |
483 if (!RemovePendingQuery(query)) { | 545 if (!RemovePendingQuery(query)) { |
484 return false; | 546 return false; |
485 } | 547 } |
486 return query->Begin(); | 548 return query->Begin(); |
487 } | 549 } |
488 | 550 |
489 bool QueryManager::EndQuery(Query* query, uint32 submit_count) { | 551 bool QueryManager::EndQuery(Query* query, uint32 submit_count) { |
490 DCHECK(query); | 552 DCHECK(query); |
491 if (!RemovePendingQuery(query)) { | 553 if (!RemovePendingQuery(query)) { |
492 return false; | 554 return false; |
493 } | 555 } |
494 return query->End(submit_count); | 556 return query->End(submit_count); |
495 } | 557 } |
496 | 558 |
497 } // namespace gles2 | 559 } // namespace gles2 |
498 } // namespace gpu | 560 } // namespace gpu |
499 | 561 |
500 | 562 |
OLD | NEW |