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 19 using ppapi::thunk::EnterResourceNoLock; 20 using ppapi::thunk::PPB_Graphics3D_API; 21 using ppapi::thunk::ResourceCreationAPI; 22 23 namespace ppapi { 24 namespace proxy { 25 26 namespace { 27 28 const int32 kCommandBufferSize = 1024 * 1024; 29 const int32 kTransferBufferSize = 1024 * 1024; 30 31 base::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 39 gpu::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 47 Graphics3D::Graphics3D(const HostResource& resource) 48 : PPB_Graphics3D_Shared(resource) { 49 } 50 51 Graphics3D::~Graphics3D() { 52 DestroyGLES2Impl(); 53 } 54 55 bool 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 68 PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) { 69 return PP_FALSE; 70 } 71 72 PP_Bool Graphics3D::Flush(int32_t put_offset) { 73 return PP_FALSE; 74 } 75 76 scoped_refptr<gpu::Buffer> Graphics3D::CreateTransferBuffer( 77 uint32_t size, 78 int32_t* id) { 79 *id = -1; 80 return NULL; 81 } 82 83 PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) { 84 return PP_FALSE; 85 } 86 87 gpu::CommandBuffer::State Graphics3D::WaitForTokenInRange(int32_t start, 88 int32_t end) { 89 return GetErrorState(); 90 } 91 92 gpu::CommandBuffer::State Graphics3D::WaitForGetOffsetInRange(int32_t start, 93 int32_t end) { 94 return GetErrorState(); 95 } 96 97 uint32_t Graphics3D::InsertSyncPoint() { 98 NOTREACHED(); 99 return 0; 100 } 101 102 uint32_t Graphics3D::InsertFutureSyncPoint() { 103 NOTREACHED(); 104 return 0; 105 } 106 107 void Graphics3D::RetireSyncPoint(uint32_t sync_point) { 108 NOTREACHED(); 109 } 110 111 gpu::CommandBuffer* Graphics3D::GetCommandBuffer() { 112 return command_buffer_.get(); 113 } 114 115 gpu::GpuControl* Graphics3D::GetGpuControl() { 116 return command_buffer_.get(); 117 } 118 119 int32 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 129 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) 130 : InterfaceProxy(dispatcher), 131 callback_factory_(this) { 132 } 133 134 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { 135 } 136 137 // static 138 PP_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 184 bool 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) 221 void 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 250 void 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 258 void 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 273 void 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 288 void 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 295 void 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 318 void 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 326 void 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 334 void 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 342 void 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 351 void 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 359 void 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) 367 void 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