Merge "hwcomposer: Fix a crash with MDP composition."
diff --git a/common.mk b/common.mk
index cefe060..e8a50c1 100644
--- a/common.mk
+++ b/common.mk
@@ -12,6 +12,8 @@
common_includes += $(TARGET_OUT_HEADERS)/pp/inc
endif
+common_header_export_path := qcom/display
+
#Common libraries external to display HAL
common_libs := liblog libutils libcutils libhardware
@@ -27,7 +29,8 @@
common_flags += -D__ARM_HAVE_NEON
endif
-ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084), true)
+ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
+ mpq8092), true)
common_flags += -DVENUS_COLOR_FORMAT
common_flags += -DMDSS_TARGET
endif
@@ -39,10 +42,10 @@
ifeq ($(TARGET_USES_QCOM_BSP),true)
# Enable QCOM Display features
common_flags += -DQCOM_BSP
+endif
ifneq ($(call is-platform-sdk-version-at-least,18),true)
common_flags += -DANDROID_JELLYBEAN_MR1=1
endif
-endif
ifeq ($(call is-vendor-board-platform,QCOM),true)
# This check is to pick the kernel headers from the right location.
# If the macro above is defined, we make the assumption that we have the kernel
diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk
index b125f11..b3d4249 100644
--- a/libcopybit/Android.mk
+++ b/libcopybit/Android.mk
@@ -16,6 +16,11 @@
include $(LOCAL_PATH)/../common.mk
include $(CLEAR_VARS)
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := copybit.h copybit_priv.h
+#Copy the headers regardless of whether copybit is built
+include $(BUILD_COPY_HEADERS)
+
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE_TAGS := optional
diff --git a/libexternal/external.h b/libexternal/external.h
index d35490f..7ab7c3f 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -58,6 +58,7 @@
int configureWFDDisplay();
int teardownHDMIDisplay();
int teardownWFDDisplay();
+ int getHDMIIndex() { return mHdmiFbNum; }
private:
void setSPDInfo(const char* node, const char* property);
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index fb2b0df..a879c5c 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -25,7 +25,9 @@
LOCAL_SHARED_LIBRARIES += libqdutils libGLESv1_CM
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdgralloc\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
-LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
+LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := gralloc_priv.h
include $(BUILD_SHARED_LIBRARY)
@@ -38,6 +40,6 @@
LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libdl
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
-LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
+LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
include $(BUILD_SHARED_LIBRARY)
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index 1851196..3109303 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -336,7 +336,7 @@
static int mapFrameBuffer(struct private_module_t* module)
{
- int err = 0;
+ int err = -1;
char property[PROPERTY_VALUE_MAX];
if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index 46c7cb8..fd3abbc 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -109,10 +109,6 @@
ioctl(mIonFd, ION_IOC_FREE, &handle_data);
return err;
}
- memset(base, 0, ionAllocData.len);
- // Clean cache after memset
- clean_buffer(base, data.size, data.offset, fd_data.fd,
- CACHE_CLEAN_AND_INVALIDATE);
}
data.base = base;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index e322357..3879f11 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -28,6 +28,7 @@
#include <sys/ioctl.h>
#include <overlay.h>
#include <overlayRotator.h>
+#include <overlayWriteback.h>
#include <mdp_version.h>
#include "hwc_utils.h"
#include "hwc_fbupdate.h"
@@ -158,7 +159,6 @@
hwc_display_contents_1_t *list, int dpy) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
- Locker::Autolock _l(ctx->mExtLock);
if (LIKELY(list && list->numHwLayers > 1) &&
ctx->dpyAttr[dpy].isActive &&
@@ -209,11 +209,14 @@
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- Locker::Autolock _l(ctx->mBlankLock);
+ Locker::Autolock _bl(ctx->mBlankLock);
+ Locker::Autolock _el(ctx->mExtLock);
reset(ctx, numDisplays, displays);
ctx->mOverlay->configBegin();
ctx->mRotMgr->configBegin();
+ overlay::Writeback::configBegin();
+
Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
for (int32_t i = numDisplays; i >= 0; i--) {
@@ -233,6 +236,7 @@
ctx->mOverlay->configDone();
ctx->mRotMgr->configDone();
+ overlay::Writeback::configDone();
return ret;
}
@@ -242,7 +246,6 @@
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- Locker::Autolock _l(ctx->mBlankLock);
switch(event) {
case HWC_EVENT_VSYNC:
if (ctx->vstate.enable == enable)
@@ -256,6 +259,7 @@
#ifdef QCOM_BSP
case HWC_EVENT_ORIENTATION:
if(dpy == HWC_DISPLAY_PRIMARY) {
+ Locker::Autolock _l(ctx->mBlankLock);
// store the primary display orientation
// will be used in hwc_video::configure to disable
// rotation animation on external display
@@ -285,6 +289,7 @@
ctx->mOverlay->configBegin();
ctx->mOverlay->configDone();
ctx->mRotMgr->clear();
+ overlay::Writeback::clear();
}
switch(dpy) {
case HWC_DISPLAY_PRIMARY:
@@ -417,7 +422,6 @@
{
ATRACE_CALL();
int ret = 0;
- Locker::Autolock _l(ctx->mExtLock);
if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
ctx->dpyAttr[dpy].connected) {
@@ -477,7 +481,8 @@
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- Locker::Autolock _l(ctx->mBlankLock);
+ Locker::Autolock _bl(ctx->mBlankLock);
+ Locker::Autolock _el(ctx->mExtLock);
for (uint32_t i = 0; i <= numDisplays; i++) {
hwc_display_contents_1_t* list = displays[i];
switch(i) {
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 28b1849..abca20b 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -206,6 +206,7 @@
case EXTERNAL_PAUSE:
{ // pause case
ALOGD("%s Received Pause event",__FUNCTION__);
+ Locker::Autolock _l(ctx->mExtLock);
ctx->dpyAttr[dpy].isActive = true;
ctx->dpyAttr[dpy].isPause = true;
break;
@@ -214,9 +215,11 @@
{ // resume case
ALOGD("%s Received resume event",__FUNCTION__);
// treat Resume as Online event
+ Locker::Autolock _l(ctx->mExtLock);
ctx->mExtDispConfiguring = true;
ctx->dpyAttr[dpy].isActive = true;
ctx->dpyAttr[dpy].isPause = false;
+ ctx->proc->invalidate(ctx->proc);
break;
}
default:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 90038f2..552b526 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -478,8 +478,8 @@
}
-static void calc_cut(float& leftCutRatio, float& topCutRatio,
- float& rightCutRatio, float& bottomCutRatio, int orient) {
+static void calc_cut(double& leftCutRatio, double& topCutRatio,
+ double& rightCutRatio, double& bottomCutRatio, int orient) {
if(orient & HAL_TRANSFORM_FLIP_H) {
swap(leftCutRatio, rightCutRatio);
}
@@ -488,7 +488,7 @@
}
if(orient & HAL_TRANSFORM_ROT_90) {
//Anti clock swapping
- float tmpCutRatio = leftCutRatio;
+ double tmpCutRatio = leftCutRatio;
leftCutRatio = topCutRatio;
topCutRatio = rightCutRatio;
rightCutRatio = bottomCutRatio;
@@ -553,26 +553,26 @@
int sci_w = abs(sci_r - sci_l);
int sci_h = abs(sci_b - sci_t);
- float leftCutRatio = 0.0f, rightCutRatio = 0.0f, topCutRatio = 0.0f,
- bottomCutRatio = 0.0f;
+ double leftCutRatio = 0.0, rightCutRatio = 0.0, topCutRatio = 0.0,
+ bottomCutRatio = 0.0;
if(dst_l < sci_l) {
- leftCutRatio = (float)(sci_l - dst_l) / (float)dst_w;
+ leftCutRatio = (double)(sci_l - dst_l) / (double)dst_w;
dst_l = sci_l;
}
if(dst_r > sci_r) {
- rightCutRatio = (float)(dst_r - sci_r) / (float)dst_w;
+ rightCutRatio = (double)(dst_r - sci_r) / (double)dst_w;
dst_r = sci_r;
}
if(dst_t < sci_t) {
- topCutRatio = (float)(sci_t - dst_t) / (float)dst_h;
+ topCutRatio = (double)(sci_t - dst_t) / (double)dst_h;
dst_t = sci_t;
}
if(dst_b > sci_b) {
- bottomCutRatio = (float)(dst_b - sci_b) / (float)dst_h;
+ bottomCutRatio = (double)(dst_b - sci_b) / (double)dst_h;
dst_b = sci_b;
}
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 2f4475e..e4da4f7 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -33,6 +33,7 @@
namespace qhwc {
#define HWC_VSYNC_THREAD_NAME "hwcVsyncThread"
+#define MAX_SYSFS_FILE_PATH 255
int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable)
{
@@ -49,10 +50,6 @@
static void *vsync_loop(void *param)
{
- const char* vsync_timestamp_fb0 = "/sys/class/graphics/fb0/vsync_event";
- const char* vsync_timestamp_fb1 = "/sys/class/graphics/fb1/vsync_event";
- int dpy = HWC_DISPLAY_PRIMARY;
-
hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
char thread_name[64] = HWC_VSYNC_THREAD_NAME;
@@ -61,16 +58,14 @@
android::PRIORITY_MORE_FAVORABLE);
const int MAX_DATA = 64;
- static char vdata[MAX_DATA];
- struct pollfd pfd;
-
- uint64_t cur_timestamp=0;
- ssize_t len = -1;
- int fb0_fd = -1;
- int ret = 0;
- bool fb1_vsync = false;
+ char vdata[MAX_DATA];
bool logvsync = false;
+ struct pollfd pfd[2];
+ int fb_fd[2];
+ uint64_t timestamp[2];
+ int num_displays;
+
char property[PROPERTY_VALUE_MAX];
if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
if(atoi(property) == 1)
@@ -82,62 +77,91 @@
logvsync = true;
}
- /* Currently read vsync timestamp from drivers
- e.g. VSYNC=41800875994
- */
- fb0_fd = open(vsync_timestamp_fb0, O_RDONLY);
- pfd.fd = fb0_fd;
- pfd.events = POLLPRI | POLLERR;
+ if (ctx->mExtDisplay->getHDMIIndex() > 0)
+ num_displays = 2;
+ else
+ num_displays = 1;
- if (fb0_fd < 0) {
- // Make sure fb device is opened before starting this thread so this
- // never happens.
- ALOGE ("FATAL:%s:not able to open file:%s, %s", __FUNCTION__,
- (fb1_vsync) ? vsync_timestamp_fb1 : vsync_timestamp_fb0,
- strerror(errno));
- ctx->vstate.fakevsync = true;
+ char vsync_node_path[MAX_SYSFS_FILE_PATH];
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+ snprintf(vsync_node_path, sizeof(vsync_node_path),
+ "/sys/class/graphics/fb%d/vsync_event",
+ dpy == HWC_DISPLAY_PRIMARY ? 0 :
+ ctx->mExtDisplay->getHDMIIndex());
+ ALOGI("%s: Reading vsync for dpy=%d from %s", __FUNCTION__, dpy,
+ vsync_node_path);
+ fb_fd[dpy] = open(vsync_node_path, O_RDONLY);
+
+ if (fb_fd[dpy] < 0) {
+ // Make sure fb device is opened before starting this thread so this
+ // never happens.
+ ALOGE ("%s:not able to open vsync node for dpy=%d, %s",
+ __FUNCTION__, dpy, strerror(errno));
+ if (dpy == HWC_DISPLAY_PRIMARY) {
+ ctx->vstate.fakevsync = true;
+ break;
+ }
+ }
+
+ pfd[dpy].fd = fb_fd[dpy];
+ if (pfd[dpy].fd >= 0)
+ pfd[dpy].events = POLLPRI | POLLERR;
}
- do {
- if (LIKELY(!ctx->vstate.fakevsync)) {
- int err = poll(&pfd, 1, -1);
+ if (LIKELY(!ctx->vstate.fakevsync)) {
+ do {
+ int err = poll(pfd, num_displays, -1);
if(err > 0) {
- if (pfd.revents & POLLPRI) {
- len = pread(fb0_fd, vdata, MAX_DATA, 0);
- if (UNLIKELY(len < 0)) {
- // If the read was just interrupted - it is not a fatal
- // error. Just continue in this case
- ALOGE ("FATAL:%s:not able to read file:%s, %s",
- __FUNCTION__,
- vsync_timestamp_fb0, strerror(errno));
- continue;
- }
- // extract timestamp
- const char *str = vdata;
- if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
- cur_timestamp = strtoull(str + strlen("VSYNC="),
- NULL, 0);
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+ if (pfd[dpy].revents & POLLPRI) {
+ int len = pread(pfd[dpy].fd, vdata, MAX_DATA, 0);
+ if (UNLIKELY(len < 0)) {
+ // If the read was just interrupted - it is not a
+ // fatal error. Just continue in this case
+ ALOGE ("%s:Unable to read vsync for dpy=%d :%s",
+ __FUNCTION__, dpy, strerror(errno));
+ continue;
+ }
+ // extract timestamp
+ if (!strncmp(vdata, "VSYNC=", strlen("VSYNC="))) {
+ timestamp[dpy] = strtoull(vdata + strlen("VSYNC="),
+ NULL, 0);
+ }
+ // send timestamp to SurfaceFlinger
+ ALOGD_IF (logvsync,
+ "%s: timestamp %llu sent to SF for dpy=%d",
+ __FUNCTION__, timestamp[dpy], dpy);
+ ctx->proc->vsync(ctx->proc, dpy, timestamp[dpy]);
}
}
+
} else {
ALOGE("%s: vsync poll failed errno: %s", __FUNCTION__,
- strerror(errno));
+ strerror(errno));
continue;
}
- } else {
- usleep(16666);
- cur_timestamp = systemTime();
- }
- // send timestamp to HAL
- if(ctx->vstate.enable) {
- ALOGD_IF (logvsync, "%s: timestamp %llu sent to HWC for %s",
- __FUNCTION__, cur_timestamp, "fb0");
- ctx->proc->vsync(ctx->proc, dpy, cur_timestamp);
- }
+ } while (true);
- } while (true);
- if(fb0_fd >= 0)
- close (fb0_fd);
+ } else {
+
+ //Fake vsync is used only when set explicitly through a property 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.
+ do {
+ usleep(16666);
+ timestamp[HWC_DISPLAY_PRIMARY] = systemTime();
+ ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY,
+ timestamp[HWC_DISPLAY_PRIMARY]);
+
+ } while (true);
+ }
+
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) {
+ if(fb_fd[dpy] >= 0)
+ close (fb_fd[dpy]);
+ }
return NULL;
}
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index a375284..560b57f 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -16,6 +16,7 @@
overlayRotator.cpp \
overlayMdpRot.cpp \
overlayMdssRot.cpp \
+ overlayWriteback.cpp \
pipes/overlayGenPipe.cpp
include $(BUILD_SHARED_LIBRARY)
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index 1f4a0be..d96317c 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -78,6 +78,21 @@
/* MSMFB_OVERLAY_3D */
bool set3D(int fd, msmfb_overlay_3d& ov);
+/* MSMFB_DISPLAY_COMMIT */
+bool displayCommit(int fd);
+
+/* MSMFB_WRITEBACK_INIT, MSMFB_WRITEBACK_START */
+bool wbInitStart(int fbfd);
+
+/* MSMFB_WRITEBACK_STOP, MSMFB_WRITEBACK_TERMINATE */
+bool wbStopTerminate(int fbfd);
+
+/* MSMFB_WRITEBACK_QUEUE_BUFFER */
+bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData);
+
+/* MSMFB_WRITEBACK_DEQUEUE_BUFFER */
+bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData);
+
/* the following are helper functions for dumping
* msm_mdp and friends*/
void dump(const char* const s, const msmfb_overlay_data& ov);
@@ -197,6 +212,61 @@
return true;
}
+inline bool displayCommit(int fd, mdp_display_commit& info) {
+ if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) {
+ ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbInitStart(int fbfd) {
+ if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s",
+ strerror(errno));
+ return false;
+ }
+ if(ioctl(fbfd, MSMFB_WRITEBACK_START, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_START err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbStopTerminate(int fbfd) {
+ if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s",
+ strerror(errno));
+ return false;
+ }
+ if(ioctl(fbfd, MSMFB_WRITEBACK_TERMINATE, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_TERMINATE err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) {
+ if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) {
+ if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
/* dump funcs */
inline void dump(const char* const s, const msmfb_overlay_data& ov) {
ALOGE("%s msmfb_overlay_data id=%d",
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index a15d0a8..5115a5b 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -70,9 +70,11 @@
//fds
if(mPipeBook[i].valid()) {
char str[32];
- sprintf(str, "Unset pipe=%s dpy=%d; ",
+ sprintf(str, "Unset=%s dpy=%d; ",
PipeBook::getDestStr((eDest)i), mPipeBook[i].mDisplay);
+#if PIPE_DEBUG
strncat(mDumpStr, str, strlen(str));
+#endif
}
mPipeBook[i].destroy();
}
@@ -89,7 +91,7 @@
if(type == OV_MDP_PIPE_ANY || type == PipeBook::getPipeType((eDest)i)) {
//If the pipe is not allocated to any display or used by the
//requesting display already in previous round.
- if((mPipeBook[i].mDisplay == PipeBook::DPY_UNUSED ||
+ if((mPipeBook[i].mDisplay == DPY_UNUSED ||
mPipeBook[i].mDisplay == dpy) &&
PipeBook::isNotAllocated(i)) {
//In block mode we don't allow line operations
@@ -112,9 +114,11 @@
if(not mPipeBook[index].valid()) {
mPipeBook[index].mPipe = new GenericPipe(dpy);
char str[32];
- snprintf(str, 32, "Set pipe=%s dpy=%d; ",
+ snprintf(str, 32, "Set=%s dpy=%d; ",
PipeBook::getDestStr(dest), dpy);
+#if PIPE_DEBUG
strncat(mDumpStr, str, strlen(str));
+#endif
}
} else {
ALOGD_IF(PIPE_DEBUG, "Pipe unavailable type=%d display=%d",
@@ -127,7 +131,7 @@
bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(type == PipeBook::getPipeType((eDest)i) &&
- mPipeBook[i].mDisplay != PipeBook::DPY_UNUSED) {
+ mPipeBook[i].mDisplay != DPY_UNUSED) {
return true;
}
}
@@ -252,7 +256,7 @@
mdp_mixer_info *minfo = NULL;
char name[64];
int fd = -1;
- for(int i = 0; i < NUM_FB_DEVICES; i++) {
+ for(int i = 0; i < MAX_FB_DEVICES; i++) {
snprintf(name, 64, FB_DEVICE_TEMPLATE, i);
ALOGD("initoverlay:: opening the device:: %s", name);
fd = ::open(name, O_RDWR, 0);
@@ -288,13 +292,54 @@
fd = -1;
}
}
+
+ FILE *displayDeviceFP = NULL;
+ const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
+ char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+ char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
+ const char *strDtvPanel = "dtv panel";
+ const char *strWbPanel = "writeback panel";
+
+ for(int num = 1; num < MAX_FB_DEVICES; num++) {
+ snprintf (msmFbTypePath, sizeof(msmFbTypePath),
+ "/sys/class/graphics/fb%d/msm_fb_type", num);
+ displayDeviceFP = fopen(msmFbTypePath, "r");
+
+ if(displayDeviceFP){
+ fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+ displayDeviceFP);
+
+ if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) {
+ sDpyFbMap[DPY_EXTERNAL] = num;
+ } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) {
+ sDpyFbMap[DPY_WRITEBACK] = num;
+ }
+
+ fclose(displayDeviceFP);
+ }
+ }
+
return 0;
}
-void Overlay::dump() const {
- if(strlen(mDumpStr)) { //dump only on state change
- ALOGD_IF(PIPE_DEBUG, "%s\n", mDumpStr);
+bool Overlay::displayCommit(const int& fd) {
+ //Commit
+ struct mdp_display_commit info;
+ memset(&info, 0, sizeof(struct mdp_display_commit));
+ info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
+ if(!mdp_wrapper::displayCommit(fd, info)) {
+ ALOGE("%s: commit failed", __func__);
+ return false;
}
+ return true;
+}
+
+void Overlay::dump() const {
+#if PIPE_DEBUG
+ if(strlen(mDumpStr)) { //dump only on state change
+ ALOGD("%s\n", mDumpStr);
+ }
+#endif
}
void Overlay::getDump(char *buf, size_t len) {
@@ -343,6 +388,7 @@
Overlay* Overlay::sInstance = 0;
int Overlay::sExtFbIndex = 1;
+int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
int Overlay::sDMAMode = DMA_LINE_MODE;
int Overlay::PipeBook::NUM_PIPES = 0;
int Overlay::PipeBook::sPipeUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index cfceaff..10ae10d 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -41,6 +41,12 @@
class Overlay : utils::NoCopy {
public:
enum { DMA_BLOCK_MODE, DMA_LINE_MODE };
+ //Abstract Display types. Each backed by a LayerMixer,
+ //represented by a fb node.
+ //High res panels can be backed by 2 layer mixers and a single fb node.
+ enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_WRITEBACK, DPY_UNUSED };
+ enum { DPY_MAX = DPY_UNUSED };
+ enum { MAX_FB_DEVICES = DPY_MAX };
/* dtor close */
~Overlay();
@@ -85,6 +91,7 @@
/* set the framebuffer index for external display */
void setExtFbNum(int fbNum);
/* Returns framebuffer index of the current external display */
+ /* TODO Deprecate */
int getExtFbNum();
/* Returns pipe dump. Expects a NULL terminated buffer of big enough size
* to populate.
@@ -94,6 +101,9 @@
void clear(int dpy);
static void setDMAMode(const int& mode);
static int getDMAMode();
+ /* Returns the framebuffer node backing up the display */
+ static int getFbForDpy(const int& dpy);
+ static bool displayCommit(const int& fd);
private:
/* Ctor setup */
@@ -104,8 +114,6 @@
/* Just like a Facebook for pipes, but much less profile info */
struct PipeBook {
- enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_UNUSED };
-
void init();
void destroy();
/* Check if pipe exists and return true, false otherwise */
@@ -153,11 +161,13 @@
PipeBook mPipeBook[utils::OV_INVALID]; //Used as max
/* Dump string */
- char mDumpStr[256];
+ char mDumpStr[1024];
/* Singleton Instance*/
static Overlay *sInstance;
+ //TODO Deprecate
static int sExtFbIndex;
+ static int sDpyFbMap[DPY_MAX];
static int sDMAMode;
};
@@ -171,7 +181,7 @@
inline int Overlay::availablePipes(int dpy) {
int avail = 0;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
- if((mPipeBook[i].mDisplay == PipeBook::DPY_UNUSED ||
+ if((mPipeBook[i].mDisplay == DPY_UNUSED ||
mPipeBook[i].mDisplay == dpy) && PipeBook::isNotAllocated(i)) {
avail++;
}
@@ -196,6 +206,11 @@
return sDMAMode;
}
+inline int Overlay::getFbForDpy(const int& dpy) {
+ OVASSERT(dpy >= 0 && dpy < DPY_MAX, "Invalid dpy %d", dpy);
+ return sDpyFbMap[dpy];
+}
+
inline bool Overlay::PipeBook::valid() {
return (mPipe != NULL);
}
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 30d7ccd..b8a2417 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -279,7 +279,7 @@
int aHeight = ovutils::align(mRotInfo.src_rect.h, 4);
int rau_cnt = aWidth/64;
int stride0 = (64 * 4 * rau_cnt) + rau_cnt/8;
- int stride1 = (64 * 2 * rau_cnt) + rau_cnt/8;
+ int stride1 = ((64 * 2 * rau_cnt) + rau_cnt/8) * 2;
int stride0_off = (aHeight/4);
int stride1_off = (aHeight/2);
diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h
index 5fbe91b..061d197 100644
--- a/liboverlay/overlayMem.h
+++ b/liboverlay/overlayMem.h
@@ -121,8 +121,9 @@
if(isSecure) {
allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP;
allocFlags |= GRALLOC_USAGE_PROTECTED;
- allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
}
+ // Allocate uncached rotator buffers
+ allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
int err = 0;
OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz);
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 4bb2151..b543018 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -78,7 +78,6 @@
#endif
#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
-#define NUM_FB_DEVICES 3
namespace overlay {
@@ -368,15 +367,8 @@
f = static_cast<eMdpFlags>(clrBit(f, v));
}
-// fb 0/1/2
enum { FB0, FB1, FB2 };
-//Panels could be categorized as primary and external
-enum { PRIMARY, EXTERNAL };
-
-// 2 for rgb0/1 double bufs
-enum { RGB_PIPE_NUM_BUFS = 2 };
-
struct ScreenInfo {
ScreenInfo() : mFBWidth(0),
mFBHeight(0),
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
new file mode 100644
index 0000000..b6ed53c
--- /dev/null
+++ b/liboverlay/overlayWriteback.cpp
@@ -0,0 +1,215 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "overlay.h"
+#include "overlayWriteback.h"
+#include "mdpWrapper.h"
+
+namespace overlay {
+
+//=========== class WritebackMem ==============================================
+bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
+ if(mBuf.bufSz() == size) {
+ return true;
+ }
+ if(mBuf.valid()) {
+ if(!mBuf.close()) {
+ ALOGE("%s error closing mem", __func__);
+ return false;
+ }
+ }
+ return alloc(size, isSecure);
+}
+
+bool WritebackMem::alloc(uint32_t size, bool isSecure) {
+ if(!mBuf.open(NUM_BUFS, size, isSecure)){
+ ALOGE("%s: Failed to open", __func__);
+ mBuf.close();
+ return false;
+ }
+
+ OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
+ OVASSERT(mBuf.getFD() != -1, "getFd is -1");
+
+ mCurrOffsetIndex = 0;
+ for (uint32_t i = 0; i < NUM_BUFS; i++) {
+ mOffsets[i] = i * size;
+ }
+ return true;
+}
+
+bool WritebackMem::dealloc() {
+ bool ret = true;
+ if(mBuf.valid()) {
+ ret = mBuf.close();
+ }
+ return ret;
+}
+
+//=========== class Writeback =================================================
+Writeback::Writeback() : mXres(0), mYres(0) {
+ int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+ if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
+ ALOGE("%s failed to init %s", __func__, Res::fbPath);
+ return;
+ }
+ startSession();
+}
+
+Writeback::~Writeback() {
+ stopSession();
+ if (!mFd.close()) {
+ ALOGE("%s error closing fd", __func__);
+ }
+}
+
+bool Writeback::startSession() {
+ if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::stopSession() {
+ if(mFd.valid()) {
+ if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ } else {
+ ALOGE("%s Invalid fd", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::configureDpyInfo(int xres, int yres) {
+ if(mXres != xres || mYres != yres) {
+ fb_var_screeninfo vinfo;
+ memset(&vinfo, 0, sizeof(fb_var_screeninfo));
+ if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ vinfo.xres = xres;
+ vinfo.yres = yres;
+ vinfo.xres_virtual = xres;
+ vinfo.yres_virtual = yres;
+ vinfo.xoffset = 0;
+ vinfo.yoffset = 0;
+ if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ mXres = xres;
+ mYres = yres;
+ }
+ return true;
+}
+
+bool Writeback::configureMemory(uint32_t size, bool isSecure) {
+ if(!mWbMem.manageMem(size, isSecure)) {
+ ALOGE("%s failed, memory failure", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
+ memset(&mFbData, 0, sizeof(struct msmfb_data));
+ //Queue
+ mFbData.offset = opOffset;
+ mFbData.memory_id = opFd;
+ mFbData.id = 0;
+ mFbData.flags = 0;
+ if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
+ ALOGE("%s: queuebuffer failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::dequeueBuffer() {
+ //Dequeue
+ mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
+ if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
+ ALOGE("%s: dequeuebuffer failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::writeSync(int opFd, uint32_t opOffset) {
+ if(!queueBuffer(opFd, opOffset)) {
+ return false;
+ }
+ if(!Overlay::displayCommit(mFd.getFD())) {
+ return false;
+ }
+ if(!dequeueBuffer()) {
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::writeSync() {
+ mWbMem.useNextBuffer();
+ return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
+}
+
+//static
+
+Writeback *Writeback::getInstance() {
+ if(sWb == NULL) {
+ sWb = new Writeback();
+ }
+ sUsed = true;
+ return sWb;
+}
+
+void Writeback::configDone() {
+ if(sUsed == false && sWb) {
+ delete sWb;
+ sWb = NULL;
+ }
+}
+
+void Writeback::clear() {
+ sUsed = false;
+ if(sWb) {
+ delete sWb;
+ sWb = NULL;
+ }
+}
+
+Writeback *Writeback::sWb = 0;
+bool Writeback::sUsed = false;
+
+} //namespace overlay
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
new file mode 100644
index 0000000..fbfd889
--- /dev/null
+++ b/liboverlay/overlayWriteback.h
@@ -0,0 +1,108 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef OVERLAY_WRITEBACK_H
+#define OVERLAY_WRITEBACK_H
+
+#include "overlayMem.h"
+
+namespace overlay {
+
+class WritebackMgr;
+
+class WritebackMem {
+public:
+ explicit WritebackMem() : mCurrOffsetIndex(0) {
+ memset(&mOffsets, 0, sizeof(mOffsets));
+ }
+ ~WritebackMem() { dealloc(); }
+ bool manageMem(uint32_t size, bool isSecure);
+ void useNextBuffer() {
+ mCurrOffsetIndex = (mCurrOffsetIndex + 1) % NUM_BUFS;
+ }
+ uint32_t getOffset() const { return mOffsets[mCurrOffsetIndex]; }
+ int getDstFd() const { return mBuf.getFD(); }
+private:
+ bool alloc(uint32_t size, bool isSecure);
+ bool dealloc();
+ enum { NUM_BUFS = 2 };
+ OvMem mBuf;
+ uint32_t mOffsets[NUM_BUFS];
+ uint32_t mCurrOffsetIndex;
+};
+
+//Abstracts the WB2 interface of MDP
+//Has modes to either manage memory or work with memory allocated elsewhere
+class Writeback {
+public:
+ ~Writeback();
+ bool configureDpyInfo(int xres, int yres);
+ bool configureMemory(uint32_t size, bool isSecure);
+ /* Blocking write. (queue, commit, dequeue)
+ * This class will do writeback memory management.
+ * This class will call display-commit on writeback mixer.
+ */
+ bool writeSync();
+ /* Blocking write. (queue, commit, dequeue)
+ * Client must do writeback memory management.
+ * Client must not call display-commit on writeback mixer.
+ */
+ bool writeSync(int opFd, uint32_t opOffset);
+ /* Async queue. (Does not write)
+ * Client must do writeback memory management.
+ * Client must call display-commit on their own.
+ * Client must use sync mechanism e.g sync pt.
+ */
+ bool queueBuffer(int opFd, uint32_t opOffset);
+ uint32_t getOffset() const { return mWbMem.getOffset(); }
+ int getDstFd() const { return mWbMem.getDstFd(); }
+
+ static Writeback* getInstance();
+ static void configBegin() { sUsed = false; }
+ static void configDone();
+ static void clear();
+
+private:
+ explicit Writeback();
+ bool startSession();
+ bool stopSession();
+ //Actually block_until_write_done for the usage here.
+ bool dequeueBuffer();
+ OvFD mFd;
+ WritebackMem mWbMem;
+ struct msmfb_data mFbData;
+ int mXres;
+ int mYres;
+
+ static bool sUsed;
+ static Writeback *sWb;
+};
+
+}
+
+#endif
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 3ab0d19..0de7129 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -33,7 +33,7 @@
namespace overlay {
-GenericPipe::GenericPipe(int dpy) : mFbNum(dpy), mRotDownscaleOpt(false),
+GenericPipe::GenericPipe(int dpy) : mDpy(dpy), mRotDownscaleOpt(false),
pipeState(CLOSED) {
init();
}
@@ -46,17 +46,24 @@
{
ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
mRotDownscaleOpt = false;
- if(mFbNum)
- mFbNum = Overlay::getInstance()->getExtFbNum();
- ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, mFbNum);
+ int fbNum = 0;
+ //TODO Remove the if block. What's in else block should be the standard way
+ //EXTERNAL's meaning has been overloaded in hwc to mean WFD also!
+ if(mDpy == Overlay::DPY_EXTERNAL) {
+ fbNum = Overlay::getInstance()->getExtFbNum();
+ } else if(mDpy == Overlay::DPY_WRITEBACK) {
+ fbNum = Overlay::getFbForDpy(mDpy);
+ }
- if(!mCtrlData.ctrl.init(mFbNum)) {
+ ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, fbNum);
+
+ if(!mCtrlData.ctrl.init(fbNum)) {
ALOGE("GenericPipe failed to init ctrl");
return false;
}
- if(!mCtrlData.data.init(mFbNum)) {
+ if(!mCtrlData.data.init(fbNum)) {
ALOGE("GenericPipe failed to init data");
return false;
}
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 9a66632..2472f4e 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -82,7 +82,7 @@
/* set Closed pipe */
bool setClosed();
- int mFbNum;
+ int mDpy;
/* Ctrl/Data aggregator */
CtrlData mCtrlData;
//Whether we will do downscale opt. This is just a request. If the frame is
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index eb04afb..459f548 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -15,7 +15,7 @@
include $(CLEAR_VARS)
-LOCAL_COPY_HEADERS_TO := qcom/display
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
LOCAL_COPY_HEADERS := qdMetaData.h
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := liblog libcutils
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 4f03968..97176a4 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -45,6 +45,7 @@
unsigned int idleSleepTime) {
ALOGD_IF(II_DEBUG, "%s", __func__);
+ Locker::Autolock _l(mLock);
/* store registered handler */
mHandler = reg_handler;
mHwcContext = user_data;
@@ -55,6 +56,8 @@
bool IdleInvalidator::threadLoop() {
ALOGD_IF(II_DEBUG, "%s", __func__);
usleep(mSleepTime * 500);
+
+ Locker::Autolock _l(mLock);
if(mSleepAgain) {
//We need to sleep again!
mSleepAgain = false;
@@ -75,6 +78,7 @@
}
void IdleInvalidator::markForSleep() {
+ Locker::Autolock _l(mLock);
mSleepAgain = true;
//Triggers the threadLoop to run, if not already running.
run(threadName, android::PRIORITY_AUDIO);
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index 82b1ac0..abd9b29 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -32,6 +32,7 @@
#include <cutils/log.h>
#include <utils/threads.h>
+#include <gr.h>
typedef void (*InvalidatorHandler)(void*);
@@ -41,6 +42,7 @@
unsigned int mSleepTime;
static InvalidatorHandler mHandler;
static android::sp<IdleInvalidator> sInstance;
+ mutable Locker mLock;
public:
IdleInvalidator();
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index e1585e4..17b2eda 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -12,5 +12,9 @@
LOCAL_SRC_FILES := QService.cpp \
IQService.cpp \
IQClient.cpp
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := IQService.h \
+ IQClient.h
+
include $(BUILD_SHARED_LIBRARY)