| 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 int32 Graphics3D::DoSwapBuffers() { | 120 int32 Graphics3D::DoSwapBuffers() { |
| 249 // gles2_impl()->SwapBuffers() results in CommandBuffer calls, and we already | |
| 250 // have the proxy lock. | |
| 251 ScopedNoLocking already_locked(this); | |
| 252 | |
| 253 gles2_impl()->SwapBuffers(); | 121 gles2_impl()->SwapBuffers(); |
| 254 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( | 122 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( |
| 255 API_ID_PPB_GRAPHICS_3D, host_resource()); | 123 API_ID_PPB_GRAPHICS_3D, host_resource()); |
| 256 msg->set_unblock(true); | 124 msg->set_unblock(true); |
| 257 PluginDispatcher::GetForResource(this)->Send(msg); | 125 PluginDispatcher::GetForResource(this)->Send(msg); |
| 258 | 126 |
| 259 return PP_OK_COMPLETIONPENDING; | 127 return PP_OK_COMPLETIONPENDING; |
| 260 } | 128 } |
| 261 | 129 |
| 262 void Graphics3D::PushAlreadyLocked() { | |
| 263 ppapi::ProxyLock::AssertAcquired(); | |
| 264 if (!locking_command_buffer_) { | |
| 265 NOTREACHED(); | |
| 266 return; | |
| 267 } | |
| 268 if (num_already_locked_calls_ == 0) | |
| 269 locking_command_buffer_->set_need_to_lock(false); | |
| 270 ++num_already_locked_calls_; | |
| 271 } | |
| 272 | |
| 273 void Graphics3D::PopAlreadyLocked() { | |
| 274 // We must have Pushed before we can Pop. | |
| 275 DCHECK(!locking_command_buffer_->need_to_lock()); | |
| 276 DCHECK_GT(num_already_locked_calls_, 0); | |
| 277 ppapi::ProxyLock::AssertAcquired(); | |
| 278 if (!locking_command_buffer_) { | |
| 279 NOTREACHED(); | |
| 280 return; | |
| 281 } | |
| 282 --num_already_locked_calls_; | |
| 283 if (num_already_locked_calls_ == 0) | |
| 284 locking_command_buffer_->set_need_to_lock(true); | |
| 285 } | |
| 286 | |
| 287 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) | 130 PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) |
| 288 : InterfaceProxy(dispatcher), | 131 : InterfaceProxy(dispatcher), |
| 289 callback_factory_(this) { | 132 callback_factory_(this) { |
| 290 } | 133 } |
| 291 | 134 |
| 292 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { | 135 PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { |
| 293 } | 136 } |
| 294 | 137 |
| 295 // static | 138 // static |
| 296 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( | 139 PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 int32_t result, | 342 int32_t result, |
| 500 const HostResource& context) { | 343 const HostResource& context) { |
| 501 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( | 344 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( |
| 502 API_ID_PPB_GRAPHICS_3D, context, result)); | 345 API_ID_PPB_GRAPHICS_3D, context, result)); |
| 503 } | 346 } |
| 504 #endif // !defined(OS_NACL) | 347 #endif // !defined(OS_NACL) |
| 505 | 348 |
| 506 } // namespace proxy | 349 } // namespace proxy |
| 507 } // namespace ppapi | 350 } // namespace ppapi |
| 508 | 351 |
| OLD | NEW |