blob: 5f5b2cca91b255a63b4c0df6270fe0f7eee1659a [file] [log] [blame]
// Copyright 2015 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 "ui/aura/mus/mus_context_factory.h"
#include "base/bind.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "components/viz/common/gpu/context_provider.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/scheduling_priority.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "services/ws/public/cpp/gpu/command_buffer_metrics.h"
#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window_tree_host.h"
namespace aura {
namespace {
constexpr int32_t kContextStreamId = 0;
// TODO(crbug.com/947271): If MusContextFactory is used for non-priviledged
// clients then stream priority should be configurable so non-priviledged
// clients use a lower priority.
constexpr gpu::SchedulingPriority kContextStreamPriority =
gpu::SchedulingPriority::kHigh;
constexpr ws::command_buffer_metrics::ContextType kContextType =
ws::command_buffer_metrics::ContextType::MUS_CLIENT;
// URL used to identify contexts providers created here.
const char* kContextUrl = "chrome://gpu/MusContextFactory";
// TODO(kylechar): Refactor this function into another target. Also remove the
// DEPS entry for gpu/command_buffer/client/gles2_interface.h at the same time.
bool IsContextLost(viz::ContextProvider* context_provider) {
if (!context_provider)
return false;
return context_provider->ContextGL()->GetGraphicsResetStatusKHR() !=
GL_NO_ERROR;
}
// There is no software compositing fallback available on Chrome OS and we don't
// expect fatal errors to happen. If there is a fatal failure it's not expected
// to be recoverable so crash instead of drawing nothing.
void OnFatalContextCreationError() {
LOG(FATAL) << "Unexpected fatal context failure";
}
} // namespace
MusContextFactory::MusContextFactory(
gpu::GpuChannelEstablishFactory* gpu_channel_establish_factory)
: gpu_channel_establish_factory_(gpu_channel_establish_factory),
shared_worker_context_provider_factory_(kContextStreamId,
kContextStreamPriority,
GURL(kContextUrl),
kContextType) {}
MusContextFactory::~MusContextFactory() = default;
void MusContextFactory::ResetContextProviders() {
shared_worker_context_provider_factory_.Reset();
main_context_provider_.reset();
}
gpu::ContextResult MusContextFactory::ValidateMainContextProvider(
scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
if (IsContextLost(main_context_provider_.get()))
main_context_provider_.reset();
if (main_context_provider_)
return gpu::ContextResult::kSuccess;
if (!gpu_channel)
return gpu::ContextResult::kFatalFailure;
// This is for an offscreen context for a mus client, so the default
// framebuffer doesn't need alpha, depth, stencil or antialiasing.
gpu::ContextCreationAttribs attributes;
attributes.alpha_size = -1;
attributes.depth_size = 0;
attributes.stencil_size = 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;
attributes.enable_gles2_interface = true;
attributes.enable_raster_interface = false;
attributes.enable_oop_rasterization = false;
// TODO(kylechar): Share main thread context creation parameters with
// VizProcessTransportFactory.
main_context_provider_ =
base::MakeRefCounted<ws::ContextProviderCommandBuffer>(
std::move(gpu_channel), GetGpuMemoryBufferManager(), kContextStreamId,
kContextStreamPriority, gpu::kNullSurfaceHandle, GURL(kContextUrl),
/*automatic_flushes=*/false,
/*support_locking=*/false,
/*support_grcontext=*/false, gpu::SharedMemoryLimits(), attributes,
kContextType);
gpu::ContextResult context_result =
main_context_provider_->BindToCurrentThread();
// If this is a transient error then we'll retry.
if (context_result != gpu::ContextResult::kSuccess)
main_context_provider_.reset();
return context_result;
}
void MusContextFactory::OnEstablishedGpuChannel(
base::WeakPtr<ui::Compositor> compositor,
scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
if (!compositor)
return;
WindowTreeHost* host =
WindowTreeHost::GetForAcceleratedWidget(compositor->widget());
WindowPortMus* window_port = WindowPortMus::Get(host->window());
// There should always be a WindowPortMus for WindowTreeHost::window(). If
// there isn't, it likely means we got the wrong WindowTreeHost.
//
// TODO(sky): make Compositor extend SupportsUserData so that this code
// doesn't need to use GetForAcceleratedWidget().
CHECK(window_port);
DCHECK_EQ(host->compositor(), compositor.get());
auto context_result = ValidateMainContextProvider(gpu_channel);
if (gpu::IsFatalOrSurfaceFailure(context_result)) {
OnFatalContextCreationError();
} else if (context_result != gpu::ContextResult::kSuccess) {
// Try again for transient failures until kSuccess or kFatalFailure.
gpu_channel_establish_factory_->EstablishGpuChannel(
base::BindOnce(&MusContextFactory::OnEstablishedGpuChannel,
weak_ptr_factory_.GetWeakPtr(), compositor));
return;
}
auto worker_context_result = shared_worker_context_provider_factory_.Validate(
std::move(gpu_channel), GetGpuMemoryBufferManager());
if (gpu::IsFatalOrSurfaceFailure(worker_context_result)) {
OnFatalContextCreationError();
} else if (worker_context_result != gpu::ContextResult::kSuccess) {
// Try again for transient failures until kSuccess or kFatalFailure.
gpu_channel_establish_factory_->EstablishGpuChannel(
base::BindOnce(&MusContextFactory::OnEstablishedGpuChannel,
weak_ptr_factory_.GetWeakPtr(), compositor));
return;
}
window_port->CreateLayerTreeFrameSink(
main_context_provider_,
shared_worker_context_provider_factory_.provider(),
GetGpuMemoryBufferManager());
}
void MusContextFactory::CreateLayerTreeFrameSink(
base::WeakPtr<ui::Compositor> compositor) {
gpu_channel_establish_factory_->EstablishGpuChannel(
base::BindOnce(&MusContextFactory::OnEstablishedGpuChannel,
weak_ptr_factory_.GetWeakPtr(), compositor));
}
scoped_refptr<viz::ContextProvider>
MusContextFactory::SharedMainThreadContextProvider() {
auto context_result = gpu::ContextResult::kTransientFailure;
while (context_result != gpu::ContextResult::kSuccess) {
context_result = ValidateMainContextProvider(
gpu_channel_establish_factory_->EstablishGpuChannelSync());
if (gpu::IsFatalOrSurfaceFailure(context_result))
OnFatalContextCreationError();
}
return main_context_provider_;
}
scoped_refptr<viz::RasterContextProvider>
MusContextFactory::SharedMainThreadRasterContextProvider() {
// Exo is currently the only client requesting this context provider.
// Exo does not request this context in MUS.
NOTREACHED();
return nullptr;
}
void MusContextFactory::RemoveCompositor(ui::Compositor* compositor) {
// No per compositor state is kept so there is nothing to do here.
}
gpu::GpuMemoryBufferManager* MusContextFactory::GetGpuMemoryBufferManager() {
return gpu_channel_establish_factory_->GetGpuMemoryBufferManager();
}
cc::TaskGraphRunner* MusContextFactory::GetTaskGraphRunner() {
return raster_thread_helper_.task_graph_runner();
}
bool MusContextFactory::SyncTokensRequiredForDisplayCompositor() {
// The display compositor is out-of-process, so must be using a different
// context from the UI compositor, and requires synchronization between them.
return true;
}
} // namespace aura