Index: ui/gfx/compositor/compositor.cc |
diff --git a/ui/gfx/compositor/compositor.cc b/ui/gfx/compositor/compositor.cc |
index 4fbd94cc4e54a5dd14e1721731a2a19334b39bad..6dd9fc3e576d8538b40903321c2f4a54bae10b5b 100644 |
--- a/ui/gfx/compositor/compositor.cc |
+++ b/ui/gfx/compositor/compositor.cc |
@@ -4,31 +4,175 @@ |
#include "ui/gfx/compositor/compositor.h" |
+#include "base/command_line.h" |
+#include "third_party/skia/include/images/SkImageEncoder.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositor.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoint.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" |
#include "ui/gfx/compositor/compositor_observer.h" |
+#include "ui/gfx/compositor/compositor_switches.h" |
+#include "ui/gfx/compositor/test_web_graphics_context_3d.h" |
#include "ui/gfx/compositor/layer.h" |
+#include "ui/gfx/gl/gl_context.h" |
+#include "ui/gfx/gl/gl_surface.h" |
+#include "ui/gfx/gl/gl_implementation.h" |
+#include "ui/gfx/gl/scoped_make_current.h" |
+#include "webkit/glue/webthread_impl.h" |
+#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h" |
+ |
+namespace { |
+ |
+const double kDefaultRefreshRate = 60.0; |
+const double kTestRefreshRate = 100.0; |
+ |
+webkit_glue::WebThreadImpl* g_compositor_thread = NULL; |
+ |
+bool test_compositor_enabled = false; |
+ |
+} // anonymous namespace |
namespace ui { |
-TextureDrawParams::TextureDrawParams() |
- : blend(false), |
- has_valid_alpha_channel(false), |
- opacity(1.0f), |
- vertically_flipped(false) { |
+SharedResources::SharedResources() : initialized_(false) { |
+} |
+ |
+ |
+SharedResources::~SharedResources() { |
+} |
+ |
+// static |
+SharedResources* SharedResources::GetInstance() { |
+ // We use LeakySingletonTraits so that we don't race with |
+ // the tear down of the gl_bindings. |
+ SharedResources* instance = Singleton<SharedResources, |
+ LeakySingletonTraits<SharedResources> >::get(); |
+ if (instance->Initialize()) { |
+ return instance; |
+ } else { |
+ instance->Destroy(); |
+ return NULL; |
+ } |
+} |
+ |
+bool SharedResources::Initialize() { |
+ if (initialized_) |
+ return true; |
+ |
+ { |
+ // The following line of code exists soley to disable IO restrictions |
+ // on this thread long enough to perform the GL bindings. |
+ // TODO(wjmaclean) Remove this when GL initialisation cleaned up. |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
+ if (!gfx::GLSurface::InitializeOneOff() || |
+ gfx::GetGLImplementation() == gfx::kGLImplementationNone) { |
+ LOG(ERROR) << "Could not load the GL bindings"; |
+ return false; |
+ } |
+ } |
+ |
+ surface_ = gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)); |
+ if (!surface_.get()) { |
+ LOG(ERROR) << "Unable to create offscreen GL surface."; |
+ return false; |
+ } |
+ |
+ context_ = gfx::GLContext::CreateGLContext( |
+ NULL, surface_.get(), gfx::PreferIntegratedGpu); |
+ if (!context_.get()) { |
+ LOG(ERROR) << "Unable to create GL context."; |
+ return false; |
+ } |
+ |
+ initialized_ = true; |
+ return true; |
+} |
+ |
+void SharedResources::Destroy() { |
+ context_ = NULL; |
+ surface_ = NULL; |
+ |
+ initialized_ = false; |
+} |
+ |
+gfx::ScopedMakeCurrent* SharedResources::GetScopedMakeCurrent() { |
+ DCHECK(initialized_); |
+ if (initialized_) |
+ return new gfx::ScopedMakeCurrent(context_.get(), surface_.get()); |
+ else |
+ return NULL; |
+} |
+ |
+void* SharedResources::GetDisplay() { |
+ return surface_->GetDisplay(); |
+} |
+ |
+gfx::GLShareGroup* SharedResources::GetShareGroup() { |
+ DCHECK(initialized_); |
+ return context_->share_group(); |
+} |
+ |
+Texture::Texture() |
+ : texture_id_(0), |
+ flipped_(false) { |
+} |
+ |
+Texture::~Texture() { |
} |
-Compositor::Compositor(CompositorDelegate* delegate, const gfx::Size& size) |
+Compositor::Compositor(CompositorDelegate* delegate, |
+ gfx::AcceleratedWidget widget, |
+ const gfx::Size& size) |
: delegate_(delegate), |
size_(size), |
- root_layer_(NULL) { |
+ root_layer_(NULL), |
+ widget_(widget), |
+ root_web_layer_(WebKit::WebLayer::create()) { |
+ WebKit::WebLayerTreeView::Settings settings; |
+ CommandLine* command_line = CommandLine::ForCurrentProcess(); |
+ settings.showFPSCounter = |
+ command_line->HasSwitch(switches::kUIShowFPSCounter); |
+ settings.showPlatformLayerTree = |
+ command_line->HasSwitch(switches::kUIShowLayerTree); |
+ settings.refreshRate = test_compositor_enabled ? |
+ kTestRefreshRate : kDefaultRefreshRate; |
+ settings.partialSwapEnabled = |
+ command_line->HasSwitch(switches::kUIEnablePartialSwap); |
+ |
+ host_ = WebKit::WebLayerTreeView::create(this, root_web_layer_, settings); |
+ root_web_layer_.setAnchorPoint(WebKit::WebFloatPoint(0.f, 0.f)); |
+ WidgetSizeChanged(size_); |
} |
Compositor::~Compositor() { |
+ // There's a cycle between |root_web_layer_| and |host_|, which results in |
+ // leaking and/or crashing. Explicitly set the root layer to NULL so the cycle |
+ // is broken. |
+ host_.setRootLayer(NULL); |
if (root_layer_) |
root_layer_->SetCompositor(NULL); |
} |
+void Compositor::Initialize(bool use_thread) { |
+ if (use_thread) |
+ g_compositor_thread = new webkit_glue::WebThreadImpl("Browser Compositor"); |
+ WebKit::WebCompositor::initialize(g_compositor_thread); |
+} |
+ |
+void Compositor::Terminate() { |
+ WebKit::WebCompositor::shutdown(); |
+ if (g_compositor_thread) { |
+ delete g_compositor_thread; |
+ g_compositor_thread = NULL; |
+ } |
+} |
+ |
void Compositor::ScheduleDraw() { |
- delegate_->ScheduleDraw(); |
+ if (g_compositor_thread) |
+ host_.composite(); |
+ else |
+ delegate_->ScheduleDraw(); |
} |
void Compositor::SetRootLayer(Layer* root_layer) { |
@@ -39,18 +183,46 @@ void Compositor::SetRootLayer(Layer* root_layer) { |
root_layer_ = root_layer; |
if (root_layer_ && !root_layer_->GetCompositor()) |
root_layer_->SetCompositor(this); |
- OnRootLayerChanged(); |
+ root_web_layer_.removeAllChildren(); |
+ if (root_layer_) |
+ root_web_layer_.addChild(root_layer_->web_layer()); |
} |
void Compositor::Draw(bool force_clear) { |
if (!root_layer_) |
return; |
- NotifyStart(force_clear); |
- DrawTree(); |
- if (!CompositesAsynchronously()) { |
+ host_.composite(); |
+ if (!g_compositor_thread) |
NotifyEnd(); |
+} |
+ |
+bool Compositor::ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds) { |
+ if (bounds.right() > size().width() || bounds.bottom() > size().height()) |
+ return false; |
+ // Convert to OpenGL coordinates. |
+ gfx::Point new_origin(bounds.x(), |
+ size().height() - bounds.height() - bounds.y()); |
+ |
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, |
+ bounds.width(), bounds.height()); |
+ bitmap->allocPixels(); |
+ SkAutoLockPixels lock_image(*bitmap); |
+ unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); |
+ if (host_.compositeAndReadback(pixels, |
+ gfx::Rect(new_origin, bounds.size()))) { |
+ SwizzleRGBAToBGRAAndFlip(pixels, bounds.size()); |
+ return true; |
} |
+ return false; |
+} |
+ |
+void Compositor::WidgetSizeChanged(const gfx::Size& size) { |
+ if (size.IsEmpty()) |
+ return; |
+ size_ = size; |
+ host_.setViewportSize(size_); |
+ root_web_layer_.setBounds(size_); |
} |
void Compositor::AddObserver(CompositorObserver* observer) { |
@@ -65,15 +237,60 @@ bool Compositor::HasObserver(CompositorObserver* observer) { |
return observer_list_.HasObserver(observer); |
} |
-void Compositor::OnRootLayerChanged() { |
- ScheduleDraw(); |
+ |
+void Compositor::updateAnimations(double frameBeginTime) { |
} |
-void Compositor::DrawTree() { |
+void Compositor::layout() { |
} |
-bool Compositor::CompositesAsynchronously() { |
- return false; |
+void Compositor::applyScrollAndScale(const WebKit::WebSize& scrollDelta, |
+ float scaleFactor) { |
+} |
+ |
+WebKit::WebGraphicsContext3D* Compositor::createContext3D() { |
+ WebKit::WebGraphicsContext3D* context; |
+ if (test_compositor_enabled) { |
+ // Use context that results in no rendering to the screen. |
+ context = new TestWebGraphicsContext3D(); |
+ } else { |
+#if defined(OS_MACOSX) && !defined(USE_AURA) |
+ // Non-Aura builds compile this code but doesn't call it. Unfortunately |
+ // this is where we translate gfx::AcceleratedWidget to |
+ // gfx::PluginWindowHandle, and they are different on non-Aura Mac. |
+ // TODO(piman): remove ifdefs when AcceleratedWidget is rationalized on Mac. |
+ NOTIMPLEMENTED(); |
+ return NULL; |
+#else |
+ gfx::GLShareGroup* share_group = |
+ SharedResources::GetInstance()->GetShareGroup(); |
+ context = new webkit::gpu::WebGraphicsContext3DInProcessImpl( |
+ widget_, share_group); |
+#endif |
+ } |
+ WebKit::WebGraphicsContext3D::Attributes attrs; |
+ context->initialize(attrs, 0, true); |
+ |
+ CommandLine* command_line = CommandLine::ForCurrentProcess(); |
+ if (!command_line->HasSwitch(switches::kDisableUIVsync)) { |
+ context->makeContextCurrent(); |
+ gfx::GLContext* gl_context = gfx::GLContext::GetCurrent(); |
+ gl_context->SetSwapInterval(1); |
+ gl_context->ReleaseCurrent(NULL); |
+ } |
+ |
+ return context; |
+} |
+ |
+void Compositor::didCompleteSwapBuffers() { |
+ NotifyEnd(); |
+} |
+ |
+void Compositor::didRebindGraphicsContext(bool success) { |
+} |
+ |
+void Compositor::scheduleComposite() { |
+ ScheduleDraw(); |
} |
void Compositor::SwizzleRGBAToBGRAAndFlip(unsigned char* pixels, |
@@ -100,14 +317,20 @@ void Compositor::SwizzleRGBAToBGRAAndFlip(unsigned char* pixels, |
} |
void Compositor::NotifyEnd() { |
- OnNotifyEnd(); |
FOR_EACH_OBSERVER(CompositorObserver, |
observer_list_, |
OnCompositingEnded(this)); |
} |
-void Compositor::NotifyStart(bool clear) { |
- OnNotifyStart(clear); |
+COMPOSITOR_EXPORT void SetupTestCompositor() { |
+ if (!CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kDisableTestCompositor)) { |
+ test_compositor_enabled = true; |
+ } |
+} |
+ |
+COMPOSITOR_EXPORT void DisableTestCompositor() { |
+ test_compositor_enabled = false; |
} |
} // namespace ui |