// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/at_exit.h" #include "base/command_line.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/timer/timer.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/surface_factory_ozone.h" #include "ui/ozone/public/surface_ozone_canvas.h" #include "ui/ozone/public/ui_thread_gpu.h" #include "ui/platform_window/platform_window.h" #include "ui/platform_window/platform_window_delegate.h" const int kTestWindowWidth = 800; const int kTestWindowHeight = 600; const int kFrameDelayMilliseconds = 16; const int kAnimationSteps = 240; const char kDisableGpu[] = "disable-gpu"; class DemoWindow : public ui::PlatformWindowDelegate { public: DemoWindow() : widget_(gfx::kNullAcceleratedWidget), iteration_(0) { platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow( this, gfx::Rect(kTestWindowWidth, kTestWindowHeight)); } virtual ~DemoWindow() {} gfx::AcceleratedWidget GetAcceleratedWidget() { // TODO(spang): We should start rendering asynchronously. DCHECK_NE(widget_, gfx::kNullAcceleratedWidget) << "Widget not available synchronously"; return widget_; } gfx::Size GetSize() { return platform_window_->GetBounds().size(); } void Start() { if (!CommandLine::ForCurrentProcess()->HasSwitch(kDisableGpu) && gfx::GLSurface::InitializeOneOff() && StartInProcessGpu() && InitializeGLSurface()) { StartAnimationGL(); } else if (InitializeSoftwareSurface()) { StartAnimationSoftware(); } else { LOG(ERROR) << "Failed to create drawing surface"; Quit(); } } void Quit() { StopAnimation(); base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&base::DeletePointer<DemoWindow>, this)); } // PlatformWindowDelegate: virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {} virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {} virtual void DispatchEvent(ui::Event* event) OVERRIDE {} virtual void OnCloseRequest() OVERRIDE { Quit(); } virtual void OnClosed() OVERRIDE {} virtual void OnWindowStateChanged( ui::PlatformWindowState new_state) OVERRIDE {} virtual void OnLostCapture() OVERRIDE {} virtual void OnAcceleratedWidgetAvailable( gfx::AcceleratedWidget widget) OVERRIDE { DCHECK_NE(widget, gfx::kNullAcceleratedWidget); widget_ = widget; } virtual void OnActivationChanged(bool active) OVERRIDE {} private: bool InitializeGLSurface() { surface_ = gfx::GLSurface::CreateViewGLSurface(GetAcceleratedWidget()); if (!surface_.get()) { LOG(ERROR) << "Failed to create GL surface"; return false; } context_ = gfx::GLContext::CreateGLContext( NULL, surface_.get(), gfx::PreferIntegratedGpu); if (!context_.get()) { LOG(ERROR) << "Failed to create GL context"; surface_ = NULL; return false; } surface_->Resize(GetSize()); if (!context_->MakeCurrent(surface_.get())) { LOG(ERROR) << "Failed to make GL context current"; surface_ = NULL; context_ = NULL; return false; } return true; } bool InitializeSoftwareSurface() { software_surface_ = ui::SurfaceFactoryOzone::GetInstance()->CreateCanvasForWidget( GetAcceleratedWidget()); if (!software_surface_) { LOG(ERROR) << "Failed to create software surface"; return false; } software_surface_->ResizeCanvas(GetSize()); return true; } void StartAnimationGL() { timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds), this, &DemoWindow::RenderFrameGL); } void StartAnimationSoftware() { timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds), this, &DemoWindow::RenderFrameSoftware); } void StopAnimation() { timer_.Stop(); } float NextFraction() { float fraction = (sinf(iteration_ * 2 * M_PI / kAnimationSteps) + 1) / 2; iteration_++; iteration_ %= kAnimationSteps; return fraction; } void RenderFrameGL() { float fraction = NextFraction(); gfx::Size window_size = GetSize(); glViewport(0, 0, window_size.width(), window_size.height()); glClearColor(1 - fraction, fraction, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (!surface_->SwapBuffers()) LOG(FATAL) << "Failed to swap buffers"; } void RenderFrameSoftware() { float fraction = NextFraction(); gfx::Size window_size = GetSize(); skia::RefPtr<SkCanvas> canvas = software_surface_->GetCanvas(); SkColor color = SkColorSetARGB(0xff, 0, 0xff * fraction, 0xff * (1 - fraction)); canvas->clear(color); software_surface_->PresentCanvas(gfx::Rect(window_size)); } bool StartInProcessGpu() { return ui_thread_gpu_.Initialize(); } // Timer for animation. base::RepeatingTimer<DemoWindow> timer_; // Bits for GL rendering. scoped_refptr<gfx::GLSurface> surface_; scoped_refptr<gfx::GLContext> context_; // Bits for software rendeirng. scoped_ptr<ui::SurfaceOzoneCanvas> software_surface_; // Window-related state. scoped_ptr<ui::PlatformWindow> platform_window_; gfx::AcceleratedWidget widget_; // Helper for applications that do GL on main thread. ui::UiThreadGpu ui_thread_gpu_; // Animation state. int iteration_; DISALLOW_COPY_AND_ASSIGN(DemoWindow); }; int main(int argc, char** argv) { CommandLine::Init(argc, argv); base::AtExitManager exit_manager; // Build UI thread message loop. This is used by platform // implementations for event polling & running background tasks. base::MessageLoopForUI message_loop; ui::OzonePlatform::InitializeForUI(); DemoWindow* window = new DemoWindow; window->Start(); // Run the message loop until there's nothing left to do. // TODO(spang): Should we use QuitClosure instead? base::RunLoop run_loop; run_loop.RunUntilIdle(); return 0; }