OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "cc/raster/one_copy_tile_task_worker_pool.h" | 5 #include "cc/raster/one_copy_tile_task_worker_pool.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 105 |
106 OneCopyTileTaskWorkerPool::StagingBuffer::~StagingBuffer() { | 106 OneCopyTileTaskWorkerPool::StagingBuffer::~StagingBuffer() { |
107 DCHECK_EQ(texture_id, 0u); | 107 DCHECK_EQ(texture_id, 0u); |
108 DCHECK_EQ(image_id, 0u); | 108 DCHECK_EQ(image_id, 0u); |
109 DCHECK_EQ(query_id, 0u); | 109 DCHECK_EQ(query_id, 0u); |
110 } | 110 } |
111 | 111 |
112 void OneCopyTileTaskWorkerPool::StagingBuffer::DestroyGLResources( | 112 void OneCopyTileTaskWorkerPool::StagingBuffer::DestroyGLResources( |
113 gpu::gles2::GLES2Interface* gl) { | 113 gpu::gles2::GLES2Interface* gl) { |
114 if (query_id) { | 114 if (query_id) { |
115 gl->DeleteQueriesEXT(1, &query_id); | 115 if (gl) |
| 116 gl->DeleteQueriesEXT(1, &query_id); |
116 query_id = 0; | 117 query_id = 0; |
117 } | 118 } |
118 if (image_id) { | 119 if (image_id) { |
119 gl->DestroyImageCHROMIUM(image_id); | 120 if (gl) |
| 121 gl->DestroyImageCHROMIUM(image_id); |
120 image_id = 0; | 122 image_id = 0; |
121 } | 123 } |
122 if (texture_id) { | 124 if (texture_id) { |
123 gl->DeleteTextures(1, &texture_id); | 125 if (gl) |
| 126 gl->DeleteTextures(1, &texture_id); |
124 texture_id = 0; | 127 texture_id = 0; |
125 } | 128 } |
126 } | 129 } |
127 | 130 |
128 void OneCopyTileTaskWorkerPool::StagingBuffer::OnMemoryDump( | 131 void OneCopyTileTaskWorkerPool::StagingBuffer::OnMemoryDump( |
129 base::trace_event::ProcessMemoryDump* pmd, | 132 base::trace_event::ProcessMemoryDump* pmd, |
130 ResourceFormat format, | 133 ResourceFormat format, |
131 bool in_free_list) const { | 134 bool in_free_list) const { |
132 if (!gpu_memory_buffer) | 135 if (!gpu_memory_buffer) |
133 return; | 136 return; |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 } | 420 } |
418 | 421 |
419 ContextProvider* context_provider = | 422 ContextProvider* context_provider = |
420 resource_provider_->output_surface()->worker_context_provider(); | 423 resource_provider_->output_surface()->worker_context_provider(); |
421 DCHECK(context_provider); | 424 DCHECK(context_provider); |
422 | 425 |
423 { | 426 { |
424 ContextProvider::ScopedContextLock scoped_context(context_provider); | 427 ContextProvider::ScopedContextLock scoped_context(context_provider); |
425 | 428 |
426 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | 429 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
427 DCHECK(gl); | 430 if (gl) { |
| 431 unsigned image_target = resource_provider_->GetImageTextureTarget( |
| 432 resource_provider_->memory_efficient_texture_format()); |
428 | 433 |
429 unsigned image_target = resource_provider_->GetImageTextureTarget( | 434 // Create and bind staging texture. |
430 resource_provider_->memory_efficient_texture_format()); | 435 if (!staging_buffer->texture_id) { |
| 436 gl->GenTextures(1, &staging_buffer->texture_id); |
| 437 gl->BindTexture(image_target, staging_buffer->texture_id); |
| 438 gl->TexParameteri(image_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 439 gl->TexParameteri(image_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 440 gl->TexParameteri(image_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 441 gl->TexParameteri(image_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 442 } else { |
| 443 gl->BindTexture(image_target, staging_buffer->texture_id); |
| 444 } |
431 | 445 |
432 // Create and bind staging texture. | 446 // Create and bind image. |
433 if (!staging_buffer->texture_id) { | 447 if (!staging_buffer->image_id) { |
434 gl->GenTextures(1, &staging_buffer->texture_id); | 448 if (staging_buffer->gpu_memory_buffer) { |
435 gl->BindTexture(image_target, staging_buffer->texture_id); | 449 staging_buffer->image_id = gl->CreateImageCHROMIUM( |
436 gl->TexParameteri(image_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 450 staging_buffer->gpu_memory_buffer->AsClientBuffer(), |
437 gl->TexParameteri(image_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 451 staging_buffer->size.width(), staging_buffer->size.height(), |
438 gl->TexParameteri(image_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 452 GLInternalFormat( |
439 gl->TexParameteri(image_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 453 resource_provider_->memory_efficient_texture_format())); |
440 } else { | 454 gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); |
441 gl->BindTexture(image_target, staging_buffer->texture_id); | 455 } |
442 } | 456 } else { |
443 | 457 gl->ReleaseTexImage2DCHROMIUM(image_target, staging_buffer->image_id); |
444 // Create and bind image. | |
445 if (!staging_buffer->image_id) { | |
446 if (staging_buffer->gpu_memory_buffer) { | |
447 staging_buffer->image_id = gl->CreateImageCHROMIUM( | |
448 staging_buffer->gpu_memory_buffer->AsClientBuffer(), | |
449 staging_buffer->size.width(), staging_buffer->size.height(), | |
450 GLInternalFormat( | |
451 resource_provider_->memory_efficient_texture_format())); | |
452 gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); | 458 gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); |
453 } | 459 } |
454 } else { | |
455 gl->ReleaseTexImage2DCHROMIUM(image_target, staging_buffer->image_id); | |
456 gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); | |
457 } | |
458 | 460 |
459 // Unbind staging texture. | 461 // Unbind staging texture. |
460 gl->BindTexture(image_target, 0); | 462 gl->BindTexture(image_target, 0); |
461 | 463 |
462 if (resource_provider_->use_sync_query()) { | 464 if (resource_provider_->use_sync_query()) { |
463 if (!staging_buffer->query_id) | 465 if (!staging_buffer->query_id) |
464 gl->GenQueriesEXT(1, &staging_buffer->query_id); | 466 gl->GenQueriesEXT(1, &staging_buffer->query_id); |
465 | 467 |
466 #if defined(OS_CHROMEOS) | 468 #if defined(OS_CHROMEOS) |
467 // TODO(reveman): This avoids a performance problem on some ChromeOS | 469 // TODO(reveman): This avoids a performance problem on some ChromeOS |
468 // devices. This needs to be removed to support native GpuMemoryBuffer | 470 // devices. This needs to be removed to support native GpuMemoryBuffer |
469 // implementations. crbug.com/436314 | 471 // implementations. crbug.com/436314 |
470 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, staging_buffer->query_id); | 472 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, |
| 473 staging_buffer->query_id); |
471 #else | 474 #else |
472 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, | 475 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, |
473 staging_buffer->query_id); | 476 staging_buffer->query_id); |
474 #endif | 477 #endif |
| 478 } |
| 479 |
| 480 int bytes_per_row = |
| 481 (BitsPerPixel(resource_provider_->memory_efficient_texture_format()) * |
| 482 resource->size().width()) / |
| 483 8; |
| 484 int chunk_size_in_rows = |
| 485 std::max(1, max_bytes_per_copy_operation_ / bytes_per_row); |
| 486 // Align chunk size to 4. Required to support compressed texture formats. |
| 487 chunk_size_in_rows = MathUtil::UncheckedRoundUp(chunk_size_in_rows, 4); |
| 488 int y = 0; |
| 489 int height = resource->size().height(); |
| 490 while (y < height) { |
| 491 // Copy at most |chunk_size_in_rows|. |
| 492 int rows_to_copy = std::min(chunk_size_in_rows, height - y); |
| 493 DCHECK_GT(rows_to_copy, 0); |
| 494 |
| 495 gl->CopySubTextureCHROMIUM(GL_TEXTURE_2D, staging_buffer->texture_id, |
| 496 resource_lock->texture_id(), 0, y, 0, y, |
| 497 resource->size().width(), rows_to_copy, |
| 498 false, false, false); |
| 499 y += rows_to_copy; |
| 500 |
| 501 // Increment |bytes_scheduled_since_last_flush_| by the amount of memory |
| 502 // used for this copy operation. |
| 503 bytes_scheduled_since_last_flush_ += rows_to_copy * bytes_per_row; |
| 504 |
| 505 if (bytes_scheduled_since_last_flush_ >= |
| 506 max_bytes_per_copy_operation_) { |
| 507 gl->ShallowFlushCHROMIUM(); |
| 508 bytes_scheduled_since_last_flush_ = 0; |
| 509 } |
| 510 } |
| 511 |
| 512 if (resource_provider_->use_sync_query()) { |
| 513 #if defined(OS_CHROMEOS) |
| 514 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); |
| 515 #else |
| 516 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); |
| 517 #endif |
| 518 } |
| 519 |
| 520 // Barrier to sync worker context output to cc context. |
| 521 gl->OrderingBarrierCHROMIUM(); |
475 } | 522 } |
476 | |
477 int bytes_per_row = | |
478 (BitsPerPixel(resource_provider_->memory_efficient_texture_format()) * | |
479 resource->size().width()) / | |
480 8; | |
481 int chunk_size_in_rows = | |
482 std::max(1, max_bytes_per_copy_operation_ / bytes_per_row); | |
483 // Align chunk size to 4. Required to support compressed texture formats. | |
484 chunk_size_in_rows = MathUtil::UncheckedRoundUp(chunk_size_in_rows, 4); | |
485 int y = 0; | |
486 int height = resource->size().height(); | |
487 while (y < height) { | |
488 // Copy at most |chunk_size_in_rows|. | |
489 int rows_to_copy = std::min(chunk_size_in_rows, height - y); | |
490 DCHECK_GT(rows_to_copy, 0); | |
491 | |
492 gl->CopySubTextureCHROMIUM(GL_TEXTURE_2D, staging_buffer->texture_id, | |
493 resource_lock->texture_id(), 0, y, 0, y, | |
494 resource->size().width(), rows_to_copy, false, | |
495 false, false); | |
496 y += rows_to_copy; | |
497 | |
498 // Increment |bytes_scheduled_since_last_flush_| by the amount of memory | |
499 // used for this copy operation. | |
500 bytes_scheduled_since_last_flush_ += rows_to_copy * bytes_per_row; | |
501 | |
502 if (bytes_scheduled_since_last_flush_ >= max_bytes_per_copy_operation_) { | |
503 gl->ShallowFlushCHROMIUM(); | |
504 bytes_scheduled_since_last_flush_ = 0; | |
505 } | |
506 } | |
507 | |
508 if (resource_provider_->use_sync_query()) { | |
509 #if defined(OS_CHROMEOS) | |
510 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); | |
511 #else | |
512 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); | |
513 #endif | |
514 } | |
515 | |
516 // Barrier to sync worker context output to cc context. | |
517 gl->OrderingBarrierCHROMIUM(); | |
518 } | 523 } |
519 | 524 |
520 staging_buffer->last_usage = base::TimeTicks::Now(); | 525 staging_buffer->last_usage = base::TimeTicks::Now(); |
521 busy_buffers_.push_back(staging_buffer.Pass()); | 526 busy_buffers_.push_back(staging_buffer.Pass()); |
522 | 527 |
523 ScheduleReduceMemoryUsage(); | 528 ScheduleReduceMemoryUsage(); |
524 } | 529 } |
525 | 530 |
526 bool OneCopyTileTaskWorkerPool::OnMemoryDump( | 531 bool OneCopyTileTaskWorkerPool::OnMemoryDump( |
527 const base::trace_event::MemoryDumpArgs& args, | 532 const base::trace_event::MemoryDumpArgs& args, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 | 596 |
592 scoped_ptr<StagingBuffer> staging_buffer; | 597 scoped_ptr<StagingBuffer> staging_buffer; |
593 | 598 |
594 ContextProvider* context_provider = | 599 ContextProvider* context_provider = |
595 resource_provider_->output_surface()->worker_context_provider(); | 600 resource_provider_->output_surface()->worker_context_provider(); |
596 DCHECK(context_provider); | 601 DCHECK(context_provider); |
597 | 602 |
598 ContextProvider::ScopedContextLock scoped_context(context_provider); | 603 ContextProvider::ScopedContextLock scoped_context(context_provider); |
599 | 604 |
600 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | 605 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
601 DCHECK(gl); | 606 if (gl) { |
| 607 // Check if any busy buffers have become available. |
| 608 if (resource_provider_->use_sync_query()) { |
| 609 while (!busy_buffers_.empty()) { |
| 610 if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id)) |
| 611 break; |
602 | 612 |
603 // Check if any busy buffers have become available. | |
604 if (resource_provider_->use_sync_query()) { | |
605 while (!busy_buffers_.empty()) { | |
606 if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id)) | |
607 break; | |
608 | |
609 MarkStagingBufferAsFree(busy_buffers_.front()); | |
610 free_buffers_.push_back(busy_buffers_.take_front()); | |
611 } | |
612 } | |
613 | |
614 // Wait for memory usage of non-free buffers to become less than the limit. | |
615 while ( | |
616 (staging_buffer_usage_in_bytes_ - free_staging_buffer_usage_in_bytes_) >= | |
617 max_staging_buffer_usage_in_bytes_) { | |
618 // Stop when there are no more busy buffers to wait for. | |
619 if (busy_buffers_.empty()) | |
620 break; | |
621 | |
622 if (resource_provider_->use_sync_query()) { | |
623 WaitForQueryResult(gl, busy_buffers_.front()->query_id); | |
624 MarkStagingBufferAsFree(busy_buffers_.front()); | |
625 free_buffers_.push_back(busy_buffers_.take_front()); | |
626 } else { | |
627 // Fall-back to glFinish if CHROMIUM_sync_query is not available. | |
628 gl->Finish(); | |
629 while (!busy_buffers_.empty()) { | |
630 MarkStagingBufferAsFree(busy_buffers_.front()); | 613 MarkStagingBufferAsFree(busy_buffers_.front()); |
631 free_buffers_.push_back(busy_buffers_.take_front()); | 614 free_buffers_.push_back(busy_buffers_.take_front()); |
632 } | 615 } |
633 } | 616 } |
| 617 |
| 618 // Wait for memory usage of non-free buffers to become less than the limit. |
| 619 while ((staging_buffer_usage_in_bytes_ - |
| 620 free_staging_buffer_usage_in_bytes_) >= |
| 621 max_staging_buffer_usage_in_bytes_) { |
| 622 // Stop when there are no more busy buffers to wait for. |
| 623 if (busy_buffers_.empty()) |
| 624 break; |
| 625 |
| 626 if (resource_provider_->use_sync_query()) { |
| 627 WaitForQueryResult(gl, busy_buffers_.front()->query_id); |
| 628 MarkStagingBufferAsFree(busy_buffers_.front()); |
| 629 free_buffers_.push_back(busy_buffers_.take_front()); |
| 630 } else { |
| 631 // Fall-back to glFinish if CHROMIUM_sync_query is not available. |
| 632 gl->Finish(); |
| 633 while (!busy_buffers_.empty()) { |
| 634 MarkStagingBufferAsFree(busy_buffers_.front()); |
| 635 free_buffers_.push_back(busy_buffers_.take_front()); |
| 636 } |
| 637 } |
| 638 } |
634 } | 639 } |
635 | 640 |
636 // Find a staging buffer that allows us to perform partial raster when | 641 // Find a staging buffer that allows us to perform partial raster when |
637 // using persistent GpuMemoryBuffers. | 642 // using persistent GpuMemoryBuffers. |
638 if (use_persistent_gpu_memory_buffers_ && previous_content_id) { | 643 if (use_persistent_gpu_memory_buffers_ && previous_content_id) { |
639 StagingBufferDeque::iterator it = | 644 StagingBufferDeque::iterator it = |
640 std::find_if(free_buffers_.begin(), free_buffers_.end(), | 645 std::find_if(free_buffers_.begin(), free_buffers_.end(), |
641 [previous_content_id](const StagingBuffer* buffer) { | 646 [previous_content_id](const StagingBuffer* buffer) { |
642 return buffer->content_id == previous_content_id; | 647 return buffer->content_id == previous_content_id; |
643 }); | 648 }); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 lock_.AssertAcquired(); | 743 lock_.AssertAcquired(); |
739 | 744 |
740 ContextProvider* context_provider = | 745 ContextProvider* context_provider = |
741 resource_provider_->output_surface()->worker_context_provider(); | 746 resource_provider_->output_surface()->worker_context_provider(); |
742 DCHECK(context_provider); | 747 DCHECK(context_provider); |
743 | 748 |
744 { | 749 { |
745 ContextProvider::ScopedContextLock scoped_context(context_provider); | 750 ContextProvider::ScopedContextLock scoped_context(context_provider); |
746 | 751 |
747 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | 752 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
748 DCHECK(gl); | |
749 | 753 |
750 // Note: Front buffer is guaranteed to be LRU so we can stop releasing | 754 // Note: Front buffer is guaranteed to be LRU so we can stop releasing |
751 // buffers as soon as we find a buffer that has been used since |time|. | 755 // buffers as soon as we find a buffer that has been used since |time|. |
752 while (!free_buffers_.empty()) { | 756 while (!free_buffers_.empty()) { |
753 if (free_buffers_.front()->last_usage > time) | 757 if (free_buffers_.front()->last_usage > time) |
754 return; | 758 return; |
755 | 759 |
756 free_buffers_.front()->DestroyGLResources(gl); | 760 free_buffers_.front()->DestroyGLResources(gl); |
757 MarkStagingBufferAsBusy(free_buffers_.front()); | 761 MarkStagingBufferAsBusy(free_buffers_.front()); |
758 RemoveStagingBuffer(free_buffers_.front()); | 762 RemoveStagingBuffer(free_buffers_.front()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 | 811 |
808 staging_state->SetInteger("staging_buffer_count", | 812 staging_state->SetInteger("staging_buffer_count", |
809 static_cast<int>(buffers_.size())); | 813 static_cast<int>(buffers_.size())); |
810 staging_state->SetInteger("busy_count", | 814 staging_state->SetInteger("busy_count", |
811 static_cast<int>(busy_buffers_.size())); | 815 static_cast<int>(busy_buffers_.size())); |
812 staging_state->SetInteger("free_count", | 816 staging_state->SetInteger("free_count", |
813 static_cast<int>(free_buffers_.size())); | 817 static_cast<int>(free_buffers_.size())); |
814 } | 818 } |
815 | 819 |
816 } // namespace cc | 820 } // namespace cc |
OLD | NEW |