1 // Copyright (c) 2012 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.
5 #include "base/at_exit.h"
7 #include "base/command_line.h"
8 #include "base/i18n/icu_util.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop.h"
11 #include "base/strings/string_split.h"
12 #include "base/time.h"
13 #include "third_party/khronos/GLES2/gl2.h"
14 #include "third_party/skia/include/core/SkXfermode.h"
15 #include "ui/aura/client/default_capture_client.h"
16 #include "ui/aura/env.h"
17 #include "ui/aura/focus_manager.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/aura/test/test_screen.h"
20 #include "ui/aura/window.h"
21 #include "ui/base/hit_test.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/base/ui_base_paths.h"
24 #include "ui/compositor/compositor.h"
25 #include "ui/compositor/compositor_observer.h"
26 #include "ui/compositor/debug_utils.h"
27 #include "ui/compositor/layer.h"
28 #include "ui/compositor/test/compositor_test_support.h"
29 #include "ui/gfx/canvas.h"
30 #include "ui/gfx/rect.h"
31 #include "ui/gfx/skia_util.h"
32 #ifndef GL_GLEXT_PROTOTYPES
33 #define GL_GLEXT_PROTOTYPES 1
35 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
36 #include "third_party/khronos/GLES2/gl2ext.h"
39 #include "base/message_pump_aurax11.h"
42 using base::TimeTicks
;
45 using ui::LayerDelegate
;
46 using WebKit::WebGraphicsContext3D
;
50 class ColoredLayer
: public Layer
, public LayerDelegate
{
52 explicit ColoredLayer(SkColor color
)
53 : Layer(ui::LAYER_TEXTURED
),
59 virtual ~ColoredLayer() {}
61 // Overridden from LayerDelegate:
62 virtual void OnPaintLayer(gfx::Canvas
* canvas
) OVERRIDE
{
64 canvas
->DrawColor(color_
);
68 virtual void OnDeviceScaleFactorChanged(float device_scale_factor
) OVERRIDE
{
71 virtual base::Closure
PrepareForLayerBoundsChange() OVERRIDE
{
72 return base::Closure();
75 void set_color(SkColor color
) { color_
= color
; }
76 void set_draw(bool draw
) { draw_
= draw
; }
82 DISALLOW_COPY_AND_ASSIGN(ColoredLayer
);
85 const int kFrames
= 100;
87 // Benchmark base class, hooks up drawing callback and displaying FPS.
88 class BenchCompositorObserver
: public ui::CompositorObserver
{
90 explicit BenchCompositorObserver(int max_frames
)
93 max_frames_(max_frames
) {
96 virtual void OnCompositingDidCommit(ui::Compositor
* compositor
) OVERRIDE
{}
98 virtual void OnCompositingStarted(Compositor
* compositor
,
99 base::TimeTicks start_time
) OVERRIDE
{}
101 virtual void OnCompositingEnded(Compositor
* compositor
) OVERRIDE
{
102 if (start_time_
.is_null()) {
103 start_time_
= TimeTicks::Now();
106 if (frames_
% kFrames
== 0) {
107 TimeTicks now
= TimeTicks::Now();
108 double ms
= (now
- start_time_
).InMillisecondsF() / kFrames
;
109 LOG(INFO
) << "FPS: " << 1000.f
/ ms
<< " (" << ms
<< " ms)";
113 if (max_frames_
&& frames_
== max_frames_
) {
114 MessageLoop::current()->Quit();
120 virtual void OnCompositingAborted(Compositor
* compositor
) OVERRIDE
{}
122 virtual void OnCompositingLockStateChanged(
123 Compositor
* compositor
) OVERRIDE
{}
125 virtual void OnUpdateVSyncParameters(ui::Compositor
* compositor
,
126 base::TimeTicks timebase
,
127 base::TimeDelta interval
) OVERRIDE
{
130 virtual void Draw() {}
132 int frames() const { return frames_
; }
135 TimeTicks start_time_
;
139 DISALLOW_COPY_AND_ASSIGN(BenchCompositorObserver
);
142 class WebGLTexture
: public ui::Texture
{
144 WebGLTexture(WebGraphicsContext3D
* context
, const gfx::Size
& size
)
145 : ui::Texture(false, size
, 1.0f
),
147 texture_id_(context_
->createTexture()) {
148 context_
->bindTexture(GL_TEXTURE_2D
, texture_id_
);
149 context_
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
150 context_
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
151 context_
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
152 context_
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
153 context_
->texImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
,
154 size
.width(), size
.height(), 0,
155 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
158 virtual unsigned int PrepareTexture() OVERRIDE
{
162 virtual WebGraphicsContext3D
* HostContext3D() OVERRIDE
{
167 virtual ~WebGLTexture() {
168 context_
->deleteTexture(texture_id_
);
171 WebGraphicsContext3D
* context_
;
172 unsigned texture_id_
;
174 DISALLOW_COPY_AND_ASSIGN(WebGLTexture
);
177 // A benchmark that adds a texture layer that is updated every frame.
178 class WebGLBench
: public BenchCompositorObserver
{
180 WebGLBench(Layer
* parent
, Compositor
* compositor
, int max_frames
)
181 : BenchCompositorObserver(max_frames
),
183 webgl_(ui::LAYER_TEXTURED
),
184 compositor_(compositor
),
189 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
190 do_draw_
= !command_line
->HasSwitch("disable-draw");
192 std::string webgl_size
= command_line
->GetSwitchValueASCII("webgl-size");
195 if (!webgl_size
.empty()) {
196 std::vector
<std::string
> split_size
;
197 base::SplitString(webgl_size
, 'x', &split_size
);
198 if (split_size
.size() == 2) {
199 width
= atoi(split_size
[0].c_str());
200 height
= atoi(split_size
[1].c_str());
203 if (!width
|| !height
) {
207 gfx::Rect
bounds(width
, height
);
208 webgl_
.SetBounds(bounds
);
209 parent_
->Add(&webgl_
);
211 context_
.reset(ui::ContextFactory::GetInstance()->CreateOffscreenContext());
212 context_
->makeContextCurrent();
213 texture_
= new WebGLTexture(context_
.get(), bounds
.size());
214 fbo_
= context_
->createFramebuffer();
215 compositor
->AddObserver(this);
216 webgl_
.SetExternalTexture(texture_
);
217 context_
->bindFramebuffer(GL_FRAMEBUFFER
, fbo_
);
218 context_
->framebufferTexture2D(
219 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
220 GL_TEXTURE_2D
, texture_
->PrepareTexture(), 0);
221 context_
->clearColor(0.f
, 1.f
, 0.f
, 1.f
);
222 context_
->clear(GL_COLOR_BUFFER_BIT
);
226 virtual ~WebGLBench() {
227 context_
->makeContextCurrent();
228 context_
->deleteFramebuffer(fbo_
);
229 webgl_
.SetExternalTexture(NULL
);
231 compositor_
->RemoveObserver(this);
234 virtual void Draw() OVERRIDE
{
236 context_
->makeContextCurrent();
237 context_
->clearColor((frames() % kFrames
)*1.0/kFrames
, 1.f
, 0.f
, 1.f
);
238 context_
->clear(GL_COLOR_BUFFER_BIT
);
241 webgl_
.SetExternalTexture(texture_
);
242 webgl_
.SchedulePaint(gfx::Rect(webgl_
.bounds().size()));
243 compositor_
->ScheduleDraw();
249 Compositor
* compositor_
;
250 scoped_ptr
<WebGraphicsContext3D
> context_
;
251 scoped_refptr
<WebGLTexture
> texture_
;
253 // The FBO that is used to render to the texture.
256 // Whether or not to draw to the texture every frame.
259 DISALLOW_COPY_AND_ASSIGN(WebGLBench
);
262 // A benchmark that paints (in software) all tiles every frame.
263 class SoftwareScrollBench
: public BenchCompositorObserver
{
265 SoftwareScrollBench(ColoredLayer
* layer
,
266 Compositor
* compositor
,
268 : BenchCompositorObserver(max_frames
),
270 compositor_(compositor
) {
271 compositor
->AddObserver(this);
273 !CommandLine::ForCurrentProcess()->HasSwitch("disable-draw"));
276 virtual ~SoftwareScrollBench() {
277 compositor_
->RemoveObserver(this);
280 virtual void Draw() OVERRIDE
{
282 SkColorSetARGBInline(255*(frames() % kFrames
)/kFrames
, 255, 0, 255));
283 layer_
->SchedulePaint(gfx::Rect(layer_
->bounds().size()));
287 ColoredLayer
* layer_
;
288 Compositor
* compositor_
;
290 DISALLOW_COPY_AND_ASSIGN(SoftwareScrollBench
);
295 int main(int argc
, char** argv
) {
296 CommandLine::Init(argc
, argv
);
298 base::AtExitManager exit_manager
;
300 ui::RegisterPathProvider();
301 icu_util::Initialize();
302 ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL
);
304 MessageLoop
message_loop(MessageLoop::TYPE_UI
);
305 ui::CompositorTestSupport::Initialize();
306 aura::Env::GetInstance();
307 scoped_ptr
<aura::TestScreen
> test_screen(
308 aura::TestScreen::CreateFullscreen());
309 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, test_screen
.get());
310 scoped_ptr
<aura::RootWindow
> root_window(
311 test_screen
->CreateRootWindowForPrimaryDisplay());
312 aura::client::SetCaptureClient(
314 new aura::client::DefaultCaptureClient(root_window
.get()));
316 scoped_ptr
<aura::client::FocusClient
> focus_client(new aura::FocusManager
);
317 aura::client::SetFocusClient(root_window
.get(), focus_client
.get());
320 ColoredLayer
background(SK_ColorRED
);
321 background
.SetBounds(root_window
->bounds());
322 root_window
->layer()->Add(&background
);
324 ColoredLayer
window(SK_ColorBLUE
);
325 window
.SetBounds(gfx::Rect(background
.bounds().size()));
326 background
.Add(&window
);
328 Layer
content_layer(ui::LAYER_NOT_DRAWN
);
330 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
331 bool force
= command_line
->HasSwitch("force-render-surface");
332 content_layer
.SetForceRenderSurface(force
);
333 gfx::Rect
bounds(window
.bounds().size());
334 bounds
.Inset(0, 30, 0, 0);
335 content_layer
.SetBounds(bounds
);
336 window
.Add(&content_layer
);
338 ColoredLayer
page_background(SK_ColorWHITE
);
339 page_background
.SetBounds(gfx::Rect(content_layer
.bounds().size()));
340 content_layer
.Add(&page_background
);
342 int frames
= atoi(command_line
->GetSwitchValueASCII("frames").c_str());
343 scoped_ptr
<BenchCompositorObserver
> bench
;
345 if (command_line
->HasSwitch("bench-software-scroll")) {
346 bench
.reset(new SoftwareScrollBench(&page_background
,
347 root_window
->compositor(),
350 bench
.reset(new WebGLBench(&page_background
,
351 root_window
->compositor(),
356 ui::PrintLayerHierarchy(root_window
->layer(), gfx::Point(100, 100));
359 root_window
->ShowRootWindow();
360 MessageLoopForUI::current()->Run();
361 focus_client
.reset();
364 ui::CompositorTestSupport::Terminate();