diff options
author | dnicoara@chromium.org <dnicoara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-29 17:22:50 +0000 |
---|---|---|
committer | dnicoara@chromium.org <dnicoara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-29 17:22:50 +0000 |
commit | 26ce20d5512fadbcfeb3462656da42ce42b67803 (patch) | |
tree | d2bf4c1a80f81e722d06c37b03772aefe9bbbdfc /ui/ozone | |
parent | 54743a5071e673a394501c3da0f3de7409cf3891 (diff) | |
download | chromium_src-26ce20d5512fadbcfeb3462656da42ce42b67803.zip chromium_src-26ce20d5512fadbcfeb3462656da42ce42b67803.tar.gz chromium_src-26ce20d5512fadbcfeb3462656da42ce42b67803.tar.bz2 |
GBM Ozone implementation
Adding an accelerated platform for the X11-less build. This uses GBM (EGL_MESA_platform_gbm) as the backing Mesa platform.
BUG=377497
Review URL: https://codereview.chromium.org/106633002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273509 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/ozone')
26 files changed, 878 insertions, 169 deletions
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp index 9261add..ca937bc 100644 --- a/ui/ozone/ozone.gyp +++ b/ui/ozone/ozone.gyp @@ -92,7 +92,7 @@ 'platform/caca/caca.gypi', ], }], - ['<(ozone_platform_dri) == 1', { + ['<(ozone_platform_dri) == 1 or <(ozone_platform_gbm) == 1', { 'includes': [ 'platform/dri/dri.gypi', ], @@ -102,6 +102,11 @@ 'platform/egltest/egltest.gypi', ], }], + ['<(ozone_platform_gbm) == 1', { + 'includes': [ + 'platform/dri/gbm.gypi', + ], + }], ['<(ozone_platform_test) == 1', { 'includes': [ 'platform/test/test.gypi', diff --git a/ui/ozone/ozone_unittests.gypi b/ui/ozone/ozone_unittests.gypi index f4469f3..b57f47e 100644 --- a/ui/ozone/ozone_unittests.gypi +++ b/ui/ozone/ozone_unittests.gypi @@ -12,6 +12,8 @@ 'platform/dri/test/mock_dri_surface.h', 'platform/dri/test/mock_dri_wrapper.cc', 'platform/dri/test/mock_dri_wrapper.h', + 'platform/dri/test/mock_surface_generator.cc', + 'platform/dri/test/mock_surface_generator.h', ], 'conditions': [ ['ozone_platform_dri == 1', { diff --git a/ui/ozone/platform/dri/dri.gypi b/ui/ozone/platform/dri/dri.gypi index 9157a9d..2bbcd47 100644 --- a/ui/ozone/platform/dri/dri.gypi +++ b/ui/ozone/platform/dri/dri.gypi @@ -8,7 +8,7 @@ 'ozone_platform_dri', ], 'internal_ozone_platforms': [ - 'dri' + 'dri', ], }, 'targets': [ @@ -57,6 +57,7 @@ 'ozone_platform_dri.h', 'screen_manager.cc', 'screen_manager.h', + 'scanout_surface.h', ], }, ], diff --git a/ui/ozone/platform/dri/dri_surface.cc b/ui/ozone/platform/dri/dri_surface.cc index 6b296cc2..d6b4f59 100644 --- a/ui/ozone/platform/dri/dri_surface.cc +++ b/ui/ozone/platform/dri/dri_surface.cc @@ -66,6 +66,10 @@ void DriSurface::SwapBuffers() { front_buffer_ ^= 1; } +gfx::Size DriSurface::Size() const { + return size_; +} + SkCanvas* DriSurface::GetDrawableForWidget() { CHECK(backbuffer()); return backbuffer()->canvas(); diff --git a/ui/ozone/platform/dri/dri_surface.h b/ui/ozone/platform/dri/dri_surface.h index 2fde4d4..2abae45 100644 --- a/ui/ozone/platform/dri/dri_surface.h +++ b/ui/ozone/platform/dri/dri_surface.h @@ -10,6 +10,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/skia_util.h" #include "ui/ozone/ozone_export.h" +#include "ui/ozone/platform/dri/scanout_surface.h" class SkCanvas; @@ -18,129 +19,22 @@ namespace ui { class DriBuffer; class DriWrapper; -// DriSurface is used to represent a surface that can be scanned out -// to a monitor. It will store the internal state associated with the drawing -// surface associated with it. DriSurface also performs all the needed -// operations to initialize and update the drawing surface. -// -// The implementation uses dumb buffers, which is used for software rendering. -// The intent is to have one DriSurface implementation for a -// HardwareDisplayController. -// -// DoubleBufferedSurface is intended to be the software analog to -// EGLNativeSurface while DriSurface is intended to provide the glue -// necessary to initialize and display the surface to the screen. -// -// The typical usage pattern is: -// ----------------------------------------------------------------------------- -// HardwareDisplayController controller; -// // Initialize controller -// -// DriSurface* surface = new DriSurface(dri_wrapper, size); -// surface.Initialize(); -// controller.BindSurfaceToController(surface); -// -// while (true) { -// SkCanvas* canvas = surface->GetDrawableForWidget(); -// DrawStuff(canvas); -// controller.SchedulePageFlip(); -// -// Wait for page flip event. The DRM page flip handler will call -// surface.SwapBuffers(); -// } -// -// delete surface; -// ----------------------------------------------------------------------------- -// In the above example the wait consists of reading a DRM pageflip event from -// the graphics card file descriptor. This is done by calling |drmHandleEvent|, -// which will read and process the event. |drmHandleEvent| will call a callback -// registered by |SchedulePageFlip| which will update the internal state. -// -// |SchedulePageFlip| can also be used to limit drawing to the screen's vsync -// since page flips only happen on vsync. In a threaded environment a message -// loop would listen on the graphics card file descriptor for an event and -// |drmHandleEvent| would be called from the message loop. The event handler -// would also be responsible for updating the renderer's state and signal that -// it is OK to start drawing the next frame. -// -// The following example will illustrate the system state transitions in one -// iteration of the above loop. -// -// 1. Both buffers contain the same image with b[0] being the front buffer -// (star will represent the frontbuffer). -// ------- ------- -// | | | | -// | | | | -// | | | | -// | | | | -// ------- ------- -// b[0]* b[1] -// -// 2. Call |GetBackbuffer| to get a SkCanvas wrapper for the backbuffer and draw -// to it. -// ------- ------- -// | | | | -// | | | d | -// | | | | -// | | | | -// ------- ------- -// b[0]* b[1] -// -// 3. Call |SchedulePageFlip| to display the backbuffer. At this point we can't -// modify b[0] because it is the frontbuffer and we can't modify b[1] since it -// has been scheduled for pageflip. If we do draw in b[1] it is possible that -// the pageflip and draw happen at the same time and we could get tearing. -// -// 4. The pageflip callback is called which will call |SwapSurfaces|. Before -// |SwapSurfaces| is called the state is as following from the hardware's -// perspective: -// ------- ------- -// | | | | -// | | | d | -// | | | | -// | | | | -// ------- ------- -// b[0] b[1]* -// -// 5. |SwapSurfaces| will update out internal reference to the front buffer and -// synchronize the damaged area such that both buffers are identical. The -// damaged area is used from the SkCanvas clip. -// ------- ------- -// | | | | -// | d | | d | -// | | | | -// | | | | -// ------- ------- -// b[0] b[1]* -// -// The synchronization consists of copying the damaged area from the frontbuffer -// to the backbuffer. -// -// At this point we're back to step 1 and can start a new draw iteration. -class OZONE_EXPORT DriSurface { +// An implementation of ScanoutSurface which uses dumb buffers (used for +// software rendering). +class OZONE_EXPORT DriSurface : public ScanoutSurface { public: DriSurface(DriWrapper* dri, const gfx::Size& size); virtual ~DriSurface(); - // Used to allocate all necessary buffers for this surface. If the - // initialization succeeds, the device is ready to be used for drawing - // operations. - // Returns true if the initialization is successful, false otherwise. - bool Initialize(); - - // Returns the ID of the current backbuffer. - uint32_t GetFramebufferId() const; - - // Returns the handle for the current backbuffer. - uint32_t GetHandle() const; - - // Synchronizes and swaps the back buffer with the front buffer. - void SwapBuffers(); - // Get a Skia canvas for a backbuffer. SkCanvas* GetDrawableForWidget(); - const gfx::Size& size() const { return size_; } + // ScanoutSurface: + virtual bool Initialize() OVERRIDE; + virtual uint32_t GetFramebufferId() const OVERRIDE; + virtual uint32_t GetHandle() const OVERRIDE; + virtual void SwapBuffers() OVERRIDE; + virtual gfx::Size Size() const OVERRIDE; private: DriBuffer* frontbuffer() const { return bitmaps_[front_buffer_].get(); } diff --git a/ui/ozone/platform/dri/dri_surface_factory.cc b/ui/ozone/platform/dri/dri_surface_factory.cc index 93fc4b4..71cb4ce 100644 --- a/ui/ozone/platform/dri/dri_surface_factory.cc +++ b/ui/ozone/platform/dri/dri_surface_factory.cc @@ -96,7 +96,8 @@ scoped_ptr<gfx::VSyncProvider> DriSurfaceAdapter::CreateVSyncProvider() { } void DriSurfaceAdapter::UpdateNativeSurface(const gfx::Rect& damage) { - SkCanvas* canvas = controller_->surface()->GetDrawableForWidget(); + SkCanvas* canvas = static_cast<DriSurface*>(controller_->surface()) + ->GetDrawableForWidget(); // The DriSurface is double buffered, so the current back buffer is // missing the previous update. Expand damage region. diff --git a/ui/ozone/platform/dri/dri_surface_factory.h b/ui/ozone/platform/dri/dri_surface_factory.h index b2ba52c..f26b9ed 100644 --- a/ui/ozone/platform/dri/dri_surface_factory.h +++ b/ui/ozone/platform/dri/dri_surface_factory.h @@ -59,7 +59,7 @@ class OZONE_EXPORT DriSurfaceFactory : public gfx::SurfaceFactoryOzone { void UnsetHardwareCursor(gfx::AcceleratedWidget window); - private: + protected: // Draw the last set cursor & update the cursor plane. void ResetCursor(gfx::AcceleratedWidget w); diff --git a/ui/ozone/platform/dri/dri_surface_factory_unittest.cc b/ui/ozone/platform/dri/dri_surface_factory_unittest.cc index 1622e7e..4cdd1bf 100644 --- a/ui/ozone/platform/dri/dri_surface_factory_unittest.cc +++ b/ui/ozone/platform/dri/dri_surface_factory_unittest.cc @@ -18,6 +18,7 @@ #include "ui/ozone/platform/dri/screen_manager.h" #include "ui/ozone/platform/dri/test/mock_dri_surface.h" #include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/test/mock_surface_generator.h" namespace { @@ -53,25 +54,17 @@ class MockDriSurfaceFactory : public ui::DriSurfaceFactory { class MockScreenManager : public ui::ScreenManager { public: - MockScreenManager(ui::DriWrapper* dri) - : ScreenManager(dri), + MockScreenManager(ui::DriWrapper* dri, + ui::ScanoutSurfaceGenerator* surface_generator) + : ScreenManager(dri, surface_generator), dri_(dri) {} virtual ~MockScreenManager() {} - const std::vector<ui::MockDriSurface*>& get_surfaces() const { - return surfaces_; - } - // Normally we'd use DRM to figure out the controller configuration. But we // can't use DRM in unit tests, so we just create a fake configuration. virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE { ConfigureDisplayController(1, 2, kDefaultMode); } - virtual ui::DriSurface* CreateSurface(const gfx::Size& size) OVERRIDE { - ui::MockDriSurface* surface = new ui::MockDriSurface(dri_, size); - surfaces_.push_back(surface); - return surface; - } private: ui::DriWrapper* dri_; // Not owned. @@ -91,6 +84,7 @@ class DriSurfaceFactoryTest : public testing::Test { protected: scoped_ptr<base::MessageLoop> message_loop_; scoped_ptr<ui::MockDriWrapper> dri_; + scoped_ptr<ui::MockSurfaceGenerator> surface_generator_; scoped_ptr<MockScreenManager> screen_manager_; scoped_ptr<MockDriSurfaceFactory> factory_; @@ -101,7 +95,9 @@ class DriSurfaceFactoryTest : public testing::Test { void DriSurfaceFactoryTest::SetUp() { message_loop_.reset(new base::MessageLoopForUI); dri_.reset(new ui::MockDriWrapper(3)); - screen_manager_.reset(new MockScreenManager(dri_.get())); + surface_generator_.reset(new ui::MockSurfaceGenerator(dri_.get())); + screen_manager_.reset(new MockScreenManager(dri_.get(), + surface_generator_.get())); factory_.reset(new MockDriSurfaceFactory(dri_.get(), screen_manager_.get())); } @@ -147,7 +143,7 @@ TEST_F(DriSurfaceFactoryTest, CheckNativeSurfaceContents) { gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2)); const std::vector<ui::DriBuffer*>& bitmaps = - screen_manager_->get_surfaces()[0]->bitmaps(); + surface_generator_->surfaces()[0]->bitmaps(); SkBitmap image; bitmaps[1]->canvas()->readPixels(&image, 0, 0); diff --git a/ui/ozone/platform/dri/dri_surface_unittest.cc b/ui/ozone/platform/dri/dri_surface_unittest.cc index af47a64..397e54f 100644 --- a/ui/ozone/platform/dri/dri_surface_unittest.cc +++ b/ui/ozone/platform/dri/dri_surface_unittest.cc @@ -61,7 +61,7 @@ TEST_F(DriSurfaceTest, SuccessfulInitialization) { TEST_F(DriSurfaceTest, CheckFBIDOnSwap) { EXPECT_TRUE(surface_->Initialize()); - controller_->BindSurfaceToController(surface_.PassAs<ui::DriSurface>(), + controller_->BindSurfaceToController(surface_.PassAs<ui::ScanoutSurface>(), kDefaultMode); // Check that the framebuffer ID is correct. diff --git a/ui/ozone/platform/dri/gbm.gypi b/ui/ozone/platform/dri/gbm.gypi new file mode 100644 index 0000000..a3c5555 --- /dev/null +++ b/ui/ozone/platform/dri/gbm.gypi @@ -0,0 +1,41 @@ +# 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. + +{ + 'variables': { + 'internal_ozone_platform_deps': [ + 'ozone_platform_gbm', + ], + 'internal_ozone_platforms': [ + 'gbm', + ], + }, + 'targets': [ + { + 'target_name': 'ozone_platform_gbm', + 'type': 'static_library', + 'dependencies': [ + '../../base/base.gyp:base', + '../../build/linux/system.gyp:dridrm', + '../../build/linux/system.gyp:gbm', + '../../skia/skia.gyp:skia', + '../base/ui_base.gyp:ui_base', + '../events/events.gyp:events', + '../events/ozone/events_ozone.gyp:events_ozone', + '../gfx/gfx.gyp:gfx', + ], + 'defines': [ + 'OZONE_IMPLEMENTATION', + ], + 'sources': [ + 'gbm_surface.cc', + 'gbm_surface.h', + 'gbm_surface_factory.cc', + 'gbm_surface_factory.h', + 'ozone_platform_gbm.cc', + 'ozone_platform_gbm.h', + ], + }, + ], +} diff --git a/ui/ozone/platform/dri/gbm_surface.cc b/ui/ozone/platform/dri/gbm_surface.cc new file mode 100644 index 0000000..ce25072 --- /dev/null +++ b/ui/ozone/platform/dri/gbm_surface.cc @@ -0,0 +1,206 @@ +// 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 "ui/ozone/platform/dri/gbm_surface.h" + +#include <gbm.h> + +#include "base/logging.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/ozone/platform/dri/dri_buffer.h" +#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/gbm_surface.h" +#include "ui/ozone/platform/dri/hardware_display_controller.h" + +namespace ui { + +namespace { + +// Pixel configuration for the current buffer format. +// TODO(dnicoara) These will need to change once we'll query the hardware for +// supported configurations. +const uint8_t kColorDepth = 24; +const uint8_t kPixelDepth = 32; + +class BufferData { + public: + // When we create the BufferData we need to register the buffer. Once + // successfully registered, the |framebuffer_| field will hold the ID of the + // buffer. The controller will use this ID when scanning out the buffer. On + // creation we will also associate the BufferData with the buffer. + static BufferData* CreateData(DriWrapper* dri, gbm_bo* buffer); + + // Callback used by GBM to destory the BufferData associated with a buffer. + static void Destroy(gbm_bo* buffer, void* data); + + // Returns the BufferData associated with |buffer|. NULL if no data is + // associated. + static BufferData* GetData(gbm_bo* buffer); + + uint32_t framebuffer() const { return framebuffer_; } + uint32_t handle() const { return handle_; } + + private: + BufferData(DriWrapper* dri, gbm_bo* buffer); + ~BufferData(); + + DriWrapper* dri_; + + uint32_t handle_; + + // ID provided by the controller when the buffer is registered. This ID is + // used when scanning out the buffer. + uint32_t framebuffer_; + + DISALLOW_COPY_AND_ASSIGN(BufferData); +}; + +BufferData::BufferData(DriWrapper* dri, gbm_bo* buffer) + : dri_(dri), + handle_(gbm_bo_get_handle(buffer).u32), + framebuffer_(0) { + // Register the buffer with the controller. This will allow us to scan out the + // buffer once we're done drawing into it. If we can't register the buffer + // then there's no point in having BufferData associated with it. + if (!dri_->AddFramebuffer(gbm_bo_get_width(buffer), + gbm_bo_get_height(buffer), + kColorDepth, + kPixelDepth, + gbm_bo_get_stride(buffer), + handle_, + &framebuffer_)) { + LOG(ERROR) << "Failed to register buffer"; + } +} + +BufferData::~BufferData() { + if (framebuffer_) + dri_->RemoveFramebuffer(framebuffer_); +} + +// static +BufferData* BufferData::CreateData(DriWrapper* dri, + gbm_bo* buffer) { + BufferData* data = new BufferData(dri, buffer); + if (!data->framebuffer()) { + delete data; + return NULL; + } + + // GBM can destroy the buffers at any time as long as they aren't locked. This + // sets a callback such that we can clean up all our state when GBM destroys + // the buffer. + gbm_bo_set_user_data(buffer, data, BufferData::Destroy); + + return data; +} + +// static +void BufferData::Destroy(gbm_bo* buffer, void* data) { + BufferData* bd = static_cast<BufferData*>(data); + delete bd; +} + +// static +BufferData* BufferData::GetData(gbm_bo* buffer) { + return static_cast<BufferData*>(gbm_bo_get_user_data(buffer)); +} + +} // namespace + +GbmSurface::GbmSurface(gbm_device* device, + DriWrapper* dri, + const gfx::Size& size) + : gbm_device_(device), + dri_(dri), + size_(size), + native_surface_(NULL), + buffers_(), + front_buffer_(0) { + for (size_t i = 0; i < arraysize(buffers_); ++i) + buffers_[i] = NULL; +} + +GbmSurface::~GbmSurface() { + for (size_t i = 0; i < arraysize(buffers_); ++i) { + if (buffers_[i]) { + gbm_surface_release_buffer(native_surface_, buffers_[i]); + } + } + + if (native_surface_) + gbm_surface_destroy(native_surface_); +} + +bool GbmSurface::Initialize() { + // TODO(dnicoara) Check underlying system support for pixel format. + native_surface_ = gbm_surface_create( + gbm_device_, + size_.width(), + size_.height(), + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + + if (!native_surface_) + return false; + + dumb_buffer_.reset(new DriBuffer(dri_)); + if (!dumb_buffer_->Initialize(SkImageInfo::MakeN32Premul(size_.width(), + size_.height()))) + return false; + + return true; +} + +uint32_t GbmSurface::GetFramebufferId() const { + if (!buffers_[front_buffer_ ^ 1]) + return dumb_buffer_->framebuffer(); + + BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); + CHECK(data); + return data->framebuffer(); +} + +uint32_t GbmSurface::GetHandle() const { + if (!buffers_[front_buffer_ ^ 1]) + return dumb_buffer_->handle(); + + BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); + CHECK(data); + return data->handle(); +} + +gfx::Size GbmSurface::Size() const { + return size_; +} + +void GbmSurface::SwapBuffers() { + // If there was a frontbuffer, is no longer active. Release it back to GBM. + if (buffers_[front_buffer_]) + gbm_surface_release_buffer(native_surface_, buffers_[front_buffer_]); + + // Update the index to the frontbuffer. + front_buffer_ ^= 1; + // We've just released it. Since GBM doesn't guarantee we'll get the same + // buffer back, we set it to NULL so we don't keep track of objects that may + // have been destroyed. + buffers_[front_buffer_ ^ 1] = NULL; +} + +void GbmSurface::LockCurrentDrawable() { + CHECK(native_surface_); + // Lock the buffer we want to display. + buffers_[front_buffer_ ^ 1] = gbm_surface_lock_front_buffer(native_surface_); + + BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]); + // If it is a new buffer, it won't have any data associated with it. So we + // create it. On creation it will associate itself with the buffer and + // register the buffer. + if (!data) { + data = BufferData::CreateData(dri_, buffers_[front_buffer_ ^ 1]); + DCHECK(data) << "Failed to associate the buffer with the controller"; + } +} + +} // namespace ui diff --git a/ui/ozone/platform/dri/gbm_surface.h b/ui/ozone/platform/dri/gbm_surface.h new file mode 100644 index 0000000..8a33ab5 --- /dev/null +++ b/ui/ozone/platform/dri/gbm_surface.h @@ -0,0 +1,75 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_ +#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "ui/gfx/geometry/size.h" +#include "ui/ozone/platform/dri/scanout_surface.h" + +struct gbm_bo; +struct gbm_device; +struct gbm_surface; + +namespace ui { + +class DriBuffer; +class DriWrapper; + +// Implement the ScanoutSurface interface on top of GBM (Generic Buffer +// Manager). GBM provides generic access to hardware accelerated surfaces which +// can be used in association with EGL to provide accelerated drawing. +class GbmSurface : public ScanoutSurface { + public: + GbmSurface(gbm_device* device, DriWrapper* dri, const gfx::Size& size); + virtual ~GbmSurface(); + + // ScanoutSurface: + virtual bool Initialize() OVERRIDE; + virtual uint32_t GetFramebufferId() const OVERRIDE; + virtual uint32_t GetHandle() const OVERRIDE; + virtual gfx::Size Size() const OVERRIDE; + virtual void SwapBuffers() OVERRIDE; + + // Before scheduling the backbuffer to be scanned out we need to "lock" it. + // When we lock it, GBM will give a pointer to a buffer representing the + // backbuffer. It will also update its information on which buffers can not be + // used for drawing. The buffer will be released when the page flip event + // occurs (see SwapBuffers). This is called from GbmSurfaceFactory before + // scheduling a page flip. + void LockCurrentDrawable(); + + gbm_surface* native_surface() { return native_surface_; }; + + private: + gbm_device* gbm_device_; + + DriWrapper* dri_; + + gfx::Size size_; + + // The native GBM surface. In EGL this represents the EGLNativeWindowType. + gbm_surface* native_surface_; + + // Backing GBM buffers. One is the current front buffer. The other is the + // current backbuffer that is pending scan out. + gbm_bo* buffers_[2]; + + // Index to the front buffer. + int front_buffer_; + + // We can't lock (and get) an accelerated buffer from the GBM surface until + // after something draws into it. But modesetting needs to happen earlier, + // before an actual window is created and draws. So, we create a dumb buffer + // for this purpose. + scoped_ptr<DriBuffer> dumb_buffer_; + + DISALLOW_COPY_AND_ASSIGN(GbmSurface); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_ diff --git a/ui/ozone/platform/dri/gbm_surface_factory.cc b/ui/ozone/platform/dri/gbm_surface_factory.cc new file mode 100644 index 0000000..0c864d3 --- /dev/null +++ b/ui/ozone/platform/dri/gbm_surface_factory.cc @@ -0,0 +1,153 @@ +// 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 "ui/ozone/platform/dri/gbm_surface_factory.h" + +#include <EGL/egl.h> + +#include "base/files/file_path.h" +#include "ui/gfx/ozone/surface_ozone_egl.h" +#include "ui/ozone/platform/dri/dri_vsync_provider.h" +#include "ui/ozone/platform/dri/gbm_surface.h" +#include "ui/ozone/platform/dri/hardware_display_controller.h" +#include "ui/ozone/platform/dri/scanout_surface.h" +#include "ui/ozone/platform/dri/screen_manager.h" + +namespace ui { + +namespace { + +class GbmSurfaceAdapter : public gfx::SurfaceOzoneEGL { + public: + GbmSurfaceAdapter(const base::WeakPtr<HardwareDisplayController>& controller); + virtual ~GbmSurfaceAdapter(); + + // SurfaceOzoneEGL: + virtual intptr_t GetNativeWindow() OVERRIDE; + virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE; + virtual bool OnSwapBuffers() OVERRIDE; + virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE; + + private: + base::WeakPtr<HardwareDisplayController> controller_; + + DISALLOW_COPY_AND_ASSIGN(GbmSurfaceAdapter); +}; + +GbmSurfaceAdapter::GbmSurfaceAdapter( + const base::WeakPtr<HardwareDisplayController>& controller) + : controller_(controller) {} + +GbmSurfaceAdapter::~GbmSurfaceAdapter() {} + +intptr_t GbmSurfaceAdapter::GetNativeWindow() { + if (!controller_) + return 0; + + return reinterpret_cast<intptr_t>( + static_cast<GbmSurface*>(controller_->surface())->native_surface()); +} + +bool GbmSurfaceAdapter::ResizeNativeWindow(const gfx::Size& viewport_size) { + NOTIMPLEMENTED(); + return false; +} + +bool GbmSurfaceAdapter::OnSwapBuffers() { + if (!controller_) + return false; + + static_cast<GbmSurface*>(controller_->surface())->LockCurrentDrawable(); + if (controller_->SchedulePageFlip()) { + controller_->WaitForPageFlipEvent(); + return true; + } + + return false; +} + +scoped_ptr<gfx::VSyncProvider> GbmSurfaceAdapter::CreateVSyncProvider() { + return scoped_ptr<gfx::VSyncProvider>(new DriVSyncProvider(controller_)); +} + +} // namespace + +GbmSurfaceFactory::GbmSurfaceFactory(DriWrapper* dri, + gbm_device* device, + ScreenManager* screen_manager) + : DriSurfaceFactory(dri, screen_manager), + device_(device) {} + +GbmSurfaceFactory::~GbmSurfaceFactory() {} + +intptr_t GbmSurfaceFactory::GetNativeDisplay() { + CHECK(state_ == INITIALIZED); + return reinterpret_cast<intptr_t>(device_); +} + +const int32* GbmSurfaceFactory::GetEGLSurfaceProperties( + const int32* desired_list) { + static const int32 kConfigAttribs[] = { + EGL_BUFFER_SIZE, 32, + EGL_ALPHA_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + return kConfigAttribs; +} + +bool GbmSurfaceFactory::LoadEGLGLES2Bindings( + AddGLLibraryCallback add_gl_library, + SetGLGetProcAddressProcCallback set_gl_get_proc_address) { + base::NativeLibraryLoadError error; + base::NativeLibrary gles_library = base::LoadNativeLibrary( + base::FilePath("libGLESv2.so.2"), + &error); + if (!gles_library) { + LOG(WARNING) << "Failed to load GLES library: " << error.ToString(); + return false; + } + + base::NativeLibrary egl_library = base::LoadNativeLibrary( + base::FilePath("libEGL.so.1"), + &error); + if (!egl_library) { + LOG(WARNING) << "Failed to load EGL library: " << error.ToString(); + base::UnloadNativeLibrary(gles_library); + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary( + egl_library, "eglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "eglGetProcAddress not found."; + base::UnloadNativeLibrary(egl_library); + base::UnloadNativeLibrary(gles_library); + return false; + } + + set_gl_get_proc_address.Run(get_proc_address); + add_gl_library.Run(egl_library); + add_gl_library.Run(gles_library); + + return true; +} + +scoped_ptr<gfx::SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget( + gfx::AcceleratedWidget w) { + CHECK(state_ == INITIALIZED); + ResetCursor(w); + + return scoped_ptr<gfx::SurfaceOzoneEGL>( + new GbmSurfaceAdapter(screen_manager_->GetDisplayController(w))); +} + +} // namespace ui diff --git a/ui/ozone/platform/dri/gbm_surface_factory.h b/ui/ozone/platform/dri/gbm_surface_factory.h new file mode 100644 index 0000000..2fe0199 --- /dev/null +++ b/ui/ozone/platform/dri/gbm_surface_factory.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_ +#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_ + +#include "ui/ozone/platform/dri/dri_surface_factory.h" + +struct gbm_device; + +namespace ui { + +class GbmSurfaceFactory : public DriSurfaceFactory { + public: + GbmSurfaceFactory(DriWrapper* dri, + gbm_device* device, + ScreenManager* screen_manager); + virtual ~GbmSurfaceFactory(); + + // DriSurfaceFactory: + virtual intptr_t GetNativeDisplay() OVERRIDE; + virtual const int32_t* GetEGLSurfaceProperties( + const int32_t* desired_list) OVERRIDE; + virtual bool LoadEGLGLES2Bindings( + AddGLLibraryCallback add_gl_library, + SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE; + virtual scoped_ptr<gfx::SurfaceOzoneEGL> CreateEGLSurfaceForWidget( + gfx::AcceleratedWidget w) OVERRIDE; + + private: + gbm_device* device_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(GbmSurfaceFactory); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_ diff --git a/ui/ozone/platform/dri/hardware_display_controller.cc b/ui/ozone/platform/dri/hardware_display_controller.cc index 6256aee..e6ce1f5 100644 --- a/ui/ozone/platform/dri/hardware_display_controller.cc +++ b/ui/ozone/platform/dri/hardware_display_controller.cc @@ -15,9 +15,10 @@ #include "base/time/time.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" #include "ui/ozone/platform/dri/dri_buffer.h" -#include "ui/ozone/platform/dri/dri_surface.h" #include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/scanout_surface.h" namespace ui { @@ -28,7 +29,7 @@ namespace { // The old frontbuffer is no longer used by the hardware and can be used for // future draw operations. // -// |device| will contain a reference to the |DriSurface| object which +// |device| will contain a reference to the |ScanoutSurface| object which // the event belongs to. // // TODO(dnicoara) When we have a FD handler for the DRM calls in the message @@ -63,7 +64,7 @@ HardwareDisplayController::~HardwareDisplayController() { bool HardwareDisplayController::BindSurfaceToController( - scoped_ptr<DriSurface> surface, drmModeModeInfo mode) { + scoped_ptr<ScanoutSurface> surface, drmModeModeInfo mode) { CHECK(surface); if (!drm_->SetCrtc(crtc_id_, @@ -94,7 +95,6 @@ void HardwareDisplayController::Disable() { bool HardwareDisplayController::SchedulePageFlip() { CHECK(surface_); - if (!drm_->PageFlip(crtc_id_, surface_->GetFramebufferId(), this)) { @@ -127,11 +127,11 @@ void HardwareDisplayController::OnPageFlipEvent(unsigned int frame, surface_->SwapBuffers(); } -bool HardwareDisplayController::SetCursor(DriSurface* surface) { +bool HardwareDisplayController::SetCursor(ScanoutSurface* surface) { bool ret = drm_->SetCursor(crtc_id_, surface->GetHandle(), - surface->size().width(), - surface->size().height()); + surface->Size().width(), + surface->Size().height()); surface->SwapBuffers(); return ret; } diff --git a/ui/ozone/platform/dri/hardware_display_controller.h b/ui/ozone/platform/dri/hardware_display_controller.h index 11320b3..812f084 100644 --- a/ui/ozone/platform/dri/hardware_display_controller.h +++ b/ui/ozone/platform/dri/hardware_display_controller.h @@ -22,7 +22,7 @@ class Point; namespace ui { -class DriSurface; +class ScanoutSurface; // The HDCOz will handle modesettings and scannout operations for hardware // devices. @@ -91,7 +91,7 @@ class OZONE_EXPORT HardwareDisplayController ~HardwareDisplayController(); // Associate the HDCO with a surface implementation and initialize it. - bool BindSurfaceToController(scoped_ptr<DriSurface> surface, + bool BindSurfaceToController(scoped_ptr<ScanoutSurface> surface, drmModeModeInfo mode); void UnbindSurfaceFromController(); @@ -132,7 +132,7 @@ class OZONE_EXPORT HardwareDisplayController unsigned int useconds); // Set the hardware cursor to show the contents of |surface|. - bool SetCursor(DriSurface* surface); + bool SetCursor(ScanoutSurface* surface); bool UnsetCursor(); @@ -142,7 +142,7 @@ class OZONE_EXPORT HardwareDisplayController const drmModeModeInfo& get_mode() const { return mode_; }; uint32_t connector_id() const { return connector_id_; } uint32_t crtc_id() const { return crtc_id_; } - DriSurface* surface() const { + ScanoutSurface* surface() const { return surface_.get(); }; @@ -163,7 +163,7 @@ class OZONE_EXPORT HardwareDisplayController // TODO(dnicoara) Need to store all the modes. drmModeModeInfo mode_; - scoped_ptr<DriSurface> surface_; + scoped_ptr<ScanoutSurface> surface_; uint64_t time_of_last_flip_; diff --git a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc index 9a3e5dc..37ea856 100644 --- a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc +++ b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc @@ -47,7 +47,7 @@ void HardwareDisplayControllerTest::TearDown() { } TEST_F(HardwareDisplayControllerTest, CheckStateAfterSurfaceIsBound) { - scoped_ptr<ui::DriSurface> surface( + scoped_ptr<ui::ScanoutSurface> surface( new ui::MockDriSurface(drm_.get(), kDefaultModeSize)); EXPECT_TRUE(surface->Initialize()); @@ -57,7 +57,7 @@ TEST_F(HardwareDisplayControllerTest, CheckStateAfterSurfaceIsBound) { } TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) { - scoped_ptr<ui::DriSurface> surface( + scoped_ptr<ui::ScanoutSurface> surface( new ui::MockDriSurface(drm_.get(), kDefaultModeSize)); EXPECT_TRUE(surface->Initialize()); @@ -70,7 +70,7 @@ TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) { TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) { drm_->set_set_crtc_expectation(false); - scoped_ptr<ui::DriSurface> surface( + scoped_ptr<ui::ScanoutSurface> surface( new ui::MockDriSurface(drm_.get(), kDefaultModeSize)); EXPECT_TRUE(surface->Initialize()); @@ -82,7 +82,7 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) { TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) { drm_->set_page_flip_expectation(false); - scoped_ptr<ui::DriSurface> surface( + scoped_ptr<ui::ScanoutSurface> surface( new ui::MockDriSurface(drm_.get(), kDefaultModeSize)); EXPECT_TRUE(surface->Initialize()); diff --git a/ui/ozone/platform/dri/ozone_platform_dri.cc b/ui/ozone/platform/dri/ozone_platform_dri.cc index d701bee..442b485 100644 --- a/ui/ozone/platform/dri/ozone_platform_dri.cc +++ b/ui/ozone/platform/dri/ozone_platform_dri.cc @@ -9,8 +9,10 @@ #include "ui/events/ozone/evdev/event_factory_evdev.h" #include "ui/ozone/ozone_platform.h" #include "ui/ozone/platform/dri/cursor_factory_evdev_dri.h" +#include "ui/ozone/platform/dri/dri_surface.h" #include "ui/ozone/platform/dri/dri_surface_factory.h" #include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/scanout_surface.h" #include "ui/ozone/platform/dri/screen_manager.h" #if defined(OS_CHROMEOS) @@ -24,6 +26,21 @@ namespace { const char kDefaultGraphicsCardPath[] = "/dev/dri/card0"; +class DriSurfaceGenerator : public ScanoutSurfaceGenerator { + public: + DriSurfaceGenerator(DriWrapper* dri) : dri_(dri) {} + virtual ~DriSurfaceGenerator() {} + + virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE { + return new DriSurface(dri_, size); + } + + private: + DriWrapper* dri_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(DriSurfaceGenerator); +}; + // OzonePlatform for Linux DRI (Direct Rendering Infrastructure) // // This platform is Linux without any display server (no X, wayland, or @@ -32,7 +49,9 @@ class OzonePlatformDri : public OzonePlatform { public: OzonePlatformDri() : dri_(new DriWrapper(kDefaultGraphicsCardPath)), - screen_manager_(new ScreenManager(dri_.get())), + surface_generator_(new DriSurfaceGenerator(dri_.get())), + screen_manager_(new ScreenManager(dri_.get(), + surface_generator_.get())), device_manager_(CreateDeviceManager()) {} virtual ~OzonePlatformDri() {} @@ -71,6 +90,7 @@ class OzonePlatformDri : public OzonePlatform { private: scoped_ptr<DriWrapper> dri_; + scoped_ptr<DriSurfaceGenerator> surface_generator_; // TODO(dnicoara) Move ownership of |screen_manager_| to NDD. scoped_ptr<ScreenManager> screen_manager_; scoped_ptr<DeviceManager> device_manager_; diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.cc b/ui/ozone/platform/dri/ozone_platform_gbm.cc new file mode 100644 index 0000000..46e3bac --- /dev/null +++ b/ui/ozone/platform/dri/ozone_platform_gbm.cc @@ -0,0 +1,114 @@ +// 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 "ui/ozone/platform/dri/ozone_platform_gbm.h" + +#include <stdlib.h> +#include <gbm.h> + +#include "ui/base/cursor/ozone/cursor_factory_ozone.h" +#include "ui/events/ozone/device/device_manager.h" +#include "ui/events/ozone/evdev/event_factory_evdev.h" +#include "ui/ozone/ozone_platform.h" +#include "ui/ozone/platform/dri/dri_wrapper.h" +#include "ui/ozone/platform/dri/gbm_surface.h" +#include "ui/ozone/platform/dri/gbm_surface_factory.h" +#include "ui/ozone/platform/dri/scanout_surface.h" +#include "ui/ozone/platform/dri/screen_manager.h" + +#if defined(OS_CHROMEOS) +#include "ui/ozone/common/chromeos/native_display_delegate_ozone.h" +#endif + +namespace ui { + +namespace { + +const char kDefaultGraphicsCardPath[] = "/dev/dri/card0"; + +class GbmSurfaceGenerator : public ScanoutSurfaceGenerator { + public: + GbmSurfaceGenerator(DriWrapper* dri) + : dri_(dri), + device_(gbm_create_device(dri_->get_fd())) {} + virtual ~GbmSurfaceGenerator() { + gbm_device_destroy(device_); + } + + gbm_device* device() const { return device_; } + + virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE { + return new GbmSurface(device_, dri_, size); + } + + private: + DriWrapper* dri_; // Not owned. + + gbm_device* device_; + + DISALLOW_COPY_AND_ASSIGN(GbmSurfaceGenerator); +}; + +class OzonePlatformGbm : public OzonePlatform { + public: + OzonePlatformGbm() {} + virtual ~OzonePlatformGbm() {} + + // OzonePlatform: + virtual gfx::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE { + return surface_factory_ozone_.get(); + } + virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE { + return event_factory_ozone_.get(); + } + virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE { + return cursor_factory_ozone_.get(); + } +#if defined(OS_CHROMEOS) + virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() + OVERRIDE { + return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone()); + } +#endif + virtual void InitializeUI() OVERRIDE { + // Needed since the browser process creates the accelerated widgets and that + // happens through SFO. + surface_factory_ozone_.reset(new GbmSurfaceFactory(NULL, NULL, NULL)); + + device_manager_ = CreateDeviceManager(); + cursor_factory_ozone_.reset(new CursorFactoryOzone()); + event_factory_ozone_.reset(new EventFactoryEvdev( + NULL, device_manager_.get())); + } + + virtual void InitializeGPU() OVERRIDE { + dri_.reset(new DriWrapper(kDefaultGraphicsCardPath)); + surface_generator_.reset(new GbmSurfaceGenerator(dri_.get())); + screen_manager_.reset(new ScreenManager(dri_.get(), + surface_generator_.get())); + surface_factory_ozone_.reset( + new GbmSurfaceFactory(dri_.get(), + surface_generator_->device(), + screen_manager_.get())); + } + + private: + scoped_ptr<DriWrapper> dri_; + scoped_ptr<GbmSurfaceGenerator> surface_generator_; + // TODO(dnicoara) Move ownership of |screen_manager_| to NDD. + scoped_ptr<ScreenManager> screen_manager_; + scoped_ptr<DeviceManager> device_manager_; + + scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_; + scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_; + scoped_ptr<EventFactoryEvdev> event_factory_ozone_; + + DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm); +}; + +} // namespace + +OzonePlatform* CreateOzonePlatformGbm() { return new OzonePlatformGbm; } + +} // namespace ui diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.h b/ui/ozone/platform/dri/ozone_platform_gbm.h new file mode 100644 index 0000000..47f5ca7 --- /dev/null +++ b/ui/ozone/platform/dri/ozone_platform_gbm.h @@ -0,0 +1,17 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_ +#define UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_ + +namespace ui { + +class OzonePlatform; + +// Constructor hook for use in ozone_platform_list.cc +OzonePlatform* CreateOzonePlatformGbm(); + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_ diff --git a/ui/ozone/platform/dri/scanout_surface.h b/ui/ozone/platform/dri/scanout_surface.h new file mode 100644 index 0000000..d362ae1 --- /dev/null +++ b/ui/ozone/platform/dri/scanout_surface.h @@ -0,0 +1,84 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_ +#define UI_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_ + +#include <stdint.h> + +namespace gfx { +class Size; +} + +namespace ui { + +// ScanoutSurface is an interface for a surface that can be scanned out to a +// monitor using the DRM/KMS API. Implementations will store the internal state +// associated with the drawing surface. Implementations are also required to +// performs all the needed operations to initialize and update the drawing +// surface. +// +// The typical usage pattern is: +// ----------------------------------------------------------------------------- +// HardwareDisplayController controller; +// // Initialize controller +// +// ScanoutSurface* surface = new ScanoutSurfaceImpl(size); +// surface.Initialize(); +// controller.BindSurfaceToController(surface); +// +// while (true) { +// DrawIntoSurface(surface); +// controller.SchedulePageFlip(); +// +// Wait for page flip event. The DRM page flip handler will call +// surface.SwapBuffers(); +// } +// +// delete surface; +// ----------------------------------------------------------------------------- +// In the above example the wait consists of reading a DRM pageflip event from +// the graphics card file descriptor. This is done by calling |drmHandleEvent|, +// which will read and process the event. |drmHandleEvent| will call a callback +// registered by |SchedulePageFlip| which will update the internal state. +// +// |SchedulePageFlip| can also be used to limit drawing to the screen's vsync +// since page flips only happen on vsync. In a threaded environment a message +// loop would listen on the graphics card file descriptor for an event and +// |drmHandleEvent| would be called from the message loop. The event handler +// would also be responsible for updating the renderer's state and signal that +// it is OK to start drawing the next frame. +class ScanoutSurface { + public: + virtual ~ScanoutSurface() {} + + // Used to allocate all necessary buffers for this surface. If the + // initialization succeeds, the device is ready to be used for drawing + // operations. + // Returns true if the initialization is successful, false otherwise. + virtual bool Initialize() = 0; + + // Swaps the back buffer with the front buffer. + virtual void SwapBuffers() = 0; + + // Returns the ID of the current backbuffer. + virtual uint32_t GetFramebufferId() const = 0; + + // Returns the handle of the current backbuffer. + virtual uint32_t GetHandle() const = 0; + + // Returns the surface size. + virtual gfx::Size Size() const = 0; +}; + +class ScanoutSurfaceGenerator { + public: + virtual ~ScanoutSurfaceGenerator() {} + + virtual ScanoutSurface* Create(const gfx::Size& size) = 0; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_ diff --git a/ui/ozone/platform/dri/screen_manager.cc b/ui/ozone/platform/dri/screen_manager.cc index bf01636..23a43f9 100644 --- a/ui/ozone/platform/dri/screen_manager.cc +++ b/ui/ozone/platform/dri/screen_manager.cc @@ -9,14 +9,15 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -#include "ui/ozone/platform/dri/dri_surface.h" #include "ui/ozone/platform/dri/dri_util.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" +#include "ui/ozone/platform/dri/scanout_surface.h" namespace ui { -ScreenManager::ScreenManager(DriWrapper* dri) - : dri_(dri), last_added_widget_(0) { +ScreenManager::ScreenManager( + DriWrapper* dri, ScanoutSurfaceGenerator* surface_generator) + : dri_(dri), surface_generator_(surface_generator), last_added_widget_(0) { } ScreenManager::~ScreenManager() { @@ -51,8 +52,8 @@ bool ScreenManager::ConfigureDisplayController(uint32_t crtc, } // Create a surface suitable for the current controller. - scoped_ptr<DriSurface> surface( - CreateSurface(gfx::Size(mode.hdisplay, mode.vdisplay))); + scoped_ptr<ScanoutSurface> surface( + surface_generator_->Create(gfx::Size(mode.hdisplay, mode.vdisplay))); if (!surface->Initialize()) { LOG(ERROR) << "Failed to initialize surface"; @@ -131,8 +132,4 @@ void ScreenManager::ForceInitializationOfPrimaryDisplay() { displays[0]->connector()->modes[0]); } -DriSurface* ScreenManager::CreateSurface(const gfx::Size& size) { - return new DriSurface(dri_, size); -} - } // namespace ui diff --git a/ui/ozone/platform/dri/screen_manager.h b/ui/ozone/platform/dri/screen_manager.h index 252f706..fbe7bbb 100644 --- a/ui/ozone/platform/dri/screen_manager.h +++ b/ui/ozone/platform/dri/screen_manager.h @@ -23,11 +23,12 @@ class Size; namespace ui { class DriWrapper; +class ScanoutSurfaceGenerator; // Responsible for keeping track of active displays and configuring them. class OZONE_EXPORT ScreenManager { public: - ScreenManager(DriWrapper* dri); + ScreenManager(DriWrapper* dri, ScanoutSurfaceGenerator* surface_generator); virtual ~ScreenManager(); // Remove a display controller from the list of active controllers. The @@ -68,9 +69,8 @@ class OZONE_EXPORT ScreenManager { // to initialize a display. virtual void ForceInitializationOfPrimaryDisplay(); - virtual DriSurface* CreateSurface(const gfx::Size& size); - DriWrapper* dri_; // Not owned. + ScanoutSurfaceGenerator* surface_generator_; // Not owned. // Mapping between an accelerated widget and an active display. HardwareDisplayControllerMap controllers_; gfx::AcceleratedWidget last_added_widget_; diff --git a/ui/ozone/platform/dri/screen_manager_unittest.cc b/ui/ozone/platform/dri/screen_manager_unittest.cc index 457bef7..ce50f4b 100644 --- a/ui/ozone/platform/dri/screen_manager_unittest.cc +++ b/ui/ozone/platform/dri/screen_manager_unittest.cc @@ -5,8 +5,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/ozone/platform/dri/hardware_display_controller.h" #include "ui/ozone/platform/dri/screen_manager.h" -#include "ui/ozone/platform/dri/test/mock_dri_surface.h" #include "ui/ozone/platform/dri/test/mock_dri_wrapper.h" +#include "ui/ozone/platform/dri/test/mock_surface_generator.h" namespace { @@ -16,12 +16,11 @@ const drmModeModeInfo kDefaultMode = class MockScreenManager : public ui::ScreenManager { public: - MockScreenManager(ui::DriWrapper* dri) : ScreenManager(dri), dri_(dri) {} + MockScreenManager(ui::DriWrapper* dri, + ui::ScanoutSurfaceGenerator* surface_generator) + : ScreenManager(dri, surface_generator), dri_(dri) {} virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE {} - virtual ui::DriSurface* CreateSurface(const gfx::Size& size) OVERRIDE { - return new ui::MockDriSurface(dri_, size); - } private: ui::DriWrapper* dri_; @@ -38,7 +37,9 @@ class ScreenManagerTest : public testing::Test { virtual void SetUp() OVERRIDE { dri_.reset(new ui::MockDriWrapper(3)); - screen_manager_.reset(new MockScreenManager(dri_.get())); + surface_generator_.reset(new ui::MockSurfaceGenerator(dri_.get())); + screen_manager_.reset(new MockScreenManager( + dri_.get(), surface_generator_.get())); } virtual void TearDown() OVERRIDE { screen_manager_.reset(); @@ -47,6 +48,7 @@ class ScreenManagerTest : public testing::Test { protected: scoped_ptr<ui::MockDriWrapper> dri_; + scoped_ptr<ui::MockSurfaceGenerator> surface_generator_; scoped_ptr<MockScreenManager> screen_manager_; private: diff --git a/ui/ozone/platform/dri/test/mock_surface_generator.cc b/ui/ozone/platform/dri/test/mock_surface_generator.cc new file mode 100644 index 0000000..97df5bd --- /dev/null +++ b/ui/ozone/platform/dri/test/mock_surface_generator.cc @@ -0,0 +1,18 @@ +// 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 "ui/ozone/platform/dri/test/mock_surface_generator.h" + +namespace ui { + +MockSurfaceGenerator::MockSurfaceGenerator(DriWrapper* dri) : dri_(dri) {} + +MockSurfaceGenerator::~MockSurfaceGenerator() {} + +ScanoutSurface* MockSurfaceGenerator::Create(const gfx::Size& size) { + surfaces_.push_back(new MockDriSurface(dri_, size)); + return surfaces_.back(); +} + +} // namespace ui diff --git a/ui/ozone/platform/dri/test/mock_surface_generator.h b/ui/ozone/platform/dri/test/mock_surface_generator.h new file mode 100644 index 0000000..d9b77f8 --- /dev/null +++ b/ui/ozone/platform/dri/test/mock_surface_generator.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_ +#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_ + +#include <vector> + +#include "ui/ozone/platform/dri/test/mock_dri_surface.h" + +namespace gfx { +class Size; +} + +namespace ui { + +class DriWrapper; + +class MockSurfaceGenerator : public ScanoutSurfaceGenerator { + public: + MockSurfaceGenerator(DriWrapper* dri); + virtual ~MockSurfaceGenerator(); + + std::vector<MockDriSurface*> surfaces() const { return surfaces_; } + + // ScanoutSurfaceGenerator: + virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE; + + private: + DriWrapper* dri_; // Not owned. + + std::vector<MockDriSurface*> surfaces_; + + DISALLOW_COPY_AND_ASSIGN(MockSurfaceGenerator); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_ |