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 |