OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "webkit/glue/plugins/pepper_graphics_3d.h" | |
6 | |
7 #include "gpu/command_buffer/common/command_buffer.h" | |
8 #include "base/lazy_instance.h" | |
9 #include "base/thread_local.h" | |
10 #include "ppapi/c/dev/ppb_graphics_3d_dev.h" | |
11 #include "webkit/glue/plugins/pepper_common.h" | |
12 #include "webkit/glue/plugins/pepper_plugin_instance.h" | |
13 | |
14 namespace pepper { | |
15 | |
16 namespace { | |
17 | |
18 static base::LazyInstance<base::ThreadLocalPointer<Graphics3D> > | |
19 g_current_context_key(base::LINKER_INITIALIZED); | |
20 | |
21 // Size of the transfer buffer. | |
22 enum { kTransferBufferSize = 512 * 1024 }; | |
23 | |
24 PP_Bool IsGraphics3D(PP_Resource resource) { | |
25 return BoolToPPBool(!!Resource::GetAs<Graphics3D>(resource)); | |
26 } | |
27 | |
28 PP_Bool GetConfigs(int32_t* configs, int32_t config_size, int32_t* num_config) { | |
29 // TODO(neb): Implement me! | |
30 return PP_FALSE; | |
31 } | |
32 | |
33 PP_Bool ChooseConfig(const int32_t* attrib_list, int32_t* configs, | |
34 int32_t config_size, int32_t* num_config) { | |
35 // TODO(neb): Implement me! | |
36 return PP_FALSE; | |
37 } | |
38 | |
39 PP_Bool GetConfigAttrib(int32_t config, int32_t attribute, int32_t* value) { | |
40 // TODO(neb): Implement me! | |
41 return PP_FALSE; | |
42 } | |
43 | |
44 const char* QueryString(int32_t name) { | |
45 switch (name) { | |
46 case EGL_CLIENT_APIS: | |
47 return "OpenGL_ES"; | |
48 case EGL_EXTENSIONS: | |
49 return ""; | |
50 case EGL_VENDOR: | |
51 return "Google"; | |
52 case EGL_VERSION: | |
53 return "1.0 Google"; | |
54 default: | |
55 return NULL; | |
56 } | |
57 } | |
58 | |
59 PP_Resource CreateContext(PP_Instance instance_id, int32_t config, | |
60 int32_t share_context, | |
61 const int32_t* attrib_list) { | |
62 DCHECK_EQ(0, share_context); | |
63 | |
64 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
65 if (!instance) { | |
66 return 0; | |
67 } | |
68 | |
69 scoped_refptr<Graphics3D> context(new Graphics3D(instance->module())); | |
70 if (!context->Init(instance_id, config, attrib_list)) { | |
71 return 0; | |
72 } | |
73 | |
74 return context->GetReference(); | |
75 } | |
76 | |
77 void* GetProcAddress(const char* name) { | |
78 // TODO(neb): Implement me! | |
79 return NULL; | |
80 } | |
81 | |
82 PP_Bool MakeCurrent(PP_Resource graphics3d) { | |
83 if (!graphics3d) { | |
84 Graphics3D::ResetCurrent(); | |
85 return PP_TRUE; | |
86 } else { | |
87 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); | |
88 return BoolToPPBool(context.get() && context->MakeCurrent()); | |
89 } | |
90 } | |
91 | |
92 PP_Resource GetCurrentContext() { | |
93 Graphics3D* current_context = Graphics3D::GetCurrent(); | |
94 return current_context ? current_context->GetReference() : 0; | |
95 } | |
96 | |
97 PP_Bool SwapBuffers(PP_Resource graphics3d) { | |
98 scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); | |
99 return BoolToPPBool(context && context->SwapBuffers()); | |
100 } | |
101 | |
102 uint32_t GetError() { | |
103 // Technically, this should return the last error that occurred on the current | |
104 // thread, rather than an error associated with a particular context. | |
105 // TODO(apatrick): Fix this. | |
106 Graphics3D* current_context = Graphics3D::GetCurrent(); | |
107 if (!current_context) | |
108 return 0; | |
109 | |
110 return current_context->GetError(); | |
111 } | |
112 | |
113 const PPB_Graphics3D_Dev ppb_graphics3d = { | |
114 &IsGraphics3D, | |
115 &GetConfigs, | |
116 &ChooseConfig, | |
117 &GetConfigAttrib, | |
118 &QueryString, | |
119 &CreateContext, | |
120 &GetProcAddress, | |
121 &MakeCurrent, | |
122 &GetCurrentContext, | |
123 &SwapBuffers, | |
124 &GetError | |
125 }; | |
126 | |
127 } // namespace | |
128 | |
129 Graphics3D::Graphics3D(PluginModule* module) | |
130 : Resource(module), | |
131 bound_instance_(NULL) { | |
132 } | |
133 | |
134 const PPB_Graphics3D_Dev* Graphics3D::GetInterface() { | |
135 return &ppb_graphics3d; | |
136 } | |
137 | |
138 Graphics3D* Graphics3D::GetCurrent() { | |
139 return g_current_context_key.Get().Get(); | |
140 } | |
141 | |
142 void Graphics3D::ResetCurrent() { | |
143 g_current_context_key.Get().Set(NULL); | |
144 } | |
145 | |
146 Graphics3D* Graphics3D::AsGraphics3D() { | |
147 return this; | |
148 } | |
149 | |
150 Graphics3D::~Graphics3D() { | |
151 Destroy(); | |
152 } | |
153 | |
154 bool Graphics3D::Init(PP_Instance instance_id, int32_t config, | |
155 const int32_t* attrib_list) { | |
156 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
157 if (!instance) { | |
158 return false; | |
159 } | |
160 | |
161 // Create and initialize the objects required to issue GLES2 calls. | |
162 platform_context_.reset(instance->delegate()->CreateContext3D()); | |
163 if (!platform_context_.get()) { | |
164 Destroy(); | |
165 return false; | |
166 } | |
167 | |
168 if (!platform_context_->Init()) { | |
169 Destroy(); | |
170 return false; | |
171 } | |
172 | |
173 gles2_implementation_ = platform_context_->GetGLES2Implementation(); | |
174 DCHECK(gles2_implementation_); | |
175 | |
176 return true; | |
177 } | |
178 | |
179 bool Graphics3D::BindToInstance(PluginInstance* new_instance) { | |
180 if (bound_instance_ == new_instance) | |
181 return true; // Rebinding the same device, nothing to do. | |
182 if (bound_instance_ && new_instance) | |
183 return false; // Can't change a bound device. | |
184 | |
185 if (new_instance) { | |
186 // Resize the backing texture to the size of the instance when it is bound. | |
187 platform_context_->ResizeBackingTexture(new_instance->position().size()); | |
188 | |
189 // This is a temporary hack. The SwapBuffers is issued to force the resize | |
190 // to take place before any subsequent rendering. This might lead to a | |
191 // partially rendered frame being displayed. It is also not thread safe | |
192 // since the SwapBuffers is written to the command buffer and that command | |
193 // buffer might be written to by another thread. | |
194 // TODO(apatrick): Figure out the semantics of binding and resizing. | |
195 platform_context_->SwapBuffers(); | |
196 } | |
197 | |
198 bound_instance_ = new_instance; | |
199 return true; | |
200 } | |
201 | |
202 bool Graphics3D::MakeCurrent() { | |
203 if (!platform_context_.get()) | |
204 return false; | |
205 | |
206 g_current_context_key.Get().Set(this); | |
207 | |
208 // TODO(apatrick): Return false on context lost. | |
209 return true; | |
210 } | |
211 | |
212 bool Graphics3D::SwapBuffers() { | |
213 if (!platform_context_.get()) | |
214 return false; | |
215 | |
216 return platform_context_->SwapBuffers(); | |
217 } | |
218 | |
219 unsigned Graphics3D::GetError() { | |
220 if (!platform_context_.get()) | |
221 return 0; | |
222 | |
223 return platform_context_->GetError(); | |
224 } | |
225 | |
226 void Graphics3D::ResizeBackingTexture(const gfx::Size& size) { | |
227 if (!platform_context_.get()) | |
228 return; | |
229 | |
230 platform_context_->ResizeBackingTexture(size); | |
231 } | |
232 | |
233 void Graphics3D::SetSwapBuffersCallback(Callback0::Type* callback) { | |
234 if (!platform_context_.get()) | |
235 return; | |
236 | |
237 platform_context_->SetSwapBuffersCallback(callback); | |
238 } | |
239 | |
240 unsigned Graphics3D::GetBackingTextureId() { | |
241 if (!platform_context_.get()) | |
242 return 0; | |
243 | |
244 return platform_context_->GetBackingTextureId(); | |
245 } | |
246 | |
247 void Graphics3D::Destroy() { | |
248 if (GetCurrent() == this) { | |
249 ResetCurrent(); | |
250 } | |
251 | |
252 gles2_implementation_ = NULL; | |
253 | |
254 platform_context_.reset(); | |
255 } | |
256 | |
257 } // namespace pepper | |
258 | |
OLD | NEW |