blob: 49a08a3bf49b162b2a0762e90e67ab94230b00fe [file] [log] [blame]
// Copyright (c) 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 "gpu/ipc/service/raster_command_buffer_stub.h"
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/service/gl_context_virtual.h"
#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
#include "gpu/command_buffer/service/image_manager.h"
#include "gpu/command_buffer/service/logger.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/raster_decoder.h"
#include "gpu/command_buffer/service/service_utils.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/command_buffer/service/transfer_buffer_manager.h"
#include "gpu/config/gpu_crash_keys.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "gpu/ipc/service/gpu_channel.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 "gpu/ipc/service/gpu_memory_manager.h"
#include "gpu/ipc/service/gpu_memory_tracking.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_workarounds.h"
#include "ui/gl/init/gl_factory.h"
#if defined(OS_WIN)
#include "base/win/win_util.h"
#endif
#if defined(OS_ANDROID)
#include "gpu/ipc/service/stream_texture_android.h"
#endif
namespace gpu {
RasterCommandBufferStub::RasterCommandBufferStub(
GpuChannel* channel,
const GPUCreateCommandBufferConfig& init_params,
CommandBufferId command_buffer_id,
SequenceId sequence_id,
int32_t stream_id,
int32_t route_id)
: CommandBufferStub(channel,
init_params,
command_buffer_id,
sequence_id,
stream_id,
route_id) {}
RasterCommandBufferStub::~RasterCommandBufferStub() {}
gpu::ContextResult RasterCommandBufferStub::Initialize(
CommandBufferStub* share_command_buffer_stub,
const GPUCreateCommandBufferConfig& init_params,
std::unique_ptr<base::SharedMemory> shared_state_shm) {
#if defined(OS_FUCHSIA)
// TODO(crbug.com/707031): Implement this.
NOTIMPLEMENTED();
LOG(ERROR) << "ContextResult::kFatalFailure: no fuchsia support";
return gpu::ContextResult::kFatalFailure;
#else
TRACE_EVENT0("gpu", "RasterBufferStub::Initialize");
FastSetActiveURL(active_url_, active_url_hash_, channel_);
GpuChannelManager* manager = channel_->gpu_channel_manager();
DCHECK(manager);
if (share_command_buffer_stub) {
context_group_ = share_command_buffer_stub->context_group();
DCHECK(context_group_->bind_generates_resource() ==
init_params.attribs.bind_generates_resource);
} else {
scoped_refptr<gles2::FeatureInfo> feature_info =
new gles2::FeatureInfo(manager->gpu_driver_bug_workarounds());
gpu::GpuMemoryBufferFactory* gmb_factory =
manager->gpu_memory_buffer_factory();
context_group_ = new gles2::ContextGroup(
manager->gpu_preferences(), gles2::PassthroughCommandDecoderSupported(),
manager->mailbox_manager(), CreateMemoryTracker(init_params),
manager->shader_translator_cache(),
manager->framebuffer_completeness_cache(), feature_info,
init_params.attribs.bind_generates_resource, channel_->image_manager(),
gmb_factory ? gmb_factory->AsImageFactory() : nullptr,
manager->watchdog() /* progress_reporter */,
manager->gpu_feature_info(), manager->discardable_manager());
}
#if defined(OS_MACOSX)
// Virtualize PreferIntegratedGpu contexts by default on OS X to prevent
// performance regressions when enabling FCM.
// http://crbug.com/180463
if (init_params.attribs.gpu_preference == gl::PreferIntegratedGpu)
use_virtualized_gl_context_ = true;
#endif
use_virtualized_gl_context_ |=
context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
// MailboxManagerSync synchronization correctness currently depends on having
// only a single context. See crbug.com/510243 for details.
use_virtualized_gl_context_ |= manager->mailbox_manager()->UsesSync();
if (surface_handle_ != kNullSurfaceHandle) {
LOG(ERROR) << "ContextResult::kFatalFailure: "
"RenderInterface clients must render offscreen.";
return gpu::ContextResult::kFatalFailure;
}
surface_ = manager->GetDefaultOffscreenSurface();
if (!surface_) {
LOG(ERROR) << "ContextResult::kFatalFailure: "
"Failed to create default offscreen surface.";
return gpu::ContextResult::kFatalFailure;
}
command_buffer_ = std::make_unique<CommandBufferService>(
this, context_group_->transfer_buffer_manager());
std::unique_ptr<raster::RasterDecoder> decoder(raster::RasterDecoder::Create(
this, command_buffer_.get(), manager->outputter(), context_group_.get()));
sync_point_client_state_ =
channel_->sync_point_manager()->CreateSyncPointClientState(
CommandBufferNamespace::GPU_IO, command_buffer_id_, sequence_id_);
if (context_group_->use_passthrough_cmd_decoder()) {
// When using the passthrough command decoder, only share with other
// contexts in the explicitly requested share group
if (share_command_buffer_stub) {
share_group_ = share_command_buffer_stub->share_group();
} else {
share_group_ = new gl::GLShareGroup();
}
} else {
// When using the validating command decoder, always use the global share
// group
share_group_ = channel_->share_group();
}
// TODO(sunnyps): Should this use ScopedCrashKey instead?
crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
: "0");
scoped_refptr<gl::GLContext> context;
if (use_virtualized_gl_context_) {
context = share_group_->GetSharedContext(surface_.get());
if (!context) {
context = gl::init::CreateGLContext(
share_group_.get(), surface_.get(),
GenerateGLContextAttribs(init_params.attribs, context_group_.get()));
if (!context) {
// TODO(piman): This might not be fatal, we could recurse into
// CreateGLContext to get more info, tho it should be exceedingly
// rare and may not be recoverable anyway.
LOG(ERROR) << "ContextResult::kFatalFailure: "
"Failed to create shared context for virtualization.";
return gpu::ContextResult::kFatalFailure;
}
// Ensure that context creation did not lose track of the intended share
// group.
DCHECK(context->share_group() == share_group_.get());
share_group_->SetSharedContext(surface_.get(), context.get());
// This needs to be called against the real shared context, not the
// virtual context created below.
manager->gpu_feature_info().ApplyToGLContext(context.get());
}
// This should be either:
// (1) a non-virtual GL context, or
// (2) a mock/stub context.
DCHECK(context->GetHandle() ||
gl::GetGLImplementation() == gl::kGLImplementationMockGL ||
gl::GetGLImplementation() == gl::kGLImplementationStubGL);
context = base::MakeRefCounted<GLContextVirtual>(
share_group_.get(), context.get(), decoder->AsWeakPtr());
if (!context->Initialize(surface_.get(),
GenerateGLContextAttribs(init_params.attribs,
context_group_.get()))) {
// The real context created above for the default offscreen surface
// might not be compatible with this surface.
context = nullptr;
// TODO(piman): This might not be fatal, we could recurse into
// CreateGLContext to get more info, tho it should be exceedingly
// rare and may not be recoverable anyway.
LOG(ERROR) << "ContextResult::kFatalFailure: "
"Failed to initialize virtual GL context.";
return gpu::ContextResult::kFatalFailure;
}
} else {
context = gl::init::CreateGLContext(
share_group_.get(), surface_.get(),
GenerateGLContextAttribs(init_params.attribs, context_group_.get()));
if (!context) {
// TODO(piman): This might not be fatal, we could recurse into
// CreateGLContext to get more info, tho it should be exceedingly
// rare and may not be recoverable anyway.
LOG(ERROR) << "ContextResult::kFatalFailure: Failed to create context.";
return gpu::ContextResult::kFatalFailure;
}
manager->gpu_feature_info().ApplyToGLContext(context.get());
}
if (!context->MakeCurrent(surface_.get())) {
LOG(ERROR) << "ContextResult::kTransientFailure: "
"Failed to make context current.";
return gpu::ContextResult::kTransientFailure;
}
if (!context->GetGLStateRestorer()) {
context->SetGLStateRestorer(new GLStateRestorerImpl(decoder->AsWeakPtr()));
}
if (!context_group_->has_program_cache() &&
!context_group_->feature_info()->workarounds().disable_program_cache) {
context_group_->set_program_cache(manager->program_cache());
}
// Initialize the decoder with either the view or pbuffer GLContext.
auto result = decoder->Initialize(surface_, context, true /* offscreen */,
gpu::gles2::DisallowedFeatures(),
init_params.attribs);
if (result != gpu::ContextResult::kSuccess) {
DLOG(ERROR) << "Failed to initialize decoder.";
return result;
}
if (manager->gpu_preferences().enable_gpu_service_logging) {
decoder->set_log_commands(true);
}
set_decoder_context(std::move(decoder));
const size_t kSharedStateSize = sizeof(CommandBufferSharedState);
if (!shared_state_shm->Map(kSharedStateSize)) {
LOG(ERROR) << "ContextResult::kFatalFailure: "
"Failed to map shared state buffer.";
return gpu::ContextResult::kFatalFailure;
}
command_buffer_->SetSharedStateBuffer(MakeBackingFromSharedMemory(
std::move(shared_state_shm), kSharedStateSize));
if (!active_url_.is_empty())
manager->delegate()->DidCreateOffscreenContext(active_url_);
if (use_virtualized_gl_context_) {
// If virtualized GL contexts are in use, then real GL context state
// is in an indeterminate state, since the GLStateRestorer was not
// initialized at the time the GLContextVirtual was made current. In
// the case that this command decoder is the next one to be
// processed, force a "full virtual" MakeCurrent to be performed.
// Note that GpuChannel's initialization of the gpu::Capabilities
// expects the context to be left current.
context->ForceReleaseVirtuallyCurrent();
if (!context->MakeCurrent(surface_.get())) {
LOG(ERROR) << "ContextResult::kTransientFailure: "
"Failed to make context current after initialization.";
return gpu::ContextResult::kTransientFailure;
}
}
manager->delegate()->DidCreateContextSuccessfully();
initialized_ = true;
return gpu::ContextResult::kSuccess;
#endif // defined(OS_FUCHSIA)
}
// RasterInterface clients should not manipulate the front buffer.
void RasterCommandBufferStub::OnTakeFrontBuffer(const Mailbox& mailbox) {
NOTREACHED();
}
void RasterCommandBufferStub::OnReturnFrontBuffer(const Mailbox& mailbox,
bool is_lost) {
NOTREACHED();
}
} // namespace gpu