hwc: Sync for rotator
Implement sync for rotator.
If a buffer is rotated, it can be used by producer soon after
rotation (and it wont have to wait until vsync).
Mdp waits for the rotator buffer's release fence to signal
to start display.
Hwc waits for previous access to rotator buffer by MDP to finish
before using it
Change-Id: I5664806a17c44d58af62a2825ce454089fcd31cf
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 244e0d6..e322357 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -105,6 +105,8 @@
ctx->mFBUpdate[i]->reset();
if(ctx->mCopyBit[i])
ctx->mCopyBit[i]->reset();
+ if(ctx->mLayerRotMap[i])
+ ctx->mLayerRotMap[i]->reset();
}
}
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 46e25dc..90038f2 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -157,7 +157,9 @@
for (uint32_t i = 0; i < MAX_DISPLAYS; i++) {
ctx->mHwcDebug[i] = new HwcDebug(i);
+ ctx->mLayerRotMap[i] = new LayerRotMap();
}
+
MDPComp::init(ctx);
ctx->vstate.enable = false;
@@ -227,6 +229,10 @@
delete ctx->mHwcDebug[i];
ctx->mHwcDebug[i] = NULL;
}
+ if(ctx->mLayerRotMap[i]) {
+ delete ctx->mLayerRotMap[i];
+ ctx->mLayerRotMap[i] = NULL;
+ }
}
@@ -620,18 +626,25 @@
}
int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
- int fd) {
+ int fd) {
int ret = 0;
- struct mdp_buf_sync data;
int acquireFd[MAX_NUM_APP_LAYERS];
int count = 0;
int releaseFd = -1;
int fbFd = -1;
- memset(&data, 0, sizeof(data));
+ int rotFd = -1;
bool swapzero = false;
+ int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
+
+ struct mdp_buf_sync data;
+ memset(&data, 0, sizeof(data));
+ //Until B-family supports sync for rotator
+#ifdef MDSS_TARGET
data.flags = MDP_BUF_SYNC_FLAG_WAIT;
+#endif
data.acq_fen_fd = acquireFd;
data.rel_fen_fd = &releaseFd;
+
char property[PROPERTY_VALUE_MAX];
if(property_get("debug.egl.swapinterval", property, "1") > 0) {
if(atoi(property) == 0)
@@ -641,10 +654,35 @@
if(dpy)
isExtAnimating = ctx->listStats[dpy].isDisplayAnimating;
- //Accumulate acquireFenceFds
+ //Send acquireFenceFds to rotator
+#ifdef MDSS_TARGET
+ //TODO B-family
+#else
+ //A-family
+ int rotFd = ctx->mRotMgr->getRotDevFd();
+ struct msm_rotator_buf_sync rotData;
+
+ for(uint32_t i = 0; i < ctx->mLayerRotMap[dpy]->getCount(); i++) {
+ memset(&rotData, 0, sizeof(rotData));
+ int& acquireFenceFd =
+ ctx->mLayerRotMap[dpy]->getLayer(i)->acquireFenceFd;
+ rotData.acq_fen_fd = acquireFenceFd;
+ rotData.session_id = ctx->mLayerRotMap[dpy]->getRot(i)->getSessId();
+ ioctl(rotFd, MSM_ROTATOR_IOCTL_BUFFER_SYNC, &rotData);
+ close(acquireFenceFd);
+ //For MDP to wait on.
+ acquireFenceFd = dup(rotData.rel_fen_fd);
+ //A buffer is free to be used by producer as soon as its copied to
+ //rotator.
+ ctx->mLayerRotMap[dpy]->getLayer(i)->releaseFenceFd =
+ rotData.rel_fen_fd;
+ }
+#endif
+
+ //Accumulate acquireFenceFds for MDP
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if(list->hwLayers[i].compositionType == HWC_OVERLAY &&
- list->hwLayers[i].acquireFenceFd != -1) {
+ list->hwLayers[i].acquireFenceFd >= 0) {
if(UNLIKELY(swapzero))
acquireFd[count++] = -1;
else
@@ -653,19 +691,20 @@
if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
if(UNLIKELY(swapzero))
acquireFd[count++] = -1;
- else if(fd != -1) {
+ else if(fd >= 0) {
//set the acquireFD from fd - which is coming from c2d
acquireFd[count++] = fd;
// Buffer sync IOCTL should be async when using c2d fence is
// used
data.flags &= ~MDP_BUF_SYNC_FLAG_WAIT;
- } else if(list->hwLayers[i].acquireFenceFd != -1)
+ } else if(list->hwLayers[i].acquireFenceFd >= 0)
acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
}
}
data.acq_fen_fd_cnt = count;
fbFd = ctx->dpyAttr[dpy].fd;
+
//Waits for acquire fences, returns a release fence
if(LIKELY(!swapzero)) {
uint64_t start = systemTime();
@@ -686,9 +725,9 @@
if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
//Populate releaseFenceFds.
- if(UNLIKELY(swapzero))
+ if(UNLIKELY(swapzero)) {
list->hwLayers[i].releaseFenceFd = -1;
- else if(isExtAnimating) {
+ } else if(isExtAnimating) {
// Release all the app layer fds immediately,
// if animation is in progress.
hwc_layer_1_t const* layer = &list->hwLayers[i];
@@ -697,8 +736,10 @@
list->hwLayers[i].releaseFenceFd = dup(releaseFd);
} else
list->hwLayers[i].releaseFenceFd = -1;
- } else
+ } else if(list->hwLayers[i].releaseFenceFd < 0) {
+ //If rotator has not already populated this field.
list->hwLayers[i].releaseFenceFd = dup(releaseFd);
+ }
}
}
@@ -709,11 +750,22 @@
if (ctx->mCopyBit[dpy])
ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+
+#ifdef MDSS_TARGET
+ //TODO When B is implemented remove #ifdefs from here
+ //The API called applies to RotMem buffers
+#else
+ //A-family
+ //Signals when MDP finishes reading rotator buffers.
+ ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
+#endif
+
// if external is animating, close the relaseFd
if(isExtAnimating) {
close(releaseFd);
releaseFd = -1;
}
+
if(UNLIKELY(swapzero)){
list->retireFenceFd = -1;
close(releaseFd);
@@ -950,6 +1002,7 @@
ctx->mOverlay->clear(dpy);
return -1;
}
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
whf.format = (*rot)->getDstFormat();
updateSource(orient, whf, crop);
rotFlags |= ovutils::ROT_PREROTATED;
@@ -1025,6 +1078,7 @@
ctx->mOverlay->clear(dpy);
return -1;
}
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
whf.format = (*rot)->getDstFormat();
updateSource(orient, whf, crop);
rotFlags |= ROT_PREROTATED;
@@ -1158,4 +1212,25 @@
ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDSS_MDP_BWC_EN);
}
+void LayerRotMap::add(hwc_layer_1_t* layer, Rotator *rot) {
+ if(mCount >= MAX_SESS) return;
+ mLayer[mCount] = layer;
+ mRot[mCount] = rot;
+ mCount++;
+}
+
+void LayerRotMap::reset() {
+ for (int i = 0; i < MAX_SESS; i++) {
+ mLayer[i] = 0;
+ mRot[i] = 0;
+ }
+ mCount = 0;
+}
+
+void LayerRotMap::setReleaseFd(const int& fence) {
+ for(uint32_t i = 0; i < mCount; i++) {
+ mRot[i]->setReleaseFd(dup(fence));
+ }
+}
+
};//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 916a59d..4146787 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -121,6 +121,36 @@
HWC_COPYBIT = 0x00000002,
};
+class LayerRotMap {
+public:
+ LayerRotMap() { reset(); }
+ enum { MAX_SESS = 3 };
+ void add(hwc_layer_1_t* layer, overlay::Rotator *rot);
+ void reset();
+ uint32_t getCount() const;
+ hwc_layer_1_t* getLayer(uint32_t index) const;
+ overlay::Rotator* getRot(uint32_t index) const;
+ void setReleaseFd(const int& fence);
+private:
+ hwc_layer_1_t* mLayer[MAX_SESS];
+ overlay::Rotator* mRot[MAX_SESS];
+ uint32_t mCount;
+};
+
+inline uint32_t LayerRotMap::getCount() const {
+ return mCount;
+}
+
+inline hwc_layer_1_t* LayerRotMap::getLayer(uint32_t index) const {
+ if(index >= mCount) return NULL;
+ return mLayer[index];
+}
+
+inline overlay::Rotator* LayerRotMap::getRot(uint32_t index) const {
+ if(index >= mCount) return NULL;
+ return mRot[index];
+}
+
// -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_1_t const* l);
@@ -301,7 +331,6 @@
hwc_rect_t mPrevCropVideo;
hwc_rect_t mPrevDestVideo;
int mPrevTransformVideo;
-
//Securing in progress indicator
bool mSecuring;
//External Display configuring progress indicator
@@ -318,6 +347,7 @@
int mExtOrientation;
//Flags the transition of a video session
bool mVideoTransFlag;
+ qhwc::LayerRotMap *mLayerRotMap[MAX_DISPLAYS];
};
namespace qhwc {
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index ed2f503..a375284 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -6,7 +6,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc
+LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc libsync
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdoverlay\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := \
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 3861297..2995580 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -26,6 +26,8 @@
namespace overlay {
+//============Rotator=========================
+
Rotator::~Rotator() {}
Rotator* Rotator::getRotator() {
@@ -56,6 +58,9 @@
return TYPE_MDP;
}
+
+//============RotMem=========================
+
bool RotMem::close() {
bool ret = true;
for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) {
@@ -70,11 +75,46 @@
return ret;
}
+RotMem::Mem::Mem() : mCurrOffset(0) {
+ utils::memset0(mRotOffset);
+ for(int i = 0; i < ROT_NUM_BUFS; i++) {
+ mRelFence[i] = -1;
+ }
+}
+
+RotMem::Mem::~Mem() {
+ for(int i = 0; i < ROT_NUM_BUFS; i++) {
+ ::close(mRelFence[i]);
+ mRelFence[i] = -1;
+ }
+}
+
+void RotMem::Mem::setReleaseFd(const int& fence) {
+ int ret = 0;
+
+ if(mRelFence[mCurrOffset] >= 0) {
+ //Wait for previous usage of this buffer to be over.
+ //Can happen if rotation takes > vsync and a fast producer. i.e queue
+ //happens in subsequent vsyncs either because content is 60fps or
+ //because the producer is hasty sometimes.
+ ret = sync_wait(mRelFence[mCurrOffset], 1000);
+ if(ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ ::close(mRelFence[mCurrOffset]);
+ }
+ mRelFence[mCurrOffset] = fence;
+}
+
+//============RotMgr=========================
+
RotMgr::RotMgr() {
for(int i = 0; i < MAX_ROT_SESS; i++) {
mRot[i] = 0;
}
mUseCount = 0;
+ mRotDevFd = -1;
}
RotMgr::~RotMgr() {
@@ -118,6 +158,8 @@
}
}
mUseCount = 0;
+ ::close(mRotDevFd);
+ mRotDevFd = -1;
}
void RotMgr::getDump(char *buf, size_t len) {
@@ -131,4 +173,15 @@
strncat(buf, str, strlen(str));
}
+int RotMgr::getRotDevFd() {
+ //2nd check just in case
+ if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDP) {
+ mRotDevFd = ::open("/dev/msm_rotator", O_RDWR, 0);
+ if(mRotDevFd < 0) {
+ ALOGE("%s failed to open rotator device", __FUNCTION__);
+ }
+ }
+ return mRotDevFd;
+}
+
}
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 120721c..7f90160 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -38,6 +38,45 @@
namespace overlay {
+/*
+ Manages the case where new rotator memory needs to be
+ allocated, before previous is freed, due to resolution change etc. If we make
+ rotator memory to be always max size, irrespctive of source resolution then
+ we don't need this RotMem wrapper. The inner class is sufficient.
+*/
+struct RotMem {
+ // Max rotator memory allocations
+ enum { MAX_ROT_MEM = 2};
+
+ //Manages the rotator buffer offsets.
+ struct Mem {
+ Mem();
+ ~Mem();
+ bool valid() { return m.valid(); }
+ bool close() { return m.close(); }
+ uint32_t size() const { return m.bufSz(); }
+ void setReleaseFd(const int& fence);
+ // Max rotator buffers
+ enum { ROT_NUM_BUFS = 2 };
+ // rotator data info dst offset
+ uint32_t mRotOffset[ROT_NUM_BUFS];
+ int mRelFence[ROT_NUM_BUFS];
+ // current offset slot from mRotOffset
+ uint32_t mCurrOffset;
+ OvMem m;
+ };
+
+ RotMem() : _curr(0) {}
+ Mem& curr() { return m[_curr % MAX_ROT_MEM]; }
+ const Mem& curr() const { return m[_curr % MAX_ROT_MEM]; }
+ Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; }
+ RotMem& operator++() { ++_curr; return *this; }
+ void setReleaseFd(const int& fence) { curr().setReleaseFd(fence); }
+ bool close();
+ uint32_t _curr;
+ Mem m[MAX_ROT_MEM];
+};
+
class Rotator
{
public:
@@ -56,50 +95,19 @@
virtual bool queueBuffer(int fd, uint32_t offset) = 0;
virtual void dump() const = 0;
virtual void getDump(char *buf, size_t len) const = 0;
+ void setReleaseFd(const int& fence) { mMem.setReleaseFd(fence); }
static Rotator *getRotator();
protected:
+ /* Rotator memory manager */
+ RotMem mMem;
explicit Rotator() {}
static uint32_t calcOutputBufSize(const utils::Whf& destWhf);
private:
/*Returns rotator h/w type */
static int getRotatorHwType();
-};
-
-/*
- Manages the case where new rotator memory needs to be
- allocated, before previous is freed, due to resolution change etc. If we make
- rotator memory to be always max size, irrespctive of source resolution then
- we don't need this RotMem wrapper. The inner class is sufficient.
-*/
-struct RotMem {
- // Max rotator memory allocations
- enum { MAX_ROT_MEM = 2};
-
- //Manages the rotator buffer offsets.
- struct Mem {
- Mem() : mCurrOffset(0) {utils::memset0(mRotOffset); }
- bool valid() { return m.valid(); }
- bool close() { return m.close(); }
- uint32_t size() const { return m.bufSz(); }
- // Max rotator buffers
- enum { ROT_NUM_BUFS = 2 };
- // rotator data info dst offset
- uint32_t mRotOffset[ROT_NUM_BUFS];
- // current offset slot from mRotOffset
- uint32_t mCurrOffset;
- OvMem m;
- };
-
- RotMem() : _curr(0) {}
- Mem& curr() { return m[_curr % MAX_ROT_MEM]; }
- const Mem& curr() const { return m[_curr % MAX_ROT_MEM]; }
- Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; }
- RotMem& operator++() { ++_curr; return *this; }
- bool close();
- uint32_t _curr;
- Mem m[MAX_ROT_MEM];
+ friend class RotMgr;
};
/*
@@ -155,8 +163,6 @@
utils::eTransform mOrientation;
/* rotator fd */
OvFD mFd;
- /* Rotator memory manager */
- RotMem mMem;
friend Rotator* Rotator::getRotator();
};
@@ -209,8 +215,6 @@
utils::eTransform mOrientation;
/* rotator fd */
OvFD mFd;
- /* Rotator memory manager */
- RotMem mMem;
/* Enable/Disable Mdss Rot*/
bool mEnabled;
@@ -233,9 +237,11 @@
* Expects a NULL terminated buffer of big enough size.
*/
void getDump(char *buf, size_t len);
+ int getRotDevFd(); //Called on A-fam only
private:
overlay::Rotator *mRot[MAX_ROT_SESS];
int mUseCount;
+ int mRotDevFd; //A-fam
};
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 9bfa34e..c3d00f1 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -368,11 +368,6 @@
return fmt3D;
}
-bool isMdssRotator() {
- int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
- return (mdpVersion >= qdutils::MDSS_V5);
-}
-
void getDump(char *buf, size_t len, const char *prefix,
const mdp_overlay& ov) {
char str[256] = {'\0'};