OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/ppb_graphics_3d_proxy.h" | 5 #include "ppapi/proxy/ppb_graphics_3d_proxy.h" |
6 | 6 |
7 #include "gpu/command_buffer/client/gles2_implementation.h" | 7 #include "gpu/command_buffer/client/gles2_implementation.h" |
8 #include "gpu/command_buffer/common/command_buffer.h" | 8 #include "gpu/command_buffer/common/command_buffer.h" |
9 #include "ppapi/c/pp_errors.h" | 9 #include "ppapi/c/pp_errors.h" |
10 #include "ppapi/proxy/enter_proxy.h" | 10 #include "ppapi/proxy/enter_proxy.h" |
11 #include "ppapi/proxy/plugin_dispatcher.h" | 11 #include "ppapi/proxy/plugin_dispatcher.h" |
12 #include "ppapi/proxy/ppapi_command_buffer_proxy.h" | 12 #include "ppapi/proxy/ppapi_command_buffer_proxy.h" |
13 #include "ppapi/proxy/ppapi_messages.h" | 13 #include "ppapi/proxy/ppapi_messages.h" |
14 #include "ppapi/shared_impl/ppapi_globals.h" | 14 #include "ppapi/shared_impl/ppapi_globals.h" |
15 #include "ppapi/shared_impl/proxy_lock.h" | |
16 #include "ppapi/thunk/enter.h" | 15 #include "ppapi/thunk/enter.h" |
17 #include "ppapi/thunk/resource_creation_api.h" | 16 #include "ppapi/thunk/resource_creation_api.h" |
18 #include "ppapi/thunk/thunk.h" | 17 #include "ppapi/thunk/thunk.h" |
19 | 18 |
20 using ppapi::thunk::EnterResourceNoLock; | 19 using ppapi::thunk::EnterResourceNoLock; |
21 using ppapi::thunk::PPB_Graphics3D_API; | 20 using ppapi::thunk::PPB_Graphics3D_API; |
22 using ppapi::thunk::ResourceCreationAPI; | 21 using ppapi::thunk::ResourceCreationAPI; |
23 | 22 |
24 namespace ppapi { | 23 namespace ppapi { |
25 namespace proxy { | 24 namespace proxy { |
(...skipping 20 matching lines...) Expand all Loading... |
46 } | 45 } |
47 | 46 |
48 gpu::CommandBuffer::State GetErrorState() { | 47 gpu::CommandBuffer::State GetErrorState() { |
49 gpu::CommandBuffer::State error_state; | 48 gpu::CommandBuffer::State error_state; |
50 error_state.error = gpu::error::kGenericError; | 49 error_state.error = gpu::error::kGenericError; |
51 return error_state; | 50 return error_state; |
52 } | 51 } |
53 | 52 |
54 } // namespace | 53 } // namespace |
55 | 54 |
56 // This class just wraps a CommandBuffer and optionally locks around every | |
57 // method. This is used to ensure that we have the Proxy lock any time we enter | |
58 // PpapiCommandBufferProxy. | |
59 // | |
60 // Note, for performance reasons, most of this code is not truly thread | |
61 // safe in the sense of multiple threads concurrently rendering to the same | |
62 // Graphics3D context; this isn't allowed, and will likely either crash or | |
63 // result in undefined behavior. It is assumed that the thread which creates | |
64 // the Graphics3D context will be the thread on which subsequent gl rendering | |
65 // will be done. This is why it is okay to read need_to_lock_ without the lock; | |
66 // it should only ever be read and written on the same thread where the context | |
67 // was created. | |
68 // | |
69 // TODO(nfullagar): At some point, allow multiple threads to concurrently render | |
70 // each to its own context. First step is to allow a single thread (either main | |
71 // thread or background thread) to render to a single Graphics3D context. | |
72 class Graphics3D::LockingCommandBuffer : public gpu::CommandBuffer { | |
73 public: | |
74 explicit LockingCommandBuffer(gpu::CommandBuffer* gpu_command_buffer) | |
75 : gpu_command_buffer_(gpu_command_buffer), need_to_lock_(true) { | |
76 } | |
77 virtual ~LockingCommandBuffer() { | |
78 } | |
79 void set_need_to_lock(bool need_to_lock) { need_to_lock_ = need_to_lock; } | |
80 bool need_to_lock() const { return need_to_lock_; } | |
81 | |
82 private: | |
83 // MaybeLock acquires the proxy lock on construction if and only if | |
84 // need_to_lock is true. If it acquired the lock, it releases it on | |
85 // destruction. If need_to_lock is false, then the lock must already be held. | |
86 struct MaybeLock { | |
87 explicit MaybeLock(bool need_to_lock) : locked_(need_to_lock) { | |
88 if (need_to_lock) | |
89 ppapi::ProxyLock::Acquire(); | |
90 else | |
91 ppapi::ProxyLock::AssertAcquired(); | |
92 } | |
93 ~MaybeLock() { | |
94 if (locked_) | |
95 ppapi::ProxyLock::Release(); | |
96 } | |
97 private: | |
98 bool locked_; | |
99 }; | |
100 | |
101 // gpu::CommandBuffer implementation: | |
102 virtual bool Initialize() OVERRIDE { | |
103 MaybeLock lock(need_to_lock_); | |
104 return gpu_command_buffer_->Initialize(); | |
105 } | |
106 virtual State GetState() OVERRIDE { | |
107 MaybeLock lock(need_to_lock_); | |
108 return gpu_command_buffer_->GetState(); | |
109 } | |
110 virtual State GetLastState() OVERRIDE { | |
111 // During a normal scene, the vast majority of calls are to GetLastState(). | |
112 // We don't allow multi-threaded rendering on the same contex, so for | |
113 // performance reasons, avoid the global lock for this entry point. We can | |
114 // get away with this here because the underlying implementation of | |
115 // GetLastState() is trivial and does not involve global or shared state | |
116 // between other contexts. | |
117 // TODO(nfullagar): We can probably skip MaybeLock for other methods, but | |
118 // the performance gain may not be worth it. | |
119 // | |
120 // MaybeLock lock(need_to_lock_); | |
121 return gpu_command_buffer_->GetLastState(); | |
122 } | |
123 virtual int32 GetLastToken() OVERRIDE { | |
124 return GetLastState().token; | |
125 } | |
126 virtual void Flush(int32 put_offset) OVERRIDE { | |
127 MaybeLock lock(need_to_lock_); | |
128 gpu_command_buffer_->Flush(put_offset); | |
129 } | |
130 virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE { | |
131 MaybeLock lock(need_to_lock_); | |
132 return gpu_command_buffer_->FlushSync(put_offset, last_known_get); | |
133 } | |
134 virtual void SetGetBuffer(int32 transfer_buffer_id) OVERRIDE { | |
135 MaybeLock lock(need_to_lock_); | |
136 gpu_command_buffer_->SetGetBuffer(transfer_buffer_id); | |
137 } | |
138 virtual void SetGetOffset(int32 get_offset) OVERRIDE { | |
139 MaybeLock lock(need_to_lock_); | |
140 gpu_command_buffer_->SetGetOffset(get_offset); | |
141 } | |
142 virtual gpu::Buffer CreateTransferBuffer(size_t size, | |
143 int32* id) OVERRIDE { | |
144 MaybeLock lock(need_to_lock_); | |
145 return gpu_command_buffer_->CreateTransferBuffer(size, id); | |
146 } | |
147 virtual void DestroyTransferBuffer(int32 id) OVERRIDE { | |
148 MaybeLock lock(need_to_lock_); | |
149 gpu_command_buffer_->DestroyTransferBuffer(id); | |
150 } | |
151 virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE { | |
152 MaybeLock lock(need_to_lock_); | |
153 return gpu_command_buffer_->GetTransferBuffer(id); | |
154 } | |
155 virtual void SetToken(int32 token) OVERRIDE { | |
156 MaybeLock lock(need_to_lock_); | |
157 gpu_command_buffer_->SetToken(token); | |
158 } | |
159 virtual void SetParseError(gpu::error::Error error) OVERRIDE { | |
160 MaybeLock lock(need_to_lock_); | |
161 gpu_command_buffer_->SetParseError(error); | |
162 } | |
163 virtual void SetContextLostReason( | |
164 gpu::error::ContextLostReason reason) OVERRIDE { | |
165 MaybeLock lock(need_to_lock_); | |
166 gpu_command_buffer_->SetContextLostReason(reason); | |
167 } | |
168 virtual uint32 InsertSyncPoint() OVERRIDE { | |
169 MaybeLock lock(need_to_lock_); | |
170 return gpu_command_buffer_->InsertSyncPoint(); | |
171 } | |
172 | |
173 // Weak pointer - see class Graphics3D for the scopted_ptr. | |
174 gpu::CommandBuffer* gpu_command_buffer_; | |
175 | |
176 bool need_to_lock_; | |
177 }; | |
178 | |
179 Graphics3D::Graphics3D(const HostResource& resource) | 55 Graphics3D::Graphics3D(const HostResource& resource) |
180 : PPB_Graphics3D_Shared(resource), | 56 : PPB_Graphics3D_Shared(resource) { |
181 num_already_locked_calls_(0) { | |
182 } | 57 } |
183 | 58 |
184 Graphics3D::~Graphics3D() { | 59 Graphics3D::~Graphics3D() { |
185 if (gles2_impl()) | 60 if (gles2_impl()) |
186 DestroyGLES2Impl(); | 61 DestroyGLES2Impl(); |
187 } | 62 } |
188 | 63 |
189 bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2) { | 64 bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2) { |
190 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); | 65 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); |
191 if (!dispatcher) | 66 if (!dispatcher) |
192 return false; | 67 return false; |
193 | 68 |
194 command_buffer_.reset( | 69 command_buffer_.reset( |
195 new PpapiCommandBufferProxy(host_resource(), dispatcher)); | 70 new PpapiCommandBufferProxy(host_resource(), dispatcher)); |
196 locking_command_buffer_.reset( | |
197 new LockingCommandBuffer(command_buffer_.get())); | |
198 | 71 |
199 ScopedNoLocking already_locked(this); | |
200 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, | 72 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, |
201 share_gles2); | 73 share_gles2); |
202 } | 74 } |
203 | 75 |
204 PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) { | 76 PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) { |
205 return PP_FALSE; | 77 return PP_FALSE; |
206 } | 78 } |
207 | 79 |
208 gpu::CommandBuffer::State Graphics3D::GetState() { | 80 gpu::CommandBuffer::State Graphics3D::GetState() { |
209 return GetErrorState(); | 81 return GetErrorState(); |
(...skipping 25 matching lines...) Expand all Loading... |
235 int32_t last_known_get) { | 107 int32_t last_known_get) { |
236 return GetErrorState(); | 108 return GetErrorState(); |
237 } | 109 } |
238 | 110 |
239 uint32_t Graphics3D::InsertSyncPoint() { | 111 uint32_t Graphics3D::InsertSyncPoint() { |
240 NOTREACHED(); | 112 NOTREACHED(); |
241 return 0; | 113 return 0; |
242 } | 114 } |
243 | 115 |
244 gpu::CommandBuffer* Graphics3D::GetCommandBuffer() { | 116 gpu::CommandBuffer* Graphics3D::GetCommandBuffer() { |
245 return locking_command_buffer_.get(); | 117 return command_buffer_.get(); |
246 } | 118 } |
247 | 119 |
248 gpu::GpuControl* Graphics3D::GetGpuControl() { | 120 gpu::GpuControl* Graphics3D::GetGpuControl() { |
249 return command_buffer_.get(); | 121 return command_buffer_.get(); |
250 } | 122 } |
251 | 123 |
252 int32 Graphics3D::DoSwapBuffers() { | 124 int32 Graphics3D::DoSwapBuffers() { |
253 // gles2_impl()->SwapBuffers() results in CommandBuffer calls, and we already | |
254 // have the proxy lock. | |
255 ScopedNoLocking already_locked(this); | |
256 | |
257 gles2_impl()->SwapBuffers(); | 125 gles2_impl()->SwapBuffers(); |
258 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( | 126 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( |
259 API_ID_PPB_GRAPHICS_3D, host_resource()); | 127 API_ID_PPB_GRAPHICS_3D, host_resource()); |
260 msg->set_unblock(true); | 128 msg->set_unblock(true); |
261 PluginDispatcher::GetForResource(this)->Send(msg); | 129 PluginDispatcher::GetForResource(this)->Send(msg); |
262 | 130 |
263 return PP_OK_COMPLETIONPENDING; | 131 return PP_OK_COMPLETIONPENDING; |
264 } | 132 } |
265 | 133 |
266 void Graphics3D::PushAlreadyLocked() { | |
267 ppapi::ProxyLock::AssertAcquired(); | |
268 if (!locking_command_buffer_) { | |
269 NOTREACHED(); | |
270 return; | |
271 } | |
272 if (num_already_locked_calls_ == 0) | |
273 locking_command_buffer_->set_need_to_lock(false); | |
274 ++num_already_locked_calls_; | |
275 } | |
276 | |
277 void Graphics3D::PopAlreadyLocked() { | |
278 // We must have Pushed before we can Pop. | |
279 DCHECK(!locking_command_buffer_->need_to_lock()); | |
280 DCHECK_GT(num_already_locked_calls_, 0); | |
281 ppapi::ProxyLock::AssertAcquired(); | |
282 if (!locking_command_buffer_) { | |
283 NOTREACHED(); | |
284 return; | |
285 } | |
286 --num_already_locked_calls_; | |
287 if (num_already_locked_calls_ == 0) | |
288 locking_command_buffer_->set_need_to_lock(true); | |
289 } | |
290 | |
291 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) | 134 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) |
292 : InterfaceProxy(dispatcher), | 135 : InterfaceProxy(dispatcher), |
293 callback_factory_(this) { | 136 callback_factory_(this) { |
294 } | 137 } |
295 | 138 |
296 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { | 139 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { |
297 } | 140 } |
298 | 141 |
299 // static | 142 // static |
300 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( | 143 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 int32_t result, | 346 int32_t result, |
504 const HostResource& context) { | 347 const HostResource& context) { |
505 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( | 348 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( |
506 API_ID_PPB_GRAPHICS_3D, context, result)); | 349 API_ID_PPB_GRAPHICS_3D, context, result)); |
507 } | 350 } |
508 #endif // !defined(OS_NACL) | 351 #endif // !defined(OS_NACL) |
509 | 352 |
510 } // namespace proxy | 353 } // namespace proxy |
511 } // namespace ppapi | 354 } // namespace ppapi |
512 | 355 |
OLD | NEW |