blob: 6c3408bd42947e3b4fd12823b2a2573181228be5 [file] [log] [blame]
// Copyright (c) 2012 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/renderer/pepper/pepper_platform_context_3d.h"
#include "base/bind.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "ppapi/c/pp_graphics_3d.h"
#include "ui/gl/gpu_preference.h"
#include "url/gurl.h"
namespace content {
PlatformContext3D::PlatformContext3D()
: has_alpha_(false),
command_buffer_(NULL),
weak_ptr_factory_(this) {
}
PlatformContext3D::~PlatformContext3D() {
if (command_buffer_) {
DCHECK(channel_.get());
channel_->DestroyCommandBuffer(command_buffer_);
command_buffer_ = NULL;
}
channel_ = NULL;
}
bool PlatformContext3D::Init(const int32* attrib_list,
PlatformContext3D* share_context) {
// Ignore initializing more than once.
if (command_buffer_)
return true;
RenderThreadImpl* render_thread = RenderThreadImpl::current();
if (!render_thread)
return false;
gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
channel_ = render_thread->EstablishGpuChannelSync(
CAUSE_FOR_GPU_LAUNCH_PEPPERPLATFORMCONTEXT3DIMPL_INITIALIZE);
if (!channel_.get())
return false;
gfx::Size surface_size;
std::vector<int32> attribs;
// TODO(alokp): Change GpuChannelHost::CreateOffscreenCommandBuffer()
// interface to accept width and height in the attrib_list so that
// we do not need to filter for width and height here.
if (attrib_list) {
for (const int32_t* attr = attrib_list;
attr[0] != PP_GRAPHICS3DATTRIB_NONE;
attr += 2) {
switch (attr[0]) {
case PP_GRAPHICS3DATTRIB_WIDTH:
surface_size.set_width(attr[1]);
break;
case PP_GRAPHICS3DATTRIB_HEIGHT:
surface_size.set_height(attr[1]);
break;
case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE:
gpu_preference =
(attr[1] == PP_GRAPHICS3DATTRIB_GPU_PREFERENCE_LOW_POWER) ?
gfx::PreferIntegratedGpu : gfx::PreferDiscreteGpu;
break;
case PP_GRAPHICS3DATTRIB_ALPHA_SIZE:
has_alpha_ = attr[1] > 0;
// fall-through
default:
attribs.push_back(attr[0]);
attribs.push_back(attr[1]);
break;
}
}
attribs.push_back(PP_GRAPHICS3DATTRIB_NONE);
}
CommandBufferProxyImpl* share_buffer = NULL;
if (share_context) {
PlatformContext3D* share_impl =
static_cast<PlatformContext3D*>(share_context);
share_buffer = share_impl->command_buffer_;
}
command_buffer_ = channel_->CreateOffscreenCommandBuffer(
surface_size,
share_buffer,
attribs,
GURL::EmptyGURL(),
gpu_preference);
if (!command_buffer_)
return false;
if (!command_buffer_->Initialize())
return false;
std::vector<gpu::Mailbox> names;
if (!command_buffer_->GenerateMailboxNames(1, &names))
return false;
DCHECK_EQ(names.size(), 1u);
if (!command_buffer_->ProduceFrontBuffer(names[0]))
return false;
mailbox_ = names[0];
sync_point_ = command_buffer_->InsertSyncPoint();
command_buffer_->SetChannelErrorCallback(
base::Bind(&PlatformContext3D::OnContextLost,
weak_ptr_factory_.GetWeakPtr()));
command_buffer_->SetOnConsoleMessageCallback(
base::Bind(&PlatformContext3D::OnConsoleMessage,
weak_ptr_factory_.GetWeakPtr()));
return true;
}
void PlatformContext3D::GetBackingMailbox(gpu::Mailbox* mailbox,
uint32* sync_point) {
*mailbox = mailbox_;
*sync_point = sync_point_;
}
void PlatformContext3D::InsertSyncPointForBackingMailbox() {
DCHECK(command_buffer_);
sync_point_ = command_buffer_->InsertSyncPoint();
}
bool PlatformContext3D::IsOpaque() {
DCHECK(command_buffer_);
return !has_alpha_;
}
gpu::CommandBuffer* PlatformContext3D::GetCommandBuffer() {
return command_buffer_;
}
gpu::GpuControl* PlatformContext3D::GetGpuControl() {
return command_buffer_;
}
int PlatformContext3D::GetCommandBufferRouteId() {
DCHECK(command_buffer_);
return command_buffer_->GetRouteID();
}
void PlatformContext3D::SetContextLostCallback(const base::Closure& task) {
context_lost_callback_ = task;
}
void PlatformContext3D::SetOnConsoleMessageCallback(
const ConsoleMessageCallback& task) {
console_message_callback_ = task;
}
void PlatformContext3D::Echo(const base::Closure& task) {
command_buffer_->Echo(task);
}
void PlatformContext3D::OnContextLost() {
DCHECK(command_buffer_);
if (!context_lost_callback_.is_null())
context_lost_callback_.Run();
}
void PlatformContext3D::OnConsoleMessage(const std::string& msg, int id) {
DCHECK(command_buffer_);
if (!console_message_callback_.is_null())
console_message_callback_.Run(msg, id);
}
} // namespace content