1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/pepper/pepper_platform_context_3d.h" 6 7 #include "base/bind.h" 8 #include "content/common/gpu/client/context_provider_command_buffer.h" 9 #include "content/common/gpu/client/gpu_channel_host.h" 10 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 11 #include "content/renderer/render_thread_impl.h" 12 #include "gpu/command_buffer/client/gles2_cmd_helper.h" 13 #include "gpu/command_buffer/client/gles2_implementation.h" 14 #include "ppapi/c/pp_graphics_3d.h" 15 #include "ui/gl/gpu_preference.h" 16 #include "url/gurl.h" 17 18 namespace content { 19 20 PlatformContext3D::PlatformContext3D() 21 : has_alpha_(false), 22 command_buffer_(NULL), 23 weak_ptr_factory_(this) { 24 } 25 26 PlatformContext3D::~PlatformContext3D() { 27 if (command_buffer_) { 28 DCHECK(channel_.get()); 29 channel_->DestroyCommandBuffer(command_buffer_); 30 command_buffer_ = NULL; 31 } 32 33 channel_ = NULL; 34 } 35 36 bool PlatformContext3D::Init(const int32* attrib_list, 37 PlatformContext3D* share_context) { 38 // Ignore initializing more than once. 39 if (command_buffer_) 40 return true; 41 42 RenderThreadImpl* render_thread = RenderThreadImpl::current(); 43 if (!render_thread) 44 return false; 45 46 gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; 47 48 channel_ = render_thread->EstablishGpuChannelSync( 49 CAUSE_FOR_GPU_LAUNCH_PEPPERPLATFORMCONTEXT3DIMPL_INITIALIZE); 50 if (!channel_.get()) 51 return false; 52 53 gfx::Size surface_size; 54 std::vector<int32> attribs; 55 // TODO(alokp): Change GpuChannelHost::CreateOffscreenCommandBuffer() 56 // interface to accept width and height in the attrib_list so that 57 // we do not need to filter for width and height here. 58 if (attrib_list) { 59 for (const int32_t* attr = attrib_list; 60 attr[0] != PP_GRAPHICS3DATTRIB_NONE; 61 attr += 2) { 62 switch (attr[0]) { 63 case PP_GRAPHICS3DATTRIB_WIDTH: 64 surface_size.set_width(attr[1]); 65 break; 66 case PP_GRAPHICS3DATTRIB_HEIGHT: 67 surface_size.set_height(attr[1]); 68 break; 69 case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE: 70 gpu_preference = 71 (attr[1] == PP_GRAPHICS3DATTRIB_GPU_PREFERENCE_LOW_POWER) ? 72 gfx::PreferIntegratedGpu : gfx::PreferDiscreteGpu; 73 break; 74 case PP_GRAPHICS3DATTRIB_ALPHA_SIZE: 75 has_alpha_ = attr[1] > 0; 76 // fall-through 77 default: 78 attribs.push_back(attr[0]); 79 attribs.push_back(attr[1]); 80 break; 81 } 82 } 83 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); 84 } 85 86 CommandBufferProxyImpl* share_buffer = NULL; 87 if (share_context) { 88 PlatformContext3D* share_impl = 89 static_cast<PlatformContext3D*>(share_context); 90 share_buffer = share_impl->command_buffer_; 91 } 92 93 command_buffer_ = channel_->CreateOffscreenCommandBuffer( 94 surface_size, 95 share_buffer, 96 attribs, 97 GURL::EmptyGURL(), 98 gpu_preference); 99 if (!command_buffer_) 100 return false; 101 if (!command_buffer_->Initialize()) 102 return false; 103 std::vector<gpu::Mailbox> names; 104 if (!command_buffer_->GenerateMailboxNames(1, &names)) 105 return false; 106 DCHECK_EQ(names.size(), 1u); 107 if (!command_buffer_->ProduceFrontBuffer(names[0])) 108 return false; 109 mailbox_ = names[0]; 110 sync_point_ = command_buffer_->InsertSyncPoint(); 111 112 command_buffer_->SetChannelErrorCallback( 113 base::Bind(&PlatformContext3D::OnContextLost, 114 weak_ptr_factory_.GetWeakPtr())); 115 command_buffer_->SetOnConsoleMessageCallback( 116 base::Bind(&PlatformContext3D::OnConsoleMessage, 117 weak_ptr_factory_.GetWeakPtr())); 118 119 return true; 120 } 121 122 void PlatformContext3D::GetBackingMailbox(gpu::Mailbox* mailbox, 123 uint32* sync_point) { 124 *mailbox = mailbox_; 125 *sync_point = sync_point_; 126 } 127 128 void PlatformContext3D::InsertSyncPointForBackingMailbox() { 129 DCHECK(command_buffer_); 130 sync_point_ = command_buffer_->InsertSyncPoint(); 131 } 132 133 bool PlatformContext3D::IsOpaque() { 134 DCHECK(command_buffer_); 135 return !has_alpha_; 136 } 137 138 gpu::CommandBuffer* PlatformContext3D::GetCommandBuffer() { 139 return command_buffer_; 140 } 141 142 gpu::GpuControl* PlatformContext3D::GetGpuControl() { 143 return command_buffer_; 144 } 145 146 int PlatformContext3D::GetCommandBufferRouteId() { 147 DCHECK(command_buffer_); 148 return command_buffer_->GetRouteID(); 149 } 150 151 void PlatformContext3D::SetContextLostCallback(const base::Closure& task) { 152 context_lost_callback_ = task; 153 } 154 155 void PlatformContext3D::SetOnConsoleMessageCallback( 156 const ConsoleMessageCallback& task) { 157 console_message_callback_ = task; 158 } 159 160 void PlatformContext3D::Echo(const base::Closure& task) { 161 command_buffer_->Echo(task); 162 } 163 164 void PlatformContext3D::OnContextLost() { 165 DCHECK(command_buffer_); 166 167 if (!context_lost_callback_.is_null()) 168 context_lost_callback_.Run(); 169 } 170 171 void PlatformContext3D::OnConsoleMessage(const std::string& msg, int id) { 172 DCHECK(command_buffer_); 173 174 if (!console_message_callback_.is_null()) 175 console_message_callback_.Run(msg, id); 176 } 177 178 } // namespace content 179