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 "ppapi/proxy/ppb_graphics_3d_proxy.h" 6 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/thunk/enter.h" 16#include "ppapi/thunk/resource_creation_api.h" 17#include "ppapi/thunk/thunk.h" 18 19using ppapi::thunk::EnterResourceNoLock; 20using ppapi::thunk::PPB_Graphics3D_API; 21using ppapi::thunk::ResourceCreationAPI; 22 23namespace ppapi { 24namespace proxy { 25 26namespace { 27 28const int32 kCommandBufferSize = 1024 * 1024; 29const int32 kTransferBufferSize = 1024 * 1024; 30 31base::SharedMemoryHandle TransportSHMHandle( 32 Dispatcher* dispatcher, 33 const base::SharedMemoryHandle& handle) { 34 base::PlatformFile source = IPC::PlatformFileForTransitToPlatformFile(handle); 35 // Don't close the handle, it doesn't belong to us. 36 return dispatcher->ShareHandleWithRemote(source, false); 37} 38 39gpu::CommandBuffer::State GetErrorState() { 40 gpu::CommandBuffer::State error_state; 41 error_state.error = gpu::error::kGenericError; 42 return error_state; 43} 44 45} // namespace 46 47Graphics3D::Graphics3D(const HostResource& resource) 48 : PPB_Graphics3D_Shared(resource) { 49} 50 51Graphics3D::~Graphics3D() { 52 DestroyGLES2Impl(); 53} 54 55bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2, 56 const SerializedHandle& shared_state) { 57 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); 58 if (!dispatcher) 59 return false; 60 61 command_buffer_.reset( 62 new PpapiCommandBufferProxy(host_resource(), dispatcher, shared_state)); 63 64 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, 65 share_gles2); 66} 67 68PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) { 69 return PP_FALSE; 70} 71 72PP_Bool Graphics3D::Flush(int32_t put_offset) { 73 return PP_FALSE; 74} 75 76scoped_refptr<gpu::Buffer> Graphics3D::CreateTransferBuffer( 77 uint32_t size, 78 int32_t* id) { 79 *id = -1; 80 return NULL; 81} 82 83PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) { 84 return PP_FALSE; 85} 86 87gpu::CommandBuffer::State Graphics3D::WaitForTokenInRange(int32_t start, 88 int32_t end) { 89 return GetErrorState(); 90} 91 92gpu::CommandBuffer::State Graphics3D::WaitForGetOffsetInRange(int32_t start, 93 int32_t end) { 94 return GetErrorState(); 95} 96 97uint32_t Graphics3D::InsertSyncPoint() { 98 NOTREACHED(); 99 return 0; 100} 101 102uint32_t Graphics3D::InsertFutureSyncPoint() { 103 NOTREACHED(); 104 return 0; 105} 106 107void Graphics3D::RetireSyncPoint(uint32_t sync_point) { 108 NOTREACHED(); 109} 110 111gpu::CommandBuffer* Graphics3D::GetCommandBuffer() { 112 return command_buffer_.get(); 113} 114 115gpu::GpuControl* Graphics3D::GetGpuControl() { 116 return command_buffer_.get(); 117} 118 119int32 Graphics3D::DoSwapBuffers() { 120 gles2_impl()->SwapBuffers(); 121 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( 122 API_ID_PPB_GRAPHICS_3D, host_resource()); 123 msg->set_unblock(true); 124 PluginDispatcher::GetForResource(this)->Send(msg); 125 126 return PP_OK_COMPLETIONPENDING; 127} 128 129PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) 130 : InterfaceProxy(dispatcher), 131 callback_factory_(this) { 132} 133 134PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { 135} 136 137// static 138PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( 139 PP_Instance instance, 140 PP_Resource share_context, 141 const int32_t* attrib_list) { 142 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 143 if (!dispatcher) 144 return PP_ERROR_BADARGUMENT; 145 146 HostResource share_host; 147 gpu::gles2::GLES2Implementation* share_gles2 = NULL; 148 if (share_context != 0) { 149 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true); 150 if (enter.failed()) 151 return PP_ERROR_BADARGUMENT; 152 153 PPB_Graphics3D_Shared* share_graphics = 154 static_cast<PPB_Graphics3D_Shared*>(enter.object()); 155 share_host = share_graphics->host_resource(); 156 share_gles2 = share_graphics->gles2_impl(); 157 } 158 159 std::vector<int32_t> attribs; 160 if (attrib_list) { 161 for (const int32_t* attr = attrib_list; 162 attr[0] != PP_GRAPHICS3DATTRIB_NONE; 163 attr += 2) { 164 attribs.push_back(attr[0]); 165 attribs.push_back(attr[1]); 166 } 167 } 168 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); 169 170 HostResource result; 171 ppapi::proxy::SerializedHandle shared_state; 172 dispatcher->Send(new PpapiHostMsg_PPBGraphics3D_Create(API_ID_PPB_GRAPHICS_3D, 173 instance, share_host, attribs, &result, &shared_state)); 174 175 if (result.is_null()) 176 return 0; 177 178 scoped_refptr<Graphics3D> graphics_3d(new Graphics3D(result)); 179 if (!graphics_3d->Init(share_gles2, shared_state)) 180 return 0; 181 return graphics_3d->GetReference(); 182} 183 184bool PPB_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) { 185 bool handled = true; 186 IPC_BEGIN_MESSAGE_MAP(PPB_Graphics3D_Proxy, msg) 187#if !defined(OS_NACL) 188 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Create, 189 OnMsgCreate) 190 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SetGetBuffer, 191 OnMsgSetGetBuffer) 192 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_WaitForTokenInRange, 193 OnMsgWaitForTokenInRange) 194 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_WaitForGetOffsetInRange, 195 OnMsgWaitForGetOffsetInRange) 196 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_AsyncFlush, OnMsgAsyncFlush) 197 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer, 198 OnMsgCreateTransferBuffer) 199 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer, 200 OnMsgDestroyTransferBuffer) 201 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers, 202 OnMsgSwapBuffers) 203 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_InsertSyncPoint, 204 OnMsgInsertSyncPoint) 205 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_InsertFutureSyncPoint, 206 OnMsgInsertFutureSyncPoint) 207 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_RetireSyncPoint, 208 OnMsgRetireSyncPoint) 209#endif // !defined(OS_NACL) 210 211 IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics3D_SwapBuffersACK, 212 OnMsgSwapBuffersACK) 213 IPC_MESSAGE_UNHANDLED(handled = false) 214 215 IPC_END_MESSAGE_MAP() 216 // FIXME(brettw) handle bad messages! 217 return handled; 218} 219 220#if !defined(OS_NACL) 221void PPB_Graphics3D_Proxy::OnMsgCreate(PP_Instance instance, 222 HostResource share_context, 223 const std::vector<int32_t>& attribs, 224 HostResource* result, 225 SerializedHandle* shared_state) { 226 shared_state->set_null_shmem(); 227 if (attribs.empty() || 228 attribs.back() != PP_GRAPHICS3DATTRIB_NONE || 229 !(attribs.size() & 1)) 230 return; // Bad message. 231 232 thunk::EnterResourceCreation enter(instance); 233 234 if (!enter.succeeded()) 235 return; 236 237 base::SharedMemoryHandle handle = IPC::InvalidPlatformFileForTransit(); 238 result->SetHostResource( 239 instance, 240 enter.functions()->CreateGraphics3DRaw(instance, 241 share_context.host_resource(), 242 &attribs.front(), 243 &handle)); 244 if (!result->is_null()) { 245 shared_state->set_shmem(TransportSHMHandle(dispatcher(), handle), 246 sizeof(gpu::CommandBuffer::State)); 247 } 248} 249 250void PPB_Graphics3D_Proxy::OnMsgSetGetBuffer( 251 const HostResource& context, 252 int32 transfer_buffer_id) { 253 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 254 if (enter.succeeded()) 255 enter.object()->SetGetBuffer(transfer_buffer_id); 256} 257 258void PPB_Graphics3D_Proxy::OnMsgWaitForTokenInRange( 259 const HostResource& context, 260 int32 start, 261 int32 end, 262 gpu::CommandBuffer::State* state, 263 bool* success) { 264 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 265 if (enter.failed()) { 266 *success = false; 267 return; 268 } 269 *state = enter.object()->WaitForTokenInRange(start, end); 270 *success = true; 271} 272 273void PPB_Graphics3D_Proxy::OnMsgWaitForGetOffsetInRange( 274 const HostResource& context, 275 int32 start, 276 int32 end, 277 gpu::CommandBuffer::State* state, 278 bool* success) { 279 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 280 if (enter.failed()) { 281 *success = false; 282 return; 283 } 284 *state = enter.object()->WaitForGetOffsetInRange(start, end); 285 *success = true; 286} 287 288void PPB_Graphics3D_Proxy::OnMsgAsyncFlush(const HostResource& context, 289 int32 put_offset) { 290 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 291 if (enter.succeeded()) 292 enter.object()->Flush(put_offset); 293} 294 295void PPB_Graphics3D_Proxy::OnMsgCreateTransferBuffer( 296 const HostResource& context, 297 uint32 size, 298 int32* id, 299 SerializedHandle* transfer_buffer) { 300 transfer_buffer->set_null_shmem(); 301 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 302 if (enter.succeeded()) { 303 scoped_refptr<gpu::Buffer> buffer = 304 enter.object()->CreateTransferBuffer(size, id); 305 if (!buffer.get()) 306 return; 307 gpu::SharedMemoryBufferBacking* backing = 308 static_cast<gpu::SharedMemoryBufferBacking*>(buffer->backing()); 309 DCHECK(backing && backing->shared_memory()); 310 transfer_buffer->set_shmem( 311 TransportSHMHandle(dispatcher(), backing->shared_memory()->handle()), 312 buffer->size()); 313 } else { 314 *id = -1; 315 } 316} 317 318void PPB_Graphics3D_Proxy::OnMsgDestroyTransferBuffer( 319 const HostResource& context, 320 int32 id) { 321 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 322 if (enter.succeeded()) 323 enter.object()->DestroyTransferBuffer(id); 324} 325 326void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context) { 327 EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter( 328 context, callback_factory_, 329 &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context); 330 if (enter.succeeded()) 331 enter.SetResult(enter.object()->SwapBuffers(enter.callback())); 332} 333 334void PPB_Graphics3D_Proxy::OnMsgInsertSyncPoint(const HostResource& context, 335 uint32* sync_point) { 336 *sync_point = 0; 337 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 338 if (enter.succeeded()) 339 *sync_point = enter.object()->InsertSyncPoint(); 340} 341 342void PPB_Graphics3D_Proxy::OnMsgInsertFutureSyncPoint( 343 const HostResource& context, 344 uint32* sync_point) { 345 *sync_point = 0; 346 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 347 if (enter.succeeded()) 348 *sync_point = enter.object()->InsertFutureSyncPoint(); 349} 350 351void PPB_Graphics3D_Proxy::OnMsgRetireSyncPoint(const HostResource& context, 352 uint32 sync_point) { 353 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); 354 if (enter.succeeded()) 355 enter.object()->RetireSyncPoint(sync_point); 356} 357#endif // !defined(OS_NACL) 358 359void PPB_Graphics3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource, 360 int32_t pp_error) { 361 EnterPluginFromHostResource<PPB_Graphics3D_API> enter(resource); 362 if (enter.succeeded()) 363 static_cast<Graphics3D*>(enter.object())->SwapBuffersACK(pp_error); 364} 365 366#if !defined(OS_NACL) 367void PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin( 368 int32_t result, 369 const HostResource& context) { 370 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( 371 API_ID_PPB_GRAPHICS_3D, context, result)); 372} 373#endif // !defined(OS_NACL) 374 375} // namespace proxy 376} // namespace ppapi 377 378