sde: Add support for DisplayEventHandler

- Add DisplayEventHandler to receive VSync event from driver.
- Add hooks to enable/disable VSync from client.
- Propogate VSync timestamp to the client

Change-Id: I27ea9773c424d8ad85f11f292ddd8792564bbcdc
This commit is contained in:
Arun Kumar K.R
2014-11-03 19:28:21 -08:00
committed by Gerrit - the friendly Code Review server
parent eb547a0340
commit edb8bc82ff
8 changed files with 259 additions and 16 deletions

View File

@@ -274,7 +274,7 @@ class DeviceInterface {
@return \link DisplayError \endlink @return \link DisplayError \endlink
*/ */
virtual DisplayError SetVSyncState(bool enabled) = 0; virtual DisplayError SetVSyncState(bool enable) = 0;
protected: protected:
virtual ~DeviceInterface() { } virtual ~DeviceInterface() { }

View File

@@ -45,6 +45,8 @@
namespace sde { namespace sde {
const int kThreadPriorityUrgent = -9;
typedef void * Handle; typedef void * Handle;
} // namespace sde } // namespace sde

View File

@@ -38,7 +38,7 @@ DeviceBase::DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler
: device_type_(device_type), event_handler_(event_handler), hw_block_type_(hw_block_type), : device_type_(device_type), event_handler_(event_handler), hw_block_type_(hw_block_type),
hw_intf_(hw_intf), comp_manager_(comp_manager), state_(kStateOff), hw_device_(0), hw_intf_(hw_intf), comp_manager_(comp_manager), state_(kStateOff), hw_device_(0),
comp_mgr_device_(0), device_attributes_(NULL), num_modes_(0), active_mode_index_(0), comp_mgr_device_(0), device_attributes_(NULL), num_modes_(0), active_mode_index_(0),
pending_commit_(false) { pending_commit_(false), vsync_enable_(false) {
} }
DisplayError DeviceBase::Init() { DisplayError DeviceBase::Init() {
@@ -46,7 +46,7 @@ DisplayError DeviceBase::Init() {
DisplayError error = kErrorNone; DisplayError error = kErrorNone;
error = hw_intf_->Open(hw_block_type_, &hw_device_); error = hw_intf_->Open(hw_block_type_, &hw_device_, this);
if (UNLIKELY(error != kErrorNone)) { if (UNLIKELY(error != kErrorNone)) {
return error; return error;
} }
@@ -267,9 +267,30 @@ DisplayError DeviceBase::SetConfig(uint32_t mode) {
return kErrorNone; return kErrorNone;
} }
DisplayError DeviceBase::SetVSyncState(bool enabled) { DisplayError DeviceBase::SetVSyncState(bool enable) {
SCOPE_LOCK(locker_); SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
if (vsync_enable_ != enable) {
error = hw_intf_->SetVSyncState(hw_device_, enable);
if (error == kErrorNone) {
vsync_enable_ = enable;
}
}
return error;
}
DisplayError DeviceBase::VSync(int64_t timestamp) {
if (vsync_enable_) {
DeviceEventVSync vsync;
vsync.timestamp = timestamp;
event_handler_->VSync(vsync);
}
return kErrorNone;
}
DisplayError DeviceBase::Blank(bool blank) {
return kErrorNone; return kErrorNone;
} }

View File

@@ -34,7 +34,7 @@
namespace sde { namespace sde {
class DeviceBase : public DeviceInterface, DumpImpl { class DeviceBase : public DeviceInterface, DumpImpl, HWEventHandler {
public: public:
DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler, DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler,
HWBlockType hw_block_type, HWInterface *hw_intf, CompManager *comp_manager); HWBlockType hw_block_type, HWInterface *hw_intf, CompManager *comp_manager);
@@ -50,11 +50,15 @@ class DeviceBase : public DeviceInterface, DumpImpl {
virtual DisplayError GetVSyncState(bool *enabled); virtual DisplayError GetVSyncState(bool *enabled);
virtual DisplayError SetDeviceState(DeviceState state); virtual DisplayError SetDeviceState(DeviceState state);
virtual DisplayError SetConfig(uint32_t mode); virtual DisplayError SetConfig(uint32_t mode);
virtual DisplayError SetVSyncState(bool enabled); virtual DisplayError SetVSyncState(bool enable);
// DumpImpl method // DumpImpl method
virtual uint32_t GetDump(uint8_t *buffer, uint32_t length); virtual uint32_t GetDump(uint8_t *buffer, uint32_t length);
// Implement the HWEventHandlers
virtual DisplayError VSync(int64_t timestamp);
virtual DisplayError Blank(bool blank);
protected: protected:
Locker locker_; Locker locker_;
DeviceType device_type_; DeviceType device_type_;
@@ -70,6 +74,7 @@ class DeviceBase : public DeviceInterface, DumpImpl {
uint32_t active_mode_index_; uint32_t active_mode_index_;
HWLayers hw_layers_; HWLayers hw_layers_;
bool pending_commit_; bool pending_commit_;
bool vsync_enable_;
}; };
} // namespace sde } // namespace sde

View File

@@ -35,6 +35,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <pthread.h>
#include <utils/constants.h> #include <utils/constants.h>
#include "hw_framebuffer.h" #include "hw_framebuffer.h"
@@ -45,15 +48,20 @@
extern int virtual_ioctl(int fd, int cmd, ...); extern int virtual_ioctl(int fd, int cmd, ...);
extern int virtual_open(const char *file_name, int access, ...); extern int virtual_open(const char *file_name, int access, ...);
extern int virtual_close(int fd); extern int virtual_close(int fd);
extern int virtual_poll(struct pollfd *fds, nfds_t num, int timeout);
extern ssize_t virtual_pread(int fd, void *data, size_t count, off_t offset);
#endif #endif
namespace sde { namespace sde {
HWFrameBuffer::HWFrameBuffer() { HWFrameBuffer::HWFrameBuffer() : event_thread_name_("SDE_EventThread"), fake_vsync_(false),
// Point to actual driver interfaces. exit_threads_(false) {
// Pointer to actual driver interfaces.
ioctl_ = ::ioctl; ioctl_ = ::ioctl;
open_ = ::open; open_ = ::open;
close_ = ::close; close_ = ::close;
poll_ = ::poll;
pread_ = ::pread;
#ifdef DISPLAY_CORE_VIRTUAL_DRIVER #ifdef DISPLAY_CORE_VIRTUAL_DRIVER
// If debug property to use virtual driver is set, point to virtual driver interfaces. // If debug property to use virtual driver is set, point to virtual driver interfaces.
@@ -61,15 +69,83 @@ HWFrameBuffer::HWFrameBuffer() {
ioctl_ = virtual_ioctl; ioctl_ = virtual_ioctl;
open_ = virtual_open; open_ = virtual_open;
close_ = virtual_close; close_ = virtual_close;
poll_ = virtual_poll;
pread_ = virtual_pread;
} }
#endif #endif
} }
DisplayError HWFrameBuffer::Init() { DisplayError HWFrameBuffer::Init() {
DisplayError error = kErrorNone;
// TODO(user): Need to read the fbnode info, hw capabilities here
// Open nodes for polling
char node_path[kMaxStringLength] = {0};
char data[kMaxStringLength] = {0};
const char* event_name[kNumDisplayEvents] = {"vsync_event", "show_blank_event"};
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
poll_fds_[display][event].fd = -1;
}
}
if (!fake_vsync_) {
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
pollfd &poll_fd = poll_fds_[display][event];
snprintf(node_path, sizeof(node_path), "/sys/class/graphics/fb%d/%s",
(display == 0) ? 0 : 1/*TODO(user): HDMI fb node index*/, event_name[event]);
poll_fd.fd = open_(node_path, O_RDONLY);
if (poll_fd.fd < 0) {
DLOGE("open failed for display=%d event=%zu, error=%s", display, event, strerror(errno));
error = kErrorHardware;
goto CleanupOnError;
}
// Read once on all fds to clear data on all fds.
pread_(poll_fd.fd, data , kMaxStringLength, 0);
poll_fd.events = POLLPRI | POLLERR;
}
}
}
// Start the Event thread
if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
DLOGE("Failed to start %s, error = %s", event_thread_name_);
error = kErrorResources;
goto CleanupOnError;
}
return kErrorNone; return kErrorNone;
CleanupOnError:
// Close all poll fds
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
int &fd = poll_fds_[display][event].fd;
if (fd >= 0) {
close_(fd);
}
}
}
return error;
} }
DisplayError HWFrameBuffer::Deinit() { DisplayError HWFrameBuffer::Deinit() {
exit_threads_ = true;
pthread_join(event_thread_, NULL);
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
close(poll_fds_[display][event].fd);
}
}
return kErrorNone; return kErrorNone;
} }
@@ -91,7 +167,7 @@ DisplayError HWFrameBuffer::GetHWCapabilities(HWResourceInfo *hw_res_info) {
return kErrorNone; return kErrorNone;
} }
DisplayError HWFrameBuffer::Open(HWBlockType type, Handle *device) { DisplayError HWFrameBuffer::Open(HWBlockType type, Handle *device, HWEventHandler* eventhandler) {
DisplayError error = kErrorNone; DisplayError error = kErrorNone;
HWContext *hw_context = new HWContext(); HWContext *hw_context = new HWContext();
@@ -119,6 +195,8 @@ DisplayError HWFrameBuffer::Open(HWBlockType type, Handle *device) {
} }
*device = hw_context; *device = hw_context;
event_handler_[device_id] = eventhandler;
return error; return error;
} }
@@ -216,6 +294,17 @@ DisplayError HWFrameBuffer::Standby(Handle device) {
return kErrorNone; return kErrorNone;
} }
DisplayError HWFrameBuffer::SetVSyncState(Handle device, bool enable) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
int vsync_on = enable ? 1 : 0;
if (ioctl_(hw_context->device_fd, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) == -1) {
IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL);
return kErrorHardware;
}
return kErrorNone;
}
DisplayError HWFrameBuffer::Validate(Handle device, HWLayers *hw_layers) { DisplayError HWFrameBuffer::Validate(Handle device, HWLayers *hw_layers) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device); HWContext *hw_context = reinterpret_cast<HWContext *>(device);
@@ -357,5 +446,86 @@ void HWFrameBuffer::SetRect(mdp_rect *target, const LayerRect &source) {
target->h = INT(floorf(source.bottom)) - target->y; target->h = INT(floorf(source.bottom)) - target->y;
} }
} // namespace sde void* HWFrameBuffer::DisplayEventThread(void *context) {
if (context) {
return reinterpret_cast<HWFrameBuffer *>(context)->DisplayEventThreadHandler();
}
return NULL;
}
void* HWFrameBuffer::DisplayEventThreadHandler() {
char data[kMaxStringLength] = {0};
prctl(PR_SET_NAME, event_thread_name_, 0, 0, 0);
setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent);
if (fake_vsync_) {
while (!exit_threads_) {
// Fake vsync is used only when set explicitly through a property(todo) or when
// the vsync timestamp node cannot be opened at bootup. There is no
// fallback to fake vsync from the true vsync loop, ever, as the
// condition can easily escape detection.
// Also, fake vsync is delivered only for the primary display.
usleep(16666);
STRUCT_VAR(timeval, time_now);
gettimeofday(&time_now, NULL);
uint64_t ts = uint64_t(time_now.tv_sec)*1000000000LL +uint64_t(time_now.tv_usec)*1000LL;
// Send Vsync event for primary display(0)
event_handler_[0]->VSync(ts);
}
pthread_exit(0);
}
typedef void (HWFrameBuffer::*EventHandler)(int, char*);
EventHandler event_handler[kNumDisplayEvents] = { &HWFrameBuffer::HandleVSync,
&HWFrameBuffer::HandleBlank };
while (!exit_threads_) {
int error = poll_(poll_fds_[0], kNumPhysicalDisplays * kNumDisplayEvents, -1);
if (error < 0) {
DLOGE("poll failed errno: %s", strerror(errno));
continue;
}
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
pollfd &poll_fd = poll_fds_[display][event];
if (poll_fd.revents & POLLPRI) {
ssize_t length = pread_(poll_fd.fd, data, kMaxStringLength, 0);
if (length < 0) {
// If the read was interrupted - it is not a fatal error, just continue.
DLOGE("Failed to read event:%zu for display=%d : %s", event, display, strerror(errno));
continue;
}
(this->*event_handler[event])(display, data);
}
}
}
}
pthread_exit(0);
return NULL;
}
void HWFrameBuffer::HandleVSync(int display_id, char *data) {
int64_t timestamp = 0;
if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) {
timestamp = strtoull(data + strlen("VSYNC="), NULL, 0);
}
event_handler_[display_id]->VSync(timestamp);
return;
}
void HWFrameBuffer::HandleBlank(int display_id, char* data) {
// TODO(user): Need to send blank Event
return;
}
} // namespace sde

