From dd6c395b86a982c035e663c9f8c4e66aa2b54053 Mon Sep 17 00:00:00 2001 From: Saurabh Shah Date: Fri, 13 May 2011 14:48:30 -0700 Subject: [PATCH] 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 --- framebuffer.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++-- gralloc_priv.h | 55 ++++++++++++++++++++ 2 files changed, 188 insertions(+), 3 deletions(-) diff --git a/framebuffer.cpp b/framebuffer.cpp index 4965856..3537f62 100644 --- a/framebuffer.cpp +++ b/framebuffer.cpp @@ -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( 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( + 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( + 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( + 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(); + module->pOrigResTV = new OverlayOrigRes(); + 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; diff --git a/gralloc_priv.h b/gralloc_priv.h index 03f0e8f..965fc6b 100644 --- a/gralloc_priv.h +++ b/gralloc_priv.h @@ -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* pOrigResPanel; + OverlayOrigRes* pOrigResTV; + bool isOrigResStarted; + ThreadShared ts; #endif };