cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / ppapi / proxy / ppb_graphics_3d_proxy.cc
blob204466baf62bb482d4c00c184efad5e87442f4b5
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.
5 #include "ppapi/proxy/ppb_graphics_3d_proxy.h"
7 #include "gpu/command_buffer/client/gles2_implementation.h"
8 #include "gpu/command_buffer/common/command_buffer.h"
9 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/proxy/enter_proxy.h"
11 #include "ppapi/proxy/plugin_dispatcher.h"
12 #include "ppapi/proxy/ppapi_command_buffer_proxy.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/shared_impl/ppapi_globals.h"
15 #include "ppapi/shared_impl/proxy_lock.h"
16 #include "ppapi/thunk/enter.h"
17 #include "ppapi/thunk/resource_creation_api.h"
18 #include "ppapi/thunk/thunk.h"
20 using ppapi::thunk::EnterResourceNoLock;
21 using ppapi::thunk::PPB_Graphics3D_API;
22 using ppapi::thunk::ResourceCreationAPI;
24 namespace ppapi {
25 namespace proxy {
27 namespace {
29 const int32 kCommandBufferSize = 1024 * 1024;
30 const int32 kTransferBufferSize = 1024 * 1024;
32 base::SharedMemoryHandle TransportSHMHandleFromInt(Dispatcher* dispatcher,
33 int shm_handle) {
34 // TODO(piman): Change trusted interface to return a PP_FileHandle, those
35 // casts are ugly.
36 base::PlatformFile source =
37 #if defined(OS_WIN)
38 reinterpret_cast<HANDLE>(static_cast<intptr_t>(shm_handle));
39 #elif defined(OS_POSIX)
40 shm_handle;
41 #else
42 #error Not implemented.
43 #endif
44 // Don't close the handle, it doesn't belong to us.
45 return dispatcher->ShareHandleWithRemote(source, false);
48 gpu::CommandBuffer::State GetErrorState() {
49 gpu::CommandBuffer::State error_state;
50 error_state.error = gpu::error::kGenericError;
51 return error_state;
54 } // namespace
56 // This class just wraps a CommandBuffer and optionally locks around every
57 // method. This is used to ensure that we have the Proxy lock any time we enter
58 // PpapiCommandBufferProxy.
60 // Note, for performance reasons, most of this code is not truly thread
61 // safe in the sense of multiple threads concurrently rendering to the same
62 // Graphics3D context; this isn't allowed, and will likely either crash or
63 // result in undefined behavior. It is assumed that the thread which creates
64 // the Graphics3D context will be the thread on which subsequent gl rendering
65 // will be done. This is why it is okay to read need_to_lock_ without the lock;
66 // it should only ever be read and written on the same thread where the context
67 // was created.
69 // TODO(nfullagar): At some point, allow multiple threads to concurrently render
70 // each to its own context. First step is to allow a single thread (either main
71 // thread or background thread) to render to a single Graphics3D context.
72 class Graphics3D::LockingCommandBuffer : public gpu::CommandBuffer {
73 public:
74 explicit LockingCommandBuffer(gpu::CommandBuffer* gpu_command_buffer)
75 : gpu_command_buffer_(gpu_command_buffer), need_to_lock_(true) {
77 virtual ~LockingCommandBuffer() {
79 void set_need_to_lock(bool need_to_lock) { need_to_lock_ = need_to_lock; }
80 bool need_to_lock() const { return need_to_lock_; }
82 private:
83 // MaybeLock acquires the proxy lock on construction if and only if
84 // need_to_lock is true. If it acquired the lock, it releases it on
85 // destruction. If need_to_lock is false, then the lock must already be held.
86 struct MaybeLock {
87 explicit MaybeLock(bool need_to_lock) : locked_(need_to_lock) {
88 if (need_to_lock)
89 ppapi::ProxyLock::Acquire();
90 else
91 ppapi::ProxyLock::AssertAcquired();
93 ~MaybeLock() {
94 if (locked_)
95 ppapi::ProxyLock::Release();
97 private:
98 bool locked_;
101 // gpu::CommandBuffer implementation:
102 virtual bool Initialize() OVERRIDE {
103 MaybeLock lock(need_to_lock_);
104 return gpu_command_buffer_->Initialize();
106 virtual State GetState() OVERRIDE {
107 MaybeLock lock(need_to_lock_);
108 return gpu_command_buffer_->GetState();
110 virtual State GetLastState() OVERRIDE {
111 // During a normal scene, the vast majority of calls are to GetLastState().
112 // We don't allow multi-threaded rendering on the same contex, so for
113 // performance reasons, avoid the global lock for this entry point. We can
114 // get away with this here because the underlying implementation of
115 // GetLastState() is trivial and does not involve global or shared state
116 // between other contexts.
117 // TODO(nfullagar): We can probably skip MaybeLock for other methods, but
118 // the performance gain may not be worth it.
120 // MaybeLock lock(need_to_lock_);
121 return gpu_command_buffer_->GetLastState();
123 virtual int32 GetLastToken() OVERRIDE {
124 return GetLastState().token;
126 virtual void Flush(int32 put_offset) OVERRIDE {
127 MaybeLock lock(need_to_lock_);
128 gpu_command_buffer_->Flush(put_offset);
130 virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE {
131 MaybeLock lock(need_to_lock_);
132 return gpu_command_buffer_->FlushSync(put_offset, last_known_get);
134 virtual void SetGetBuffer(int32 transfer_buffer_id) OVERRIDE {
135 MaybeLock lock(need_to_lock_);
136 gpu_command_buffer_->SetGetBuffer(transfer_buffer_id);
138 virtual void SetGetOffset(int32 get_offset) OVERRIDE {
139 MaybeLock lock(need_to_lock_);
140 gpu_command_buffer_->SetGetOffset(get_offset);
142 virtual gpu::Buffer CreateTransferBuffer(size_t size,
143 int32* id) OVERRIDE {
144 MaybeLock lock(need_to_lock_);
145 return gpu_command_buffer_->CreateTransferBuffer(size, id);
147 virtual void DestroyTransferBuffer(int32 id) OVERRIDE {
148 MaybeLock lock(need_to_lock_);
149 gpu_command_buffer_->DestroyTransferBuffer(id);
151 virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE {
152 MaybeLock lock(need_to_lock_);
153 return gpu_command_buffer_->GetTransferBuffer(id);
155 virtual void SetToken(int32 token) OVERRIDE {
156 MaybeLock lock(need_to_lock_);
157 gpu_command_buffer_->SetToken(token);
159 virtual void SetParseError(gpu::error::Error error) OVERRIDE {
160 MaybeLock lock(need_to_lock_);
161 gpu_command_buffer_->SetParseError(error);
163 virtual void SetContextLostReason(
164 gpu::error::ContextLostReason reason) OVERRIDE {
165 MaybeLock lock(need_to_lock_);
166 gpu_command_buffer_->SetContextLostReason(reason);
168 virtual uint32 InsertSyncPoint() OVERRIDE {
169 MaybeLock lock(need_to_lock_);
170 return gpu_command_buffer_->InsertSyncPoint();
173 // Weak pointer - see class Graphics3D for the scopted_ptr.
174 gpu::CommandBuffer* gpu_command_buffer_;
176 bool need_to_lock_;
179 Graphics3D::Graphics3D(const HostResource& resource)
180 : PPB_Graphics3D_Shared(resource),
181 num_already_locked_calls_(0) {
184 Graphics3D::~Graphics3D() {
185 if (gles2_impl())
186 DestroyGLES2Impl();
189 bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2) {
190 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this);
191 if (!dispatcher)
192 return false;
194 command_buffer_.reset(
195 new PpapiCommandBufferProxy(host_resource(), dispatcher));
196 locking_command_buffer_.reset(
197 new LockingCommandBuffer(command_buffer_.get()));
199 ScopedNoLocking already_locked(this);
200 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize,
201 share_gles2);
204 PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) {
205 return PP_FALSE;
208 gpu::CommandBuffer::State Graphics3D::GetState() {
209 return GetErrorState();
212 PP_Bool Graphics3D::Flush(int32_t put_offset) {
213 return PP_FALSE;
216 gpu::CommandBuffer::State Graphics3D::FlushSync(int32_t put_offset) {
217 return GetErrorState();
220 int32_t Graphics3D::CreateTransferBuffer(uint32_t size) {
221 return PP_FALSE;
224 PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) {
225 return PP_FALSE;
228 PP_Bool Graphics3D::GetTransferBuffer(int32_t id,
229 int* shm_handle,
230 uint32_t* shm_size) {
231 return PP_FALSE;
234 gpu::CommandBuffer::State Graphics3D::FlushSyncFast(int32_t put_offset,
235 int32_t last_known_get) {
236 return GetErrorState();
239 uint32_t Graphics3D::InsertSyncPoint() {
240 NOTREACHED();
241 return 0;
244 gpu::CommandBuffer* Graphics3D::GetCommandBuffer() {
245 return locking_command_buffer_.get();
248 int32 Graphics3D::DoSwapBuffers() {
249 // gles2_impl()->SwapBuffers() results in CommandBuffer calls, and we already
250 // have the proxy lock.
251 ScopedNoLocking already_locked(this);
253 gles2_impl()->SwapBuffers();
254 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers(
255 API_ID_PPB_GRAPHICS_3D, host_resource());
256 msg->set_unblock(true);
257 PluginDispatcher::GetForResource(this)->Send(msg);
259 return PP_OK_COMPLETIONPENDING;
262 void Graphics3D::PushAlreadyLocked() {
263 ppapi::ProxyLock::AssertAcquired();
264 if (!locking_command_buffer_) {
265 NOTREACHED();
266 return;
268 if (num_already_locked_calls_ == 0)
269 locking_command_buffer_->set_need_to_lock(false);
270 ++num_already_locked_calls_;
273 void Graphics3D::PopAlreadyLocked() {
274 // We must have Pushed before we can Pop.
275 DCHECK(!locking_command_buffer_->need_to_lock());
276 DCHECK_GT(num_already_locked_calls_, 0);
277 ppapi::ProxyLock::AssertAcquired();
278 if (!locking_command_buffer_) {
279 NOTREACHED();
280 return;
282 --num_already_locked_calls_;
283 if (num_already_locked_calls_ == 0)
284 locking_command_buffer_->set_need_to_lock(true);
287 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher)
288 : InterfaceProxy(dispatcher),
289 callback_factory_(this) {
292 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() {
295 // static
296 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource(
297 PP_Instance instance,
298 PP_Resource share_context,
299 const int32_t* attrib_list) {
300 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
301 if (!dispatcher)
302 return PP_ERROR_BADARGUMENT;
304 HostResource share_host;
305 gpu::gles2::GLES2Implementation* share_gles2 = NULL;
306 if (share_context != 0) {
307 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
308 if (enter.failed())
309 return PP_ERROR_BADARGUMENT;
311 PPB_Graphics3D_Shared* share_graphics =
312 static_cast<PPB_Graphics3D_Shared*>(enter.object());
313 share_host = share_graphics->host_resource();
314 share_gles2 = share_graphics->gles2_impl();
317 std::vector<int32_t> attribs;
318 if (attrib_list) {
319 for (const int32_t* attr = attrib_list;
320 attr[0] != PP_GRAPHICS3DATTRIB_NONE;
321 attr += 2) {
322 attribs.push_back(attr[0]);
323 attribs.push_back(attr[1]);
326 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE);
328 HostResource result;
329 dispatcher->Send(new PpapiHostMsg_PPBGraphics3D_Create(
330 API_ID_PPB_GRAPHICS_3D, instance, share_host, attribs, &result));
331 if (result.is_null())
332 return 0;
334 scoped_refptr<Graphics3D> graphics_3d(new Graphics3D(result));
335 if (!graphics_3d->Init(share_gles2))
336 return 0;
337 return graphics_3d->GetReference();
340 bool PPB_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) {
341 bool handled = true;
342 IPC_BEGIN_MESSAGE_MAP(PPB_Graphics3D_Proxy, msg)
343 #if !defined(OS_NACL)
344 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Create,
345 OnMsgCreate)
346 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SetGetBuffer,
347 OnMsgSetGetBuffer)
348 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetState,
349 OnMsgGetState)
350 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Flush,
351 OnMsgFlush)
352 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_AsyncFlush,
353 OnMsgAsyncFlush)
354 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer,
355 OnMsgCreateTransferBuffer)
356 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer,
357 OnMsgDestroyTransferBuffer)
358 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer,
359 OnMsgGetTransferBuffer)
360 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
361 OnMsgSwapBuffers)
362 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_InsertSyncPoint,
363 OnMsgInsertSyncPoint)
364 #endif // !defined(OS_NACL)
366 IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics3D_SwapBuffersACK,
367 OnMsgSwapBuffersACK)
368 IPC_MESSAGE_UNHANDLED(handled = false)
370 IPC_END_MESSAGE_MAP()
371 // FIXME(brettw) handle bad messages!
372 return handled;
375 #if !defined(OS_NACL)
376 void PPB_Graphics3D_Proxy::OnMsgCreate(PP_Instance instance,
377 HostResource share_context,
378 const std::vector<int32_t>& attribs,
379 HostResource* result) {
380 if (attribs.empty() ||
381 attribs.back() != PP_GRAPHICS3DATTRIB_NONE ||
382 !(attribs.size() & 1))
383 return; // Bad message.
385 thunk::EnterResourceCreation enter(instance);
387 if (enter.succeeded()) {
388 result->SetHostResource(
389 instance,
390 enter.functions()->CreateGraphics3DRaw(instance,
391 share_context.host_resource(),
392 &attribs.front()));
396 void PPB_Graphics3D_Proxy::OnMsgSetGetBuffer(
397 const HostResource& context,
398 int32 transfer_buffer_id) {
399 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
400 if (enter.succeeded())
401 enter.object()->SetGetBuffer(transfer_buffer_id);
404 void PPB_Graphics3D_Proxy::OnMsgGetState(const HostResource& context,
405 gpu::CommandBuffer::State* state,
406 bool* success) {
407 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
408 if (enter.failed()) {
409 *success = false;
410 return;
412 *state = enter.object()->GetState();
413 *success = true;
416 void PPB_Graphics3D_Proxy::OnMsgFlush(const HostResource& context,
417 int32 put_offset,
418 int32 last_known_get,
419 gpu::CommandBuffer::State* state,
420 bool* success) {
421 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
422 if (enter.failed()) {
423 *success = false;
424 return;
426 *state = enter.object()->FlushSyncFast(put_offset, last_known_get);
427 *success = true;
430 void PPB_Graphics3D_Proxy::OnMsgAsyncFlush(const HostResource& context,
431 int32 put_offset) {
432 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
433 if (enter.succeeded())
434 enter.object()->Flush(put_offset);
437 void PPB_Graphics3D_Proxy::OnMsgCreateTransferBuffer(
438 const HostResource& context,
439 uint32 size,
440 int32* id) {
441 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
442 if (enter.succeeded())
443 *id = enter.object()->CreateTransferBuffer(size);
444 else
445 *id = -1;
448 void PPB_Graphics3D_Proxy::OnMsgDestroyTransferBuffer(
449 const HostResource& context,
450 int32 id) {
451 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
452 if (enter.succeeded())
453 enter.object()->DestroyTransferBuffer(id);
456 void PPB_Graphics3D_Proxy::OnMsgGetTransferBuffer(
457 const HostResource& context,
458 int32 id,
459 ppapi::proxy::SerializedHandle* transfer_buffer) {
460 transfer_buffer->set_null_shmem();
462 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
463 int shm_handle = 0;
464 uint32_t shm_size = 0;
465 if (enter.succeeded() &&
466 enter.object()->GetTransferBuffer(id, &shm_handle, &shm_size)) {
467 transfer_buffer->set_shmem(
468 TransportSHMHandleFromInt(dispatcher(), shm_handle),
469 shm_size);
473 void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context) {
474 EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter(
475 context, callback_factory_,
476 &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context);
477 if (enter.succeeded())
478 enter.SetResult(enter.object()->SwapBuffers(enter.callback()));
481 void PPB_Graphics3D_Proxy::OnMsgInsertSyncPoint(const HostResource& context,
482 uint32* sync_point) {
483 *sync_point = 0;
484 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
485 if (enter.succeeded())
486 *sync_point = enter.object()->InsertSyncPoint();
488 #endif // !defined(OS_NACL)
490 void PPB_Graphics3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource,
491 int32_t pp_error) {
492 EnterPluginFromHostResource<PPB_Graphics3D_API> enter(resource);
493 if (enter.succeeded())
494 static_cast<Graphics3D*>(enter.object())->SwapBuffersACK(pp_error);
497 #if !defined(OS_NACL)
498 void PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin(
499 int32_t result,
500 const HostResource& context) {
501 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK(
502 API_ID_PPB_GRAPHICS_3D, context, result));
504 #endif // !defined(OS_NACL)
506 } // namespace proxy
507 } // namespace ppapi