Refactor android test results logging.
[chromium-blink-merge.git] / ppapi / proxy / ppb_graphics_3d_proxy.cc
blob9919df33d19c1365c421f9b418fee8223a99309f
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 PP_Graphics3DTrustedState GetErrorState() {
49 PP_Graphics3DTrustedState error_state = { 0 };
50 error_state.error = PPB_GRAPHICS3D_TRUSTED_ERROR_GENERICERROR;
51 return error_state;
54 gpu::CommandBuffer::State GPUStateFromPPState(
55 const PP_Graphics3DTrustedState& s) {
56 gpu::CommandBuffer::State state;
57 state.num_entries = s.num_entries;
58 state.get_offset = s.get_offset;
59 state.put_offset = s.put_offset;
60 state.token = s.token;
61 state.error = static_cast<gpu::error::Error>(s.error);
62 state.generation = s.generation;
63 return state;
66 } // namespace
68 // This class just wraps a CommandBuffer and optionally locks around every
69 // method. This is used to ensure that we have the Proxy lock any time we enter
70 // PpapiCommandBufferProxy.
72 // Note, for performance reasons, most of this code is not truly thread
73 // safe in the sense of multiple threads concurrently rendering to the same
74 // Graphics3D context; this isn't allowed, and will likely either crash or
75 // result in undefined behavior. It is assumed that the thread which creates
76 // the Graphics3D context will be the thread on which subsequent gl rendering
77 // will be done.
79 // TODO(nfullagar): At some point, allow multiple threads to concurrently render
80 // each to its own context. First step is to allow a single thread (either main
81 // thread or background thread) to render to a single Graphics3D context.
82 class Graphics3D::LockingCommandBuffer : public gpu::CommandBuffer {
83 public:
84 explicit LockingCommandBuffer(gpu::CommandBuffer* gpu_command_buffer)
85 : gpu_command_buffer_(gpu_command_buffer), need_to_lock_(true) {
87 virtual ~LockingCommandBuffer() {
89 void set_need_to_lock(bool need_to_lock) { need_to_lock_ = need_to_lock; }
90 bool need_to_lock() const { return need_to_lock_; }
92 private:
93 // MaybeLock acquires the proxy lock on construction if and only if
94 // need_to_lock is true. If it acquired the lock, it releases it on
95 // destruction. If need_to_lock is false, then the lock must already be held.
96 struct MaybeLock {
97 explicit MaybeLock(bool need_to_lock) : locked_(need_to_lock) {
98 if (need_to_lock)
99 ppapi::ProxyLock::Acquire();
100 else
101 ppapi::ProxyLock::AssertAcquired();
103 ~MaybeLock() {
104 if (locked_)
105 ppapi::ProxyLock::Release();
107 private:
108 bool locked_;
111 // gpu::CommandBuffer implementation:
112 virtual bool Initialize() OVERRIDE {
113 MaybeLock lock(need_to_lock_);
114 return gpu_command_buffer_->Initialize();
116 virtual State GetState() OVERRIDE {
117 MaybeLock lock(need_to_lock_);
118 return gpu_command_buffer_->GetState();
120 virtual State GetLastState() OVERRIDE {
121 // During a normal scene, the vast majority of calls are to GetLastState().
122 // We don't allow multi-threaded rendering on the same contex, so for
123 // performance reasons, avoid the global lock for this entry point. We can
124 // get away with this here because the underlying implementation of
125 // GetLastState() is trivial and does not involve global or shared state
126 // between other contexts.
127 // TODO(nfullagar): We can probably skip MaybeLock for other methods, but
128 // the performance gain may not be worth it.
130 // MaybeLock lock(need_to_lock_);
131 return gpu_command_buffer_->GetLastState();
133 virtual void Flush(int32 put_offset) OVERRIDE {
134 MaybeLock lock(need_to_lock_);
135 gpu_command_buffer_->Flush(put_offset);
137 virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE {
138 MaybeLock lock(need_to_lock_);
139 return gpu_command_buffer_->FlushSync(put_offset, last_known_get);
141 virtual void SetGetBuffer(int32 transfer_buffer_id) OVERRIDE {
142 MaybeLock lock(need_to_lock_);
143 gpu_command_buffer_->SetGetBuffer(transfer_buffer_id);
145 virtual void SetGetOffset(int32 get_offset) OVERRIDE {
146 MaybeLock lock(need_to_lock_);
147 gpu_command_buffer_->SetGetOffset(get_offset);
149 virtual int32 CreateTransferBuffer(size_t size, int32 id_request) OVERRIDE {
150 MaybeLock lock(need_to_lock_);
151 return gpu_command_buffer_->CreateTransferBuffer(size, id_request);
153 virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory,
154 size_t size,
155 int32 id_request) OVERRIDE {
156 MaybeLock lock(need_to_lock_);
157 return gpu_command_buffer_->RegisterTransferBuffer(shared_memory, size,
158 id_request);
160 virtual void DestroyTransferBuffer(int32 id) OVERRIDE {
161 MaybeLock lock(need_to_lock_);
162 gpu_command_buffer_->DestroyTransferBuffer(id);
164 virtual gpu::Buffer GetTransferBuffer(int32 handle) OVERRIDE {
165 MaybeLock lock(need_to_lock_);
166 return gpu_command_buffer_->GetTransferBuffer(handle);
168 virtual void SetToken(int32 token) OVERRIDE {
169 MaybeLock lock(need_to_lock_);
170 gpu_command_buffer_->SetToken(token);
172 virtual void SetParseError(gpu::error::Error error) OVERRIDE {
173 MaybeLock lock(need_to_lock_);
174 gpu_command_buffer_->SetParseError(error);
176 virtual void SetContextLostReason(
177 gpu::error::ContextLostReason reason) OVERRIDE {
178 MaybeLock lock(need_to_lock_);
179 gpu_command_buffer_->SetContextLostReason(reason);
182 // Weak pointer - see class Graphics3D for the scopted_ptr.
183 gpu::CommandBuffer* gpu_command_buffer_;
185 bool need_to_lock_;
188 Graphics3D::Graphics3D(const HostResource& resource)
189 : PPB_Graphics3D_Shared(resource),
190 num_already_locked_calls_(0) {
193 Graphics3D::~Graphics3D() {
194 DestroyGLES2Impl();
197 bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2) {
198 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this);
199 if (!dispatcher)
200 return false;
202 command_buffer_.reset(
203 new PpapiCommandBufferProxy(host_resource(), dispatcher));
204 locking_command_buffer_.reset(
205 new LockingCommandBuffer(command_buffer_.get()));
207 ScopedNoLocking already_locked(this);
208 if (!command_buffer_->Initialize())
209 return false;
211 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize,
212 share_gles2);
215 PP_Bool Graphics3D::InitCommandBuffer() {
216 return PP_FALSE;
219 PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) {
220 return PP_FALSE;
223 PP_Graphics3DTrustedState Graphics3D::GetState() {
224 return GetErrorState();
227 PP_Bool Graphics3D::Flush(int32_t put_offset) {
228 return PP_FALSE;
231 PP_Graphics3DTrustedState Graphics3D::FlushSync(int32_t put_offset) {
232 return GetErrorState();
235 int32_t Graphics3D::CreateTransferBuffer(uint32_t size) {
236 return PP_FALSE;
239 PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) {
240 return PP_FALSE;
243 PP_Bool Graphics3D::GetTransferBuffer(int32_t id,
244 int* shm_handle,
245 uint32_t* shm_size) {
246 return PP_FALSE;
249 PP_Graphics3DTrustedState Graphics3D::FlushSyncFast(int32_t put_offset,
250 int32_t last_known_get) {
251 return GetErrorState();
254 gpu::CommandBuffer* Graphics3D::GetCommandBuffer() {
255 return locking_command_buffer_.get();
258 int32 Graphics3D::DoSwapBuffers() {
259 // gles2_impl()->SwapBuffers() results in CommandBuffer calls, and we already
260 // have the proxy lock.
261 ScopedNoLocking already_locked(this);
263 gles2_impl()->SwapBuffers();
264 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers(
265 API_ID_PPB_GRAPHICS_3D, host_resource());
266 msg->set_unblock(true);
267 PluginDispatcher::GetForResource(this)->Send(msg);
269 return PP_OK_COMPLETIONPENDING;
272 void Graphics3D::PushAlreadyLocked() {
273 ppapi::ProxyLock::AssertAcquired();
274 if (num_already_locked_calls_ == 0)
275 locking_command_buffer_->set_need_to_lock(false);
276 ++num_already_locked_calls_;
279 void Graphics3D::PopAlreadyLocked() {
280 // We must have Pushed before we can Pop.
281 DCHECK(!locking_command_buffer_->need_to_lock());
282 DCHECK_GT(num_already_locked_calls_, 0);
283 ppapi::ProxyLock::AssertAcquired();
284 --num_already_locked_calls_;
285 if (num_already_locked_calls_ == 0)
286 locking_command_buffer_->set_need_to_lock(true);
289 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher)
290 : InterfaceProxy(dispatcher),
291 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
294 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() {
297 // static
298 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource(
299 PP_Instance instance,
300 PP_Resource share_context,
301 const int32_t* attrib_list) {
302 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
303 if (!dispatcher)
304 return PP_ERROR_BADARGUMENT;
306 HostResource share_host;
307 gpu::gles2::GLES2Implementation* share_gles2 = NULL;
308 if (share_context != 0) {
309 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
310 if (enter.failed())
311 return PP_ERROR_BADARGUMENT;
313 PPB_Graphics3D_Shared* share_graphics =
314 static_cast<PPB_Graphics3D_Shared*>(enter.object());
315 share_host = share_graphics->host_resource();
316 share_gles2 = share_graphics->gles2_impl();
319 std::vector<int32_t> attribs;
320 if (attrib_list) {
321 for (const int32_t* attr = attrib_list;
322 attr[0] != PP_GRAPHICS3DATTRIB_NONE;
323 attr += 2) {
324 attribs.push_back(attr[0]);
325 attribs.push_back(attr[1]);
328 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE);
330 HostResource result;
331 dispatcher->Send(new PpapiHostMsg_PPBGraphics3D_Create(
332 API_ID_PPB_GRAPHICS_3D, instance, share_host, attribs, &result));
333 if (result.is_null())
334 return 0;
336 scoped_refptr<Graphics3D> graphics_3d(new Graphics3D(result));
337 if (!graphics_3d->Init(share_gles2))
338 return 0;
339 return graphics_3d->GetReference();
342 bool PPB_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) {
343 bool handled = true;
344 IPC_BEGIN_MESSAGE_MAP(PPB_Graphics3D_Proxy, msg)
345 #if !defined(OS_NACL)
346 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Create,
347 OnMsgCreate)
348 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_InitCommandBuffer,
349 OnMsgInitCommandBuffer)
350 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SetGetBuffer,
351 OnMsgSetGetBuffer)
352 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetState,
353 OnMsgGetState)
354 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Flush,
355 OnMsgFlush)
356 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_AsyncFlush,
357 OnMsgAsyncFlush)
358 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer,
359 OnMsgCreateTransferBuffer)
360 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer,
361 OnMsgDestroyTransferBuffer)
362 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer,
363 OnMsgGetTransferBuffer)
364 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
365 OnMsgSwapBuffers)
366 #endif // !defined(OS_NACL)
368 IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics3D_SwapBuffersACK,
369 OnMsgSwapBuffersACK)
370 IPC_MESSAGE_UNHANDLED(handled = false)
372 IPC_END_MESSAGE_MAP()
373 // FIXME(brettw) handle bad messages!
374 return handled;
377 #if !defined(OS_NACL)
378 void PPB_Graphics3D_Proxy::OnMsgCreate(PP_Instance instance,
379 HostResource share_context,
380 const std::vector<int32_t>& attribs,
381 HostResource* result) {
382 if (attribs.empty() ||
383 attribs.back() != PP_GRAPHICS3DATTRIB_NONE ||
384 !(attribs.size() & 1))
385 return; // Bad message.
387 thunk::EnterResourceCreation enter(instance);
389 if (enter.succeeded()) {
390 result->SetHostResource(
391 instance,
392 enter.functions()->CreateGraphics3DRaw(instance,
393 share_context.host_resource(),
394 &attribs.front()));
398 void PPB_Graphics3D_Proxy::OnMsgInitCommandBuffer(
399 const HostResource& context) {
400 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
401 if (enter.failed())
402 return;
404 if (!enter.object()->InitCommandBuffer())
405 return;
408 void PPB_Graphics3D_Proxy::OnMsgSetGetBuffer(
409 const HostResource& context,
410 int32 transfer_buffer_id) {
411 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
412 if (enter.succeeded())
413 enter.object()->SetGetBuffer(transfer_buffer_id);
416 void PPB_Graphics3D_Proxy::OnMsgGetState(const HostResource& context,
417 gpu::CommandBuffer::State* state,
418 bool* success) {
419 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
420 if (enter.failed()) {
421 *success = false;
422 return;
424 PP_Graphics3DTrustedState pp_state = enter.object()->GetState();
425 *state = GPUStateFromPPState(pp_state);
426 *success = true;
429 void PPB_Graphics3D_Proxy::OnMsgFlush(const HostResource& context,
430 int32 put_offset,
431 int32 last_known_get,
432 gpu::CommandBuffer::State* state,
433 bool* success) {
434 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
435 if (enter.failed()) {
436 *success = false;
437 return;
439 PP_Graphics3DTrustedState pp_state = enter.object()->FlushSyncFast(
440 put_offset, last_known_get);
441 *state = GPUStateFromPPState(pp_state);
442 *success = true;
445 void PPB_Graphics3D_Proxy::OnMsgAsyncFlush(const HostResource& context,
446 int32 put_offset) {
447 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
448 if (enter.succeeded())
449 enter.object()->Flush(put_offset);
452 void PPB_Graphics3D_Proxy::OnMsgCreateTransferBuffer(
453 const HostResource& context,
454 uint32 size,
455 int32* id) {
456 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
457 if (enter.succeeded())
458 *id = enter.object()->CreateTransferBuffer(size);
459 else
460 *id = 0;
463 void PPB_Graphics3D_Proxy::OnMsgDestroyTransferBuffer(
464 const HostResource& context,
465 int32 id) {
466 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
467 if (enter.succeeded())
468 enter.object()->DestroyTransferBuffer(id);
471 void PPB_Graphics3D_Proxy::OnMsgGetTransferBuffer(
472 const HostResource& context,
473 int32 id,
474 ppapi::proxy::SerializedHandle* transfer_buffer) {
475 transfer_buffer->set_null_shmem();
477 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
478 int shm_handle = 0;
479 uint32_t shm_size = 0;
480 if (enter.succeeded() &&
481 enter.object()->GetTransferBuffer(id, &shm_handle, &shm_size)) {
482 transfer_buffer->set_shmem(
483 TransportSHMHandleFromInt(dispatcher(), shm_handle),
484 shm_size);
488 void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context) {
489 EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter(
490 context, callback_factory_,
491 &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context);
492 if (enter.succeeded())
493 enter.SetResult(enter.object()->SwapBuffers(enter.callback()));
495 #endif // !defined(OS_NACL)
497 void PPB_Graphics3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource,
498 int32_t pp_error) {
499 EnterPluginFromHostResource<PPB_Graphics3D_API> enter(resource);
500 if (enter.succeeded())
501 static_cast<Graphics3D*>(enter.object())->SwapBuffersACK(pp_error);
504 #if !defined(OS_NACL)
505 void PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin(
506 int32_t result,
507 const HostResource& context) {
508 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK(
509 API_ID_PPB_GRAPHICS_3D, context, result));
511 #endif // !defined(OS_NACL)
513 } // namespace proxy
514 } // namespace ppapi