Fix Tearing, stuttering for Original resolution surface.

Design now uses OverlayUI class. Flow goes through gralloc
to avoid race conditions with mirroring, when video is
played via Gallery.

Change-Id: If18c1f84a99aae38a6a4a20da7dff804ae05b8be
CRs-fixed: 285186, 286930, 286596
This commit is contained in:
Saurabh Shah 2011-05-13 14:48:30 -07:00
parent 9c9680462d
commit dd6c395b86
2 changed files with 188 additions and 3 deletions

View File

@ -206,11 +206,16 @@ static void *disp_loop(void *ptr)
}
#if defined(HDMI_DUAL_DISPLAY)
static int postOrigResHDMI(private_module_t *);
static void *hdmi_ui_loop(void *ptr)
{
private_module_t* m = reinterpret_cast<private_module_t*>(
ptr);
while (1) {
if(m->isOrigResStarted) {
postOrigResHDMI(m);
continue;
}
pthread_mutex_lock(&m->overlayLock);
while(!(m->hdmiStateChanged))
pthread_cond_wait(&(m->overlayPost), &(m->overlayLock));
@ -226,7 +231,8 @@ static void *hdmi_ui_loop(void *ptr)
Overlay* pTemp = m->pobjOverlay;
if (!m->enableHDMIOutput)
pTemp->closeChannel();
else if (m->enableHDMIOutput && !m->videoOverlay) {
else if (m->enableHDMIOutput && !m->videoOverlay &&
!(m->isOrigResStarted)) {
if (!pTemp->isChannelUP()) {
int alignedW = ALIGN(m->info.xres, 32);
if (pTemp->startChannel(alignedW, m->info.yres,
@ -373,9 +379,12 @@ static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int enable)
dev->common.module);
pthread_mutex_lock(&m->overlayLock);
Overlay* pTemp = m->pobjOverlay;
if (!enable && pTemp)
pTemp->closeChannel();
m->enableHDMIOutput = enable;
if(m->isOrigResStarted) {
m->ts.isHDMIExitPending = !enable;
} else if (!enable && pTemp) {
pTemp->closeChannel();
}
m->hdmiStateChanged = true;
pthread_cond_signal(&(m->overlayPost));
pthread_mutex_unlock(&m->overlayLock);
@ -392,6 +401,119 @@ static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientati
return 0;
}
/* Posts buffers in their original resolution to secondary.
*/
static int postOrigResHDMI(private_module_t* m) {
int w, h, format;
buffer_handle_t buffer;
int ret = NO_ERROR;
//Wait for new buffer call and read values
pthread_mutex_lock(&m->ts.newBufferMutex);
while(m->ts.isNewBuffer == false) {
pthread_cond_wait(&m->ts.newBufferCond, &m->ts.newBufferMutex);
}
m->ts.get(w,h,format,buffer);
m->ts.isNewBuffer = false;
pthread_mutex_unlock(&m->ts.newBufferMutex);
//Post them to secondary
if(m->enableHDMIOutput) {
const bool waitForVsync = true;
const int orientation = 0;
const int fbnum = OverlayUI::FB1;
const bool useVGPipe = true;
ret = m->pOrigResTV->setSource(w, h, format, orientation, useVGPipe,
waitForVsync, fbnum);
if(ret == NO_ERROR) {
m->pOrigResTV->setPosition(0, 0, m->pOrigResTV->getFBWidth(),
m->pOrigResTV->getFBHeight());
ret = m->pOrigResTV->queueBuffer(buffer);
}
if(ret != NO_ERROR)
LOGE("Posting original resolution surface to secondary failed");
}
//Signal that we posted the buffer
pthread_mutex_lock(&m->ts.bufferPostedMutex);
m->ts.isBufferPosted = true;
pthread_cond_signal(&m->ts.bufferPostedCond);
pthread_mutex_unlock(&m->ts.bufferPostedMutex);
if(m->ts.isExitPending || m->ts.isHDMIExitPending) {
m->pOrigResTV->closeChannel();
}
return ret;
}
/* Posts buffers in their original resolution to primary.
*/
static int fb_postOrigResBuffer(struct framebuffer_device_t* dev,
buffer_handle_t buffer, int w,
int h, int format, int orientation) {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
int ret = NO_ERROR;
if (m->isOrigResStarted) {
//Share new values
pthread_mutex_lock(&m->ts.newBufferMutex);
m->ts.set(w,h,format,buffer);
m->ts.isNewBuffer = true;
pthread_cond_signal(&m->ts.newBufferCond);
pthread_mutex_unlock(&m->ts.newBufferMutex);
const bool useVGPipe = true;
const bool waitForVsync = true;
const int fbnum = OverlayUI::FB0;
ret = m->pOrigResPanel->setSource(w, h, format, orientation, useVGPipe,
waitForVsync, fbnum);
if(ret == NO_ERROR) {
ret = m->pOrigResPanel->queueBuffer(buffer);
}
if(ret != NO_ERROR)
LOGE("Posting original resolution surface to primary failed");
//Wait for HDMI to post buffers
pthread_mutex_lock(&m->ts.bufferPostedMutex);
while(m->ts.isBufferPosted == false) {
pthread_cond_wait(&m->ts.bufferPostedCond,
&m->ts.bufferPostedMutex);
}
m->ts.isBufferPosted = false;
pthread_mutex_unlock(&m->ts.bufferPostedMutex);
}
if(m->ts.isExitPending) {
m->pOrigResPanel->closeChannel();
}
return ret;
}
static int fb_startOrigResDisplay(struct framebuffer_device_t* dev) {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
int ret = NO_ERROR;
dev->videoOverlayStarted(dev, true);
m->ts.clear();
m->isOrigResStarted = true;
return ret;
}
static int fb_stopOrigResDisplay(struct framebuffer_device_t* dev) {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
int ret = NO_ERROR;
m->isOrigResStarted = false;
m->ts.isExitPending = true;
//Free the threads
m->ts.isNewBuffer = true;
m->ts.isBufferPosted = true;
pthread_cond_signal(&m->ts.newBufferCond);
pthread_cond_signal(&m->ts.bufferPostedCond);
m->pOrigResPanel->closeChannel();
m->pOrigResTV->closeChannel();
dev->videoOverlayStarted(dev, false);
return ret;
}
static int fb_postBypassBuffer(struct framebuffer_device_t* dev,
buffer_handle_t buffer, int w,
int h, int format, int orientation, int isHPDON)
@ -873,6 +995,9 @@ int mapFrameBufferLocked(struct private_module_t* module)
pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module);
module->pobjOverlayUI = new OverlayUI();
module->pOrigResPanel = new OverlayOrigRes<OverlayUI::FB0>();
module->pOrigResTV = new OverlayOrigRes<OverlayUI::FB1>();
module->isOrigResStarted = false;
#endif
return 0;
@ -901,6 +1026,8 @@ static int fb_close(struct hw_device_t *dev)
delete m->pobjOverlayUI;
m->pobjOverlayUI = 0;
delete m->pOrigResPanel;
delete m->pOrigResTV;
#endif
if (ctx) {
free(ctx);
@ -938,6 +1065,9 @@ int fb_device_open(hw_module_t const* module, const char* name,
dev->device.enableHDMIOutput = fb_enableHDMIOutput;
dev->device.postBypassBuffer = fb_postBypassBuffer;
dev->device.closeBypass = fb_closeBypass;
dev->device.postOrigResBuffer = fb_postOrigResBuffer;
dev->device.startOrigResDisplay = fb_startOrigResDisplay;
dev->device.stopOrigResDisplay = fb_stopOrigResDisplay;
#endif
private_module_t* m = (private_module_t*)module;

View File

@ -189,6 +189,57 @@ struct avail_t {
#endif
};
#ifdef __cplusplus
/* Store for shared data and synchronization */
struct ThreadShared {
int w;
int h;
int format;
buffer_handle_t buffer;
bool isNewBuffer;
bool isBufferPosted;
bool isExitPending; //Feature close
bool isHDMIExitPending; //Only HDMI close
//New buffer arrival condition
pthread_mutex_t newBufferMutex;
pthread_cond_t newBufferCond;
//Buffer posted to display condition, used instead of barrier
pthread_mutex_t bufferPostedMutex;
pthread_cond_t bufferPostedCond;
ThreadShared():w(0),h(0),format(0),buffer(0),isNewBuffer(false),
isBufferPosted(false), isExitPending(false),
isHDMIExitPending(false) {
pthread_mutex_init(&newBufferMutex, NULL);
pthread_mutex_init(&bufferPostedMutex, NULL);
pthread_cond_init(&newBufferCond, NULL);
pthread_cond_init(&bufferPostedCond, NULL);
}
void set(int w, int h, int format, buffer_handle_t buffer) {
this->w = w;
this->h = h;
this->format = format;
this->buffer = buffer;
}
void get(int& w, int& h, int& format, buffer_handle_t& buffer) {
w = this->w;
h = this->h;
format = this->format;
buffer = this->buffer;
}
void clear() {
w = h = format = 0;
buffer = 0;
isNewBuffer = isBufferPosted = isExitPending = \
isHDMIExitPending = false;
}
};
#endif
struct private_module_t {
gralloc_module_t base;
@ -237,6 +288,10 @@ struct private_module_t {
* pobjOverlayUI - UI overlay channel for comp. bypass.
*/
OverlayUI* pobjOverlayUI;
OverlayOrigRes<OverlayUI::FB0>* pOrigResPanel;
OverlayOrigRes<OverlayUI::FB1>* pOrigResTV;
bool isOrigResStarted;
ThreadShared ts;
#endif
};