OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ui/gfx/compositor/compositor.h" | |
6 | |
7 #include "base/command_line.h" | |
8 #include "base/threading/thread_restrictions.h" | |
9 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositor.h" | |
10 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoin
t.h" | |
11 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" | |
12 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" | |
13 #include "third_party/skia/include/core/SkBitmap.h" | |
14 #include "third_party/skia/include/images/SkImageEncoder.h" | |
15 #include "ui/gfx/compositor/compositor_observer.h" | |
16 #include "ui/gfx/compositor/compositor_switches.h" | |
17 #include "ui/gfx/compositor/layer.h" | |
18 #include "ui/gfx/compositor/test_web_graphics_context_3d.h" | |
19 #include "ui/gfx/gl/gl_context.h" | |
20 #include "ui/gfx/gl/gl_implementation.h" | |
21 #include "ui/gfx/gl/gl_surface.h" | |
22 #include "webkit/glue/webthread_impl.h" | |
23 #include "webkit/gpu/webgraphicscontext3d_in_process_impl.h" | |
24 | |
25 namespace { | |
26 | |
27 const double kDefaultRefreshRate = 60.0; | |
28 const double kTestRefreshRate = 100.0; | |
29 | |
30 webkit_glue::WebThreadImpl* g_compositor_thread = NULL; | |
31 | |
32 bool test_compositor_enabled = false; | |
33 | |
34 ui::ContextFactory* g_context_factory = NULL; | |
35 | |
36 } // anonymous namespace | |
37 | |
38 namespace ui { | |
39 | |
40 // static | |
41 ContextFactory* ContextFactory::GetInstance() { | |
42 // We leak the shared resources so that we don't race with | |
43 // the tear down of the gl_bindings. | |
44 if (!g_context_factory) { | |
45 DVLOG(1) << "Using DefaultSharedResource"; | |
46 scoped_ptr<DefaultContextFactory> instance( | |
47 new DefaultContextFactory()); | |
48 if (instance->Initialize()) | |
49 g_context_factory = instance.release(); | |
50 } | |
51 return g_context_factory; | |
52 } | |
53 | |
54 // static | |
55 void ContextFactory::SetInstance(ContextFactory* instance) { | |
56 g_context_factory = instance; | |
57 } | |
58 | |
59 DefaultContextFactory::DefaultContextFactory() { | |
60 } | |
61 | |
62 DefaultContextFactory::~DefaultContextFactory() { | |
63 } | |
64 | |
65 bool DefaultContextFactory::Initialize() { | |
66 // The following line of code exists soley to disable IO restrictions | |
67 // on this thread long enough to perform the GL bindings. | |
68 // TODO(wjmaclean) Remove this when GL initialisation cleaned up. | |
69 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
70 if (!gfx::GLSurface::InitializeOneOff() || | |
71 gfx::GetGLImplementation() == gfx::kGLImplementationNone) { | |
72 LOG(ERROR) << "Could not load the GL bindings"; | |
73 return false; | |
74 } | |
75 return true; | |
76 } | |
77 | |
78 WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContext( | |
79 Compositor* compositor) { | |
80 return CreateContextCommon(compositor, false); | |
81 } | |
82 | |
83 WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext( | |
84 Compositor* compositor) { | |
85 return CreateContextCommon(compositor, true); | |
86 } | |
87 | |
88 void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { | |
89 } | |
90 | |
91 WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon( | |
92 Compositor* compositor, | |
93 bool offscreen) { | |
94 WebKit::WebGraphicsContext3D::Attributes attrs; | |
95 attrs.shareResources = true; | |
96 WebKit::WebGraphicsContext3D* context = | |
97 offscreen ? | |
98 webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView( | |
99 attrs, false) : | |
100 webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow( | |
101 attrs, compositor->widget(), share_group_.get()); | |
102 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
103 if (!command_line->HasSwitch(switches::kDisableUIVsync)) { | |
104 context->makeContextCurrent(); | |
105 gfx::GLContext* gl_context = gfx::GLContext::GetCurrent(); | |
106 gl_context->SetSwapInterval(1); | |
107 gl_context->ReleaseCurrent(NULL); | |
108 } | |
109 return context; | |
110 } | |
111 | |
112 Texture::Texture(bool flipped, const gfx::Size& size) | |
113 : texture_id_(0), | |
114 flipped_(flipped), | |
115 size_(size) { | |
116 } | |
117 | |
118 Texture::~Texture() { | |
119 } | |
120 | |
121 Compositor::Compositor(CompositorDelegate* delegate, | |
122 gfx::AcceleratedWidget widget, | |
123 const gfx::Size& size) | |
124 : delegate_(delegate), | |
125 size_(size), | |
126 root_layer_(NULL), | |
127 widget_(widget), | |
128 root_web_layer_(WebKit::WebLayer::create()), | |
129 swap_posted_(false) { | |
130 WebKit::WebLayerTreeView::Settings settings; | |
131 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
132 settings.showFPSCounter = | |
133 command_line->HasSwitch(switches::kUIShowFPSCounter); | |
134 settings.showPlatformLayerTree = | |
135 command_line->HasSwitch(switches::kUIShowLayerTree); | |
136 settings.refreshRate = test_compositor_enabled ? | |
137 kTestRefreshRate : kDefaultRefreshRate; | |
138 settings.partialSwapEnabled = | |
139 command_line->HasSwitch(switches::kUIEnablePartialSwap); | |
140 settings.perTilePainting = | |
141 command_line->HasSwitch(switches::kUIEnablePerTilePainting); | |
142 | |
143 host_.initialize(this, root_web_layer_, settings); | |
144 root_web_layer_.setAnchorPoint(WebKit::WebFloatPoint(0.f, 0.f)); | |
145 WidgetSizeChanged(size_); | |
146 } | |
147 | |
148 Compositor::~Compositor() { | |
149 // There's a cycle between |root_web_layer_| and |host_|, which results in | |
150 // leaking and/or crashing. Explicitly set the root layer to NULL so the cycle | |
151 // is broken. | |
152 host_.setRootLayer(NULL); | |
153 if (root_layer_) | |
154 root_layer_->SetCompositor(NULL); | |
155 if (!test_compositor_enabled) | |
156 ContextFactory::GetInstance()->RemoveCompositor(this); | |
157 } | |
158 | |
159 void Compositor::Initialize(bool use_thread) { | |
160 if (use_thread) | |
161 g_compositor_thread = new webkit_glue::WebThreadImpl("Browser Compositor"); | |
162 WebKit::WebCompositor::initialize(g_compositor_thread); | |
163 } | |
164 | |
165 void Compositor::Terminate() { | |
166 WebKit::WebCompositor::shutdown(); | |
167 if (g_compositor_thread) { | |
168 delete g_compositor_thread; | |
169 g_compositor_thread = NULL; | |
170 } | |
171 } | |
172 | |
173 void Compositor::ScheduleDraw() { | |
174 if (g_compositor_thread) { | |
175 // TODO(nduca): Temporary while compositor calls | |
176 // compositeImmediately() directly. | |
177 layout(); | |
178 host_.composite(); | |
179 } else { | |
180 delegate_->ScheduleDraw(); | |
181 } | |
182 } | |
183 | |
184 void Compositor::SetRootLayer(Layer* root_layer) { | |
185 if (root_layer_ == root_layer) | |
186 return; | |
187 if (root_layer_) | |
188 root_layer_->SetCompositor(NULL); | |
189 root_layer_ = root_layer; | |
190 if (root_layer_ && !root_layer_->GetCompositor()) | |
191 root_layer_->SetCompositor(this); | |
192 root_web_layer_.removeAllChildren(); | |
193 if (root_layer_) | |
194 root_web_layer_.addChild(root_layer_->web_layer()); | |
195 } | |
196 | |
197 void Compositor::Draw(bool force_clear) { | |
198 if (!root_layer_) | |
199 return; | |
200 | |
201 // TODO(nduca): Temporary while compositor calls | |
202 // compositeImmediately() directly. | |
203 layout(); | |
204 host_.composite(); | |
205 if (!g_compositor_thread && !swap_posted_) | |
206 NotifyEnd(); | |
207 } | |
208 | |
209 void Compositor::ScheduleFullDraw() { | |
210 host_.setNeedsRedraw(); | |
211 } | |
212 | |
213 bool Compositor::ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds) { | |
214 if (bounds.right() > size().width() || bounds.bottom() > size().height()) | |
215 return false; | |
216 // Convert to OpenGL coordinates. | |
217 gfx::Point new_origin(bounds.x(), | |
218 size().height() - bounds.height() - bounds.y()); | |
219 | |
220 bitmap->setConfig(SkBitmap::kARGB_8888_Config, | |
221 bounds.width(), bounds.height()); | |
222 bitmap->allocPixels(); | |
223 SkAutoLockPixels lock_image(*bitmap); | |
224 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); | |
225 if (host_.compositeAndReadback(pixels, | |
226 gfx::Rect(new_origin, bounds.size()))) { | |
227 SwizzleRGBAToBGRAAndFlip(pixels, bounds.size()); | |
228 return true; | |
229 } | |
230 return false; | |
231 } | |
232 | |
233 void Compositor::WidgetSizeChanged(const gfx::Size& size) { | |
234 if (size.IsEmpty()) | |
235 return; | |
236 size_ = size; | |
237 host_.setViewportSize(size_); | |
238 root_web_layer_.setBounds(size_); | |
239 } | |
240 | |
241 void Compositor::AddObserver(CompositorObserver* observer) { | |
242 observer_list_.AddObserver(observer); | |
243 } | |
244 | |
245 void Compositor::RemoveObserver(CompositorObserver* observer) { | |
246 observer_list_.RemoveObserver(observer); | |
247 } | |
248 | |
249 bool Compositor::HasObserver(CompositorObserver* observer) { | |
250 return observer_list_.HasObserver(observer); | |
251 } | |
252 | |
253 void Compositor::OnSwapBuffersPosted() { | |
254 swap_posted_ = true; | |
255 } | |
256 | |
257 void Compositor::OnSwapBuffersComplete() { | |
258 DCHECK(swap_posted_); | |
259 swap_posted_ = false; | |
260 NotifyEnd(); | |
261 } | |
262 | |
263 void Compositor::OnSwapBuffersAborted() { | |
264 if (swap_posted_) { | |
265 swap_posted_ = false; | |
266 NotifyEnd(); | |
267 } | |
268 } | |
269 | |
270 void Compositor::updateAnimations(double frameBeginTime) { | |
271 } | |
272 | |
273 void Compositor::layout() { | |
274 if (root_layer_) | |
275 root_layer_->SendDamagedRects(); | |
276 } | |
277 | |
278 void Compositor::applyScrollAndScale(const WebKit::WebSize& scrollDelta, | |
279 float scaleFactor) { | |
280 } | |
281 | |
282 WebKit::WebGraphicsContext3D* Compositor::createContext3D() { | |
283 if (test_compositor_enabled) { | |
284 ui::TestWebGraphicsContext3D* test_context = | |
285 new ui::TestWebGraphicsContext3D(); | |
286 test_context->Initialize(); | |
287 return test_context; | |
288 } else { | |
289 return ContextFactory::GetInstance()->CreateContext(this); | |
290 } | |
291 } | |
292 | |
293 void Compositor::didRebindGraphicsContext(bool success) { | |
294 } | |
295 | |
296 void Compositor::didCommitAndDrawFrame() { | |
297 FOR_EACH_OBSERVER(CompositorObserver, | |
298 observer_list_, | |
299 OnCompositingStarted(this)); | |
300 } | |
301 | |
302 void Compositor::didCompleteSwapBuffers() { | |
303 NotifyEnd(); | |
304 } | |
305 | |
306 void Compositor::scheduleComposite() { | |
307 ScheduleDraw(); | |
308 } | |
309 | |
310 void Compositor::SwizzleRGBAToBGRAAndFlip(unsigned char* pixels, | |
311 const gfx::Size& image_size) { | |
312 // Swizzle from RGBA to BGRA | |
313 size_t bitmap_size = 4 * image_size.width() * image_size.height(); | |
314 for(size_t i = 0; i < bitmap_size; i += 4) | |
315 std::swap(pixels[i], pixels[i + 2]); | |
316 | |
317 // Vertical flip to transform from GL co-ords | |
318 size_t row_size = 4 * image_size.width(); | |
319 scoped_array<unsigned char> tmp_row(new unsigned char[row_size]); | |
320 for(int row = 0; row < image_size.height() / 2; row++) { | |
321 memcpy(tmp_row.get(), | |
322 &pixels[row * row_size], | |
323 row_size); | |
324 memcpy(&pixels[row * row_size], | |
325 &pixels[bitmap_size - (row + 1) * row_size], | |
326 row_size); | |
327 memcpy(&pixels[bitmap_size - (row + 1) * row_size], | |
328 tmp_row.get(), | |
329 row_size); | |
330 } | |
331 } | |
332 | |
333 void Compositor::NotifyEnd() { | |
334 FOR_EACH_OBSERVER(CompositorObserver, | |
335 observer_list_, | |
336 OnCompositingEnded(this)); | |
337 } | |
338 | |
339 COMPOSITOR_EXPORT void SetupTestCompositor() { | |
340 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
341 switches::kDisableTestCompositor)) { | |
342 test_compositor_enabled = true; | |
343 } | |
344 } | |
345 | |
346 COMPOSITOR_EXPORT void DisableTestCompositor() { | |
347 test_compositor_enabled = false; | |
348 } | |
349 | |
350 COMPOSITOR_EXPORT bool IsTestCompositorEnabled() { | |
351 return test_compositor_enabled; | |
352 } | |
353 | |
354 } // namespace ui | |
OLD | NEW |