| OLD | NEW |
| (Empty) |
| 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 "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/message_loop/message_loop.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "gpu/command_buffer/client/gles2_implementation.h" | |
| 12 #include "ppapi/c/ppp_graphics_3d.h" | |
| 13 #include "ppapi/thunk/enter.h" | |
| 14 #include "third_party/WebKit/public/platform/WebString.h" | |
| 15 #include "third_party/WebKit/public/web/WebConsoleMessage.h" | |
| 16 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 17 #include "third_party/WebKit/public/web/WebElement.h" | |
| 18 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 19 #include "third_party/WebKit/public/web/WebPluginContainer.h" | |
| 20 #include "webkit/plugins/plugin_switches.h" | |
| 21 #include "webkit/plugins/ppapi/plugin_module.h" | |
| 22 #include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h" | |
| 23 #include "webkit/plugins/ppapi/resource_helper.h" | |
| 24 | |
| 25 using ppapi::thunk::EnterResourceNoLock; | |
| 26 using ppapi::thunk::PPB_Graphics3D_API; | |
| 27 using WebKit::WebConsoleMessage; | |
| 28 using WebKit::WebFrame; | |
| 29 using WebKit::WebPluginContainer; | |
| 30 using WebKit::WebString; | |
| 31 | |
| 32 namespace webkit { | |
| 33 namespace ppapi { | |
| 34 | |
| 35 namespace { | |
| 36 const int32 kCommandBufferSize = 1024 * 1024; | |
| 37 const int32 kTransferBufferSize = 1024 * 1024; | |
| 38 | |
| 39 PP_Bool ShmToHandle(base::SharedMemory* shm, | |
| 40 size_t size, | |
| 41 int* shm_handle, | |
| 42 uint32_t* shm_size) { | |
| 43 if (!shm || !shm_handle || !shm_size) | |
| 44 return PP_FALSE; | |
| 45 #if defined(OS_POSIX) | |
| 46 *shm_handle = shm->handle().fd; | |
| 47 #elif defined(OS_WIN) | |
| 48 *shm_handle = reinterpret_cast<int>(shm->handle()); | |
| 49 #else | |
| 50 #error "Platform not supported." | |
| 51 #endif | |
| 52 *shm_size = size; | |
| 53 return PP_TRUE; | |
| 54 } | |
| 55 | |
| 56 } // namespace. | |
| 57 | |
| 58 PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance) | |
| 59 : PPB_Graphics3D_Shared(instance), | |
| 60 bound_to_instance_(false), | |
| 61 commit_pending_(false), | |
| 62 weak_ptr_factory_(this) { | |
| 63 } | |
| 64 | |
| 65 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() { | |
| 66 DestroyGLES2Impl(); | |
| 67 } | |
| 68 | |
| 69 // static | |
| 70 PP_Bool PPB_Graphics3D_Impl::IsGpuBlacklisted() { | |
| 71 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
| 72 if (command_line) | |
| 73 return PP_FromBool( | |
| 74 command_line->HasSwitch(switches::kDisablePepper3d)); | |
| 75 return PP_TRUE; | |
| 76 } | |
| 77 | |
| 78 // static | |
| 79 PP_Resource PPB_Graphics3D_Impl::Create(PP_Instance instance, | |
| 80 PP_Resource share_context, | |
| 81 const int32_t* attrib_list) { | |
| 82 PPB_Graphics3D_API* share_api = NULL; | |
| 83 if (IsGpuBlacklisted()) | |
| 84 return 0; | |
| 85 if (share_context) { | |
| 86 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true); | |
| 87 if (enter.failed()) | |
| 88 return 0; | |
| 89 share_api = enter.object(); | |
| 90 } | |
| 91 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d( | |
| 92 new PPB_Graphics3D_Impl(instance)); | |
| 93 if (!graphics_3d->Init(share_api, attrib_list)) | |
| 94 return 0; | |
| 95 return graphics_3d->GetReference(); | |
| 96 } | |
| 97 | |
| 98 // static | |
| 99 PP_Resource PPB_Graphics3D_Impl::CreateRaw(PP_Instance instance, | |
| 100 PP_Resource share_context, | |
| 101 const int32_t* attrib_list) { | |
| 102 PPB_Graphics3D_API* share_api = NULL; | |
| 103 if (IsGpuBlacklisted()) | |
| 104 return 0; | |
| 105 if (share_context) { | |
| 106 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true); | |
| 107 if (enter.failed()) | |
| 108 return 0; | |
| 109 share_api = enter.object(); | |
| 110 } | |
| 111 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d( | |
| 112 new PPB_Graphics3D_Impl(instance)); | |
| 113 if (!graphics_3d->InitRaw(share_api, attrib_list)) | |
| 114 return 0; | |
| 115 return graphics_3d->GetReference(); | |
| 116 } | |
| 117 | |
| 118 PP_Bool PPB_Graphics3D_Impl::SetGetBuffer(int32_t transfer_buffer_id) { | |
| 119 GetCommandBuffer()->SetGetBuffer(transfer_buffer_id); | |
| 120 return PP_TRUE; | |
| 121 } | |
| 122 | |
| 123 gpu::CommandBuffer::State PPB_Graphics3D_Impl::GetState() { | |
| 124 return GetCommandBuffer()->GetState(); | |
| 125 } | |
| 126 | |
| 127 int32_t PPB_Graphics3D_Impl::CreateTransferBuffer(uint32_t size) { | |
| 128 int32_t id = -1; | |
| 129 GetCommandBuffer()->CreateTransferBuffer(size, &id); | |
| 130 return id; | |
| 131 } | |
| 132 | |
| 133 PP_Bool PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id) { | |
| 134 GetCommandBuffer()->DestroyTransferBuffer(id); | |
| 135 return PP_TRUE; | |
| 136 } | |
| 137 | |
| 138 PP_Bool PPB_Graphics3D_Impl::GetTransferBuffer(int32_t id, | |
| 139 int* shm_handle, | |
| 140 uint32_t* shm_size) { | |
| 141 gpu::Buffer buffer = GetCommandBuffer()->GetTransferBuffer(id); | |
| 142 return ShmToHandle(buffer.shared_memory, buffer.size, shm_handle, shm_size); | |
| 143 } | |
| 144 | |
| 145 PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) { | |
| 146 GetCommandBuffer()->Flush(put_offset); | |
| 147 return PP_TRUE; | |
| 148 } | |
| 149 | |
| 150 gpu::CommandBuffer::State PPB_Graphics3D_Impl::FlushSync(int32_t put_offset) { | |
| 151 gpu::CommandBuffer::State state = GetCommandBuffer()->GetState(); | |
| 152 return GetCommandBuffer()->FlushSync(put_offset, state.get_offset); | |
| 153 } | |
| 154 | |
| 155 gpu::CommandBuffer::State PPB_Graphics3D_Impl::FlushSyncFast( | |
| 156 int32_t put_offset, | |
| 157 int32_t last_known_get) { | |
| 158 return GetCommandBuffer()->FlushSync(put_offset, last_known_get); | |
| 159 } | |
| 160 | |
| 161 uint32_t PPB_Graphics3D_Impl::InsertSyncPoint() { | |
| 162 return GetCommandBuffer()->InsertSyncPoint(); | |
| 163 } | |
| 164 | |
| 165 bool PPB_Graphics3D_Impl::BindToInstance(bool bind) { | |
| 166 bound_to_instance_ = bind; | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 bool PPB_Graphics3D_Impl::IsOpaque() { | |
| 171 return platform_context_->IsOpaque(); | |
| 172 } | |
| 173 | |
| 174 void PPB_Graphics3D_Impl::ViewWillInitiatePaint() { | |
| 175 } | |
| 176 | |
| 177 void PPB_Graphics3D_Impl::ViewInitiatedPaint() { | |
| 178 commit_pending_ = false; | |
| 179 | |
| 180 if (HasPendingSwap()) | |
| 181 SwapBuffersACK(PP_OK); | |
| 182 } | |
| 183 | |
| 184 void PPB_Graphics3D_Impl::ViewFlushedPaint() { | |
| 185 } | |
| 186 | |
| 187 gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() { | |
| 188 return platform_context_->GetCommandBuffer(); | |
| 189 } | |
| 190 | |
| 191 int32 PPB_Graphics3D_Impl::DoSwapBuffers() { | |
| 192 // We do not have a GLES2 implementation when using an OOP proxy. | |
| 193 // The plugin-side proxy is responsible for adding the SwapBuffers command | |
| 194 // to the command buffer in that case. | |
| 195 if (gles2_impl()) | |
| 196 gles2_impl()->SwapBuffers(); | |
| 197 | |
| 198 if (bound_to_instance_) { | |
| 199 // If we are bound to the instance, we need to ask the compositor | |
| 200 // to commit our backing texture so that the graphics appears on the page. | |
| 201 // When the backing texture will be committed we get notified via | |
| 202 // ViewFlushedPaint(). | |
| 203 // | |
| 204 // Don't need to check for NULL from GetPluginInstance since when we're | |
| 205 // bound, we know our instance is valid. | |
| 206 ResourceHelper::GetPluginInstance(this)->CommitBackingTexture(); | |
| 207 commit_pending_ = true; | |
| 208 } else { | |
| 209 // Wait for the command to complete on the GPU to allow for throttling. | |
| 210 platform_context_->Echo(base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers, | |
| 211 weak_ptr_factory_.GetWeakPtr())); | |
| 212 } | |
| 213 | |
| 214 | |
| 215 return PP_OK_COMPLETIONPENDING; | |
| 216 } | |
| 217 | |
| 218 bool PPB_Graphics3D_Impl::Init(PPB_Graphics3D_API* share_context, | |
| 219 const int32_t* attrib_list) { | |
| 220 if (!InitRaw(share_context, attrib_list)) | |
| 221 return false; | |
| 222 | |
| 223 gpu::CommandBuffer* command_buffer = GetCommandBuffer(); | |
| 224 if (!command_buffer->Initialize()) | |
| 225 return false; | |
| 226 | |
| 227 gpu::gles2::GLES2Implementation* share_gles2 = NULL; | |
| 228 if (share_context) { | |
| 229 share_gles2 = | |
| 230 static_cast<PPB_Graphics3D_Shared*>(share_context)->gles2_impl(); | |
| 231 } | |
| 232 | |
| 233 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, | |
| 234 share_gles2); | |
| 235 } | |
| 236 | |
| 237 bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, | |
| 238 const int32_t* attrib_list) { | |
| 239 PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this); | |
| 240 if (!plugin_instance) | |
| 241 return false; | |
| 242 | |
| 243 PluginDelegate::PlatformContext3D* share_platform_context = NULL; | |
| 244 if (share_context) { | |
| 245 PPB_Graphics3D_Impl* share_graphics = | |
| 246 static_cast<PPB_Graphics3D_Impl*>(share_context); | |
| 247 share_platform_context = share_graphics->platform_context(); | |
| 248 } | |
| 249 | |
| 250 platform_context_.reset(plugin_instance->CreateContext3D()); | |
| 251 if (!platform_context_) | |
| 252 return false; | |
| 253 | |
| 254 if (!platform_context_->Init(attrib_list, share_platform_context)) | |
| 255 return false; | |
| 256 | |
| 257 platform_context_->SetContextLostCallback( | |
| 258 base::Bind(&PPB_Graphics3D_Impl::OnContextLost, | |
| 259 weak_ptr_factory_.GetWeakPtr())); | |
| 260 | |
| 261 platform_context_->SetOnConsoleMessageCallback( | |
| 262 base::Bind(&PPB_Graphics3D_Impl::OnConsoleMessage, | |
| 263 weak_ptr_factory_.GetWeakPtr())); | |
| 264 return true; | |
| 265 } | |
| 266 | |
| 267 void PPB_Graphics3D_Impl::OnConsoleMessage(const std::string& message, | |
| 268 int id) { | |
| 269 if (!bound_to_instance_) | |
| 270 return; | |
| 271 WebPluginContainer* container = | |
| 272 ResourceHelper::GetPluginInstance(this)->container(); | |
| 273 if (!container) | |
| 274 return; | |
| 275 WebFrame* frame = container->element().document().frame(); | |
| 276 if (!frame) | |
| 277 return; | |
| 278 WebConsoleMessage console_message = WebConsoleMessage( | |
| 279 WebConsoleMessage::LevelError, WebString(UTF8ToUTF16(message))); | |
| 280 frame->addMessageToConsole(console_message); | |
| 281 } | |
| 282 | |
| 283 void PPB_Graphics3D_Impl::OnSwapBuffers() { | |
| 284 if (HasPendingSwap()) { | |
| 285 // If we're off-screen, no need to trigger and wait for compositing. | |
| 286 // Just send the swap-buffers ACK to the plugin immediately. | |
| 287 commit_pending_ = false; | |
| 288 SwapBuffersACK(PP_OK); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 void PPB_Graphics3D_Impl::OnContextLost() { | |
| 293 // Don't need to check for NULL from GetPluginInstance since when we're | |
| 294 // bound, we know our instance is valid. | |
| 295 if (bound_to_instance_) | |
| 296 ResourceHelper::GetPluginInstance(this)->BindGraphics(pp_instance(), 0); | |
| 297 | |
| 298 // Send context lost to plugin. This may have been caused by a PPAPI call, so | |
| 299 // avoid re-entering. | |
| 300 base::MessageLoop::current()->PostTask( | |
| 301 FROM_HERE, | |
| 302 base::Bind(&PPB_Graphics3D_Impl::SendContextLost, | |
| 303 weak_ptr_factory_.GetWeakPtr())); | |
| 304 } | |
| 305 | |
| 306 void PPB_Graphics3D_Impl::SendContextLost() { | |
| 307 // By the time we run this, the instance may have been deleted, or in the | |
| 308 // process of being deleted. Even in the latter case, we don't want to send a | |
| 309 // callback after DidDestroy. | |
| 310 PluginInstanceImpl* instance = ResourceHelper::GetPluginInstance(this); | |
| 311 if (!instance || !instance->container()) | |
| 312 return; | |
| 313 | |
| 314 // This PPB_Graphics3D_Impl could be deleted during the call to | |
| 315 // GetPluginInterface (which sends a sync message in some cases). We still | |
| 316 // send the Graphics3DContextLost to the plugin; the instance may care about | |
| 317 // that event even though this context has been destroyed. | |
| 318 PP_Instance this_pp_instance = pp_instance(); | |
| 319 const PPP_Graphics3D* ppp_graphics_3d = | |
| 320 static_cast<const PPP_Graphics3D*>( | |
| 321 instance->module()->GetPluginInterface( | |
| 322 PPP_GRAPHICS_3D_INTERFACE)); | |
| 323 if (ppp_graphics_3d) | |
| 324 ppp_graphics_3d->Graphics3DContextLost(this_pp_instance); | |
| 325 } | |
| 326 | |
| 327 } // namespace ppapi | |
| 328 } // namespace webkit | |
| OLD | NEW |