| // 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 |