| // 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; |
| } |