Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: ppapi/proxy/ppb_context_3d_proxy.cc

Issue 6400007: Implement proxy for 3d-related interfaces (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: separate ParamTraits<gpu::CommandBuffer::State> into own library Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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_context_3d_proxy.h"
6
7 #include "base/hash_tables.h"
8 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
9 #include "gpu/command_buffer/client/gles2_implementation.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/c/pp_resource.h"
12 #include "ppapi/c/dev/ppb_context_3d_dev.h"
13 #include "ppapi/c/dev/ppb_context_3d_trusted_dev.h"
14 #include "ppapi/proxy/plugin_dispatcher.h"
15 #include "ppapi/proxy/plugin_resource.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/proxy/ppb_surface_3d_proxy.h"
18
19 namespace pp {
20 namespace proxy {
21
22 namespace {
23
24 PP_Resource Create(PP_Instance instance,
25 PP_Config3D_Dev config,
26 PP_Resource share_context,
27 const int32_t* attrib_list) {
28 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
29 if (!dispatcher)
30 return PP_ERROR_BADARGUMENT;
31
32 // TODO(alokp): Support shared context.
33 DCHECK_EQ(0, share_context);
34 if (share_context != 0)
35 return 0;
36
37 std::vector<int32_t> attribs;
38 if (attrib_list) {
39 for (const int32_t* attr = attrib_list; attr; ++attr)
40 attribs.push_back(*attr);
41 } else {
42 attribs.push_back(0);
43 }
44
45 HostResource result;
46 dispatcher->Send(new PpapiHostMsg_PPBContext3D_Create(
47 INTERFACE_ID_PPB_CONTEXT_3D, instance, config, attribs, &result));
48
49 if (result.is_null())
50 return 0;
51 linked_ptr<Context3D> context_3d(new Context3D(result));
52 if (!context_3d->CreateImplementation())
53 return 0;
54 return PluginResourceTracker::GetInstance()->AddResource(context_3d);
55 }
56
57 PP_Bool IsContext3D(PP_Resource resource) {
58 Context3D* object = PluginResource::GetAs<Context3D>(resource);
59 return BoolToPPBool(!!object);
60 }
61
62 int32_t GetAttrib(PP_Resource context,
63 int32_t attribute,
64 int32_t* value) {
65 // TODO(alokp): Implement me.
66 return 0;
67 }
68
69 int32_t BindSurfaces(PP_Resource context_id,
70 PP_Resource draw,
71 PP_Resource read) {
72 Context3D* object = PluginResource::GetAs<Context3D>(context_id);
73 if (!object)
74 return PP_ERROR_BADRESOURCE;
75 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(
76 object->instance());
77 if (!dispatcher)
78 return PP_ERROR_FAILED;
79
80 // TODO(alokp): Support separate draw-read surfaces.
81 DCHECK_EQ(draw, read);
82 if (draw != read)
83 return PP_GRAPHICS3DERROR_BAD_MATCH;
84
85 Surface3D* draw_surface = PluginResource::GetAs<Surface3D>(draw);
86 Surface3D* read_surface = PluginResource::GetAs<Surface3D>(read);
87 if (draw && !draw_surface)
88 return PP_ERROR_BADRESOURCE;
89 if (read && !read_surface)
90 return PP_ERROR_BADRESOURCE;
91 HostResource host_draw =
92 draw_surface ? draw_surface->host_resource() : HostResource();
93 HostResource host_read =
94 read_surface ? read_surface->host_resource() : HostResource();
95
96 int32_t result;
97 dispatcher->Send(new PpapiHostMsg_PPBContext3D_BindSurfaces(
98 INTERFACE_ID_PPB_CONTEXT_3D,
99 object->host_resource(),
100 host_draw,
101 host_read,
102 &result));
103
104 if (result == PP_OK) {
brettw 2011/01/31 18:51:29 No {} since you didn't use them elsewhere.
piman 2011/01/31 19:34:29 Done.
105 object->BindSurfaces(draw_surface, read_surface);
106 }
107 return result;
108 }
109
110 int32_t GetBoundSurfaces(PP_Resource context,
111 PP_Resource* draw,
112 PP_Resource* read) {
113 Context3D* object = PluginResource::GetAs<Context3D>(context);
114 if (!object)
115 return PP_ERROR_BADRESOURCE;
116
117 Surface3D* draw_surface;
118 Surface3D* read_surface;
119 object->get_surfaces(&draw_surface, &read_surface);
120
121 *draw = draw_surface ? draw_surface->resource() : 0;
122 *read = read_surface ? read_surface->resource() : 0;
123 return PP_OK;
124 }
125
126
127 const PPB_Context3D_Dev ppb_context_3d = {
128 &Create,
129 &IsContext3D,
130 &GetAttrib,
131 &BindSurfaces,
132 &GetBoundSurfaces,
133 };
134
135 base::SharedMemoryHandle SHMHandleFromInt(int shm_handle) {
136 #if defined(OS_POSIX)
137 return base::FileDescriptor(shm_handle, true);
138 #elif defined(OS_WIN)
139 return reinterpret_cast<HANDLE>(shm_handle);
140 #else
141 #error "Platform not supported."
142 #endif
143 }
144
145 gpu::CommandBuffer::State GPUStateFromPPState(
146 const PP_Context3DTrustedState& s) {
147 gpu::CommandBuffer::State state;
148 state.num_entries = s.num_entries;
149 state.get_offset = s.get_offset;
150 state.put_offset = s.put_offset;
151 state.token = s.token;
152 state.error = static_cast<gpu::error::Error>(s.error);
153 return state;
154 }
155
156 // Size of the transfer buffer.
157 const int32 kCommandBufferSize = 1024 * 1024;
158 const int32 kTransferBufferSize = 1024 * 1024;
159
160 } // namespace
161
162 class PepperCommandBuffer : public gpu::CommandBuffer {
163 public:
164 PepperCommandBuffer(const HostResource& resource,
165 PluginDispatcher* dispatcher);
166 virtual ~PepperCommandBuffer();
167
168 // CommandBuffer implementation:
169 virtual bool Initialize(int32 size);
170 virtual gpu::Buffer GetRingBuffer();
171 virtual State GetState();
172 virtual void Flush(int32 put_offset);
173 virtual State FlushSync(int32 put_offset);
174 virtual void SetGetOffset(int32 get_offset);
175 virtual int32 CreateTransferBuffer(size_t size);
176 virtual void DestroyTransferBuffer(int32 id);
177 virtual gpu::Buffer GetTransferBuffer(int32 handle);
178 virtual void SetToken(int32 token);
179 virtual void SetParseError(gpu::error::Error error);
180
181 private:
182 bool Send(IPC::Message* msg);
183
184 int32 num_entries_;
185 scoped_ptr<base::SharedMemory> ring_buffer_;
186
187 typedef base::hash_map<int32, gpu::Buffer> TransferBufferMap;
188 TransferBufferMap transfer_buffers_;
189
190 State last_state_;
191
192 HostResource resource_;
193 PluginDispatcher* dispatcher_;
194
195 DISALLOW_COPY_AND_ASSIGN(PepperCommandBuffer);
196 };
197
198 PepperCommandBuffer::PepperCommandBuffer(
199 const HostResource& resource,
200 PluginDispatcher* dispatcher)
201 : num_entries_(0),
202 resource_(resource),
203 dispatcher_(dispatcher) {
204 }
205
206 PepperCommandBuffer::~PepperCommandBuffer() {
207 // Delete all the locally cached shared memory objects, closing the handle
208 // in this process.
209 for (TransferBufferMap::iterator it = transfer_buffers_.begin();
210 it != transfer_buffers_.end();
211 ++it) {
212 delete it->second.shared_memory;
213 it->second.shared_memory = NULL;
214 }
215 }
216
217 bool PepperCommandBuffer::Initialize(int32 size) {
218 DCHECK(!ring_buffer_.get());
219
220 // Initialize the service. Assuming we are sandboxed, the GPU
221 // process is responsible for duplicating the handle. This might not be true
222 // for NaCl.
223 base::SharedMemoryHandle handle;
224 if (Send(new PpapiHostMsg_PPBContext3D_Initialize(
225 INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &handle)) &&
226 base::SharedMemory::IsHandleValid(handle)) {
227 ring_buffer_.reset(new base::SharedMemory(handle, false));
228 if (ring_buffer_->Map(size)) {
229 num_entries_ = size / sizeof(gpu::CommandBufferEntry);
230 return true;
231 }
232
233 ring_buffer_.reset();
234 }
235
236 return false;
237 }
238
239 gpu::Buffer PepperCommandBuffer::GetRingBuffer() {
240 // Return locally cached ring buffer.
241 gpu::Buffer buffer;
242 buffer.ptr = ring_buffer_->memory();
243 buffer.size = num_entries_ * sizeof(gpu::CommandBufferEntry);
244 buffer.shared_memory = ring_buffer_.get();
245 return buffer;
246 }
247
248 gpu::CommandBuffer::State PepperCommandBuffer::GetState() {
249 // Send will flag state with lost context if IPC fails.
250 if (last_state_.error == gpu::error::kNoError) {
251 Send(new PpapiHostMsg_PPBContext3D_GetState(
252 INTERFACE_ID_PPB_CONTEXT_3D, resource_, &last_state_));
253 }
254
255 return last_state_;
256 }
257
258 void PepperCommandBuffer::Flush(int32 put_offset) {
259 if (last_state_.error != gpu::error::kNoError)
260 return;
261
262 IPC::Message* message = new PpapiHostMsg_PPBContext3D_AsyncFlush(
263 INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset);
264
265 // Do not let a synchronous flush hold up this message. If this handler is
266 // deferred until after the synchronous flush completes, it will overwrite the
267 // cached last_state_ with out-of-date data.
268 message->set_unblock(true);
269 Send(message);
270 }
271
272 gpu::CommandBuffer::State PepperCommandBuffer::FlushSync(int32 put_offset) {
273 // Send will flag state with lost context if IPC fails.
274 if (last_state_.error == gpu::error::kNoError) {
275 Send(new PpapiHostMsg_PPBContext3D_Flush(
276 INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset, &last_state_));
277 }
278
279 return last_state_;
280 }
281
282 void PepperCommandBuffer::SetGetOffset(int32 get_offset) {
283 // Not implemented in proxy.
284 NOTREACHED();
285 }
286
287 int32 PepperCommandBuffer::CreateTransferBuffer(size_t size) {
288 if (last_state_.error == gpu::error::kNoError) {
289 int32 id;
290 if (Send(new PpapiHostMsg_PPBContext3D_CreateTransferBuffer(
291 INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &id))) {
292 return id;
293 }
294 }
295
296 return -1;
297 }
298
299 void PepperCommandBuffer::DestroyTransferBuffer(int32 id) {
300 if (last_state_.error != gpu::error::kNoError)
301 return;
302
303 // Remove the transfer buffer from the client side4 cache.
304 TransferBufferMap::iterator it = transfer_buffers_.find(id);
305 DCHECK(it != transfer_buffers_.end());
306
307 // Delete the shared memory object, closing the handle in this process.
308 delete it->second.shared_memory;
309
310 transfer_buffers_.erase(it);
311
312 Send(new PpapiHostMsg_PPBContext3D_DestroyTransferBuffer(
313 INTERFACE_ID_PPB_CONTEXT_3D, resource_, id));
314 }
315
316 gpu::Buffer PepperCommandBuffer::GetTransferBuffer(int32 id) {
317 if (last_state_.error != gpu::error::kNoError)
318 return gpu::Buffer();
319
320 // Check local cache to see if there is already a client side shared memory
321 // object for this id.
322 TransferBufferMap::iterator it = transfer_buffers_.find(id);
323 if (it != transfer_buffers_.end()) {
324 return it->second;
325 }
326
327 // Assuming we are in the renderer process, the service is responsible for
328 // duplicating the handle. This might not be true for NaCl.
329 base::SharedMemoryHandle handle;
330 uint32 size;
331 if (!Send(new PpapiHostMsg_PPBContext3D_GetTransferBuffer(
332 INTERFACE_ID_PPB_CONTEXT_3D, resource_, id, &handle, &size))) {
333 return gpu::Buffer();
334 }
335
336 // Cache the transfer buffer shared memory object client side.
337 base::SharedMemory* shared_memory = new base::SharedMemory(handle, false);
brettw 2011/01/31 18:51:29 Maybe use a scoped_ptr and .release() it when you
piman 2011/01/31 19:34:29 Done.
338
339 // Map the shared memory on demand.
340 if (!shared_memory->memory()) {
341 if (!shared_memory->Map(size)) {
342 delete shared_memory;
343 return gpu::Buffer();
344 }
345 }
346
347 gpu::Buffer buffer;
348 buffer.ptr = shared_memory->memory();
349 buffer.size = size;
350 buffer.shared_memory = shared_memory;
351 transfer_buffers_[id] = buffer;
352
353 return buffer;
354 }
355
356 void PepperCommandBuffer::SetToken(int32 token) {
357 NOTREACHED();
358 }
359
360 void PepperCommandBuffer::SetParseError(gpu::error::Error error) {
361 NOTREACHED();
362 }
363
364 bool PepperCommandBuffer::Send(IPC::Message* msg) {
365 DCHECK(last_state_.error == gpu::error::kNoError);
366
367 if (dispatcher_->Send(msg)) {
368 return true;
369 } else {
brettw 2011/01/31 18:51:29 Chrome style prefers no else after return.
piman 2011/01/31 19:34:29 Done.
370 last_state_.error = gpu::error::kLostContext;
371 return false;
372 }
373 }
374
375 Context3D::Context3D(const HostResource& resource)
376 : PluginResource(resource),
brettw 2011/01/31 18:51:29 2 more spaces.
piman 2011/01/31 19:34:29 Done.
377 draw_(NULL),
378 read_(NULL),
379 transfer_buffer_id_(NULL) {
380 }
381
382 Context3D::~Context3D() {
383 if (draw_)
384 draw_->set_context(NULL);
385 }
386
387 bool Context3D::CreateImplementation() {
388 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance());
389 if (!dispatcher)
390 return false;
391
392 command_buffer_.reset(new PepperCommandBuffer(host_resource(), dispatcher));
393
394 if (!command_buffer_->Initialize(kCommandBufferSize))
395 return false;
396
397 helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get()));
398 if (!helper_->Initialize(kCommandBufferSize))
399 return false;
400
401 transfer_buffer_id_ =
402 command_buffer_->CreateTransferBuffer(kTransferBufferSize);
403 if (transfer_buffer_id_ < 0)
404 return false;
405
406 gpu::Buffer transfer_buffer =
407 command_buffer_->GetTransferBuffer(transfer_buffer_id_);
408 if (!transfer_buffer.ptr)
409 return false;
410
411 gles2_impl_.reset(new gpu::gles2::GLES2Implementation(
412 helper_.get(),
413 transfer_buffer.size,
414 transfer_buffer.ptr,
415 transfer_buffer_id_,
416 false));
417
418 return true;
419 }
420
421 void Context3D::BindSurfaces(Surface3D* draw, Surface3D* read) {
422 if (draw != draw_) {
423 if (draw_)
424 draw_->set_context(NULL);
425 if (draw) {
426 draw->set_context(this);
427 // Resize the backing texture to the size of the instance when it is
428 // bound.
429 // TODO(alokp): This should be the responsibility of plugins.
430 PluginDispatcher* dispatcher =
431 PluginDispatcher::GetForInstance(instance());
432 DCHECK(dispatcher);
433 InstanceData* data = dispatcher->GetInstanceData(instance());
434 DCHECK(data);
435 gles2_impl()->ResizeCHROMIUM(data->position.size.width,
436 data->position.size.height);
437 }
438 draw_ = draw;
439 }
440 read_ = read;
441 }
442
443 PPB_Context3D_Proxy::PPB_Context3D_Proxy(Dispatcher* dispatcher,
444 const void* target_interface)
445 : InterfaceProxy(dispatcher, target_interface) {
446 }
447
448 PPB_Context3D_Proxy::~PPB_Context3D_Proxy() {
449 }
450
451 const PPB_Context3DTrusted_Dev*
452 PPB_Context3D_Proxy::ppb_context_3d_trusted() const {
453 return static_cast<const PPB_Context3DTrusted_Dev*>(
454 dispatcher()->GetLocalInterface(
455 PPB_CONTEXT_3D_TRUSTED_DEV_INTERFACE));
456 }
457
458 const void* PPB_Context3D_Proxy::GetSourceInterface() const {
459 return &ppb_context_3d;
460 }
461
462 InterfaceID PPB_Context3D_Proxy::GetInterfaceId() const {
463 return INTERFACE_ID_PPB_CONTEXT_3D;
464 }
465
466 bool PPB_Context3D_Proxy::OnMessageReceived(const IPC::Message& msg) {
467 bool handled = true;
468 IPC_BEGIN_MESSAGE_MAP(PPB_Context3D_Proxy, msg)
469 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Create,
470 OnMsgCreate)
471 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_BindSurfaces,
472 OnMsgBindSurfaces)
473 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Initialize,
474 OnMsgInitialize)
475 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetState,
476 OnMsgGetState)
477 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Flush,
478 OnMsgFlush)
479 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_AsyncFlush,
480 OnMsgAsyncFlush)
481 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_CreateTransferBuffer,
482 OnMsgCreateTransferBuffer)
483 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_DestroyTransferBuffer,
484 OnMsgDestroyTransferBuffer)
485 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetTransferBuffer,
486 OnMsgGetTransferBuffer)
487 IPC_MESSAGE_UNHANDLED(handled = false)
488
489 IPC_END_MESSAGE_MAP()
490 // FIXME(brettw) handle bad messages!
491 return handled;
492 }
493
494 void PPB_Context3D_Proxy::OnMsgCreate(PP_Instance instance,
495 PP_Config3D_Dev config,
496 std::vector<int32_t> attribs,
497 HostResource* result) {
498 DCHECK(attribs.back() == 0);
499 PP_Resource resource = ppb_context_3d_trusted()->CreateRaw(
500 instance, config, 0, &attribs.front());
501 result->SetHostResource(instance, resource);
502 }
503
504 void PPB_Context3D_Proxy::OnMsgBindSurfaces(const HostResource& context,
505 const HostResource& draw,
506 const HostResource& read,
507 int32_t* result) {
508 *result = ppb_context_3d_target()->BindSurfaces(context.host_resource(),
509 draw.host_resource(),
510 read.host_resource());
511 }
512
513 void PPB_Context3D_Proxy::OnMsgInitialize(
514 const HostResource& context,
515 int32 size,
516 base::SharedMemoryHandle* ring_buffer) {
517 const PPB_Context3DTrusted_Dev* context_3d_trusted = ppb_context_3d_trusted();
518 *ring_buffer = base::SharedMemory::NULLHandle();
519 if (!context_3d_trusted->Initialize(context.host_resource(), size))
520 return;
521
522 int shm_handle;
523 uint32_t shm_size;
524 if (!context_3d_trusted->GetRingBuffer(context.host_resource(),
525 &shm_handle,
526 &shm_size)) {
527 return;
528 }
529
530 *ring_buffer = SHMHandleFromInt(shm_handle);
531 }
532
533 void PPB_Context3D_Proxy::OnMsgGetState(const HostResource& context,
534 gpu::CommandBuffer::State* state) {
535 PP_Context3DTrustedState pp_state =
536 ppb_context_3d_trusted()->GetState(context.host_resource());
537 *state = GPUStateFromPPState(pp_state);
538 }
539
540 void PPB_Context3D_Proxy::OnMsgFlush(const HostResource& context,
541 int32 put_offset,
542 gpu::CommandBuffer::State* state) {
543 PP_Context3DTrustedState pp_state =
544 ppb_context_3d_trusted()->FlushSync(context.host_resource(), put_offset);
545 *state = GPUStateFromPPState(pp_state);
546 }
547
548 void PPB_Context3D_Proxy::OnMsgAsyncFlush(const HostResource& context,
549 int32 put_offset) {
550 ppb_context_3d_trusted()->Flush(context.host_resource(), put_offset);
551 }
552
553 void PPB_Context3D_Proxy::OnMsgCreateTransferBuffer(
554 const HostResource& context,
555 int32 size,
556 int32* id) {
557 *id = ppb_context_3d_trusted()->CreateTransferBuffer(
558 context.host_resource(), size);
559 }
560
561 void PPB_Context3D_Proxy::OnMsgDestroyTransferBuffer(
562 const HostResource& context,
563 int32 id) {
564 ppb_context_3d_trusted()->DestroyTransferBuffer(context.host_resource(), id);
565 }
566
567 void PPB_Context3D_Proxy::OnMsgGetTransferBuffer(
568 const HostResource& context,
569 int32 id,
570 base::SharedMemoryHandle* transfer_buffer,
571 uint32* size) {
572 *transfer_buffer = base::SharedMemory::NULLHandle();
573 int shm_handle;
574 uint32_t shm_size;
575 if (!ppb_context_3d_trusted()->GetTransferBuffer(context.host_resource(),
576 id,
577 &shm_handle,
578 &shm_size)) {
brettw 2011/01/31 18:51:29 Indenting.
piman 2011/01/31 19:34:29 Done.
579 return;
580 }
581 *transfer_buffer = SHMHandleFromInt(shm_handle);
582 *size = shm_size;
583 }
584
585 } // namespace proxy
586 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698