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

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: rebase 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)
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 = object->get_draw_surface();
118 Surface3D* read_surface = object->get_read_surface();
119
120 *draw = draw_surface ? draw_surface->resource() : 0;
121 *read = read_surface ? read_surface->resource() : 0;
122 return PP_OK;
123 }
124
125
126 const PPB_Context3D_Dev ppb_context_3d = {
127 &Create,
128 &IsContext3D,
129 &GetAttrib,
130 &BindSurfaces,
131 &GetBoundSurfaces,
132 };
133
134 base::SharedMemoryHandle SHMHandleFromInt(int shm_handle) {
135 #if defined(OS_POSIX)
136 return base::FileDescriptor(shm_handle, true);
137 #elif defined(OS_WIN)
138 return reinterpret_cast<HANDLE>(shm_handle);
139 #else
140 #error "Platform not supported."
141 #endif
142 }
143
144 gpu::CommandBuffer::State GPUStateFromPPState(
145 const PP_Context3DTrustedState& s) {
146 gpu::CommandBuffer::State state;
147 state.num_entries = s.num_entries;
148 state.get_offset = s.get_offset;
149 state.put_offset = s.put_offset;
150 state.token = s.token;
151 state.error = static_cast<gpu::error::Error>(s.error);
152 return state;
153 }
154
155 // Size of the transfer buffer.
156 const int32 kCommandBufferSize = 1024 * 1024;
157 const int32 kTransferBufferSize = 1024 * 1024;
158
159 } // namespace
160
161 class PepperCommandBuffer : public gpu::CommandBuffer {
162 public:
163 PepperCommandBuffer(const HostResource& resource,
164 PluginDispatcher* dispatcher);
165 virtual ~PepperCommandBuffer();
166
167 // CommandBuffer implementation:
168 virtual bool Initialize(int32 size);
169 virtual gpu::Buffer GetRingBuffer();
170 virtual State GetState();
171 virtual void Flush(int32 put_offset);
172 virtual State FlushSync(int32 put_offset);
173 virtual void SetGetOffset(int32 get_offset);
174 virtual int32 CreateTransferBuffer(size_t size);
175 virtual void DestroyTransferBuffer(int32 id);
176 virtual gpu::Buffer GetTransferBuffer(int32 handle);
177 virtual void SetToken(int32 token);
178 virtual void SetParseError(gpu::error::Error error);
179
180 private:
181 bool Send(IPC::Message* msg);
182
183 int32 num_entries_;
184 scoped_ptr<base::SharedMemory> ring_buffer_;
185
186 typedef base::hash_map<int32, gpu::Buffer> TransferBufferMap;
187 TransferBufferMap transfer_buffers_;
188
189 State last_state_;
190
191 HostResource resource_;
192 PluginDispatcher* dispatcher_;
193
194 DISALLOW_COPY_AND_ASSIGN(PepperCommandBuffer);
195 };
196
197 PepperCommandBuffer::PepperCommandBuffer(
198 const HostResource& resource,
199 PluginDispatcher* dispatcher)
200 : num_entries_(0),
201 resource_(resource),
202 dispatcher_(dispatcher) {
203 }
204
205 PepperCommandBuffer::~PepperCommandBuffer() {
206 // Delete all the locally cached shared memory objects, closing the handle
207 // in this process.
208 for (TransferBufferMap::iterator it = transfer_buffers_.begin();
209 it != transfer_buffers_.end();
210 ++it) {
211 delete it->second.shared_memory;
212 it->second.shared_memory = NULL;
213 }
214 }
215
216 bool PepperCommandBuffer::Initialize(int32 size) {
217 DCHECK(!ring_buffer_.get());
218
219 // Initialize the service. Assuming we are sandboxed, the GPU
220 // process is responsible for duplicating the handle. This might not be true
221 // for NaCl.
222 base::SharedMemoryHandle handle;
223 if (Send(new PpapiHostMsg_PPBContext3D_Initialize(
224 INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &handle)) &&
225 base::SharedMemory::IsHandleValid(handle)) {
226 ring_buffer_.reset(new base::SharedMemory(handle, false));
227 if (ring_buffer_->Map(size)) {
228 num_entries_ = size / sizeof(gpu::CommandBufferEntry);
229 return true;
230 }
231
232 ring_buffer_.reset();
233 }
234
235 return false;
236 }
237
238 gpu::Buffer PepperCommandBuffer::GetRingBuffer() {
239 // Return locally cached ring buffer.
240 gpu::Buffer buffer;
241 buffer.ptr = ring_buffer_->memory();
242 buffer.size = num_entries_ * sizeof(gpu::CommandBufferEntry);
243 buffer.shared_memory = ring_buffer_.get();
244 return buffer;
245 }
246
247 gpu::CommandBuffer::State PepperCommandBuffer::GetState() {
248 // Send will flag state with lost context if IPC fails.
249 if (last_state_.error == gpu::error::kNoError) {
250 Send(new PpapiHostMsg_PPBContext3D_GetState(
251 INTERFACE_ID_PPB_CONTEXT_3D, resource_, &last_state_));
252 }
253
254 return last_state_;
255 }
256
257 void PepperCommandBuffer::Flush(int32 put_offset) {
258 if (last_state_.error != gpu::error::kNoError)
259 return;
260
261 IPC::Message* message = new PpapiHostMsg_PPBContext3D_AsyncFlush(
262 INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset);
263
264 // Do not let a synchronous flush hold up this message. If this handler is
265 // deferred until after the synchronous flush completes, it will overwrite the
266 // cached last_state_ with out-of-date data.
267 message->set_unblock(true);
268 Send(message);
269 }
270
271 gpu::CommandBuffer::State PepperCommandBuffer::FlushSync(int32 put_offset) {
272 // Send will flag state with lost context if IPC fails.
273 if (last_state_.error == gpu::error::kNoError) {
274 Send(new PpapiHostMsg_PPBContext3D_Flush(
275 INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset, &last_state_));
276 }
277
278 return last_state_;
279 }
280
281 void PepperCommandBuffer::SetGetOffset(int32 get_offset) {
282 // Not implemented in proxy.
283 NOTREACHED();
284 }
285
286 int32 PepperCommandBuffer::CreateTransferBuffer(size_t size) {
287 if (last_state_.error == gpu::error::kNoError) {
288 int32 id;
289 if (Send(new PpapiHostMsg_PPBContext3D_CreateTransferBuffer(
290 INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &id))) {
291 return id;
292 }
293 }
294
295 return -1;
296 }
297
298 void PepperCommandBuffer::DestroyTransferBuffer(int32 id) {
299 if (last_state_.error != gpu::error::kNoError)
300 return;
301
302 // Remove the transfer buffer from the client side4 cache.
303 TransferBufferMap::iterator it = transfer_buffers_.find(id);
304 DCHECK(it != transfer_buffers_.end());
305
306 // Delete the shared memory object, closing the handle in this process.
307 delete it->second.shared_memory;
308
309 transfer_buffers_.erase(it);
310
311 Send(new PpapiHostMsg_PPBContext3D_DestroyTransferBuffer(
312 INTERFACE_ID_PPB_CONTEXT_3D, resource_, id));
313 }
314
315 gpu::Buffer PepperCommandBuffer::GetTransferBuffer(int32 id) {
316 if (last_state_.error != gpu::error::kNoError)
317 return gpu::Buffer();
318
319 // Check local cache to see if there is already a client side shared memory
320 // object for this id.
321 TransferBufferMap::iterator it = transfer_buffers_.find(id);
322 if (it != transfer_buffers_.end()) {
323 return it->second;
324 }
325
326 // Assuming we are in the renderer process, the service is responsible for
327 // duplicating the handle. This might not be true for NaCl.
328 base::SharedMemoryHandle handle;
329 uint32 size;
330 if (!Send(new PpapiHostMsg_PPBContext3D_GetTransferBuffer(
331 INTERFACE_ID_PPB_CONTEXT_3D, resource_, id, &handle, &size))) {
332 return gpu::Buffer();
333 }
334
335 // Cache the transfer buffer shared memory object client side.
336 scoped_ptr<base::SharedMemory> shared_memory(
337 new base::SharedMemory(handle, false));
338
339 // Map the shared memory on demand.
340 if (!shared_memory->memory()) {
341 if (!shared_memory->Map(size)) {
342 return gpu::Buffer();
343 }
344 }
345
346 gpu::Buffer buffer;
347 buffer.ptr = shared_memory->memory();
348 buffer.size = size;
349 buffer.shared_memory = shared_memory.release();
350 transfer_buffers_[id] = buffer;
351
352 return buffer;
353 }
354
355 void PepperCommandBuffer::SetToken(int32 token) {
356 NOTREACHED();
357 }
358
359 void PepperCommandBuffer::SetParseError(gpu::error::Error error) {
360 NOTREACHED();
361 }
362
363 bool PepperCommandBuffer::Send(IPC::Message* msg) {
364 DCHECK(last_state_.error == gpu::error::kNoError);
365
366 if (dispatcher_->Send(msg))
367 return true;
368
369 last_state_.error = gpu::error::kLostContext;
370 return false;
371 }
372
373 Context3D::Context3D(const HostResource& resource)
374 : PluginResource(resource),
375 draw_(NULL),
376 read_(NULL),
377 transfer_buffer_id_(NULL) {
378 }
379
380 Context3D::~Context3D() {
381 if (draw_)
382 draw_->set_context(NULL);
383 }
384
385 bool Context3D::CreateImplementation() {
386 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance());
387 if (!dispatcher)
388 return false;
389
390 command_buffer_.reset(new PepperCommandBuffer(host_resource(), dispatcher));
391
392 if (!command_buffer_->Initialize(kCommandBufferSize))
393 return false;
394
395 helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get()));
396 if (!helper_->Initialize(kCommandBufferSize))
397 return false;
398
399 transfer_buffer_id_ =
400 command_buffer_->CreateTransferBuffer(kTransferBufferSize);
401 if (transfer_buffer_id_ < 0)
402 return false;
403
404 gpu::Buffer transfer_buffer =
405 command_buffer_->GetTransferBuffer(transfer_buffer_id_);
406 if (!transfer_buffer.ptr)
407 return false;
408
409 gles2_impl_.reset(new gpu::gles2::GLES2Implementation(
410 helper_.get(),
411 transfer_buffer.size,
412 transfer_buffer.ptr,
413 transfer_buffer_id_,
414 false));
415
416 return true;
417 }
418
419 void Context3D::BindSurfaces(Surface3D* draw, Surface3D* read) {
420 if (draw != draw_) {
421 if (draw_)
422 draw_->set_context(NULL);
423 if (draw) {
424 draw->set_context(this);
425 // Resize the backing texture to the size of the instance when it is
426 // bound.
427 // TODO(alokp): This should be the responsibility of plugins.
428 PluginDispatcher* dispatcher =
429 PluginDispatcher::GetForInstance(instance());
430 DCHECK(dispatcher);
431 InstanceData* data = dispatcher->GetInstanceData(instance());
432 DCHECK(data);
433 gles2_impl()->ResizeCHROMIUM(data->position.size.width,
434 data->position.size.height);
435 }
436 draw_ = draw;
437 }
438 read_ = read;
439 }
440
441 PPB_Context3D_Proxy::PPB_Context3D_Proxy(Dispatcher* dispatcher,
442 const void* target_interface)
443 : InterfaceProxy(dispatcher, target_interface) {
444 }
445
446 PPB_Context3D_Proxy::~PPB_Context3D_Proxy() {
447 }
448
449 const PPB_Context3DTrusted_Dev*
450 PPB_Context3D_Proxy::ppb_context_3d_trusted() const {
451 return static_cast<const PPB_Context3DTrusted_Dev*>(
452 dispatcher()->GetLocalInterface(
453 PPB_CONTEXT_3D_TRUSTED_DEV_INTERFACE));
454 }
455
456 const void* PPB_Context3D_Proxy::GetSourceInterface() const {
457 return &ppb_context_3d;
458 }
459
460 InterfaceID PPB_Context3D_Proxy::GetInterfaceId() const {
461 return INTERFACE_ID_PPB_CONTEXT_3D;
462 }
463
464 bool PPB_Context3D_Proxy::OnMessageReceived(const IPC::Message& msg) {
465 bool handled = true;
466 IPC_BEGIN_MESSAGE_MAP(PPB_Context3D_Proxy, msg)
467 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Create,
468 OnMsgCreate)
469 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_BindSurfaces,
470 OnMsgBindSurfaces)
471 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Initialize,
472 OnMsgInitialize)
473 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetState,
474 OnMsgGetState)
475 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Flush,
476 OnMsgFlush)
477 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_AsyncFlush,
478 OnMsgAsyncFlush)
479 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_CreateTransferBuffer,
480 OnMsgCreateTransferBuffer)
481 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_DestroyTransferBuffer,
482 OnMsgDestroyTransferBuffer)
483 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetTransferBuffer,
484 OnMsgGetTransferBuffer)
485 IPC_MESSAGE_UNHANDLED(handled = false)
486
487 IPC_END_MESSAGE_MAP()
488 // FIXME(brettw) handle bad messages!
489 return handled;
490 }
491
492 void PPB_Context3D_Proxy::OnMsgCreate(PP_Instance instance,
493 PP_Config3D_Dev config,
494 std::vector<int32_t> attribs,
495 HostResource* result) {
496 DCHECK(attribs.back() == 0);
497 PP_Resource resource = ppb_context_3d_trusted()->CreateRaw(
498 instance, config, 0, &attribs.front());
499 result->SetHostResource(instance, resource);
500 }
501
502 void PPB_Context3D_Proxy::OnMsgBindSurfaces(const HostResource& context,
503 const HostResource& draw,
504 const HostResource& read,
505 int32_t* result) {
506 *result = ppb_context_3d_target()->BindSurfaces(context.host_resource(),
507 draw.host_resource(),
508 read.host_resource());
509 }
510
511 void PPB_Context3D_Proxy::OnMsgInitialize(
512 const HostResource& context,
513 int32 size,
514 base::SharedMemoryHandle* ring_buffer) {
515 const PPB_Context3DTrusted_Dev* context_3d_trusted = ppb_context_3d_trusted();
516 *ring_buffer = base::SharedMemory::NULLHandle();
517 if (!context_3d_trusted->Initialize(context.host_resource(), size))
518 return;
519
520 int shm_handle;
521 uint32_t shm_size;
522 if (!context_3d_trusted->GetRingBuffer(context.host_resource(),
523 &shm_handle,
524 &shm_size)) {
525 return;
526 }
527
528 *ring_buffer = SHMHandleFromInt(shm_handle);
529 }
530
531 void PPB_Context3D_Proxy::OnMsgGetState(const HostResource& context,
532 gpu::CommandBuffer::State* state) {
533 PP_Context3DTrustedState pp_state =
534 ppb_context_3d_trusted()->GetState(context.host_resource());
535 *state = GPUStateFromPPState(pp_state);
536 }
537
538 void PPB_Context3D_Proxy::OnMsgFlush(const HostResource& context,
539 int32 put_offset,
540 gpu::CommandBuffer::State* state) {
541 PP_Context3DTrustedState pp_state =
542 ppb_context_3d_trusted()->FlushSync(context.host_resource(), put_offset);
543 *state = GPUStateFromPPState(pp_state);
544 }
545
546 void PPB_Context3D_Proxy::OnMsgAsyncFlush(const HostResource& context,
547 int32 put_offset) {
548 ppb_context_3d_trusted()->Flush(context.host_resource(), put_offset);
549 }
550
551 void PPB_Context3D_Proxy::OnMsgCreateTransferBuffer(
552 const HostResource& context,
553 int32 size,
554 int32* id) {
555 *id = ppb_context_3d_trusted()->CreateTransferBuffer(
556 context.host_resource(), size);
557 }
558
559 void PPB_Context3D_Proxy::OnMsgDestroyTransferBuffer(
560 const HostResource& context,
561 int32 id) {
562 ppb_context_3d_trusted()->DestroyTransferBuffer(context.host_resource(), id);
563 }
564
565 void PPB_Context3D_Proxy::OnMsgGetTransferBuffer(
566 const HostResource& context,
567 int32 id,
568 base::SharedMemoryHandle* transfer_buffer,
569 uint32* size) {
570 *transfer_buffer = base::SharedMemory::NULLHandle();
571 int shm_handle;
572 uint32_t shm_size;
573 if (!ppb_context_3d_trusted()->GetTransferBuffer(context.host_resource(),
574 id,
575 &shm_handle,
576 &shm_size)) {
577 return;
578 }
579 *transfer_buffer = SHMHandleFromInt(shm_handle);
580 *size = shm_size;
581 }
582
583 } // namespace proxy
584 } // namespace pp
OLDNEW
« no previous file with comments | « ppapi/proxy/ppb_context_3d_proxy.h ('k') | ppapi/proxy/ppb_gles_chromium_texture_mapping_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698