View File

@@ -26,6 +26,8 @@
#define __HW_FRAMEBUFFER_H__ #define __HW_FRAMEBUFFER_H__
#include <linux/msm_mdp.h> #include <linux/msm_mdp.h>
#include <poll.h>
#include <pthread.h>
#include "hw_interface.h" #include "hw_interface.h"
namespace sde { namespace sde {
@@ -36,14 +38,15 @@ class HWFrameBuffer : public HWInterface {
DisplayError Init(); DisplayError Init();
DisplayError Deinit(); DisplayError Deinit();
virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info); virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info);
virtual DisplayError Open(HWBlockType type, Handle *device); virtual DisplayError Open(HWBlockType type, Handle *device, HWEventHandler *eventhandler);
virtual DisplayError Close(Handle device); virtual DisplayError Close(Handle device);
virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count); virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count);
virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes, virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes,
uint32_t mode); uint32_t mode);
virtual DisplayError PowerOn(Handle device); virtual DisplayError PowerOn(Handle device);
virtual DisplayError PowerOff(Handle device); virtual DisplayError PowerOff(Handle device);
virtual DisplayError Doze(Handle device); virtual DisplayError Doze(Handle device);
virtual DisplayError SetVSyncState(Handle device, bool enable);
virtual DisplayError Standby(Handle device); virtual DisplayError Standby(Handle device);
virtual DisplayError Validate(Handle device, HWLayers *hw_layers); virtual DisplayError Validate(Handle device, HWLayers *hw_layers);
virtual DisplayError Commit(Handle device, HWLayers *hw_layers); virtual DisplayError Commit(Handle device, HWLayers *hw_layers);
@@ -54,14 +57,40 @@ class HWFrameBuffer : public HWInterface {
int device_fd; int device_fd;
}; };
enum {
kHWEventVSync,
kHWEventBlank,
};
static const int kMaxStringLength = 1024;
static const int kNumPhysicalDisplays = 2;
static const int kNumDisplayEvents = 2;
inline void SetFormat(uint32_t *target, const LayerBufferFormat &source); inline void SetFormat(uint32_t *target, const LayerBufferFormat &source);
inline void SetBlending(uint32_t *target, const LayerBlending &source); inline void SetBlending(uint32_t *target, const LayerBlending &source);
inline void SetRect(mdp_rect *target, const LayerRect &source); inline void SetRect(mdp_rect *target, const LayerRect &source);
// For dynamically linking virtual driver // Event Thread to receive vsync/blank events
static void* DisplayEventThread(void *context);
void* DisplayEventThreadHandler();
void HandleVSync(int display_id, char *data);
void HandleBlank(int display_id, char *data);
// Pointers to system calls which are either mapped to actual system call or virtual driver.
int (*ioctl_)(int, int, ...); int (*ioctl_)(int, int, ...);
int (*open_)(const char *, int, ...); int (*open_)(const char *, int, ...);
int (*close_)(int); int (*close_)(int);
int (*poll_)(struct pollfd *, nfds_t, int);
ssize_t (*pread_)(int, void *, size_t, off_t);
// Store the Device EventHandlers - used for callback
HWEventHandler *event_handler_[kNumPhysicalDisplays];
pollfd poll_fds_[kNumPhysicalDisplays][kNumDisplayEvents];
pthread_t event_thread_;
const char *event_thread_name_;
bool fake_vsync_;
bool exit_threads_;
}; };
} // namespace sde } // namespace sde

