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
23 const int kTestWindowWidth = 800;
24 const int kTestWindowHeight = 600;
25
26 const int kFrameDelayMilliseconds = 16;
27
28 const int kAnimationSteps = 240;
29
30 const char kDisableGpu[] = "disable-gpu";
31
32 class DemoWindow : public ui::PlatformWindowDelegate {
33 public:
DemoWindow()34 DemoWindow() : widget_(gfx::kNullAcceleratedWidget), iteration_(0) {
35 platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
36 this, gfx::Rect(kTestWindowWidth, kTestWindowHeight));
37 }
~DemoWindow()38 virtual ~DemoWindow() {}
39
GetAcceleratedWidget()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
GetSize()47 gfx::Size GetSize() { return platform_window_->GetBounds().size(); }
48
Start()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
Quit()62 void Quit() {
63 StopAnimation();
64 base::MessageLoop::current()->PostTask(
65 FROM_HERE, base::Bind(&base::DeletePointer<DemoWindow>, this));
66 }
67
68 // PlatformWindowDelegate:
OnBoundsChanged(const gfx::Rect & new_bounds)69 virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {}
OnDamageRect(const gfx::Rect & damaged_region)70 virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {}
DispatchEvent(ui::Event * event)71 virtual void DispatchEvent(ui::Event* event) OVERRIDE {}
OnCloseRequest()72 virtual void OnCloseRequest() OVERRIDE {
73 Quit();
74 }
OnClosed()75 virtual void OnClosed() OVERRIDE {}
OnWindowStateChanged(ui::PlatformWindowState new_state)76 virtual void OnWindowStateChanged(
77 ui::PlatformWindowState new_state) OVERRIDE {}
OnLostCapture()78 virtual void OnLostCapture() OVERRIDE {}
OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget)79 virtual void OnAcceleratedWidgetAvailable(
80 gfx::AcceleratedWidget widget) OVERRIDE {
81 DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
82 widget_ = widget;
83 }
OnActivationChanged(bool active)84 virtual void OnActivationChanged(bool active) OVERRIDE {}
85
86 private:
InitializeGLSurface()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
InitializeSoftwareSurface()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
StartAnimationGL()127 void StartAnimationGL() {
128 timer_.Start(FROM_HERE,
129 base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds),
130 this,
131 &DemoWindow::RenderFrameGL);
132 }
133
StartAnimationSoftware()134 void StartAnimationSoftware() {
135 timer_.Start(FROM_HERE,
136 base::TimeDelta::FromMicroseconds(kFrameDelayMilliseconds),
137 this,
138 &DemoWindow::RenderFrameSoftware);
139 }
140
StopAnimation()141 void StopAnimation() { timer_.Stop(); }
142
NextFraction()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
RenderFrameGL()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
RenderFrameSoftware()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
StartInProcessGpu()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
main(int argc,char ** argv)203 int 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