Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(566)

Side by Side Diff: components/exo/buffer.cc

Issue 2666233002: exo: Cleanup and make buffer release code more robust. (Closed)
Patch Set: fix typo Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/exo/buffer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « components/exo/buffer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698