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.
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/skia/include/core/SkCanvas.h"
11 #include "third_party/skia/include/core/SkColor.h"
12 #include "ui/gfx/ozone/surface_factory_ozone.h"
13 #include "ui/gfx/ozone/surface_ozone_canvas.h"
14 #include "ui/ozone/platform/dri/dri_buffer.h"
15 #include "ui/ozone/platform/dri/dri_surface.h"
16 #include "ui/ozone/platform/dri/dri_surface_factory.h"
17 #include "ui/ozone/platform/dri/dri_wrapper.h"
18 #include "ui/ozone/platform/dri/hardware_display_controller.h"
22 const drmModeModeInfo kDefaultMode =
23 {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
25 // Mock file descriptor ID.
29 const uint32_t kConnectorId = 1;
32 const uint32_t kCrtcId = 1;
34 const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
36 // The real DriWrapper makes actual DRM calls which we can't use in unit tests.
37 class MockDriWrapper : public ui::DriWrapper {
39 MockDriWrapper(int fd) : DriWrapper(""),
40 add_framebuffer_expectation_(true),
41 page_flip_expectation_(true) {
45 virtual ~MockDriWrapper() { fd_ = -1; }
47 virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
48 return new drmModeCrtc;
51 virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
55 virtual bool SetCrtc(uint32_t crtc_id,
58 drmModeModeInfo* mode) OVERRIDE {
62 virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
66 virtual bool AddFramebuffer(const drmModeModeInfo& mode,
71 uint32_t* framebuffer) OVERRIDE {
72 return add_framebuffer_expectation_;
75 virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE { return true; }
77 virtual bool PageFlip(uint32_t crtc_id,
79 void* data) OVERRIDE {
80 static_cast<ui::HardwareDisplayController*>(data)->get_surface()
82 return page_flip_expectation_;
85 virtual bool SetProperty(uint32_t connector_id,
87 uint64_t value) OVERRIDE { return true; }
89 virtual void FreeProperty(drmModePropertyRes* prop) OVERRIDE { delete prop; }
91 virtual drmModePropertyBlobRes* GetPropertyBlob(drmModeConnector* connector,
92 const char* name) OVERRIDE {
93 return new drmModePropertyBlobRes;
96 virtual void FreePropertyBlob(drmModePropertyBlobRes* blob) OVERRIDE {
100 virtual bool SetCursor(uint32_t crtc_id,
103 uint32_t height) OVERRIDE { return true; }
105 virtual bool MoveCursor(uint32_t crtc_id, int x, int y) OVERRIDE {
109 void set_add_framebuffer_expectation(bool state) {
110 add_framebuffer_expectation_ = state;
113 void set_page_flip_expectation(bool state) {
114 page_flip_expectation_ = state;
118 bool add_framebuffer_expectation_;
119 bool page_flip_expectation_;
121 DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
124 class MockDriBuffer : public ui::DriBuffer {
126 MockDriBuffer(ui::DriWrapper* dri) : DriBuffer(dri) {}
127 virtual ~MockDriBuffer() {
131 virtual bool Initialize(const SkImageInfo& info) OVERRIDE {
132 surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
133 surface_->getCanvas()->clear(SK_ColorBLACK);
139 DISALLOW_COPY_AND_ASSIGN(MockDriBuffer);
142 class MockDriSurface : public ui::DriSurface {
144 MockDriSurface(ui::DriWrapper* dri, const gfx::Size& size)
145 : DriSurface(dri, size), dri_(dri) {}
146 virtual ~MockDriSurface() {}
148 const std::vector<MockDriBuffer*>& bitmaps() const { return bitmaps_; }
151 virtual ui::DriBuffer* CreateBuffer() OVERRIDE {
152 MockDriBuffer* bitmap = new MockDriBuffer(dri_);
153 bitmaps_.push_back(bitmap);
158 ui::DriWrapper* dri_; // Not owned.
159 std::vector<MockDriBuffer*> bitmaps_; // Not owned.
161 DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
164 // SSFO would normally allocate DRM resources. We can't rely on having a DRM
165 // backend to allocate and display our buffers. Thus, we replace these
166 // resources with stubs. For DRM calls, we simply use stubs that do nothing and
167 // for buffers we use the default SkBitmap allocator.
168 class MockDriSurfaceFactory : public ui::DriSurfaceFactory {
170 MockDriSurfaceFactory()
171 : DriSurfaceFactory(),
173 drm_wrapper_expectation_(true),
174 initialize_controller_expectation_(true) {}
175 virtual ~MockDriSurfaceFactory() {};
177 void set_drm_wrapper_expectation(bool state) {
178 drm_wrapper_expectation_ = state;
181 void set_initialize_controller_expectation(bool state) {
182 initialize_controller_expectation_ = state;
185 MockDriWrapper* get_drm() const {
189 const std::vector<MockDriSurface*>& get_surfaces() const { return surfaces_; }
192 virtual ui::DriSurface* CreateSurface(const gfx::Size& size) OVERRIDE {
193 MockDriSurface* surface = new MockDriSurface(mock_drm_, size);
194 surfaces_.push_back(surface);
198 virtual ui::DriWrapper* CreateWrapper() OVERRIDE {
199 if (drm_wrapper_expectation_)
200 mock_drm_ = new MockDriWrapper(kFd);
202 mock_drm_ = new MockDriWrapper(-1);
207 // Normally we'd use DRM to figure out the controller configuration. But we
208 // can't use DRM in unit tests, so we just create a fake configuration.
209 virtual bool InitializePrimaryDisplay() OVERRIDE {
210 if (initialize_controller_expectation_) {
211 return CreateHardwareDisplayController(
212 kConnectorId, kCrtcId, kDefaultMode);
218 virtual void WaitForPageFlipEvent(int fd) OVERRIDE {}
220 MockDriWrapper* mock_drm_;
221 bool drm_wrapper_expectation_;
222 bool initialize_controller_expectation_;
223 std::vector<MockDriSurface*> surfaces_; // Not owned.
225 DISALLOW_COPY_AND_ASSIGN(MockDriSurfaceFactory);
230 class DriSurfaceFactoryTest : public testing::Test {
232 DriSurfaceFactoryTest() {}
234 virtual void SetUp() OVERRIDE;
235 virtual void TearDown() OVERRIDE;
237 scoped_ptr<base::MessageLoop> message_loop_;
238 scoped_ptr<MockDriSurfaceFactory> factory_;
241 DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactoryTest);
244 void DriSurfaceFactoryTest::SetUp() {
245 message_loop_.reset(new base::MessageLoopForUI);
246 factory_.reset(new MockDriSurfaceFactory());
249 void DriSurfaceFactoryTest::TearDown() {
251 message_loop_.reset();
254 TEST_F(DriSurfaceFactoryTest, FailInitialization) {
255 factory_->set_drm_wrapper_expectation(false);
257 EXPECT_EQ(gfx::SurfaceFactoryOzone::FAILED, factory_->InitializeHardware());
260 TEST_F(DriSurfaceFactoryTest, SuccessfulInitialization) {
261 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
262 factory_->InitializeHardware());
265 TEST_F(DriSurfaceFactoryTest, FailSurfaceInitialization) {
266 factory_->set_initialize_controller_expectation(false);
268 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
269 factory_->InitializeHardware());
271 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
272 EXPECT_EQ(kDefaultWidgetHandle, w);
274 EXPECT_FALSE(factory_->CreateCanvasForWidget(w));
277 TEST_F(DriSurfaceFactoryTest, FailBindingSurfaceToController) {
278 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
279 factory_->InitializeHardware());
281 factory_->get_drm()->set_add_framebuffer_expectation(false);
283 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
284 EXPECT_EQ(kDefaultWidgetHandle, w);
286 EXPECT_FALSE(factory_->CreateCanvasForWidget(w));
289 TEST_F(DriSurfaceFactoryTest, SuccessfulWidgetRealization) {
290 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
291 factory_->InitializeHardware());
293 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
294 EXPECT_EQ(kDefaultWidgetHandle, w);
296 EXPECT_TRUE(factory_->CreateCanvasForWidget(w));
299 TEST_F(DriSurfaceFactoryTest, FailSchedulePageFlip) {
300 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
301 factory_->InitializeHardware());
303 factory_->get_drm()->set_page_flip_expectation(false);
305 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
306 EXPECT_EQ(kDefaultWidgetHandle, w);
308 scoped_ptr<gfx::SurfaceOzoneCanvas> surf = factory_->CreateCanvasForWidget(w);
311 EXPECT_FALSE(factory_->SchedulePageFlip(w));
314 TEST_F(DriSurfaceFactoryTest, SuccessfulSchedulePageFlip) {
315 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
316 factory_->InitializeHardware());
318 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
319 EXPECT_EQ(kDefaultWidgetHandle, w);
321 scoped_ptr<gfx::SurfaceOzoneCanvas> surf = factory_->CreateCanvasForWidget(w);
324 EXPECT_TRUE(factory_->SchedulePageFlip(w));
327 TEST_F(DriSurfaceFactoryTest, SetCursorImage) {
328 EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
329 factory_->InitializeHardware());
331 gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
332 EXPECT_EQ(kDefaultWidgetHandle, w);
334 scoped_ptr<gfx::SurfaceOzoneCanvas> surf = factory_->CreateCanvasForWidget(w);
338 SkImageInfo info = SkImageInfo::Make(
339 6, 4, kPMColor_SkColorType, kPremul_SkAlphaType);
340 image.allocPixels(info);
341 image.eraseColor(SK_ColorWHITE);
343 factory_->SetHardwareCursor(w, image, gfx::Point(4, 2));
344 const std::vector<MockDriSurface*>& surfaces = factory_->get_surfaces();
346 // The first surface is the cursor surface since it is allocated early in the
347 // initialization process.
348 const std::vector<MockDriBuffer*>& bitmaps = surfaces[0]->bitmaps();
350 // The surface should have been initialized to a double-buffered surface.
351 EXPECT_EQ(2u, bitmaps.size());
354 bitmaps[1]->canvas()->readPixels(&cursor, 0, 0);
356 // Check that the frontbuffer is displaying the right image as set above.
357 for (int i = 0; i < cursor.height(); ++i) {
358 for (int j = 0; j < cursor.width(); ++j) {
359 if (j < info.width() && i < info.height())
360 EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i));
362 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
363 cursor.getColor(j, i));