| Index: content/renderer/android/synchronous_compositor_frame_sink.cc
|
| diff --git a/content/renderer/android/synchronous_compositor_frame_sink.cc b/content/renderer/android/synchronous_compositor_frame_sink.cc
|
| index 4b43874b6f5f6f364cd5c0b5ec2dd16f1d9878c8..b6bbf340b869734fd9dc4f0ddc865d494d78e323 100644
|
| --- a/content/renderer/android/synchronous_compositor_frame_sink.cc
|
| +++ b/content/renderer/android/synchronous_compositor_frame_sink.cc
|
| @@ -20,6 +20,8 @@
|
| #include "cc/output/renderer_settings.h"
|
| #include "cc/output/software_output_device.h"
|
| #include "cc/output/texture_mailbox_deleter.h"
|
| +#include "cc/quads/render_pass.h"
|
| +#include "cc/quads/surface_draw_quad.h"
|
| #include "cc/surfaces/display.h"
|
| #include "cc/surfaces/surface_factory.h"
|
| #include "cc/surfaces/surface_id_allocator.h"
|
| @@ -86,7 +88,7 @@ class SynchronousCompositorFrameSink::SoftwareOutputSurface
|
| float scale_factor,
|
| const gfx::ColorSpace& color_space,
|
| bool has_alpha) override {
|
| - // Intentional no-op. Surface size controlled by embedder.
|
| + surface_size_ = size;
|
| }
|
| uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
|
| cc::OverlayCandidateValidator* GetOverlayCandidateValidator() const override {
|
| @@ -97,10 +99,6 @@ class SynchronousCompositorFrameSink::SoftwareOutputSurface
|
| bool SurfaceIsSuspendForRecycle() const override { return false; }
|
| bool HasExternalStencilTest() const override { return false; }
|
| void ApplyExternalStencil() override {}
|
| -
|
| - void SetSurfaceSize(const gfx::Size surface_size) {
|
| - surface_size_ = surface_size;
|
| - }
|
| };
|
|
|
| SynchronousCompositorFrameSink::SynchronousCompositorFrameSink(
|
| @@ -173,10 +171,9 @@ bool SynchronousCompositorFrameSink::BindToClient(
|
|
|
| cc::RendererSettings software_renderer_settings;
|
|
|
| - std::unique_ptr<SoftwareOutputSurface> compositor_frame_sink(
|
| - new SoftwareOutputSurface(
|
| - base::MakeUnique<SoftwareDevice>(¤t_sw_canvas_)));
|
| - software_compositor_frame_sink_ = compositor_frame_sink.get();
|
| + auto output_surface = base::MakeUnique<SoftwareOutputSurface>(
|
| + base::MakeUnique<SoftwareDevice>(¤t_sw_canvas_));
|
| + software_output_surface_ = output_surface.get();
|
|
|
| // The shared_bitmap_manager and gpu_memory_buffer_manager here are null as
|
| // this Display is only used for resourcesless software draws, where no
|
| @@ -185,7 +182,7 @@ bool SynchronousCompositorFrameSink::BindToClient(
|
| display_.reset(new cc::Display(
|
| nullptr /* shared_bitmap_manager */,
|
| nullptr /* gpu_memory_buffer_manager */, software_renderer_settings,
|
| - nullptr /* begin_frame_source */, std::move(compositor_frame_sink),
|
| + nullptr /* begin_frame_source */, std::move(output_surface),
|
| nullptr /* scheduler */, nullptr /* texture_mailbox_deleter */));
|
| display_->Initialize(&display_client_, surface_manager_.get(), kFrameSinkId);
|
| display_->SetVisible(true);
|
| @@ -200,11 +197,13 @@ void SynchronousCompositorFrameSink::DetachFromClient() {
|
| if (registered_)
|
| registry_->UnregisterCompositorFrameSink(routing_id_, this);
|
| client_->SetTreeActivationCallback(base::Closure());
|
| - if (!delegated_surface_id_.is_null())
|
| - surface_factory_->Destroy(delegated_surface_id_);
|
| + if (!root_surface_id_.is_null()) {
|
| + surface_factory_->Destroy(root_surface_id_);
|
| + surface_factory_->Destroy(child_surface_id_);
|
| + }
|
| surface_manager_->UnregisterSurfaceFactoryClient(kFrameSinkId);
|
| surface_manager_->InvalidateFrameSinkId(kFrameSinkId);
|
| - software_compositor_frame_sink_ = nullptr;
|
| + software_output_surface_ = nullptr;
|
| display_ = nullptr;
|
| surface_factory_ = nullptr;
|
| surface_id_allocator_ = nullptr;
|
| @@ -234,20 +233,68 @@ void SynchronousCompositorFrameSink::SwapBuffers(cc::CompositorFrame frame) {
|
| // the |frame| for the software path below.
|
| swap_frame.metadata = frame.metadata.Clone();
|
|
|
| - if (delegated_surface_id_.is_null()) {
|
| - delegated_surface_id_ = surface_id_allocator_->GenerateId();
|
| - surface_factory_->Create(delegated_surface_id_);
|
| + if (root_surface_id_.is_null()) {
|
| + root_surface_id_ = surface_id_allocator_->GenerateId();
|
| + surface_factory_->Create(root_surface_id_);
|
| + child_surface_id_ = surface_id_allocator_->GenerateId();
|
| + surface_factory_->Create(child_surface_id_);
|
| }
|
|
|
| - display_->SetSurfaceId(delegated_surface_id_,
|
| + display_->SetSurfaceId(root_surface_id_,
|
| frame.metadata.device_scale_factor);
|
|
|
| - gfx::Size frame_size =
|
| - frame.delegated_frame_data->render_pass_list.back()->output_rect.size();
|
| - display_->Resize(frame_size);
|
| -
|
| - surface_factory_->SubmitCompositorFrame(
|
| - delegated_surface_id_, std::move(frame), base::Bind(&NoOpDrawCallback));
|
| + // The layer compositor should be giving a frame that covers the
|
| + // |sw_viewport_for_current_draw_| but at 0,0.
|
| + gfx::Size child_size = sw_viewport_for_current_draw_.size();
|
| + DCHECK(gfx::Rect(child_size) ==
|
| + frame.delegated_frame_data->render_pass_list.back()->output_rect);
|
| +
|
| + // Make a size that covers from 0,0 and includes the area coming from the
|
| + // layer compositor.
|
| + gfx::Size display_size(sw_viewport_for_current_draw_.right(),
|
| + sw_viewport_for_current_draw_.bottom());
|
| + display_->Resize(display_size);
|
| +
|
| + // The offset for the child frame relative to the origin of the canvas being
|
| + // drawn into.
|
| + gfx::Transform child_transform;
|
| + child_transform.Translate(
|
| + gfx::Vector2dF(sw_viewport_for_current_draw_.OffsetFromOrigin()));
|
| +
|
| + // Make a root frame that embeds the frame coming from the layer compositor
|
| + // and positions it based on the provided viewport.
|
| + // TODO(danakj): We could apply the transform here instead of passing it to
|
| + // the CompositorFrameSink client too? (We'd have to do the same for
|
| + // hardware frames in SurfacesInstance?)
|
| + cc::CompositorFrame embed_frame;
|
| + embed_frame.delegated_frame_data =
|
| + base::MakeUnique<cc::DelegatedFrameData>();
|
| + embed_frame.delegated_frame_data->render_pass_list.push_back(
|
| + cc::RenderPass::Create());
|
| +
|
| + // The embedding RenderPass covers the entire Display's area.
|
| + const auto& embed_render_pass =
|
| + embed_frame.delegated_frame_data->render_pass_list.back();
|
| + embed_render_pass->SetAll(cc::RenderPassId(1, 1), gfx::Rect(display_size),
|
| + gfx::Rect(display_size), gfx::Transform(), false);
|
| +
|
| + // The RenderPass has a single SurfaceDrawQuad (and SharedQuadState for it).
|
| + auto* shared_quad_state =
|
| + embed_render_pass->CreateAndAppendSharedQuadState();
|
| + auto* surface_quad =
|
| + embed_render_pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
|
| + shared_quad_state->SetAll(
|
| + child_transform, child_size, gfx::Rect(child_size),
|
| + gfx::Rect() /* clip_rect */, false /* is_clipped */, 1.f /* opacity */,
|
| + SkXfermode::kSrcOver_Mode, 0 /* sorting_context_id */);
|
| + surface_quad->SetNew(shared_quad_state, gfx::Rect(child_size),
|
| + gfx::Rect(child_size), child_surface_id_);
|
| +
|
| + surface_factory_->SubmitCompositorFrame(child_surface_id_, std::move(frame),
|
| + base::Bind(&NoOpDrawCallback));
|
| + surface_factory_->SubmitCompositorFrame(root_surface_id_,
|
| + std::move(embed_frame),
|
| + base::Bind(&NoOpDrawCallback));
|
| display_->DrawAndSwap();
|
| } else {
|
| // For hardware draws we send the whole frame to the client so it can draw
|
| @@ -322,20 +369,26 @@ void SynchronousCompositorFrameSink::DemandDrawSw(SkCanvas* canvas) {
|
| gfx::Transform transform(gfx::Transform::kSkipInitialization);
|
| transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
|
|
|
| + // We will resize the Display to ensure it covers the entire |viewport|, so
|
| + // save it for later.
|
| + sw_viewport_for_current_draw_ = viewport;
|
| +
|
| base::AutoReset<bool> set_in_software_draw(&in_software_draw_, true);
|
| - display_->SetExternalViewport(viewport);
|
| - display_->SetExternalClip(viewport);
|
| - software_compositor_frame_sink_->SetSurfaceSize(
|
| - gfx::SkISizeToSize(canvas->getBaseLayerSize()));
|
| InvokeComposite(transform, viewport);
|
| }
|
|
|
| void SynchronousCompositorFrameSink::InvokeComposite(
|
| const gfx::Transform& transform,
|
| const gfx::Rect& viewport) {
|
| + did_swap_ = false;
|
| + // Adjust transform so that the layer compositor draws the |viewport| rect
|
| + // at its origin. The offset of the |viewport| we pass to the layer compositor
|
| + // is ignored for drawing, so its okay to not match the transform.
|
| + // TODO(danakj): Why do we pass a viewport origin and then not really use it
|
| + // (only for comparing to the viewport passed in
|
| + // SetExternalTilePriorityConstraints), surely this could be more clear?
|
| gfx::Transform adjusted_transform = transform;
|
| adjusted_transform.matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
|
| - did_swap_ = false;
|
| client_->OnDraw(adjusted_transform, viewport, in_software_draw_);
|
|
|
| if (did_swap_) {
|
|
|