1// Copyright 2014 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 "base/at_exit.h" 6#include "base/command_line.h" 7#include "base/message_loop/message_loop.h" 8#include "base/run_loop.h" 9#include "base/timer/timer.h" 10#include "third_party/skia/include/core/SkCanvas.h" 11#include "third_party/skia/include/core/SkColor.h" 12#include "ui/gfx/geometry/size.h" 13#include "ui/gl/gl_bindings.h" 14#include "ui/gl/gl_context.h" 15#include "ui/gl/gl_surface.h" 16#include "ui/ozone/public/ozone_platform.h" 17#include "ui/ozone/public/surface_factory_ozone.h" 18#include "ui/ozone/public/surface_ozone_canvas.h" 19#include "ui/ozone/public/ui_thread_gpu.h" 20#include "ui/platform_window/platform_window.h" 21#include "ui/platform_window/platform_window_delegate.h" 22 23const int kTestWindowWidth = 800; 24const int kTestWindowHeight = 600; 25 26const int kFrameDelayMilliseconds = 16; 27 28const int kAnimationSteps = 240; 29 30const char kDisableGpu[] = "disable-gpu"; 31 32class DemoWindow : public ui::PlatformWindowDelegate { 33 public: 34 DemoWindow() : widget_(gfx::kNullAcceleratedWidget), iteration_(0) { 35 platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow( 36 this, gfx::Rect(kTestWindowWidth, kTestWindowHeight)); 37 } 38 virtual ~DemoWindow() {} 39 40 gfx::AcceleratedWidget GetAcceleratedWidget() { 41 // TODO(spang): We should start rendering asynchronously. 42 DCHECK_NE(widget_, gfx::kNullAcceleratedWidget) 43 << "Widget not available synchronously"; 44 return widget_; 45 } 46 47 gfx::Size GetSize() { return platform_window_->GetBounds().size(); } 48 49 void Start() { 50 if (!CommandLine::ForCurrentProcess()->HasSwitch(kDisableGpu) && 51 gfx::GLSurface::InitializeOneOff() && StartInProcessGpu() && 52 InitializeGLSurface()) { 53 StartAnimationGL(); 54 } else if (InitializeSoftwareSurface()) { 55 StartAnimationSoftware(); 56 } else { 57 LOG(ERROR) << "Failed to create drawing surface"; 58 Quit(); 59 } 60 } 61 62 void Quit() { 63 StopAnimation(); 64 base::MessageLoop::current()->PostTask( 65 FROM_HERE, base::Bind(&base::DeletePointer<DemoWindow>, this)); 66 } 67 68 // PlatformWindowDelegate: 69 virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {} 70 virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {} 71 virtual void DispatchEvent(ui::Event* event) OVERRIDE {} 72 virtual void OnCloseRequest() OVERRIDE { 73 Quit(); 74 } 75 virtual void OnClosed() OVERRIDE {} 76 virtual void OnWindowStateChanged( 77 ui::PlatformWindowState new_state) OVERRIDE {} 78 virtual void OnLostCapture() OVERRIDE {} 79 virtual void OnAcceleratedWidgetAvailable( 80 gfx::AcceleratedWidget widget) OVERRIDE { 81 DCHECK_NE(widget, gfx::kNullAcceleratedWidget); 82 widget_ = widget; 83 } 84 virtual void OnActivationChanged(bool active) OVERRIDE {} 85 86 private: 87 bool InitializeGLSurface() { 88 surface_ = gfx::GLSurface::CreateViewGLSurface(GetAcceleratedWidget()); 89 if (!surface_.get()) { 90 LOG(ERROR) << "Failed to create GL surface"; 91 return false; 92 } 93 94 context_ = gfx::GLContext::CreateGLContext( 95 NULL, surface_.get(), gfx::PreferIntegratedGpu); 96 if (!context_.get()) { 97 LOG(ERROR) << "Failed to create GL context"; 98 surface_ = NULL; 99 return false; 100 } 101 102 surface_->Resize(GetSize()); 103 104 if (!context_->MakeCurrent(surface_.get())) { 105 LOG(ERROR) << "Failed to make GL context current"; 106 surface_ = NULL; 107 context_ = NULL; 108 return false; 109 } 110 111 return true; 112 } 113 114 bool InitializeSoftwareSurface() { 115 software_surface_ = 116 ui::SurfaceFactoryOzone::GetInstance()->CreateCanvasForWidget( 117 GetAcceleratedWidget()); 118 if (!software_surface_) { 119 LOG(ERROR) << "Failed to create software surface"; 120 return false; 121 } 122 123 software_surface_->ResizeCanvas(GetSize()); 124 return true; 125 } 126 127 void StartAnimationGL() { 128 timer_.Start(FROM_HERE, 129 base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds), 130 this, 131 &DemoWindow::RenderFrameGL); 132 } 133 134 void StartAnimationSoftware() { 135 timer_.Start(FROM_HERE, 136 base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds), 137 this, 138 &DemoWindow::RenderFrameSoftware); 139 } 140 141 void StopAnimation() { timer_.Stop(); } 142 143 float NextFraction() { 144 float fraction = (sinf(iteration_ * 2 * M_PI / kAnimationSteps) + 1) / 2; 145 146 iteration_++; 147 iteration_ %= kAnimationSteps; 148 149 return fraction; 150 } 151 152 void RenderFrameGL() { 153 float fraction = NextFraction(); 154 gfx::Size window_size = GetSize(); 155 156 glViewport(0, 0, window_size.width(), window_size.height()); 157 glClearColor(1 - fraction, fraction, 0.0, 1.0); 158 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 159 160 if (!surface_->SwapBuffers()) 161 LOG(FATAL) << "Failed to swap buffers"; 162 } 163 164 void RenderFrameSoftware() { 165 float fraction = NextFraction(); 166 gfx::Size window_size = GetSize(); 167 168 skia::RefPtr<SkCanvas> canvas = software_surface_->GetCanvas(); 169 170 SkColor color = 171 SkColorSetARGB(0xff, 0, 0xff * fraction, 0xff * (1 - fraction)); 172 173 canvas->clear(color); 174 175 software_surface_->PresentCanvas(gfx::Rect(window_size)); 176 } 177 178 bool StartInProcessGpu() { return ui_thread_gpu_.Initialize(); } 179 180 // Timer for animation. 181 base::RepeatingTimer<DemoWindow> timer_; 182 183 // Bits for GL rendering. 184 scoped_refptr<gfx::GLSurface> surface_; 185 scoped_refptr<gfx::GLContext> context_; 186 187 // Bits for software rendeirng. 188 scoped_ptr<ui::SurfaceOzoneCanvas> software_surface_; 189 190 // Window-related state. 191 scoped_ptr<ui::PlatformWindow> platform_window_; 192 gfx::AcceleratedWidget widget_; 193 194 // Helper for applications that do GL on main thread. 195 ui::UiThreadGpu ui_thread_gpu_; 196 197 // Animation state. 198 int iteration_; 199 200 DISALLOW_COPY_AND_ASSIGN(DemoWindow); 201}; 202 203int main(int argc, char** argv) { 204 CommandLine::Init(argc, argv); 205 base::AtExitManager exit_manager; 206 207 // Build UI thread message loop. This is used by platform 208 // implementations for event polling & running background tasks. 209 base::MessageLoopForUI message_loop; 210 211 ui::OzonePlatform::InitializeForUI(); 212 213 DemoWindow* window = new DemoWindow; 214 window->Start(); 215 216 // Run the message loop until there's nothing left to do. 217 // TODO(spang): Should we use QuitClosure instead? 218 base::RunLoop run_loop; 219 run_loop.RunUntilIdle(); 220 221 return 0; 222} 223