blob: 50a66bbc1f97095b492a49ac2d931bc6377f2255 [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 "content/browser/compositor/gpu_process_transport_factory.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/base/histograms.h"
#include "cc/output/texture_mailbox_deleter.h"
#include "cc/output/vulkan_in_process_context_provider.h"
#include "cc/raster/single_thread_task_graph_runner.h"
#include "cc/raster/task_graph_runner.h"
#include "cc/scheduler/begin_frame_source.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "cc/surfaces/direct_compositor_frame_sink.h"
#include "cc/surfaces/display.h"
#include "cc/surfaces/display_scheduler.h"
#include "cc/surfaces/surface_manager.h"
#include "components/display_compositor/compositor_overlay_candidate_validator.h"
#include "components/display_compositor/gl_helper.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
#include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
#include "content/browser/compositor/offscreen_browser_compositor_output_surface.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/browser/compositor/software_browser_compositor_output_surface.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/host/gpu_memory_buffer_support.h"
#include "services/service_manager/runner/common/client_util.h"
#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_constants.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/compositor/layer.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_switches.h"
#if defined(USE_AURA)
#include "content/browser/compositor/mus_browser_compositor_output_surface.h"
#include "content/public/common/service_manager_connection.h"
#include "ui/aura/window_tree_host.h"
#endif
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "components/display_compositor/compositor_overlay_candidate_validator_win.h"
#include "content/browser/compositor/software_output_device_win.h"
#include "ui/gfx/win/rendering_window_manager.h"
#elif defined(USE_OZONE)
#include "components/display_compositor/compositor_overlay_candidate_validator_ozone.h"
#include "content/browser/compositor/software_output_device_ozone.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
#include "ui/ozone/public/overlay_manager_ozone.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#elif defined(USE_X11)
#include "content/browser/compositor/software_output_device_x11.h"
#elif defined(OS_MACOSX)
#include "components/display_compositor/compositor_overlay_candidate_validator_mac.h"
#include "content/browser/compositor/gpu_output_surface_mac.h"
#include "content/browser/compositor/software_output_device_mac.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/base/ui_base_switches.h"
#elif defined(OS_ANDROID)
#include "components/display_compositor/compositor_overlay_candidate_validator_android.h"
#endif
#if !defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
#include "gpu/ipc/common/gpu_surface_tracker.h"
#endif
#if defined(ENABLE_VULKAN)
#include "content/browser/compositor/vulkan_browser_compositor_output_surface.h"
#endif
using cc::ContextProvider;
using gpu::gles2::GLES2Interface;
namespace {
const int kNumRetriesBeforeSoftwareFallback = 4;
// The client_id used here should not conflict with the client_id generated
// from RenderWidgetHostImpl.
constexpr uint32_t kDefaultClientId = 0u;
bool IsUsingMus() {
return service_manager::ServiceManagerIsRemote();
}
bool IsGpuVSyncSignalSupported() {
#if defined(OS_WIN)
// TODO(stanisc): http://crbug.com/467617 Limit to Windows 8+ for now because
// of locking issue caused by waiting for VSync on Win7.
return base::win::GetVersion() >= base::win::VERSION_WIN8 &&
base::FeatureList::IsEnabled(features::kD3DVsync);
#else
return false;
#endif // defined(OS_WIN)
}
scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextCommon(
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
gpu::SurfaceHandle surface_handle,
bool need_alpha_channel,
bool need_stencil_bits,
bool support_locking,
ui::ContextProviderCommandBuffer* shared_context_provider,
ui::command_buffer_metrics::ContextType type) {
DCHECK(
content::GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor());
DCHECK(gpu_channel_host);
// This is called from a few places to create different contexts:
// - The shared main thread context (offscreen).
// - The compositor context, which is used by the browser compositor
// (offscreen) for synchronization mostly, and by the display compositor
// (onscreen, except for with mus) for actual GL drawing.
// - The compositor worker context (offscreen) used for GPU raster.
// So ask for capabilities needed by any of these cases (we can optimize by
// branching on |surface_handle| being null if these needs diverge).
//
// The default framebuffer for an offscreen context is not used, so it does
// not need alpha, stencil, depth, antialiasing. The display compositor does
// not use these things either (except for alpha when using mus for
// non-opaque ui that overlaps the system's window borders or stencil bits
// for overdraw feedback), so we can request only that when needed.
gpu::gles2::ContextCreationAttribHelper attributes;
attributes.alpha_size = need_alpha_channel ? 8 : -1;
attributes.depth_size = 0;
attributes.stencil_size = need_stencil_bits ? 8 : 0;
attributes.samples = 0;
attributes.sample_buffers = 0;
attributes.bind_generates_resource = false;
attributes.lose_context_when_out_of_memory = true;
attributes.buffer_preserved = false;
constexpr bool automatic_flushes = false;
GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
gpu::GpuStreamPriority::NORMAL, surface_handle, url, automatic_flushes,
support_locking, gpu::SharedMemoryLimits(), attributes,
shared_context_provider, type));
}
#if defined(OS_MACOSX)
bool IsCALayersDisabledFromCommandLine() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
return command_line->HasSwitch(switches::kDisableMacOverlays);
}
#endif
} // namespace
namespace content {
struct GpuProcessTransportFactory::PerCompositorData {
gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
BrowserCompositorOutputSurface* display_output_surface = nullptr;
// Either |synthetic_begin_frame_source| or |gpu_vsync_begin_frame_source| is
// valid but not both at the same time.
std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source;
std::unique_ptr<GpuVSyncBeginFrameSource> gpu_vsync_begin_frame_source;
ReflectorImpl* reflector = nullptr;
std::unique_ptr<cc::Display> display;
bool output_is_secure = false;
};
GpuProcessTransportFactory::GpuProcessTransportFactory()
: frame_sink_id_allocator_(kDefaultClientId),
task_graph_runner_(new cc::SingleThreadTaskGraphRunner),
callback_factory_(this) {
cc::SetClientNameForMetrics("Browser");
surface_manager_ = base::WrapUnique(new cc::SurfaceManager);
task_graph_runner_->Start("CompositorTileWorker1",
base::SimpleThread::Options());
#if defined(OS_WIN)
software_backing_.reset(new OutputDeviceBacking);
#endif
}
GpuProcessTransportFactory::~GpuProcessTransportFactory() {
DCHECK(per_compositor_data_.empty());
// Make sure the lost context callback doesn't try to run during destruction.
callback_factory_.InvalidateWeakPtrs();
task_graph_runner_->Shutdown();
}
std::unique_ptr<cc::SoftwareOutputDevice>
GpuProcessTransportFactory::CreateSoftwareOutputDevice(
ui::Compositor* compositor) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kHeadless))
return base::WrapUnique(new cc::SoftwareOutputDevice);
#if defined(USE_AURA)
if (service_manager::ServiceManagerIsRemote()) {
NOTREACHED();
return nullptr;
}
#endif
#if defined(OS_WIN)
return std::unique_ptr<cc::SoftwareOutputDevice>(
new SoftwareOutputDeviceWin(software_backing_.get(), compositor));
#elif defined(USE_OZONE)
return SoftwareOutputDeviceOzone::Create(compositor);
#elif defined(USE_X11)
return std::unique_ptr<cc::SoftwareOutputDevice>(
new SoftwareOutputDeviceX11(compositor));
#elif defined(OS_MACOSX)
return std::unique_ptr<cc::SoftwareOutputDevice>(
new SoftwareOutputDeviceMac(compositor));
#else
NOTREACHED();
return std::unique_ptr<cc::SoftwareOutputDevice>();
#endif
}
std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
CreateOverlayCandidateValidator(gfx::AcceleratedWidget widget) {
std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
validator;
#if defined(USE_OZONE)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableHardwareOverlays)) {
std::string enable_overlay_flag =
command_line->GetSwitchValueASCII(switches::kEnableHardwareOverlays);
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates =
ui::OzonePlatform::GetInstance()
->GetOverlayManager()
->CreateOverlayCandidates(widget);
validator.reset(
new display_compositor::CompositorOverlayCandidateValidatorOzone(
std::move(overlay_candidates), enable_overlay_flag));
}
#elif defined(OS_MACOSX)
// Overlays are only supported through the remote layer API.
if (ui::RemoteLayerAPISupported()) {
static bool overlays_disabled_at_command_line =
IsCALayersDisabledFromCommandLine();
const bool ca_layers_disabled =
overlays_disabled_at_command_line ||
GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
gpu::DISABLE_OVERLAY_CA_LAYERS);
validator.reset(
new display_compositor::CompositorOverlayCandidateValidatorMac(
ca_layers_disabled));
}
#elif defined(OS_ANDROID)
validator.reset(
new display_compositor::CompositorOverlayCandidateValidatorAndroid());
#elif defined(OS_WIN)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableHardwareOverlays)) {
validator = base::MakeUnique<
display_compositor::CompositorOverlayCandidateValidatorWin>();
}
#endif
return validator;
}
static bool ShouldCreateGpuCompositorFrameSink(ui::Compositor* compositor) {
#if defined(OS_CHROMEOS)
// Software fallback does not happen on Chrome OS.
return true;
#endif
if (IsUsingMus())
return true;
#if defined(OS_WIN)
if (::GetProp(compositor->widget(), kForceSoftwareCompositor) &&
::RemoveProp(compositor->widget(), kForceSoftwareCompositor))
return false;
#endif
return GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor();
}
void GpuProcessTransportFactory::CreateCompositorFrameSink(
base::WeakPtr<ui::Compositor> compositor) {
DCHECK(!!compositor);
PerCompositorData* data = per_compositor_data_[compositor.get()].get();
if (!data) {
data = CreatePerCompositorData(compositor.get());
} else {
// TODO(danakj): We can destroy the |data->display| and
// |data->begin_frame_source| here when the compositor destroys its
// CompositorFrameSink before calling back here.
data->display_output_surface = nullptr;
}
#if defined(OS_WIN)
gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
compositor->widget());
#endif
const bool use_vulkan = static_cast<bool>(SharedVulkanContextProvider());
const bool create_gpu_output_surface =
ShouldCreateGpuCompositorFrameSink(compositor.get());
if (create_gpu_output_surface && !use_vulkan) {
gpu::GpuChannelEstablishedCallback callback(
base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
callback_factory_.GetWeakPtr(), compositor,
create_gpu_output_surface, 0));
DCHECK(gpu_channel_factory_);
gpu_channel_factory_->EstablishGpuChannel(callback);
} else {
EstablishedGpuChannel(compositor, create_gpu_output_surface, 0, nullptr);
}
}
void GpuProcessTransportFactory::EstablishedGpuChannel(
base::WeakPtr<ui::Compositor> compositor,
bool create_gpu_output_surface,
int num_attempts,
scoped_refptr<gpu::GpuChannelHost> established_channel_host) {
if (!compositor)
return;
// The widget might have been released in the meantime.
PerCompositorDataMap::iterator it =
per_compositor_data_.find(compositor.get());
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
if (num_attempts > kNumRetriesBeforeSoftwareFallback) {
bool fatal = IsUsingMus();
#if defined(OS_CHROMEOS)
fatal = true;
#endif
LOG_IF(FATAL, fatal) << "Unable to create a UI graphics context, and "
<< "cannot use software compositing on ChromeOS.";
create_gpu_output_surface = false;
}
bool support_stencil = false;
#if defined(OS_CHROMEOS)
// ChromeOS uses surfaceless when running on a real device and stencil
// buffers can then be added dynamically so supporting them does not have an
// impact on normal usage. If we are not running on a real ChromeOS device
// but instead on a workstation for development, then stencil support is
// useful as it allows the overdraw feedback debugging feature to be used.
support_stencil = true;
#endif
#if defined(OS_WIN)
gfx::RenderingWindowManager::GetInstance()->RegisterParent(
compositor->widget());
#endif
scoped_refptr<cc::VulkanInProcessContextProvider> vulkan_context_provider =
SharedVulkanContextProvider();
scoped_refptr<ui::ContextProviderCommandBuffer> context_provider;
if (create_gpu_output_surface && !vulkan_context_provider) {
// Try to reuse existing worker context provider.
if (shared_worker_context_provider_) {
bool lost;
{
// Note: If context is lost, we delete reference after releasing the
// lock.
base::AutoLock lock(*shared_worker_context_provider_->GetLock());
lost = shared_worker_context_provider_->ContextGL()
->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
}
if (lost)
shared_worker_context_provider_ = nullptr;
}
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host;
if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
gpu_channel_host = std::move(established_channel_host);
if (!gpu_channel_host) {
shared_worker_context_provider_ = nullptr;
} else {
if (!shared_worker_context_provider_) {
bool need_alpha_channel = false;
const bool support_locking = true;
shared_worker_context_provider_ = CreateContextCommon(
gpu_channel_host, gpu::kNullSurfaceHandle, need_alpha_channel,
false /* support_stencil */, support_locking, nullptr,
ui::command_buffer_metrics::BROWSER_WORKER_CONTEXT);
// TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is
// fixed. Tracking time in BindToCurrentThread.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"125248"
" GpuProcessTransportFactory::EstablishedGpuChannel"
"::Worker"));
if (!shared_worker_context_provider_->BindToCurrentThread())
shared_worker_context_provider_ = nullptr;
}
// The |context_provider| is used for both the browser compositor and the
// display compositor. It shares resources with the worker context, so if
// we failed to make a worker context, just start over and try again.
if (shared_worker_context_provider_) {
// For mus, we create an offscreen context for a mus window, and we will
// use CommandBufferProxyImpl::TakeFrontBuffer() to take the context's
// front buffer into a mailbox, insert a sync token, and send the
// mailbox+sync to the ui service process.
gpu::SurfaceHandle surface_handle =
IsUsingMus() ? gpu::kNullSurfaceHandle : data->surface_handle;
bool need_alpha_channel = IsUsingMus();
bool support_locking = false;
context_provider = CreateContextCommon(
std::move(gpu_channel_host), surface_handle, need_alpha_channel,
support_stencil, support_locking,
shared_worker_context_provider_.get(),
ui::command_buffer_metrics::DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT);
// TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is
// fixed. Tracking time in BindToCurrentThread.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"125248"
" GpuProcessTransportFactory::EstablishedGpuChannel"
"::Compositor"));
#if defined(OS_MACOSX)
// On Mac, GpuCommandBufferMsg_SwapBuffersCompleted must be handled in
// a nested message loop during resize.
context_provider->SetDefaultTaskRunner(
ui::WindowResizeHelperMac::Get()->task_runner());
#endif
if (!context_provider->BindToCurrentThread())
context_provider = nullptr;
}
}
bool created_gpu_browser_compositor =
!!context_provider && !!shared_worker_context_provider_;
UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor",
created_gpu_browser_compositor);
if (!created_gpu_browser_compositor) {
// Try again.
gpu::GpuChannelEstablishedCallback callback(
base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
callback_factory_.GetWeakPtr(), compositor,
create_gpu_output_surface, num_attempts + 1));
DCHECK(gpu_channel_factory_);
gpu_channel_factory_->EstablishGpuChannel(callback);
return;
}
}
BrowserCompositorOutputSurface::UpdateVSyncParametersCallback vsync_callback =
base::Bind(&ui::Compositor::SetDisplayVSyncParameters, compositor);
cc::BeginFrameSource* begin_frame_source = nullptr;
GpuVSyncControl* gpu_vsync_control = nullptr;
std::unique_ptr<BrowserCompositorOutputSurface> display_output_surface;
#if defined(ENABLE_VULKAN)
std::unique_ptr<VulkanBrowserCompositorOutputSurface> vulkan_surface;
if (vulkan_context_provider) {
vulkan_surface.reset(new VulkanBrowserCompositorOutputSurface(
vulkan_context_provider, vsync_callback));
if (!vulkan_surface->Initialize(compositor.get()->widget())) {
vulkan_surface->Destroy();
vulkan_surface.reset();
} else {
display_output_surface = std::move(vulkan_surface);
}
}
#endif
if (!display_output_surface) {
if (!create_gpu_output_surface) {
display_output_surface =
base::MakeUnique<SoftwareBrowserCompositorOutputSurface>(
CreateSoftwareOutputDevice(compositor.get()), vsync_callback,
compositor->task_runner());
} else {
DCHECK(context_provider);
const auto& capabilities = context_provider->ContextCapabilities();
if (data->surface_handle == gpu::kNullSurfaceHandle) {
display_output_surface =
base::MakeUnique<OffscreenBrowserCompositorOutputSurface>(
context_provider, vsync_callback,
std::unique_ptr<
display_compositor::CompositorOverlayCandidateValidator>());
} else if (capabilities.surfaceless) {
#if defined(OS_MACOSX)
display_output_surface = base::MakeUnique<GpuOutputSurfaceMac>(
compositor->widget(), context_provider, data->surface_handle,
vsync_callback,
CreateOverlayCandidateValidator(compositor->widget()),
GetGpuMemoryBufferManager());
#else
auto gpu_output_surface =
base::MakeUnique<GpuSurfacelessBrowserCompositorOutputSurface>(
context_provider, data->surface_handle, vsync_callback,
CreateOverlayCandidateValidator(compositor->widget()),
GL_TEXTURE_2D, GL_RGB,
display::DisplaySnapshot::PrimaryFormat(),
GetGpuMemoryBufferManager());
gpu_vsync_control = gpu_output_surface.get();
display_output_surface = std::move(gpu_output_surface);
#endif
} else {
std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
validator;
const bool use_mus = IsUsingMus();
#if !defined(OS_MACOSX)
// Overlays are only supported on surfaceless output surfaces on Mac.
if (!use_mus)
validator = CreateOverlayCandidateValidator(compositor->widget());
#endif
if (!use_mus) {
auto gpu_output_surface =
base::MakeUnique<GpuBrowserCompositorOutputSurface>(
context_provider, vsync_callback, std::move(validator));
gpu_vsync_control = gpu_output_surface.get();
display_output_surface = std::move(gpu_output_surface);
} else {
#if defined(USE_AURA)
aura::WindowTreeHost* host =
aura::WindowTreeHost::GetForAcceleratedWidget(
compositor->widget());
auto mus_output_surface =
base::MakeUnique<MusBrowserCompositorOutputSurface>(
host->window(), context_provider, GetGpuMemoryBufferManager(),
vsync_callback, std::move(validator));
// We use the ExternalBeginFrameSource provided by the output surface
// instead of our own synthetic one.
begin_frame_source = mus_output_surface->GetBeginFrameSource();
DCHECK(begin_frame_source);
display_output_surface = std::move(mus_output_surface);
#else
NOTREACHED();
#endif
}
}
}
}
std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source;
std::unique_ptr<GpuVSyncBeginFrameSource> gpu_vsync_begin_frame_source;
if (!begin_frame_source) {
if (!compositor->GetRendererSettings().disable_display_vsync) {
if (gpu_vsync_control && IsGpuVSyncSignalSupported()) {
gpu_vsync_begin_frame_source =
base::MakeUnique<GpuVSyncBeginFrameSource>(gpu_vsync_control);
begin_frame_source = gpu_vsync_begin_frame_source.get();
} else {
synthetic_begin_frame_source =
base::MakeUnique<cc::DelayBasedBeginFrameSource>(
base::MakeUnique<cc::DelayBasedTimeSource>(
compositor->task_runner().get()));
begin_frame_source = synthetic_begin_frame_source.get();
}
} else {
synthetic_begin_frame_source =
base::MakeUnique<cc::BackToBackBeginFrameSource>(
base::MakeUnique<cc::DelayBasedTimeSource>(
compositor->task_runner().get()));
begin_frame_source = synthetic_begin_frame_source.get();
}
}
if (data->reflector)
data->reflector->OnSourceSurfaceReady(data->display_output_surface);
#if defined(OS_WIN)
gfx::RenderingWindowManager::GetInstance()->DoSetParentOnChild(
compositor->widget());
#endif
std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
compositor->task_runner().get(),
display_output_surface->capabilities().max_frames_pending));
// The Display owns and uses the |display_output_surface| created above.
data->display = base::MakeUnique<cc::Display>(
HostSharedBitmapManager::current(), GetGpuMemoryBufferManager(),
compositor->GetRendererSettings(), compositor->frame_sink_id(),
begin_frame_source, std::move(display_output_surface),
std::move(scheduler), base::MakeUnique<cc::TextureMailboxDeleter>(
compositor->task_runner().get()));
// Note that we are careful not to destroy prior BeginFrameSource objects
// until we have reset |data->display|.
data->synthetic_begin_frame_source = std::move(synthetic_begin_frame_source);
data->gpu_vsync_begin_frame_source = std::move(gpu_vsync_begin_frame_source);
// The |delegated_output_surface| is given back to the compositor, it
// delegates to the Display as its root surface. Importantly, it shares the
// same ContextProvider as the Display's output surface.
auto compositor_frame_sink =
vulkan_context_provider
? base::MakeUnique<cc::DirectCompositorFrameSink>(
compositor->frame_sink_id(), surface_manager_.get(),
data->display.get(),
static_cast<scoped_refptr<cc::VulkanContextProvider>>(
vulkan_context_provider))
: base::MakeUnique<cc::DirectCompositorFrameSink>(
compositor->frame_sink_id(), surface_manager_.get(),
data->display.get(), context_provider,
shared_worker_context_provider_, GetGpuMemoryBufferManager(),
HostSharedBitmapManager::current());
data->display->Resize(compositor->size());
data->display->SetOutputIsSecure(data->output_is_secure);
compositor->SetCompositorFrameSink(std::move(compositor_frame_sink));
}
std::unique_ptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
ui::Compositor* source_compositor,
ui::Layer* target_layer) {
PerCompositorData* source_data =
per_compositor_data_[source_compositor].get();
DCHECK(source_data);
std::unique_ptr<ReflectorImpl> reflector(
new ReflectorImpl(source_compositor, target_layer));
source_data->reflector = reflector.get();
if (auto* source_surface = source_data->display_output_surface)
reflector->OnSourceSurfaceReady(source_surface);
return std::move(reflector);
}
void GpuProcessTransportFactory::RemoveReflector(ui::Reflector* reflector) {
ReflectorImpl* reflector_impl = static_cast<ReflectorImpl*>(reflector);
PerCompositorData* data =
per_compositor_data_[reflector_impl->mirrored_compositor()].get();
DCHECK(data);
data->reflector->Shutdown();
data->reflector = nullptr;
}
void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
#if !defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
if (data->surface_handle)
gpu::GpuSurfaceTracker::Get()->RemoveSurface(data->surface_handle);
#endif
per_compositor_data_.erase(it);
if (per_compositor_data_.empty()) {
// Destroying the GLHelper may cause some async actions to be cancelled,
// causing things to request a new GLHelper. Due to crbug.com/176091 the
// GLHelper created in this case would be lost/leaked if we just reset()
// on the |gl_helper_| variable directly. So instead we call reset() on a
// local std::unique_ptr.
std::unique_ptr<display_compositor::GLHelper> helper =
std::move(gl_helper_);
// If there are any observer left at this point, make sure they clean up
// before we destroy the GLHelper.
for (auto& observer : observer_list_)
observer.OnLostResources();
helper.reset();
DCHECK(!gl_helper_) << "Destroying the GLHelper should not cause a new "
"GLHelper to be created.";
}
#if defined(OS_WIN)
gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
compositor->widget());
#endif
}
bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
uint32_t GpuProcessTransportFactory::GetImageTextureTarget(
gfx::BufferFormat format,
gfx::BufferUsage usage) {
return gpu::GetImageTextureTarget(format, usage);
}
gpu::GpuMemoryBufferManager*
GpuProcessTransportFactory::GetGpuMemoryBufferManager() {
return gpu_channel_factory_->GetGpuMemoryBufferManager();
}
cc::TaskGraphRunner* GpuProcessTransportFactory::GetTaskGraphRunner() {
return task_graph_runner_.get();
}
ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() {
return this;
}
ui::ContextFactoryPrivate*
GpuProcessTransportFactory::GetContextFactoryPrivate() {
return this;
}
cc::FrameSinkId GpuProcessTransportFactory::AllocateFrameSinkId() {
return frame_sink_id_allocator_.NextFrameSinkId();
}
void GpuProcessTransportFactory::SetDisplayVisible(ui::Compositor* compositor,
bool visible) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
// The compositor will always SetVisible on the Display once it is set up, so
// do nothing if |display| is null.
if (data->display)
data->display->SetVisible(visible);
}
void GpuProcessTransportFactory::ResizeDisplay(ui::Compositor* compositor,
const gfx::Size& size) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
if (data->display)
data->display->Resize(size);
}
void GpuProcessTransportFactory::SetDisplayColorSpace(
ui::Compositor* compositor,
const gfx::ColorSpace& color_space) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
// The compositor will always SetColorSpace on the Display once it is set up,
// so do nothing if |display| is null.
if (data->display)
data->display->SetColorSpace(color_space);
}
void GpuProcessTransportFactory::SetAuthoritativeVSyncInterval(
ui::Compositor* compositor,
base::TimeDelta interval) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
if (data->synthetic_begin_frame_source)
data->synthetic_begin_frame_source->SetAuthoritativeVSyncInterval(interval);
}
void GpuProcessTransportFactory::SetDisplayVSyncParameters(
ui::Compositor* compositor,
base::TimeTicks timebase,
base::TimeDelta interval) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
if (data->synthetic_begin_frame_source) {
data->synthetic_begin_frame_source->OnUpdateVSyncParameters(timebase,
interval);
} else if (data->gpu_vsync_begin_frame_source) {
data->gpu_vsync_begin_frame_source->OnVSync(timebase, interval);
}
}
void GpuProcessTransportFactory::SetOutputIsSecure(ui::Compositor* compositor,
bool secure) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
data->output_is_secure = secure;
if (data->display)
data->display->SetOutputIsSecure(secure);
}
void GpuProcessTransportFactory::AddObserver(
ui::ContextFactoryObserver* observer) {
observer_list_.AddObserver(observer);
}
void GpuProcessTransportFactory::RemoveObserver(
ui::ContextFactoryObserver* observer) {
observer_list_.RemoveObserver(observer);
}
cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() {
return surface_manager_.get();
}
display_compositor::GLHelper* GpuProcessTransportFactory::GetGLHelper() {
if (!gl_helper_ && !per_compositor_data_.empty()) {
scoped_refptr<cc::ContextProvider> provider =
SharedMainThreadContextProvider();
if (provider.get())
gl_helper_.reset(new display_compositor::GLHelper(
provider->ContextGL(), provider->ContextSupport()));
}
return gl_helper_.get();
}
void GpuProcessTransportFactory::SetGpuChannelEstablishFactory(
gpu::GpuChannelEstablishFactory* factory) {
DCHECK(!gpu_channel_factory_ || !factory);
gpu_channel_factory_ = factory;
}
#if defined(OS_MACOSX)
void GpuProcessTransportFactory::SetCompositorSuspendedForRecycle(
ui::Compositor* compositor,
bool suspended) {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second.get();
DCHECK(data);
if (data->display_output_surface)
data->display_output_surface->SetSurfaceSuspendedForRecycle(suspended);
}
#endif
scoped_refptr<cc::ContextProvider>
GpuProcessTransportFactory::SharedMainThreadContextProvider() {
if (shared_main_thread_contexts_)
return shared_main_thread_contexts_;
if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
return nullptr;
DCHECK(gpu_channel_factory_);
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
gpu_channel_factory_->EstablishGpuChannelSync();
if (!gpu_channel_host)
return nullptr;
// We need a separate context from the compositor's so that skia and gl_helper
// don't step on each other.
bool need_alpha_channel = false;
bool support_locking = false;
shared_main_thread_contexts_ = CreateContextCommon(
std::move(gpu_channel_host), gpu::kNullSurfaceHandle, need_alpha_channel,
false, support_locking, nullptr,
ui::command_buffer_metrics::BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
shared_main_thread_contexts_->SetLostContextCallback(base::Bind(
&GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback,
callback_factory_.GetWeakPtr()));
// TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is
// fixed. Tracking time in BindToCurrentThread.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"125248"
" GpuProcessTransportFactory::SharedMainThreadContextProvider"));
if (!shared_main_thread_contexts_->BindToCurrentThread())
shared_main_thread_contexts_ = nullptr;
return shared_main_thread_contexts_;
}
GpuProcessTransportFactory::PerCompositorData*
GpuProcessTransportFactory::CreatePerCompositorData(
ui::Compositor* compositor) {
DCHECK(!per_compositor_data_[compositor]);
gfx::AcceleratedWidget widget = compositor->widget();
auto data = base::MakeUnique<PerCompositorData>();
if (widget == gfx::kNullAcceleratedWidget) {
data->surface_handle = gpu::kNullSurfaceHandle;
} else {
#if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
data->surface_handle = widget;
#else
gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
data->surface_handle = tracker->AddSurfaceForNativeWidget(widget);
#endif
}
PerCompositorData* return_ptr = data.get();
per_compositor_data_[compositor] = std::move(data);
return return_ptr;
}
void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
callback_factory_.GetWeakPtr()));
}
void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
LOG(ERROR) << "Lost UI shared context.";
// Keep old resources around while we call the observers, but ensure that
// new resources are created if needed.
// Kill shared contexts for both threads in tandem so they are always in
// the same share group.
scoped_refptr<cc::ContextProvider> lost_shared_main_thread_contexts =
shared_main_thread_contexts_;
shared_main_thread_contexts_ = NULL;
std::unique_ptr<display_compositor::GLHelper> lost_gl_helper =
std::move(gl_helper_);
for (auto& observer : observer_list_)
observer.OnLostResources();
// Kill things that use the shared context before killing the shared context.
lost_gl_helper.reset();
lost_shared_main_thread_contexts = NULL;
}
scoped_refptr<cc::VulkanInProcessContextProvider>
GpuProcessTransportFactory::SharedVulkanContextProvider() {
if (!shared_vulkan_context_provider_initialized_) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableVulkan)) {
shared_vulkan_context_provider_ =
cc::VulkanInProcessContextProvider::Create();
}
shared_vulkan_context_provider_initialized_ = true;
}
return shared_vulkan_context_provider_;
}
} // namespace content