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