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