| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/exo/buffer.h" | 5 #include "components/exo/buffer.h" |
| 6 | 6 |
| 7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
| 8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
| 9 #include <GLES2/gl2extchromium.h> | 9 #include <GLES2/gl2extchromium.h> |
| 10 #include <stdint.h> | 10 #include <stdint.h> |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 | 399 |
| 400 Buffer::~Buffer() {} | 400 Buffer::~Buffer() {} |
| 401 | 401 |
| 402 bool Buffer::ProduceTransferableResource( | 402 bool Buffer::ProduceTransferableResource( |
| 403 CompositorFrameSinkHolder* compositor_frame_sink_holder, | 403 CompositorFrameSinkHolder* compositor_frame_sink_holder, |
| 404 cc::ResourceId resource_id, | 404 cc::ResourceId resource_id, |
| 405 bool secure_output_only, | 405 bool secure_output_only, |
| 406 bool client_usage, | 406 bool client_usage, |
| 407 cc::TransferableResource* resource) { | 407 cc::TransferableResource* resource) { |
| 408 DCHECK(attach_count_); | 408 DCHECK(attach_count_); |
| 409 DLOG_IF(WARNING, use_count_ && client_usage) | 409 DLOG_IF(WARNING, !release_contents_callback_.IsCancelled() && client_usage) |
| 410 << "Producing a texture mailbox for a buffer that has not been released"; | 410 << "Producing a texture mailbox for a buffer that has not been released"; |
| 411 | 411 |
| 412 // Some clients think that they can reuse a buffer before it's released by | |
| 413 // performing a fast blit into the buffer. This behavior is bad as it prevents | |
| 414 // the client from knowing when the buffer is actually released (e.g. the | |
| 415 // release notification for the previous use of buffer can arrive after the | |
| 416 // buffer has been reused). We stop running the release callback when this | |
| 417 // type of behavior is detected as having the buffer always be busy will | |
| 418 // result in fewer drawing artifacts. | |
| 419 if (use_count_ && client_usage) | |
| 420 release_callback_.Reset(); | |
| 421 | |
| 422 // Increment the use count for this buffer. | |
| 423 ++use_count_; | |
| 424 | |
| 425 // If textures are lost, destroy them to ensure that we create new ones below. | 412 // If textures are lost, destroy them to ensure that we create new ones below. |
| 426 if (contents_texture_ && contents_texture_->IsLost()) | 413 if (contents_texture_ && contents_texture_->IsLost()) |
| 427 contents_texture_.reset(); | 414 contents_texture_.reset(); |
| 428 if (texture_ && texture_->IsLost()) | 415 if (texture_ && texture_->IsLost()) |
| 429 texture_.reset(); | 416 texture_.reset(); |
| 430 | 417 |
| 431 ui::ContextFactory* context_factory = | 418 ui::ContextFactory* context_factory = |
| 432 aura::Env::GetInstance()->context_factory(); | 419 aura::Env::GetInstance()->context_factory(); |
| 433 // Note: This can fail if GPU acceleration has been disabled. | 420 // Note: This can fail if GPU acceleration has been disabled. |
| 434 scoped_refptr<cc::ContextProvider> context_provider = | 421 scoped_refptr<cc::ContextProvider> context_provider = |
| 435 context_factory->SharedMainThreadContextProvider(); | 422 context_factory->SharedMainThreadContextProvider(); |
| 436 if (!context_provider) { | 423 if (!context_provider) { |
| 437 DLOG(WARNING) << "Failed to acquire a context provider"; | 424 DLOG(WARNING) << "Failed to acquire a context provider"; |
| 438 Release(); // Decrements the use count | |
| 439 resource->id = 0; | 425 resource->id = 0; |
| 440 resource->size = gfx::Size(); | 426 resource->size = gfx::Size(); |
| 441 return false; | 427 return false; |
| 442 } | 428 } |
| 443 | 429 |
| 444 // The reference to the CompositorFrameSinkHolder keeps it alive until a | 430 // The reference to the CompositorFrameSinkHolder keeps it alive until a |
| 445 // release callback is received. | 431 // release callback is received. |
| 446 compositor_frame_sink_holder_ = compositor_frame_sink_holder; | 432 compositor_frame_sink_holder_ = compositor_frame_sink_holder; |
| 447 | 433 |
| 448 resource->id = resource_id; | 434 resource->id = resource_id; |
| 449 resource->format = cc::RGBA_8888; | 435 resource->format = cc::RGBA_8888; |
| 450 resource->filter = GL_LINEAR; | 436 resource->filter = GL_LINEAR; |
| 451 resource->size = gpu_memory_buffer_->GetSize(); | 437 resource->size = gpu_memory_buffer_->GetSize(); |
| 452 | 438 |
| 453 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_| | 439 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_| |
| 454 // if one doesn't already exist. The contents of this buffer are copied to | 440 // if one doesn't already exist. The contents of this buffer are copied to |
| 455 // |texture| using a call to CopyTexImage. | 441 // |texture| using a call to CopyTexImage. |
| 456 if (!contents_texture_) { | 442 if (!contents_texture_) { |
| 457 contents_texture_ = base::MakeUnique<Texture>( | 443 contents_texture_ = base::MakeUnique<Texture>( |
| 458 context_factory, context_provider.get(), gpu_memory_buffer_.get(), | 444 context_factory, context_provider.get(), gpu_memory_buffer_.get(), |
| 459 texture_target_, query_type_); | 445 texture_target_, query_type_); |
| 460 } | 446 } |
| 447 Texture* contents_texture = contents_texture_.get(); |
| 461 | 448 |
| 449 // Cancel pending contents release callback. |
| 450 release_contents_callback_.Reset( |
| 451 base::Bind(&Buffer::ReleaseContents, base::Unretained(this))); |
| 452 |
| 453 // Zero-copy means using the contents texture directly. |
| 462 if (use_zero_copy_) { | 454 if (use_zero_copy_) { |
| 463 // Zero-copy means using the contents texture directly. | 455 // This binds the latest contents of this buffer to |contents_texture|. |
| 464 Texture* texture = contents_texture_.get(); | 456 gpu::SyncToken sync_token = contents_texture->BindTexImage(); |
| 465 | 457 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(), |
| 466 // This binds the latest contents of this buffer to |texture|. | 458 sync_token, texture_target_); |
| 467 gpu::SyncToken sync_token = texture->BindTexImage(); | |
| 468 resource->mailbox_holder = | |
| 469 gpu::MailboxHolder(texture->mailbox(), sync_token, texture_target_); | |
| 470 resource->is_overlay_candidate = is_overlay_candidate_; | 459 resource->is_overlay_candidate = is_overlay_candidate_; |
| 471 | 460 |
| 472 // The contents texture will be released when no longer used by the | 461 // The contents texture will be released when no longer used by the |
| 473 // compositor. | 462 // compositor. |
| 474 compositor_frame_sink_holder_->SetResourceReleaseCallback( | 463 compositor_frame_sink_holder_->SetResourceReleaseCallback( |
| 475 resource_id, | 464 resource_id, |
| 476 base::Bind(&Buffer::Texture::ReleaseTexImage, base::Unretained(texture), | 465 base::Bind(&Buffer::Texture::ReleaseTexImage, |
| 466 base::Unretained(contents_texture), |
| 477 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(), | 467 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(), |
| 478 base::Passed(&contents_texture_)))); | 468 base::Passed(&contents_texture_), |
| 469 release_contents_callback_.callback()))); |
| 479 return true; | 470 return true; |
| 480 } | 471 } |
| 481 | 472 |
| 482 // Create a mailbox texture that we copy the buffer contents to. | 473 // Create a mailbox texture that we copy the buffer contents to. |
| 483 if (!texture_) { | 474 if (!texture_) { |
| 484 texture_ = | 475 texture_ = |
| 485 base::MakeUnique<Texture>(context_factory, context_provider.get()); | 476 base::MakeUnique<Texture>(context_factory, context_provider.get()); |
| 486 } | 477 } |
| 478 Texture* texture = texture_.get(); |
| 487 | 479 |
| 488 // Copy the contents of |contents_texture| to |texture| and produce a | 480 // Copy the contents of |contents_texture| to |texture| and produce a |
| 489 // texture mailbox from the result in |texture|. | 481 // texture mailbox from the result in |texture|. The contents texture will |
| 490 Texture* contents_texture = contents_texture_.get(); | 482 // be released when copy has completed. |
| 491 Texture* texture = texture_.get(); | |
| 492 | |
| 493 // The contents texture will be released when copy has completed. | |
| 494 gpu::SyncToken sync_token = contents_texture->CopyTexImage( | 483 gpu::SyncToken sync_token = contents_texture->CopyTexImage( |
| 495 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(), | 484 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(), |
| 496 base::Passed(&contents_texture_))); | 485 base::Passed(&contents_texture_), |
| 486 release_contents_callback_.callback())); |
| 497 resource->mailbox_holder = | 487 resource->mailbox_holder = |
| 498 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D); | 488 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D); |
| 499 resource->is_overlay_candidate = false; | 489 resource->is_overlay_candidate = false; |
| 500 | 490 |
| 501 // The mailbox texture will be released when no longer used by the | 491 // The mailbox texture will be released when no longer used by the |
| 502 // compositor. | 492 // compositor. |
| 503 compositor_frame_sink_holder_->SetResourceReleaseCallback( | 493 compositor_frame_sink_holder_->SetResourceReleaseCallback( |
| 504 resource_id, | 494 resource_id, |
| 505 base::Bind(&Buffer::Texture::Release, base::Unretained(texture), | 495 base::Bind(&Buffer::Texture::Release, base::Unretained(texture), |
| 506 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(), | 496 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(), |
| 507 base::Passed(&texture_)))); | 497 base::Passed(&texture_)))); |
| 508 return true; | 498 return true; |
| 509 } | 499 } |
| 510 | 500 |
| 511 void Buffer::OnAttach() { | 501 void Buffer::OnAttach() { |
| 512 DLOG_IF(WARNING, attach_count_ > 0u) | 502 DLOG_IF(WARNING, attach_count_) |
| 513 << "Reattaching a buffer that is already attached to another surface."; | 503 << "Reattaching a buffer that is already attached to another surface."; |
| 514 attach_count_++; | 504 ++attach_count_; |
| 515 } | 505 } |
| 516 | 506 |
| 517 void Buffer::OnDetach() { | 507 void Buffer::OnDetach() { |
| 518 DCHECK_GT(attach_count_, 0u); | 508 DCHECK_GT(attach_count_, 0u); |
| 519 --attach_count_; | 509 --attach_count_; |
| 520 CheckReleaseCallback(); | 510 |
| 511 // Release buffer if no longer attached to a surface and content has been |
| 512 // released. |
| 513 if (!attach_count_ && release_contents_callback_.IsCancelled()) |
| 514 Release(); |
| 521 } | 515 } |
| 522 | 516 |
| 523 gfx::Size Buffer::GetSize() const { | 517 gfx::Size Buffer::GetSize() const { |
| 524 return gpu_memory_buffer_->GetSize(); | 518 return gpu_memory_buffer_->GetSize(); |
| 525 } | 519 } |
| 526 | 520 |
| 527 gfx::BufferFormat Buffer::GetFormat() const { | 521 gfx::BufferFormat Buffer::GetFormat() const { |
| 528 return gpu_memory_buffer_->GetFormat(); | 522 return gpu_memory_buffer_->GetFormat(); |
| 529 } | 523 } |
| 530 | 524 |
| 531 std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const { | 525 std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const { |
| 532 std::unique_ptr<base::trace_event::TracedValue> value( | 526 std::unique_ptr<base::trace_event::TracedValue> value( |
| 533 new base::trace_event::TracedValue()); | 527 new base::trace_event::TracedValue()); |
| 534 gfx::Size size = gpu_memory_buffer_->GetSize(); | 528 gfx::Size size = gpu_memory_buffer_->GetSize(); |
| 535 value->SetInteger("width", size.width()); | 529 value->SetInteger("width", size.width()); |
| 536 value->SetInteger("height", size.height()); | 530 value->SetInteger("height", size.height()); |
| 537 value->SetInteger("format", | 531 value->SetInteger("format", |
| 538 static_cast<int>(gpu_memory_buffer_->GetFormat())); | 532 static_cast<int>(gpu_memory_buffer_->GetFormat())); |
| 539 return value; | 533 return value; |
| 540 } | 534 } |
| 541 | 535 |
| 542 //////////////////////////////////////////////////////////////////////////////// | 536 //////////////////////////////////////////////////////////////////////////////// |
| 543 // Buffer, private: | 537 // Buffer, private: |
| 544 | 538 |
| 545 void Buffer::Release() { | 539 void Buffer::Release() { |
| 546 DCHECK_GT(use_count_, 0u); | |
| 547 --use_count_; | |
| 548 CheckReleaseCallback(); | |
| 549 } | |
| 550 | |
| 551 void Buffer::CheckReleaseCallback() { | |
| 552 if (attach_count_ || use_count_) | |
| 553 return; | |
| 554 | |
| 555 // Run release callback to notify the client that buffer has been released. | 540 // Run release callback to notify the client that buffer has been released. |
| 556 if (!release_callback_.is_null()) | 541 if (!release_callback_.is_null()) |
| 557 release_callback_.Run(); | 542 release_callback_.Run(); |
| 558 | |
| 559 compositor_frame_sink_holder_ = nullptr; | |
| 560 } | 543 } |
| 561 | 544 |
| 562 void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) { | 545 void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) { |
| 563 texture_ = std::move(texture); | 546 texture_ = std::move(texture); |
| 564 } | 547 } |
| 565 | 548 |
| 566 void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture) { | 549 void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture, |
| 567 TRACE_EVENT0("exo", "Buffer::ReleaseContentsTexture"); | 550 const base::Closure& callback) { |
| 568 contents_texture_ = std::move(texture); | 551 contents_texture_ = std::move(texture); |
| 569 Release(); | 552 callback.Run(); |
| 553 } |
| 554 |
| 555 void Buffer::ReleaseContents() { |
| 556 TRACE_EVENT0("exo", "Buffer::ReleaseContents"); |
| 557 |
| 558 // Cancel callback to indicate that buffer has been released. |
| 559 release_contents_callback_.Cancel(); |
| 560 |
| 561 // Release buffer if not attached to surface. |
| 562 if (!attach_count_) |
| 563 Release(); |
| 570 } | 564 } |
| 571 | 565 |
| 572 } // namespace exo | 566 } // namespace exo |
| OLD | NEW |