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();
  }
}
}