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