View File

@@ -99,12 +99,21 @@ struct HWDeviceAttributes : DeviceConfigVariableInfo {
HWDeviceAttributes() : is_device_split(false), split_left(0) { } HWDeviceAttributes() : is_device_split(false), split_left(0) { }
}; };
// HWEventHandler - Implemented in DeviceBase and HWInterface implementation
class HWEventHandler {
public:
virtual DisplayError VSync(int64_t timestamp) = 0;
virtual DisplayError Blank(bool blank)= 0;
protected:
virtual ~HWEventHandler() {}
};
class HWInterface { class HWInterface {
public: public:
static DisplayError Create(HWInterface **intf); static DisplayError Create(HWInterface **intf);
static DisplayError Destroy(HWInterface *intf); static DisplayError Destroy(HWInterface *intf);
virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info) = 0; virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info) = 0;
virtual DisplayError Open(HWBlockType type, Handle *device) = 0; virtual DisplayError Open(HWBlockType type, Handle *device, HWEventHandler *eventhandler) = 0;
virtual DisplayError Close(Handle device) = 0; virtual DisplayError Close(Handle device) = 0;
virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count) = 0; virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count) = 0;
virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes, virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes,
@@ -112,6 +121,7 @@ class HWInterface {
virtual DisplayError PowerOn(Handle device) = 0; virtual DisplayError PowerOn(Handle device) = 0;
virtual DisplayError PowerOff(Handle device) = 0; virtual DisplayError PowerOff(Handle device) = 0;
virtual DisplayError Doze(Handle device) = 0; virtual DisplayError Doze(Handle device) = 0;
virtual DisplayError SetVSyncState(Handle device, bool enable) = 0;
virtual DisplayError Standby(Handle device) = 0; virtual DisplayError Standby(Handle device) = 0;
virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0; virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0;
virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0; virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0;

View File

@@ -144,12 +144,18 @@ int HWCSink::SetState(DeviceState state) {
} }
DisplayError HWCSink::VSync(const DeviceEventVSync &vsync) { DisplayError HWCSink::VSync(const DeviceEventVSync &vsync) {
(*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp); if (*hwc_procs_) {
(*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
}
return kErrorNone; return kErrorNone;
} }
DisplayError HWCSink::Refresh() { DisplayError HWCSink::Refresh() {
(*hwc_procs_)->invalidate(*hwc_procs_); if (*hwc_procs_) {
(*hwc_procs_)->invalidate(*hwc_procs_);
}
return kErrorNone; return kErrorNone;
} }