📄 ddipu_sdc_tv.cpp
字号:
//-----------------------------------------------------------------------------
// Copyright (C) 2004-2005, MOTOROLA, INC. All Rights Reserved
// THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
// BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
// MOTOROLA, INC.
//------------------------------------------------------------------------------
//
// Copyright (C) 2005-2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
//
// File: ddipu_sdc_tv.cpp
//
// Implementation of DDIPU_SDC TV mode-related functions.
//
//------------------------------------------------------------------------------
#include "precomp.h"
//------------------------------------------------------------------------------
// External Functions
//------------------------------------------------------------------------------
// External Variables
//------------------------------------------------------------------------------
// Defines
#define RETAIL_MSGS 0
#define LOCK_PP() EnterCriticalSection(&m_csPPLock)
#define UNLOCK_PP() LeaveCriticalSection(&m_csPPLock)
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------------
// Local Variables
//------------------------------------------------------------------------------
// Local Functions
//------------------------------------------------------------------------------
//
// Function: TVUpdateThread
//
// This method is a thread executed whenever we enter TV mode.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
void DDIPU_SDC::TVUpdateThread(LPVOID lpParameter)
{
DDIPU_SDC *pDDIPU_SDC = (DDIPU_SDC *)lpParameter;
pDDIPU_SDC->TVUpdateRoutine();
return;
}
//------------------------------------------------------------------------------
//
// Function: TVUpdateRoutine
//
// This routine is activated whenever the UI needs to be
// updated. It then waits on the SDC BG EOF interrupt, and
// calls to perform upsizing and set the upsized UI as the
// next SDC BG buffer.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
void DDIPU_SDC::TVUpdateRoutine(void)
{
while (1)
{
UINT32 time, iOverlayInterval;
// Wait for request to update the surface
WaitForSingleObject(m_hTVUpdateRequest, INFINITE);
EnterCriticalSection(&m_csDrawLock);
// Check to make sure we are still in TV mode and
// thus requiring the TV update.
if (!m_bTVModeActive)
{
LeaveCriticalSection(&m_csDrawLock);
continue;
}
time = GetTickCount();
//DEBUGMSG(1, (TEXT("%s: TV Update request received at time %d:%d\r\n"), __WFUNCTION__, time/60, time%60));
// Wait for background plane to complete current refresh.
DisplayPlaneWaitForNotBusy(DisplayPlane_0);
// We have received SDC BG EOF interrupt, so
// now we upscale and update the buffer.
TVUpdateBuffer();
LeaveCriticalSection(&m_csDrawLock);
// We would like to put the UI update to sleep
// when we know that video playback or other heavy
// use of overlays is occurring. However, relying
// on whether the overlay is currently being shown
// is not sufficient. We would ideally be able to
// flag when video is being played, and change our
// Sleep time here based on whether overlays are in
// heavy use or not.
iOverlayInterval = GetTickCount() - m_iLastOverlayUpdateTime;
//DEBUGMSG(1, (TEXT("%s: Interval since last overlay update: %d\r\n"), __WFUNCTION__, iOverlayInterval));
if (iOverlayInterval > 500)
{
// Now sleep for 33ms, so that we only update at a
// maximum of a 30FPS rate. 1000/30 = 33.3
Sleep(20);
}
else
{
Sleep(100);
}
}
}
//------------------------------------------------------------------------------
//
// Function: TVUpdateBuffer
//
// This method upsizes the current primary buffer and puts the result
// in a TV out buffer.
//
// Parameters:
// None.
//
// Returns:
// S_OK successful
// others failed
//
//------------------------------------------------------------------------------
void DDIPU_SDC::TVUpdateBuffer(void)
{
DDIPU_SDCSurf *ppOutputSurf;
ppBuffers bufs;
static int lastRotation = DMDO_0;
UINT32 iDirtyRegions;
LPRECT pRectangles;
UINT32 i;
UINT32 srcBufOffset, dstBufOffset;
static BOOL singleRegionConfig = FALSE;
UINT32 time;
time = GetTickCount();
RETAILMSG(RETAIL_MSGS, (TEXT("%s: Waiting for PP Lock for TV %d:%d\r\n"), __WFUNCTION__, time/60, time%60));
LOCK_PP();
RETAILMSG(RETAIL_MSGS, (TEXT("%s: Locking PP for TV %d:%d\r\n"), __WFUNCTION__, time/60, time%60));
// Determine source and target rectangle by reading
// dirty rectangle regions
EnterCriticalSection(&m_csDirtyRect);
iDirtyRegions = m_pDirtyRect->GetNumDirtyRegions();
pRectangles = (LPRECT) LocalAlloc(LPTR, sizeof(RECT) * iDirtyRegions);
m_pDirtyRect->GetDirtyRegions(pRectangles, iDirtyRegions);
// Reset event to re-synchronize updates to primary surface
// with calls to update the TV.
ResetEvent(m_hTVUpdateRequest);
LeaveCriticalSection(&m_csDirtyRect);
// TODO: Update based on dirty rectangles....
if ((iDirtyRegions == 0) || (iDirtyRegions == m_iNumDirtyRegions))
{
// If no dirty regions, just update the entire UI.
if (singleRegionConfig || (m_PPConfiguration != PPConfiguration_TV))
{
// Stop whomever is already running the PP,
// so that it can be reconfigured and run for TV.
PPStop(m_hPP);
RECT fullUI = {0, 0, 319, 239};
SetPPConfigForTV(fullUI);
m_PPConfiguration = PPConfiguration_TV;
PPConfigure(m_hPP, &m_ppData_TV);
RETAILMSG(RETAIL_MSGS, (TEXT("%s: Configged for TV\r\n"), __WFUNCTION__));
// Start PP task
// Note: The post-processor will not acutally
// process frames until the buffers are added.
// This occurs within SetVisibleSurfaceOverlay
PPStart(m_hPP);
singleRegionConfig = FALSE;
}
// Set Post-processing output to TV buffer
ppOutputSurf = m_pTVBuffer1;
RETAILMSG(0, (TEXT("%s: m_nLAWPhysical = %x \nm_pPrimarySurface->OffsetInVideoMemory() = %x\r\n"),
__WFUNCTION__, m_nLAWPhysical, m_pPrimarySurface->OffsetInVideoMemory()));
// Add input and output buffers to PP queues.
bufs.inputBuf = (UINT32 *)(m_nLAWPhysical + m_pPrimarySurface->OffsetInVideoMemory());
bufs.outputBuf = (UINT32 *)(m_nLAWPhysical + ppOutputSurf->OffsetInVideoMemory());
PPAddBuffers(m_hPP, &bufs);
// Wait for End of Frame
WaitForSingleObject(m_hPPEOFEvent, INFINITE);
}
else
{
// Currently, we update the entire primary surface.
for (i = 0; i < iDirtyRegions; i++)
{
// Only stop, configure, and start if one of the following
// cases is true:
// 1) Current configuration is for Overlay
// 2) Current configuration
if (!(singleRegionConfig && (m_PPConfiguration == PPConfiguration_TV)))
{
// Stop whomever is already running the PP,
// so that it can be reconfigured and run for TV.
PPStop(m_hPP);
SetPPConfigForTV(pRectangles[i]);
m_PPConfiguration = PPConfiguration_TV;
PPConfigure(m_hPP, &m_ppData_TV);
RETAILMSG(RETAIL_MSGS, (TEXT("%s: Configged for TV\r\n"), __WFUNCTION__));
// Start PP task
// Note: The post-processor will not actually
// process frames until the buffers are added.
// This occurs within SetVisibleSurfaceOverlay
PPStart(m_hPP);
singleRegionConfig = TRUE;
}
// Set Post-processing output to TV buffer
ppOutputSurf = m_pTVBuffer1;
RETAILMSG(0, (TEXT("%s: m_nLAWPhysical = %x \nm_pPrimarySurface->OffsetInVideoMemory() = %x\r\n"),
__WFUNCTION__, m_nLAWPhysical, m_pPrimarySurface->OffsetInVideoMemory()));
// Compute buffer offset from source rectangle
switch (m_iRotate)
{
case DMDO_0:
case DMDO_180:
srcBufOffset = (pRectangles[i].top * m_nScreenWidth + pRectangles[i].left) * m_pMode->Bpp / 8;
dstBufOffset = ((pRectangles[i].top * 2) * (m_nScreenWidth * 2) + pRectangles[i].left * 2) * m_pMode->Bpp / 8;
break;
case DMDO_90:
case DMDO_270:
srcBufOffset = (pRectangles[i].left * m_nScreenHeight + (m_nScreenHeight - pRectangles[i].bottom)) * m_pMode->Bpp / 8;
dstBufOffset = ((pRectangles[i].top * 2) * (m_nScreenWidth * 2) + pRectangles[i].left * 2) * m_pMode->Bpp / 8;
break;
}
// Add input and output buffers to PP queues.
bufs.inputBuf = (UINT32 *)(m_nLAWPhysical + m_pPrimarySurface->OffsetInVideoMemory() + srcBufOffset);
bufs.outputBuf = (UINT32 *)(m_nLAWPhysical + ppOutputSurf->OffsetInVideoMemory() + dstBufOffset);
PPAddBuffers(m_hPP, &bufs);
// Wait for End of Frame
WaitForSingleObject(m_hPPEOFEvent, INFINITE);
}
}
//RETAILMSG(1, (TEXT("%s: Finished TV UI processing, regions = %d, time = %d\r\n"), __WFUNCTION__, iDirtyRegions, GetTickCount() - time));
RETAILMSG(RETAIL_MSGS, (TEXT("%s: Unlocking PP for TV %d:%d\r\n"), __WFUNCTION__, time/60, time%60));
UNLOCK_PP();
LocalFree(pRectangles);
return;
}
//------------------------------------------------------------------------------
//
// Function: ConfigPPForTV
//
// This function configure the Post-processor to perform rotation,
// color space conversion, and resizing for the video overlay.
//
// Parameters:
// pOverlaySurf
// [in] Overlay surface.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
void DDIPU_SDC::SetPPConfigForTV(RECT srcRect)
{
UINT16 rectWidth, rectHeight;
int srcSurfWidth;
// Set up post-processing configuration data
//RETAILMSG(1, (TEXT("%s: Configuring for TV\r\n"), __WFUNCTION__));
// Set up input format and data width
m_ppData_TV.inputFormat = ppFormat_RGB;
m_ppData_TV.inputDataWidth = ppDataWidth_16BPP;
m_ppData_TV.inputRGBPixelFormat.component0_offset = 0;
m_ppData_TV.inputRGBPixelFormat.component1_offset = 5;
m_ppData_TV.inputRGBPixelFormat.component2_offset = 11;
m_ppData_TV.inputRGBPixelFormat.component0_width = 5;
m_ppData_TV.inputRGBPixelFormat.component1_width = 6;
m_ppData_TV.inputRGBPixelFormat.component2_width = 5;
// Set up output format and data width
m_ppData_TV.outputFormat = ppFormat_RGB;
m_ppData_TV.outputDataWidth = ppDataWidth_16BPP;
m_ppData_TV.outputRGBPixelFormat.component0_offset = 0;
m_ppData_TV.outputRGBPixelFormat.component1_offset = 5;
m_ppData_TV.outputRGBPixelFormat.component2_offset = 11;
m_ppData_TV.outputRGBPixelFormat.component0_width = 5;
m_ppData_TV.outputRGBPixelFormat.component1_width = 6;
m_ppData_TV.outputRGBPixelFormat.component2_width = 5;
// Set up post-processing channel CSC parameters
m_ppData_TV.CSCEquation = ppCSCNoOp;
rectWidth = (UINT16) (srcRect.right - srcRect.left + 1);
rectHeight = (UINT16) (srcRect.bottom - srcRect.top + 1);
switch (m_iRotate)
{
case DMDO_0:
case DMDO_180:
m_ppData_TV.inputSize.height = rectHeight;
m_ppData_TV.inputSize.width = rectWidth;
srcSurfWidth = m_pMode->width;
break;
case DMDO_270:
case DMDO_90:
m_ppData_TV.inputSize.height = rectWidth;
m_ppData_TV.inputSize.width = rectHeight;
srcSurfWidth = m_pMode->height;
break;
}
m_ppData_TV.inputStride = srcSurfWidth * (m_pMode->Bpp / 8);
// If our screen orientation is rotated, we want to undo that
// rotation for TV out. TV out should never be rotated.
switch (m_iRotate)
{
case DMDO_0:
m_ppData_TV.flipRot.verticalFlip = FALSE;
m_ppData_TV.flipRot.horizontalFlip = FALSE;
m_ppData_TV.flipRot.rotate90 = FALSE;
break;
case DMDO_90:
// Rotate another 270
m_ppData_TV.flipRot.verticalFlip = FALSE;
m_ppData_TV.flipRot.horizontalFlip = FALSE;
m_ppData_TV.flipRot.rotate90 = TRUE;
break;
case DMDO_180:
// Rotate 180
m_ppData_TV.flipRot.verticalFlip = TRUE;
m_ppData_TV.flipRot.horizontalFlip = TRUE;
m_ppData_TV.flipRot.rotate90 = FALSE;
break;
case DMDO_270:
// Rotate 90
m_ppData_TV.flipRot.verticalFlip = TRUE;
m_ppData_TV.flipRot.horizontalFlip = TRUE;
m_ppData_TV.flipRot.rotate90 = TRUE;
break;
}
// TV out dimensions: size of 640x480, 16bpp
m_ppData_TV.outputSize.height = m_ppData_TV.inputSize.width * 2;
m_ppData_TV.outputSize.width = m_ppData_TV.inputSize.height * 2;
m_ppData_TV.outputStride = 640 * 2;
m_ppData_TV.directDisplay = FALSE;
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -