blob: 36a4f1f88a8faaae72f73a8a9d9774654c281287 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/hardware_renderer.h"
#include "android_webview/browser/aw_gl_surface.h"
#include "android_webview/browser/aw_render_thread_context_provider.h"
#include "android_webview/browser/child_frame.h"
#include "android_webview/browser/deferred_gpu_command_service.h"
#include "android_webview/browser/parent_compositor_draw_constraints.h"
#include "android_webview/browser/parent_output_surface.h"
#include "android_webview/browser/shared_renderer_state.h"
#include "android_webview/public/browser/draw_gl.h"
#include "base/auto_reset.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/output_surface.h"
#include "cc/output/renderer_settings.h"
#include "cc/quads/shared_quad_state.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"
#include "gpu/command_buffer/client/gl_in_process_context.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/transform.h"
#include "ui/gl/gl_bindings.h"
namespace android_webview {
HardwareRenderer::HardwareRenderer(SharedRendererState* state)
: shared_renderer_state_(state),
last_egl_context_(eglGetCurrentContext()),
gl_surface_(new AwGLSurface),
output_surface_(NULL) {
DCHECK(last_egl_context_);
cc::RendererSettings settings;
// Should be kept in sync with compositor_impl_android.cc.
settings.allow_antialiasing = false;
settings.highp_threshold_min = 2048;
// Webview does not own the surface so should not clear it.
settings.should_clear_root_render_pass = false;
surface_manager_.reset(new cc::SurfaceManager);
surface_id_allocator_.reset(new cc::SurfaceIdAllocator(1));
display_.reset(new cc::Display(this, surface_manager_.get(), nullptr, nullptr,
settings));
surface_factory_.reset(new cc::SurfaceFactory(surface_manager_.get(), this));
}
HardwareRenderer::~HardwareRenderer() {
// Must reset everything before |surface_factory_| to ensure all
// resources are returned before resetting.
if (!root_id_.is_null())
surface_factory_->Destroy(root_id_);
if (!child_id_.is_null())
surface_factory_->Destroy(child_id_);
display_.reset();
surface_factory_.reset();
// Reset draw constraints.
shared_renderer_state_->PostExternalDrawConstraintsToChildCompositorOnRT(
ParentCompositorDrawConstraints());
}
void HardwareRenderer::CommitFrame() {
TRACE_EVENT0("android_webview", "CommitFrame");
scroll_offset_ = shared_renderer_state_->GetScrollOffsetOnRT();
{
scoped_ptr<ChildFrame> child_frame =
shared_renderer_state_->PassCompositorFrameOnRT();
if (!child_frame.get())
return;
child_frame_ = child_frame.Pass();
}
scoped_ptr<cc::CompositorFrame> frame = child_frame_->frame.Pass();
DCHECK(frame.get());
DCHECK(!frame->gl_frame_data);
// On Android we put our browser layers in physical pixels and set our
// browser CC device_scale_factor to 1, so suppress the transform between
// DIP and pixels.
frame->delegated_frame_data->device_scale_factor = 1.0f;
gfx::Size frame_size =
frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
bool size_changed = frame_size != frame_size_;
frame_size_ = frame_size;
if (child_id_.is_null() || size_changed) {
if (!child_id_.is_null())
surface_factory_->Destroy(child_id_);
child_id_ = surface_id_allocator_->GenerateId();
surface_factory_->Create(child_id_);
}
surface_factory_->SubmitFrame(child_id_, frame.Pass(),
cc::SurfaceFactory::DrawCallback());
}
void HardwareRenderer::DrawGL(bool stencil_enabled,
int framebuffer_binding_ext,
AwDrawGLInfo* draw_info) {
TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
// We need to watch if the current Android context has changed and enforce
// a clean-up in the compositor.
EGLContext current_context = eglGetCurrentContext();
DCHECK(current_context) << "DrawGL called without EGLContext";
// TODO(boliu): Handle context loss.
if (last_egl_context_ != current_context)
DLOG(WARNING) << "EGLContextChanged";
gfx::Transform transform(gfx::Transform::kSkipInitialization);
transform.matrix().setColMajorf(draw_info->transform);
transform.Translate(scroll_offset_.x(), scroll_offset_.y());
gfx::Size viewport(draw_info->width, draw_info->height);
// Need to post the new transform matrix back to child compositor
// because there is no onDraw during a Render Thread animation, and child
// compositor might not have the tiles rasterized as the animation goes on.
ParentCompositorDrawConstraints draw_constraints(
draw_info->is_layer, transform, viewport.IsEmpty());
if (!child_frame_.get() || draw_constraints.NeedUpdate(*child_frame_)) {
shared_renderer_state_->PostExternalDrawConstraintsToChildCompositorOnRT(
draw_constraints);
}
if (child_id_.is_null())
return;
gfx::Rect clip(draw_info->clip_left, draw_info->clip_top,
draw_info->clip_right - draw_info->clip_left,
draw_info->clip_bottom - draw_info->clip_top);
// Create a frame with a single SurfaceDrawQuad referencing the child
// Surface and transformed using the given transform.
scoped_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
render_pass->SetAll(cc::RenderPassId(1, 1), gfx::Rect(viewport), clip,
gfx::Transform(), true);
cc::SharedQuadState* quad_state =
render_pass->CreateAndAppendSharedQuadState();
quad_state->quad_to_target_transform = transform;
quad_state->quad_layer_bounds = frame_size_;
quad_state->visible_quad_layer_rect = gfx::Rect(frame_size_);
quad_state->opacity = 1.f;
cc::SurfaceDrawQuad* surface_quad =
render_pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
surface_quad->SetNew(quad_state, gfx::Rect(quad_state->quad_layer_bounds),
gfx::Rect(quad_state->quad_layer_bounds), child_id_);
scoped_ptr<cc::DelegatedFrameData> delegated_frame(
new cc::DelegatedFrameData);
delegated_frame->render_pass_list.push_back(render_pass.Pass());
scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
frame->delegated_frame_data = delegated_frame.Pass();
if (root_id_.is_null()) {
root_id_ = surface_id_allocator_->GenerateId();
surface_factory_->Create(root_id_);
display_->SetSurfaceId(root_id_, 1.f);
}
surface_factory_->SubmitFrame(root_id_, frame.Pass(),
cc::SurfaceFactory::DrawCallback());
display_->Resize(viewport);
gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
if (!output_surface_) {
scoped_refptr<cc::ContextProvider> context_provider =
AwRenderThreadContextProvider::Create(
gl_surface_, DeferredGpuCommandService::GetInstance());
scoped_ptr<ParentOutputSurface> output_surface_holder(
new ParentOutputSurface(context_provider));
output_surface_ = output_surface_holder.get();
display_->Initialize(output_surface_holder.Pass(), nullptr);
}
output_surface_->SetExternalStencilTest(stencil_enabled);
display_->SetExternalClip(clip);
display_->DrawAndSwap();
gl_surface_->ResetBackingFrameBufferObject();
}
void HardwareRenderer::ReturnResources(
const cc::ReturnedResourceArray& resources) {
shared_renderer_state_->InsertReturnedResourcesOnRT(resources);
}
} // namespace android_webview