Chromium Code Reviews| Index: components/exo/surface.cc |
| diff --git a/components/exo/surface.cc b/components/exo/surface.cc |
| index 8a86434211e5cb68e06bdde071602263b1d0c537..8619d27de4412aad7bd36e8110ad4ddf749e3284 100644 |
| --- a/components/exo/surface.cc |
| +++ b/components/exo/surface.cc |
| @@ -12,10 +12,20 @@ |
| #include "base/memory/ptr_util.h" |
| #include "base/trace_event/trace_event.h" |
| #include "base/trace_event/trace_event_argument.h" |
| +#include "cc/quads/render_pass.h" |
| +#include "cc/quads/shared_quad_state.h" |
| +#include "cc/quads/solid_color_draw_quad.h" |
| +#include "cc/quads/texture_draw_quad.h" |
| #include "cc/resources/single_release_callback.h" |
| +#include "cc/surfaces/surface.h" |
| +#include "cc/surfaces/surface_factory.h" |
| +#include "cc/surfaces/surface_id_allocator.h" |
| +#include "cc/surfaces/surface_manager.h" |
| #include "components/exo/buffer.h" |
| #include "components/exo/surface_delegate.h" |
| #include "components/exo/surface_observer.h" |
| +#include "third_party/khronos/GLES2/gl2.h" |
| +#include "ui/aura/env.h" |
| #include "ui/aura/window_delegate.h" |
| #include "ui/aura/window_property.h" |
| #include "ui/aura/window_targeter.h" |
| @@ -28,6 +38,7 @@ |
| #include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/gfx/gpu_memory_buffer.h" |
| #include "ui/gfx/path.h" |
| +#include "ui/gfx/skia_util.h" |
| #include "ui/gfx/transform_util.h" |
| #include "ui/views/widget/widget.h" |
| @@ -127,8 +138,48 @@ class CustomWindowTargeter : public aura::WindowTargeter { |
| DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter); |
| }; |
| +void SatisfyCallback(cc::SurfaceManager* manager, |
| + cc::SurfaceSequence sequence) { |
| + std::vector<uint32_t> sequences; |
| + sequences.push_back(sequence.sequence); |
| + manager->DidSatisfySequences(sequence.id_namespace, &sequences); |
| +} |
| + |
| +void RequireCallback(cc::SurfaceManager* manager, |
| + cc::SurfaceId id, |
| + cc::SurfaceSequence sequence) { |
| + cc::Surface* surface = manager->GetSurfaceForId(id); |
| + if (!surface) { |
| + LOG(ERROR) << "Attempting to require callback on nonexistent surface"; |
| + return; |
| + } |
| + surface->AddDestructionDependency(sequence); |
| +} |
| + |
| } // namespace |
| +SurfaceFactoryOwner::SurfaceFactoryOwner() {} |
| +SurfaceFactoryOwner::~SurfaceFactoryOwner() {} |
| + |
| +void SurfaceFactoryOwner::ReturnResources( |
| + const cc::ReturnedResourceArray& resources) { |
| + scoped_refptr<SurfaceFactoryOwner> holder(this); |
| + for (auto& resource : resources) { |
| + auto it = release_callbacks_.find(resource.id); |
| + DCHECK(it != release_callbacks_.end()); |
| + it->second.second->Run(resource.sync_token, resource.lost); |
| + release_callbacks_.erase(it); |
| + } |
| +} |
| +void SurfaceFactoryOwner::WillDrawSurface(cc::SurfaceId id, |
| + const gfx::Rect& damage_rect) { |
| + if (surface_) |
| + surface_->WillDraw(id); |
| +} |
| + |
| +void SurfaceFactoryOwner::SetBeginFrameSource( |
| + cc::BeginFrameSource* begin_frame_source) {} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // Surface, public: |
| @@ -152,7 +203,23 @@ Surface::Surface() |
| Init(ui::LAYER_SOLID_COLOR); |
| SetEventTargeter(base::WrapUnique(new CustomWindowTargeter)); |
| set_owned_by_parent(false); |
| - AddObserver(this); |
| + CHECK(aura::Env::GetInstance()); |
| + CHECK(aura::Env::GetInstance()->context_factory()); |
|
reveman
2016/05/27 18:25:41
do we need these CHECKs? can they be DCHECKs at le
|
| + surface_manager_ = |
| + aura::Env::GetInstance()->context_factory()->GetSurfaceManager(); |
| + if (use_surface_layer_) { |
| + factory_owner_ = make_scoped_refptr(new SurfaceFactoryOwner); |
| + factory_owner_->surface_ = this; |
| + CHECK(surface_manager_); |
| + factory_owner_->id_allocator_ = |
| + aura::Env::GetInstance()->context_factory()->CreateSurfaceIdAllocator(); |
| + factory_owner_->surface_factory_.reset( |
| + new cc::SurfaceFactory(surface_manager_, factory_owner_.get())); |
| + } |
| + |
| + if (!factory_owner_) { |
| + AddObserver(this); |
| + } |
| } |
| Surface::~Surface() { |
| @@ -160,7 +227,11 @@ Surface::~Surface() { |
| layer()->SetShowSolidColorContent(); |
| - RemoveObserver(this); |
| + if (factory_owner_) { |
| + factory_owner_->surface_ = nullptr; |
| + } else { |
| + RemoveObserver(this); |
| + } |
| if (compositor_) |
| compositor_->RemoveObserver(this); |
| @@ -171,6 +242,9 @@ Surface::~Surface() { |
| frame_callbacks_); |
| for (const auto& frame_callback : active_frame_callbacks_) |
| frame_callback.Run(base::TimeTicks()); |
| + |
| + if (!surface_id_.is_null()) |
| + factory_owner_->surface_factory_->Destroy(surface_id_); |
| } |
| // static |
| @@ -178,6 +252,11 @@ Surface* Surface::AsSurface(const aura::Window* window) { |
| return window->GetProperty(kSurfaceKey); |
| } |
| +// static |
| +void Surface::SetUseSurfaceLayer(bool use_surface_layer) { |
| + use_surface_layer_ = use_surface_layer; |
| +} |
| + |
| void Surface::Attach(Buffer* buffer) { |
| TRACE_EVENT1("exo", "Surface::Attach", "buffer", |
| buffer ? buffer->GetSize().ToString() : "null"); |
| @@ -348,10 +427,7 @@ void Surface::Commit() { |
| CommitSurfaceHierarchy(); |
| } |
| -void Surface::CommitSurfaceHierarchy() { |
| - DCHECK(needs_commit_surface_hierarchy_); |
| - needs_commit_surface_hierarchy_ = false; |
| - |
| +void Surface::CommitLayerContents() { |
| // We update contents if Attach() has been called since last commit. |
| if (has_pending_contents_) { |
| has_pending_contents_ = false; |
| @@ -417,8 +493,10 @@ void Surface::CommitSurfaceHierarchy() { |
| pending_damage_.setEmpty(); |
| } |
| - // Update current input region. |
| - input_region_ = pending_input_region_; |
| + if (layer()->has_external_content()) { |
| + layer()->SetTextureAlpha(pending_alpha_); |
| + alpha_ = pending_alpha_; |
| + } |
| // Move pending frame callbacks to the end of |frame_callbacks_|. |
| frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_); |
| @@ -430,11 +508,156 @@ void Surface::CommitSurfaceHierarchy() { |
| pending_blend_mode_ == SkXfermode::kSrc_Mode || |
| pending_opaque_region_.contains( |
| gfx::RectToSkIRect(gfx::Rect(layer()->size())))); |
| - if (layer()->has_external_content()) { |
| - layer()->SetTextureAlpha(pending_alpha_); |
| +} |
| + |
| +void Surface::CommitSurfaceContents() { |
| + // We update contents if Attach() has been called since last commit. |
| + if (has_pending_contents_) { |
| + has_pending_contents_ = false; |
| + |
| + current_buffer_ = pending_buffer_; |
| + pending_buffer_.reset(); |
| + |
| + bool secure_output_only = pending_only_visible_on_secure_output_; |
| + pending_only_visible_on_secure_output_ = false; |
| + |
| + cc::TextureMailbox texture_mailbox; |
| + std::unique_ptr<cc::SingleReleaseCallback> texture_mailbox_release_callback; |
| + if (current_buffer_) { |
| + texture_mailbox_release_callback = current_buffer_->ProduceTextureMailbox( |
| + &texture_mailbox, secure_output_only, false); |
| + } |
| + |
| + cc::SurfaceId old_surface_id = surface_id_; |
| + surface_id_ = factory_owner_->id_allocator_->GenerateId(); |
| + factory_owner_->surface_factory_->Create(surface_id_); |
| + |
| + gfx::Size texture_size_in_dip = gfx::ScaleToFlooredSize( |
| + texture_mailbox.size_in_pixels(), 1.0f / pending_buffer_scale_); |
| + gfx::Size contents_size = texture_size_in_dip; |
| + if (!pending_viewport_.IsEmpty()) { |
| + contents_size = pending_viewport_; |
| + } else if (!pending_crop_.IsEmpty()) { |
| + DLOG_IF(WARNING, !gfx::IsExpressibleAsInt(pending_crop_.width()) || |
| + !gfx::IsExpressibleAsInt(pending_crop_.height())) |
| + << "Crop rectangle size (" << pending_crop_.size().ToString() |
| + << ") most be expressible using integers when viewport is not set"; |
| + contents_size = gfx::ToCeiledSize(pending_crop_.size()); |
| + } |
| + |
| + float frame_device_scale_factor = 1.0; |
|
reveman
2016/05/27 18:25:41
is this correct when display DSF is 2? e.g. chrome
|
| + |
| + std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create(); |
| + render_pass->SetAll(cc::RenderPassId(1, 1), gfx::Rect(contents_size), |
| + gfx::Rect(contents_size), gfx::Transform(), false); |
| + |
| + gfx::Rect quad_rect = gfx::Rect(contents_size); |
| + cc::SharedQuadState* quad_state = |
| + render_pass->CreateAndAppendSharedQuadState(); |
| + quad_state->quad_layer_bounds = contents_size; |
| + quad_state->visible_quad_layer_rect = quad_rect; |
| + quad_state->opacity = alpha_; |
| alpha_ = pending_alpha_; |
| + |
| + bool frame_is_opaque = false; |
| + |
| + std::unique_ptr<cc::DelegatedFrameData> delegated_frame( |
| + new cc::DelegatedFrameData); |
| + if (texture_mailbox_release_callback) { |
| + cc::TransferableResource resource; |
| + resource.id = next_resource_id_++; |
| + resource.format = cc::RGBA_8888; |
| + resource.filter = |
| + texture_mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR; |
| + resource.size = texture_mailbox.size_in_pixels(); |
| + resource.mailbox_holder = gpu::MailboxHolder(texture_mailbox.mailbox(), |
| + texture_mailbox.sync_token(), |
| + texture_mailbox.target()); |
| + resource.is_overlay_candidate = texture_mailbox.is_overlay_candidate(); |
| + |
| + cc::TextureDrawQuad* texture_quad = |
| + render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); |
| + float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0}; |
| + gfx::Rect opaque_rect; |
| + frame_is_opaque = |
| + pending_blend_mode_ == SkXfermode::kSrc_Mode || |
| + pending_opaque_region_.contains(gfx::RectToSkIRect(quad_rect)); |
| + if (frame_is_opaque) { |
| + opaque_rect = quad_rect; |
| + } else if (pending_opaque_region_.isRect()) { |
| + opaque_rect = gfx::SkIRectToRect(pending_opaque_region_.getBounds()); |
| + } |
| + |
| + gfx::PointF uv_top_left(0.f, 0.f); |
| + gfx::PointF uv_bottom_right(1.f, 1.f); |
| + if (!pending_crop_.IsEmpty()) { |
| + uv_top_left = pending_crop_.origin(); |
| + uv_top_left.Scale(1.f / texture_size_in_dip.width(), |
| + 1.f / texture_size_in_dip.height()); |
| + uv_bottom_right = pending_crop_.bottom_right(); |
| + uv_bottom_right.Scale(1.f / texture_size_in_dip.width(), |
| + 1.f / texture_size_in_dip.height()); |
| + } |
| + |
| + texture_quad->SetNew(quad_state, quad_rect, opaque_rect, quad_rect, |
| + resource.id, true, uv_top_left, uv_bottom_right, |
| + SK_ColorTRANSPARENT, vertex_opacity, false, false, |
| + secure_output_only); |
| + |
| + factory_owner_->release_callbacks_[resource.id] = std::make_pair( |
| + factory_owner_, std::move(texture_mailbox_release_callback)); |
| + delegated_frame->resource_list.push_back(resource); |
| + } else { |
| + cc::SolidColorDrawQuad* surface_quad = |
| + render_pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>(); |
| + surface_quad->SetNew(quad_state, gfx::Rect(quad_state->quad_layer_bounds), |
| + gfx::Rect(quad_state->quad_layer_bounds), |
| + SK_ColorBLACK, false); |
| + frame_is_opaque = true; |
| + } |
| + |
| + delegated_frame->render_pass_list.push_back(std::move(render_pass)); |
| + std::unique_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame); |
| + frame->delegated_frame_data = std::move(delegated_frame); |
| + |
| + factory_owner_->surface_factory_->SubmitCompositorFrame( |
| + surface_id_, std::move(frame), cc::SurfaceFactory::DrawCallback()); |
| + |
| + if (!old_surface_id.is_null()) { |
| + factory_owner_->surface_factory_->SetPreviousFrameSurface(surface_id_, |
| + old_surface_id); |
| + factory_owner_->surface_factory_->Destroy(old_surface_id); |
| + } |
| + |
| + layer()->SetShowSurface( |
| + surface_id_, |
| + base::Bind(&SatisfyCallback, base::Unretained(surface_manager_)), |
| + base::Bind(&RequireCallback, base::Unretained(surface_manager_)), |
| + contents_size, frame_device_scale_factor, contents_size); |
| + layer()->SetBounds(gfx::Rect(layer()->bounds().origin(), contents_size)); |
| + layer()->SetFillsBoundsOpaquely(alpha_ == 1.0f && frame_is_opaque); |
| + |
| + // Reset damage. |
| + pending_damage_.setEmpty(); |
| + } |
| + // Move pending frame callbacks to the end of active_frame_callbacks_ |
| + active_frame_callbacks_.splice(active_frame_callbacks_.end(), |
| + pending_frame_callbacks_); |
| +} |
| + |
| +void Surface::CommitSurfaceHierarchy() { |
| + DCHECK(needs_commit_surface_hierarchy_); |
| + needs_commit_surface_hierarchy_ = false; |
| + |
| + if (factory_owner_) { |
| + CommitSurfaceContents(); |
| + } else { |
| + CommitLayerContents(); |
| } |
| + // Update current input region. |
| + input_region_ = pending_input_region_; |
| + |
| // Synchronize window hierarchy. This will position and update the stacking |
| // order of all sub-surfaces after committing all pending state of sub-surface |
| // descendants. |
| @@ -542,6 +765,7 @@ std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const { |
| void Surface::OnWindowAddedToRootWindow(aura::Window* window) { |
| DCHECK(!compositor_); |
| + DCHECK(!factory_owner_); |
| compositor_ = layer()->GetCompositor(); |
| compositor_->AddObserver(this); |
| } |
| @@ -557,6 +781,7 @@ void Surface::OnWindowRemovingFromRootWindow(aura::Window* window, |
| // ui::CompositorObserver overrides: |
| void Surface::OnCompositingDidCommit(ui::Compositor* compositor) { |
| + DCHECK(!factory_owner_); |
| // Move frame callbacks to the end of |active_frame_callbacks_|. |
| active_frame_callbacks_.splice(active_frame_callbacks_.end(), |
| frame_callbacks_); |
| @@ -614,4 +839,13 @@ void Surface::OnCompositingShuttingDown(ui::Compositor* compositor) { |
| compositor_ = nullptr; |
| } |
| +void Surface::WillDraw(cc::SurfaceId id) { |
| + while (!active_frame_callbacks_.empty()) { |
| + active_frame_callbacks_.front().Run(base::TimeTicks::Now()); |
| + active_frame_callbacks_.pop_front(); |
| + } |
| +} |
| + |
| +bool Surface::use_surface_layer_ = false; |
| + |
| } // namespace exo |