OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "webkit/glue/plugins/pepper_graphics_3d.h" | 5 #include "webkit/glue/plugins/pepper_graphics_3d.h" |
6 | 6 |
7 #include "gpu/command_buffer/common/command_buffer.h" | 7 #include "gpu/command_buffer/common/command_buffer.h" |
8 #include "base/singleton.h" | 8 #include "base/singleton.h" |
9 #include "base/thread_local.h" | 9 #include "base/thread_local.h" |
10 #include "ppapi/c/dev/ppb_graphics_3d_dev.h" | 10 #include "ppapi/c/dev/ppb_graphics_3d_dev.h" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 if (!graphics3d) { | 84 if (!graphics3d) { |
85 Graphics3D::ResetCurrent(); | 85 Graphics3D::ResetCurrent(); |
86 return true; | 86 return true; |
87 } else { | 87 } else { |
88 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); | 88 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); |
89 return context.get() && context->MakeCurrent(); | 89 return context.get() && context->MakeCurrent(); |
90 } | 90 } |
91 } | 91 } |
92 | 92 |
93 PP_Resource GetCurrentContext() { | 93 PP_Resource GetCurrentContext() { |
94 Graphics3D* currentContext = Graphics3D::GetCurrent(); | 94 Graphics3D* current_context = Graphics3D::GetCurrent(); |
95 return currentContext ? currentContext->GetReference() : 0; | 95 return current_context ? current_context->GetReference() : 0; |
96 } | 96 } |
97 | 97 |
98 bool SwapBuffers(PP_Resource graphics3d) { | 98 bool SwapBuffers(PP_Resource graphics3d) { |
99 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); | 99 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); |
100 return context && context->SwapBuffers(); | 100 return context && context->SwapBuffers(); |
101 } | 101 } |
102 | 102 |
103 uint32_t GetError() { | 103 uint32_t GetError() { |
104 // TODO(neb): Figure out error checking. | 104 // Technically, this should return the last error that occurred on the current |
105 return PP_GRAPHICS_3D_ERROR_SUCCESS; | 105 // thread, rather than an error associated with a particular context. |
| 106 // TODO(apatrick): Fix this. |
| 107 Graphics3D* current_context = Graphics3D::GetCurrent(); |
| 108 if (!current_context) |
| 109 return 0; |
| 110 |
| 111 return current_context->GetError(); |
106 } | 112 } |
107 | 113 |
108 const PPB_Graphics3D_Dev ppb_graphics3d = { | 114 const PPB_Graphics3D_Dev ppb_graphics3d = { |
109 &IsGraphics3D, | 115 &IsGraphics3D, |
110 &GetConfigs, | 116 &GetConfigs, |
111 &ChooseConfig, | 117 &ChooseConfig, |
112 &GetConfigAttrib, | 118 &GetConfigAttrib, |
113 &QueryString, | 119 &QueryString, |
114 &CreateContext, | 120 &CreateContext, |
115 &GetProcAddress, | 121 &GetProcAddress, |
116 &MakeCurrent, | 122 &MakeCurrent, |
117 &GetCurrentContext, | 123 &GetCurrentContext, |
118 &SwapBuffers, | 124 &SwapBuffers, |
119 &GetError | 125 &GetError |
120 }; | 126 }; |
121 | 127 |
122 } // namespace | 128 } // namespace |
123 | 129 |
124 Graphics3D::Graphics3D(PluginModule* module) | 130 Graphics3D::Graphics3D(PluginModule* module) |
125 : Resource(module), | 131 : Resource(module), |
126 command_buffer_(NULL), | 132 bound_instance_(NULL) { |
127 transfer_buffer_id_(0), | |
128 method_factory3d_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
129 } | 133 } |
130 | 134 |
131 const PPB_Graphics3D_Dev* Graphics3D::GetInterface() { | 135 const PPB_Graphics3D_Dev* Graphics3D::GetInterface() { |
132 return &ppb_graphics3d; | 136 return &ppb_graphics3d; |
133 } | 137 } |
134 | 138 |
135 Graphics3D* Graphics3D::GetCurrent() { | 139 Graphics3D* Graphics3D::GetCurrent() { |
136 return CurrentContextKey::get()->Get(); | 140 return CurrentContextKey::get()->Get(); |
137 } | 141 } |
138 | 142 |
139 void Graphics3D::ResetCurrent() { | 143 void Graphics3D::ResetCurrent() { |
140 CurrentContextKey::get()->Set(NULL); | 144 CurrentContextKey::get()->Set(NULL); |
141 } | 145 } |
142 | 146 |
143 Graphics3D::~Graphics3D() { | 147 Graphics3D::~Graphics3D() { |
144 Destroy(); | 148 Destroy(); |
145 } | 149 } |
146 | 150 |
147 bool Graphics3D::Init(PP_Instance instance_id, int32_t config, | 151 bool Graphics3D::Init(PP_Instance instance_id, int32_t config, |
148 const int32_t* attrib_list) { | 152 const int32_t* attrib_list) { |
149 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | 153 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); |
150 if (!instance) { | 154 if (!instance) { |
151 return false; | 155 return false; |
152 } | 156 } |
153 | 157 |
154 // Create and initialize the objects required to issue GLES2 calls. | 158 // Create and initialize the objects required to issue GLES2 calls. |
155 platform_context_.reset(instance->delegate()->CreateContext3D()); | 159 platform_context_.reset(instance->delegate()->CreateContext3D()); |
156 if (!platform_context_.get()) | 160 if (!platform_context_.get()) { |
157 return false; | 161 Destroy(); |
158 | |
159 if (!platform_context_->Init(instance->position(), | |
160 instance->clip())) { | |
161 platform_context_.reset(); | |
162 return false; | 162 return false; |
163 } | 163 } |
164 command_buffer_ = platform_context_->GetCommandBuffer(); | 164 |
165 gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_)); | 165 if (!platform_context_->Init()) { |
166 gpu::Buffer buffer = command_buffer_->GetRingBuffer(); | 166 Destroy(); |
167 if (gles2_helper_->Initialize(buffer.size)) { | 167 return false; |
168 transfer_buffer_id_ = | |
169 command_buffer_->CreateTransferBuffer(kTransferBufferSize); | |
170 gpu::Buffer transfer_buffer = | |
171 command_buffer_->GetTransferBuffer(transfer_buffer_id_); | |
172 if (transfer_buffer.ptr) { | |
173 gles2_implementation_.reset(new gpu::gles2::GLES2Implementation( | |
174 gles2_helper_.get(), | |
175 transfer_buffer.size, | |
176 transfer_buffer.ptr, | |
177 transfer_buffer_id_, | |
178 false)); | |
179 platform_context_->SetNotifyRepaintTask( | |
180 method_factory3d_.NewRunnableMethod(&Graphics3D::HandleRepaint, | |
181 instance_id)); | |
182 return true; | |
183 } | |
184 } | 168 } |
185 | 169 |
186 // Tear everything down if initialization failed. | 170 gles2_implementation_ = platform_context_->GetGLES2Implementation(); |
187 Destroy(); | 171 DCHECK(gles2_implementation_); |
188 return false; | 172 |
| 173 return true; |
| 174 } |
| 175 |
| 176 bool Graphics3D::BindToInstance(PluginInstance* new_instance) { |
| 177 if (bound_instance_ == new_instance) |
| 178 return true; // Rebinding the same device, nothing to do. |
| 179 if (bound_instance_ && new_instance) |
| 180 return false; // Can't change a bound device. |
| 181 |
| 182 if (new_instance) { |
| 183 // Resize the backing texture to the size of the instance when it is bound. |
| 184 platform_context_->ResizeBackingTexture(new_instance->position().size()); |
| 185 |
| 186 // This is a temporary hack. The SwapBuffers is issued to force the resize |
| 187 // to take place before any subsequent rendering. This might lead to a |
| 188 // partially rendered frame being displayed. It is also not thread safe |
| 189 // since the SwapBuffers is written to the command buffer and that command |
| 190 // buffer might be written to by another thread. |
| 191 // TODO(apatrick): Figure out the semantics of binding and resizing. |
| 192 platform_context_->SwapBuffers(); |
| 193 } |
| 194 |
| 195 bound_instance_ = new_instance; |
| 196 return true; |
189 } | 197 } |
190 | 198 |
191 bool Graphics3D::MakeCurrent() { | 199 bool Graphics3D::MakeCurrent() { |
192 if (!command_buffer_) | 200 if (!platform_context_.get()) |
193 return false; | 201 return false; |
194 | 202 |
195 CurrentContextKey::get()->Set(this); | 203 CurrentContextKey::get()->Set(this); |
196 | 204 |
197 // Don't request latest error status from service. Just use the locally | 205 // TODO(apatrick): Return false on context lost. |
198 // cached information from the last flush. | |
199 // TODO(apatrick): I'm not sure if this should actually change the | |
200 // current context if it fails. For now it gets changed even if it fails | |
201 // becuase making GL calls with a NULL context crashes. | |
202 // TODO(neb): Figure out error checking. | |
203 // if (command_buffer_->GetCachedError() != gpu::error::kNoError) | |
204 // return false; | |
205 return true; | 206 return true; |
206 } | 207 } |
207 | 208 |
208 bool Graphics3D::SwapBuffers() { | 209 bool Graphics3D::SwapBuffers() { |
209 if (!command_buffer_) | 210 if (!platform_context_.get()) |
210 return false; | 211 return false; |
211 | 212 |
212 // Don't request latest error status from service. Just use the locally cached | 213 return platform_context_->SwapBuffers(); |
213 // information from the last flush. | 214 } |
214 // TODO(neb): Figure out error checking. | |
215 // if (command_buffer_->GetCachedError() != gpu::error::kNoError) | |
216 // return false; | |
217 | 215 |
218 gles2_implementation_->SwapBuffers(); | 216 unsigned Graphics3D::GetError() { |
219 return true; | 217 if (!platform_context_.get()) |
| 218 return 0; |
| 219 |
| 220 return platform_context_->GetError(); |
| 221 } |
| 222 |
| 223 void Graphics3D::ResizeBackingTexture(const gfx::Size& size) { |
| 224 if (!platform_context_.get()) |
| 225 return; |
| 226 |
| 227 platform_context_->ResizeBackingTexture(size); |
| 228 } |
| 229 |
| 230 void Graphics3D::SetSwapBuffersCallback(Callback0::Type* callback) { |
| 231 if (!platform_context_.get()) |
| 232 return; |
| 233 |
| 234 platform_context_->SetSwapBuffersCallback(callback); |
| 235 } |
| 236 |
| 237 unsigned Graphics3D::GetBackingTextureId() { |
| 238 if (!platform_context_.get()) |
| 239 return 0; |
| 240 |
| 241 return platform_context_->GetBackingTextureId(); |
220 } | 242 } |
221 | 243 |
222 void Graphics3D::Destroy() { | 244 void Graphics3D::Destroy() { |
223 if (GetCurrent() == this) { | 245 if (GetCurrent() == this) { |
224 ResetCurrent(); | 246 ResetCurrent(); |
225 } | 247 } |
226 | 248 |
227 method_factory3d_.RevokeAll(); | 249 gles2_implementation_ = NULL; |
228 | 250 |
229 gles2_implementation_.reset(); | |
230 | |
231 if (command_buffer_ && transfer_buffer_id_ != 0) { | |
232 command_buffer_->DestroyTransferBuffer(transfer_buffer_id_); | |
233 transfer_buffer_id_ = 0; | |
234 } | |
235 | |
236 gles2_helper_.reset(); | |
237 | |
238 // Platform context owns the command buffer. | |
239 platform_context_.reset(); | 251 platform_context_.reset(); |
240 command_buffer_ = NULL; | |
241 } | |
242 | |
243 void Graphics3D::HandleRepaint(PP_Instance instance_id) { | |
244 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
245 if (instance) { | |
246 instance->Graphics3DContextLost(); | |
247 if (platform_context_.get()) { | |
248 platform_context_->SetNotifyRepaintTask( | |
249 method_factory3d_.NewRunnableMethod(&Graphics3D::HandleRepaint, | |
250 instance_id)); | |
251 } | |
252 } | |
253 } | 252 } |
254 | 253 |
255 } // namespace pepper | 254 } // namespace pepper |
256 | 255 |
OLD | NEW |