blob: 6177aaeb404dd67a5997a5f75f5bce565a6d5ddd [file] [log] [blame]
// Copyright 2017 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 "components/viz/service/display_embedder/gpu_display_provider.h"
#include <utility>
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/base/switches.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/display_embedder/external_begin_frame_controller_impl.h"
#include "components/viz/service/display_embedder/gl_output_surface.h"
#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "components/viz/service/display_embedder/software_output_surface.h"
#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
#include "gpu/command_buffer/service/image_factory.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "ui/base/ui_base_switches.h"
#if defined(OS_WIN)
#include "components/viz/service/display_embedder/gl_output_surface_win.h"
#include "components/viz/service/display_embedder/software_output_device_win.h"
#endif
#if defined(OS_MACOSX)
#include "components/viz/service/display_embedder/gl_output_surface_mac.h"
#include "components/viz/service/display_embedder/software_output_device_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
#endif
#if defined(USE_X11)
#include "components/viz/service/display_embedder/software_output_device_x11.h"
#endif
#if defined(USE_OZONE)
#include "components/viz/service/display_embedder/gl_output_surface_ozone.h"
#include "components/viz/service/display_embedder/software_output_device_ozone.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#endif
namespace {
gpu::ImageFactory* GetImageFactory(gpu::GpuChannelManager* channel_manager) {
auto* buffer_factory = channel_manager->gpu_memory_buffer_factory();
return buffer_factory ? buffer_factory->AsImageFactory() : nullptr;
}
} // namespace
namespace viz {
GpuDisplayProvider::GpuDisplayProvider(
uint32_t restart_id,
GpuServiceImpl* gpu_service_impl,
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
gpu::GpuChannelManager* gpu_channel_manager,
bool headless,
bool wait_for_all_pipeline_stages_before_draw)
: restart_id_(restart_id),
gpu_service_impl_(gpu_service_impl),
gpu_service_(std::move(gpu_service)),
gpu_channel_manager_delegate_(gpu_channel_manager->delegate()),
gpu_memory_buffer_manager_(
std::make_unique<InProcessGpuMemoryBufferManager>(
gpu_channel_manager)),
image_factory_(GetImageFactory(gpu_channel_manager)),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
headless_(headless),
wait_for_all_pipeline_stages_before_draw_(
wait_for_all_pipeline_stages_before_draw) {
DCHECK_NE(restart_id_, BeginFrameSource::kNotRestartableId);
}
GpuDisplayProvider::~GpuDisplayProvider() = default;
std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) {
BeginFrameSource* display_begin_frame_source = nullptr;
std::unique_ptr<DelayBasedBeginFrameSource> synthetic_begin_frame_source;
if (external_begin_frame_controller) {
display_begin_frame_source =
external_begin_frame_controller->begin_frame_source();
} else {
synthetic_begin_frame_source = std::make_unique<DelayBasedBeginFrameSource>(
std::make_unique<DelayBasedTimeSource>(task_runner_.get()),
restart_id_);
display_begin_frame_source = synthetic_begin_frame_source.get();
}
// TODO(penghuang): Merge two output surfaces into one when GLRenderer and
// software compositor is removed.
std::unique_ptr<OutputSurface> output_surface;
SkiaOutputSurface* skia_output_surface = nullptr;
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle), task_runner_);
} else if (renderer_settings.use_skia_renderer &&
renderer_settings.use_skia_deferred_display_list) {
#if defined(OS_MACOSX) || defined(OS_WIN)
// TODO(penghuang): Support DDL for all platforms.
NOTIMPLEMENTED();
// Workaround compile error: private field 'gpu_service_impl_' is not used.
ALLOW_UNUSED_LOCAL(gpu_service_impl_);
#else
// Create an offscreen context_provider for SkiaOutputSurfaceImpl, because
// SkiaRenderer still needs it to draw RenderPass into a texture.
// TODO(penghuang): remove this context when we figure out how to use DDL
// to draw RenderPass. https://crbug.com/825901
auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
gpu_service_, gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
image_factory_, gpu_channel_manager_delegate_,
gpu::SharedMemoryLimits());
auto result = context_provider->BindToCurrentThread();
CHECK_EQ(result, gpu::ContextResult::kSuccess);
output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
gpu_service_impl_, surface_handle, std::move(context_provider),
synthetic_begin_frame_source.get());
skia_output_surface = static_cast<SkiaOutputSurface*>(output_surface.get());
#endif
} else {
scoped_refptr<VizProcessContextProvider> context_provider;
// Retry creating and binding |context_provider| on transient failures.
gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure;
while (context_result != gpu::ContextResult::kSuccess) {
context_provider = base::MakeRefCounted<VizProcessContextProvider>(
gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
image_factory_, gpu_channel_manager_delegate_,
gpu::SharedMemoryLimits());
context_result = context_provider->BindToCurrentThread();
// TODO(crbug.com/819474): Don't crash here, instead fallback to software
// compositing for fatal failures.
CHECK_NE(context_result, gpu::ContextResult::kFatalFailure);
}
if (context_provider->ContextCapabilities().surfaceless) {
#if defined(USE_OZONE)
output_surface = std::make_unique<GLOutputSurfaceOzone>(
std::move(context_provider), surface_handle,
synthetic_begin_frame_source.get(), gpu_memory_buffer_manager_.get(),
GL_TEXTURE_2D, GL_BGRA_EXT);
#elif defined(OS_MACOSX)
output_surface = std::make_unique<GLOutputSurfaceMac>(
std::move(context_provider), surface_handle,
synthetic_begin_frame_source.get(), gpu_memory_buffer_manager_.get(),
renderer_settings.allow_overlays);
#else
NOTREACHED();
#endif
} else {
#if defined(OS_WIN)
const auto& capabilities = context_provider->ContextCapabilities();
const bool use_overlays =
capabilities.dc_layers && capabilities.use_dc_overlays_for_video;
output_surface = std::make_unique<GLOutputSurfaceWin>(
std::move(context_provider), synthetic_begin_frame_source.get(),
use_overlays);
#else
output_surface = std::make_unique<GLOutputSurface>(
std::move(context_provider), synthetic_begin_frame_source.get());
#endif
}
}
int max_frames_pending = output_surface->capabilities().max_frames_pending;
DCHECK_GT(max_frames_pending, 0);
auto scheduler = std::make_unique<DisplayScheduler>(
display_begin_frame_source, task_runner_.get(), max_frames_pending,
wait_for_all_pipeline_stages_before_draw_);
// The ownership of the BeginFrameSource is transferred to the caller.
*out_begin_frame_source = std::move(synthetic_begin_frame_source);
return std::make_unique<Display>(
ServerSharedBitmapManager::current(), renderer_settings, frame_sink_id,
std::move(output_surface), std::move(scheduler), task_runner_,
skia_output_surface);
}
std::unique_ptr<SoftwareOutputDevice>
GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
gpu::SurfaceHandle surface_handle) {
if (headless_)
return std::make_unique<SoftwareOutputDevice>();
#if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
gfx::AcceleratedWidget widget = surface_handle;
#endif
#if defined(OS_WIN)
if (!output_device_backing_)
output_device_backing_ = std::make_unique<OutputDeviceBacking>();
return std::make_unique<SoftwareOutputDeviceWin>(
output_device_backing_.get(), widget,
/*force_disable_hwnd_composited=*/true);
#elif defined(OS_MACOSX)
// TODO(crbug.com/730660): What do we do to get something we can draw to? Can
// we use an IO surface? Can we use CA layers and overlays like we do for gpu
// compositing? See https://crrev.com/c/792295 to no longer have
// GpuSurfaceTracker. Part of the SoftwareOutputDeviceMac::EndPaint probably
// needs to move to the browser process, and we need to set up transport of an
// IO surface to here?
NOTIMPLEMENTED();
(void)widget;
return nullptr;
#elif defined(OS_ANDROID)
// Android does not do software compositing, so we can't get here.
NOTREACHED();
return nullptr;
#elif defined(USE_OZONE)
ui::SurfaceFactoryOzone* factory =
ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
factory->CreateCanvasForWidget(widget);
CHECK(surface_ozone);
return std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone));
#elif defined(USE_X11)
return std::make_unique<SoftwareOutputDeviceX11>(widget);
#endif
}
} // namespace viz