This source file includes following definitions.
- HandlePageFlipEvent
- GetDriProperty
- GetCrtc
- UpdateCursorImage
- dri_
- InitializeCanvas
- GetCanvas
- PresentCanvas
- CreateVSyncProvider
- controller_
- InitializeHardware
- ShutdownHardware
- GetAcceleratedWidget
- CreateSurfaceForWidget
- LoadEGLGLES2Bindings
- SchedulePageFlip
- GetCanvasForWidget
- CreateVSyncProvider
- SetHardwareCursor
- MoveHardwareCursor
- UnsetHardwareCursor
- CreateSurface
- CreateWrapper
- InitializeControllerForPrimaryDisplay
- WaitForPageFlipEvent
- ResetCursor
#include "ui/gfx/ozone/dri/dri_surface_factory.h"
#include <drm.h>
#include <errno.h>
#include <xf86drm.h>
#include "base/message_loop/message_loop.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkDevice.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/ozone/dri/dri_skbitmap.h"
#include "ui/gfx/ozone/dri/dri_surface.h"
#include "ui/gfx/ozone/dri/dri_vsync_provider.h"
#include "ui/gfx/ozone/dri/dri_wrapper.h"
#include "ui/gfx/ozone/dri/hardware_display_controller.h"
#include "ui/gfx/ozone/surface_ozone_base.h"
namespace gfx {
namespace {
const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
const char kDPMSProperty[] = "DPMS";
const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
const gfx::Size kCursorSize(64, 64);
void HandlePageFlipEvent(int fd,
unsigned int frame,
unsigned int seconds,
unsigned int useconds,
void* controller) {
static_cast<HardwareDisplayController*>(controller)
->OnPageFlipEvent(frame, seconds, useconds);
}
uint32_t GetDriProperty(int fd, drmModeConnector* connector, const char* name) {
for (int i = 0; i < connector->count_props; ++i) {
drmModePropertyPtr property = drmModeGetProperty(fd, connector->props[i]);
if (!property)
continue;
if (strcmp(property->name, name) == 0) {
uint32_t id = property->prop_id;
drmModeFreeProperty(property);
return id;
}
drmModeFreeProperty(property);
}
return 0;
}
uint32_t GetCrtc(int fd, drmModeRes* resources, drmModeConnector* connector) {
if (connector->encoder_id) {
drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoder_id);
if (encoder) {
if (encoder->crtc_id) {
uint32_t crtc = encoder->crtc_id;
drmModeFreeEncoder(encoder);
return crtc;
}
drmModeFreeEncoder(encoder);
}
}
for (int i = 0; i < connector->count_encoders; ++i) {
drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoders[i]);
if (!encoder)
continue;
for (int j = 0; j < resources->count_crtcs; ++j) {
if (!(encoder->possible_crtcs & (1 << j)))
continue;
drmModeFreeEncoder(encoder);
return resources->crtcs[j];
}
}
return 0;
}
void UpdateCursorImage(DriSurface* cursor, const SkBitmap& image) {
SkRect damage;
image.getBounds(&damage);
SkCanvas* canvas = cursor->GetDrawableForWidget();
canvas->clear(SK_ColorTRANSPARENT);
SkRect clip;
clip.set(
0, 0, canvas->getDeviceSize().width(), canvas->getDeviceSize().height());
canvas->clipRect(clip, SkRegion::kReplace_Op);
canvas->drawBitmapRectToRect(image, &damage, damage);
}
class DriSurfaceAdapter : public SurfaceOzoneBase {
public:
DriSurfaceAdapter(gfx::AcceleratedWidget w, DriSurfaceFactory* dri)
: widget_(w), dri_(dri) {}
virtual ~DriSurfaceAdapter() {}
virtual bool InitializeCanvas() OVERRIDE { return true; }
virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE {
return skia::SharePtr(dri_->GetCanvasForWidget(widget_));
}
virtual bool PresentCanvas() OVERRIDE {
return dri_->SchedulePageFlip(widget_);
}
virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
return dri_->CreateVSyncProvider(widget_);
}
private:
gfx::AcceleratedWidget widget_;
DriSurfaceFactory* dri_;
};
}
DriSurfaceFactory::DriSurfaceFactory()
: drm_(),
state_(UNINITIALIZED),
controller_() {
}
DriSurfaceFactory::~DriSurfaceFactory() {
if (state_ == INITIALIZED)
ShutdownHardware();
}
SurfaceFactoryOzone::HardwareState
DriSurfaceFactory::InitializeHardware() {
CHECK(state_ == UNINITIALIZED);
drm_.reset(CreateWrapper());
if (drm_->get_fd() < 0) {
LOG(ERROR) << "Cannot open graphics card '"
<< kDefaultGraphicsCardPath << "': " << strerror(errno);
state_ = FAILED;
return state_;
}
cursor_surface_.reset(CreateSurface(kCursorSize));
if (!cursor_surface_->Initialize()) {
LOG(ERROR) << "Failed to initialize cursor surface";
state_ = FAILED;
return state_;
}
state_ = INITIALIZED;
return state_;
}
void DriSurfaceFactory::ShutdownHardware() {
CHECK(state_ == INITIALIZED);
controller_.reset();
drm_.reset();
state_ = UNINITIALIZED;
}
gfx::AcceleratedWidget DriSurfaceFactory::GetAcceleratedWidget() {
CHECK(state_ != FAILED);
if (!controller_.get())
controller_.reset(new HardwareDisplayController());
return kDefaultWidgetHandle;
}
scoped_ptr<SurfaceOzone> DriSurfaceFactory::CreateSurfaceForWidget(
gfx::AcceleratedWidget w) {
CHECK(state_ == INITIALIZED);
CHECK(w == kDefaultWidgetHandle);
CHECK(controller_->get_state() ==
HardwareDisplayController::UNASSOCIATED);
if (!InitializeControllerForPrimaryDisplay(drm_.get(), controller_.get())) {
LOG(ERROR) << "Failed to initialize controller";
return scoped_ptr<SurfaceOzone>();
}
scoped_ptr<DriSurface> surface(CreateSurface(
Size(controller_->get_mode().hdisplay,
controller_->get_mode().vdisplay)));
if (!surface->Initialize()) {
LOG(ERROR) << "Failed to initialize surface";
return scoped_ptr<SurfaceOzone>();
}
if (!controller_->BindSurfaceToController(surface.Pass())) {
LOG(ERROR) << "Failed to bind surface to controller";
return scoped_ptr<SurfaceOzone>();
}
ResetCursor();
return make_scoped_ptr<SurfaceOzone>(new DriSurfaceAdapter(w, this));
}
bool DriSurfaceFactory::LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
return false;
}
bool DriSurfaceFactory::SchedulePageFlip(gfx::AcceleratedWidget w) {
CHECK(state_ == INITIALIZED);
CHECK(base::MessageLoopForUI::IsCurrent());
CHECK(w == kDefaultWidgetHandle);
if (!controller_->SchedulePageFlip())
return false;
WaitForPageFlipEvent(drm_->get_fd());
return true;
}
SkCanvas* DriSurfaceFactory::GetCanvasForWidget(
gfx::AcceleratedWidget w) {
CHECK(state_ == INITIALIZED);
CHECK_EQ(kDefaultWidgetHandle, w);
return controller_->get_surface()->GetDrawableForWidget();
}
scoped_ptr<gfx::VSyncProvider> DriSurfaceFactory::CreateVSyncProvider(
gfx::AcceleratedWidget w) {
CHECK(state_ == INITIALIZED);
return scoped_ptr<VSyncProvider>(new DriVSyncProvider(controller_.get()));
}
void DriSurfaceFactory::SetHardwareCursor(gfx::AcceleratedWidget window,
const SkBitmap& image,
const gfx::Point& location) {
cursor_bitmap_ = image;
cursor_location_ = location;
if (state_ != INITIALIZED)
return;
ResetCursor();
}
void DriSurfaceFactory::MoveHardwareCursor(gfx::AcceleratedWidget window,
const gfx::Point& location) {
cursor_location_ = location;
if (state_ != INITIALIZED)
return;
controller_->MoveCursor(location);
}
void DriSurfaceFactory::UnsetHardwareCursor(gfx::AcceleratedWidget window) {
cursor_bitmap_.reset();
if (state_ != INITIALIZED)
return;
ResetCursor();
}
DriSurface* DriSurfaceFactory::CreateSurface(const gfx::Size& size) {
return new DriSurface(drm_.get(), size);
}
DriWrapper* DriSurfaceFactory::CreateWrapper() {
return new DriWrapper(kDefaultGraphicsCardPath);
}
bool DriSurfaceFactory::InitializeControllerForPrimaryDisplay(
DriWrapper* drm,
HardwareDisplayController* controller) {
CHECK(state_ == SurfaceFactoryOzone::INITIALIZED);
drmModeRes* resources = drmModeGetResources(drm->get_fd());
for (int i = 0; i < resources->count_connectors; ++i) {
drmModeConnector* connector = drmModeGetConnector(
drm->get_fd(),
resources->connectors[i]);
if (!connector)
continue;
if (connector->connection != DRM_MODE_CONNECTED ||
connector->count_modes == 0) {
drmModeFreeConnector(connector);
continue;
}
uint32_t crtc = GetCrtc(drm->get_fd(), resources, connector);
if (!crtc)
continue;
uint32_t dpms_property_id = GetDriProperty(drm->get_fd(),
connector,
kDPMSProperty);
controller->SetControllerInfo(
drm,
connector->connector_id,
crtc,
dpms_property_id,
connector->modes[0]);
drmModeFreeConnector(connector);
return true;
}
return false;
}
void DriSurfaceFactory::WaitForPageFlipEvent(int fd) {
drmEventContext drm_event;
drm_event.version = DRM_EVENT_CONTEXT_VERSION;
drm_event.page_flip_handler = HandlePageFlipEvent;
drm_event.vblank_handler = NULL;
drmHandleEvent(fd, &drm_event);
}
void DriSurfaceFactory::ResetCursor() {
if (!cursor_bitmap_.empty()) {
UpdateCursorImage(cursor_surface_.get(), cursor_bitmap_);
controller_->MoveCursor(cursor_location_);
controller_->SetCursor(cursor_surface_.get());
} else {
controller_->UnsetCursor();
}
}
}