winsurf2.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:134k
源码类别:

Symbian

开发平台:

Visual C++

  1.                     pItem->rcDst.right = rcSize.cx;
  2.                     pItem->rcDst.bottom = rcSize.cy;
  3.                 }
  4.                 SetLastScale(&pItem->rcSrc, &pItem->rcDst);
  5.                 double dScaleX = m_scaleFactorX,
  6.                        dScaleY = m_scaleFactorY;
  7.                 // Setup new src and dest rects....
  8.                 _ConstructRects( pItem->rcSrc,
  9.                                  pItem->rcDst,
  10.                                  FALSE,
  11.                                  nNumRects,
  12.                                  &m_paSrcRects,
  13.                                  &m_paDestRects);
  14.                 if (nNumRects != 1)
  15.                 {
  16.                     HXxPoint screenOffset = m_pSite->GetScreenOffset();
  17.                     if (!m_paSrcRects)
  18.                         m_paSrcRects = (HXxRect*)malloc(sizeof(HXxRect));
  19.                     if (!m_paDestRects)
  20.                         m_paDestRects = (HXxRect*)malloc(sizeof(HXxRect));;
  21.                     m_paSrcRects[0] = pItem->rcSrc;
  22.                     m_paDestRects[0] = pItem->rcDst;
  23.                     m_paSrcRects[0].left += screenOffset.x;
  24.                     m_paSrcRects[0].top += screenOffset.y;
  25.                     m_paSrcRects[0].right += screenOffset.x;
  26.                     m_paSrcRects[0].bottom += screenOffset.y;
  27.                 }
  28.                 if (m_paSrcRects && m_paDestRects)
  29.                 {
  30.                     ForceUpdateOverlay(&m_paDestRects[0], &m_paSrcRects[0], HX_OVER_SHOW|HX_OVER_KEYDEST, TRUE);
  31.                 }
  32.                 if (m_bNeedColorKeyFilled)
  33.                 {
  34.                     m_bDisableFillColorKey = FALSE;
  35.                     _FillColorKey();
  36.                 }
  37.                 // Alpha blended images are drawn before the video so the scaling gets messed up on
  38.                 // static images.  Force a redraw to correct the problem.
  39.                 if ((dScaleX != m_scaleFactorX || dScaleY != m_scaleFactorY) && m_pSite->IsFullScreen())
  40.                 {
  41.                     HXxRect dirty = {m_pSite->m_pTopLevelSite->m_topleft.x,
  42.                                      m_pSite->m_pTopLevelSite->m_topleft.y,
  43.                                      m_pSite->m_pTopLevelSite->m_topleft.x+m_pSite->m_pTopLevelSite->m_size.cx,
  44.                                      m_pSite->m_pTopLevelSite->m_topleft.y+m_pSite->m_pTopLevelSite->m_size.cy};
  45.                     m_pSite->m_pTopLevelSite->_RecursiveDamageRect(&dirty, TRUE);
  46.                     m_pSite->m_pTopLevelSite->_ForceRedrawAll();
  47.                 }
  48.             }
  49.         }
  50.         else if (HXR_FAIL == hr)
  51.         {
  52.             // Turn off overlay
  53.             m_bMultipleOverlay = TRUE;
  54.         }
  55.     }
  56.     else if (pItem->nBltMode == HX_BLT_YUV_STRETCH)
  57.     {
  58.         // If no src rect is specified, use surface
  59.         if (!pItem->rcSrc.right && !pItem->rcSrc.bottom)
  60.         {
  61.             pItem->rcSrc.right = m_allocatedFallbackSize.cx;
  62.             pItem->rcSrc.bottom = m_allocatedFallbackSize.cy;
  63.         }
  64.         // If no src rect is specified, use surface
  65.         if (!pItem->rcDst.right && !pItem->rcDst.bottom)
  66.         {
  67.             m_pSite->GetSize(rcSize);
  68.             pItem->rcDst.right = rcSize.cx;
  69.             pItem->rcDst.bottom = rcSize.cy;
  70.         }
  71.         SetLastScale(&pItem->rcSrc, &pItem->rcDst);
  72.         if (bVisibleSite && !m_bFlushing)
  73.         {
  74.             m_nLastBltMode = HX_BLT_YUV_STRETCH;
  75.             // Ok, this is great. We need to add the regions from our
  76.             // yuv alphablending rects to our m_Region so that
  77.             // constructrects will return the correct scaled rects for
  78.             // us to blt. We have to do this here because
  79.             // _ConstructRects doesn't know anything about YUV
  80.             // optimized alphablending.  It works in overlay because
  81.             // we have m_pAdditionalColorKey
  82.             //
  83.             HXREGION* pTmp = NULL;
  84.             if( pItem->pAlphaList && m_pSite->m_Region )
  85.             {
  86.                 pTmp = HXCreateRegion();
  87.                 HXUnionRegion( pTmp, m_pSite->m_Region, pTmp );
  88.                 for( int w=0 ; w<pItem->count; w++)
  89.                 {
  90.                     HXRECTANGLE pRect;
  91.                     pRect.x      = (short)pItem->pAlphaList[w].rcImageRect.left;
  92.                     pRect.y      = (short)pItem->pAlphaList[w].rcImageRect.top;
  93.                     pRect.width  = (short)HXxRECT_WIDTH(pItem->pAlphaList[w].rcImageRect);
  94.                     pRect.height = (short)HXxRECT_HEIGHT(pItem->pAlphaList[w].rcImageRect);
  95.                     //Add in our offsets from the corner of the
  96.                     //toplevel site.
  97.                     pRect.x += (short)m_pSite->m_topleft.x;
  98.                     pRect.y += (short)m_pSite->m_topleft.y;
  99.                     // We must scale this rect to the scale factor of
  100.                     // this surface. This really only comes into play
  101.                     // if we are shrinking the site to sub 1x and we
  102.                     // are still BLTing a YUV surface.
  103.                     pRect.x      = (int)((double)pRect.x*m_scaleFactorX+.5);
  104.                     pRect.y      = (int)((double)pRect.y*m_scaleFactorY+.5);
  105.                     HXUnionRectWithRegion( &pRect, pTmp, pTmp );
  106.                 }
  107.             }
  108.             // Setup new src and dest rects....
  109.             _ConstructRects( pItem->rcSrc,
  110.                              pItem->rcDst,
  111.                              FALSE,
  112.                              nNumRects,
  113.                              &m_paSrcRects,
  114.                              &m_paDestRects,
  115.                              pTmp);
  116.             if( pTmp )
  117.             {
  118.                 HXDestroyRegion(pTmp);
  119.             }
  120.             bSub1x = IsShrinking() && !_AllowsOverlayShrinking();
  121.             BOOL bLoseOverlay = FALSE;
  122.             // Lose overlay
  123.             if (HX_OVERLAY_BLT == m_nBltMode && bSub1x)
  124.             {
  125.                 bLoseOverlay = TRUE;
  126.                 m_bDisableFillColorKey = TRUE;
  127.             }
  128.             CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  129.             WINDRAW* pWindraw = pSurface->GetWinDraw();
  130.             EnterCriticalSection(&m_csFallback);
  131.             // Do an offscreen blt for each display rect
  132.             for( int j=0 ; j<nNumRects ; j++ )
  133.             {
  134.                 hr = WinDrawSurface_Blt(pWindraw, &m_fallbackSurface, (RECT*)&m_paDestRects[j], (RECT*)&m_paSrcRects[j]);
  135.                 if (hr != DD_OK)
  136.                 {
  137.                     // Some boards fail on yuv blts, so try a new format on strange errors
  138.                     if (DDERR_INVALIDRECT   != hr &&
  139.                         DDERR_INVALIDPARAMS != hr &&
  140.                         DDERR_SURFACEBUSY   != hr &&
  141.                         DDERR_SURFACELOST   != hr)
  142.                     {
  143.                         if (HXR_OK == TryNewFallback())
  144.                         {
  145.                             // we created a new surface, discard this frame
  146.                             break;
  147.                         }
  148.                     }
  149.                     break;
  150.                 }
  151.             }
  152.             LeaveCriticalSection(&m_csFallback);
  153.             if (bLoseOverlay)
  154.             {
  155.                 m_bDisableFillColorKey = TRUE;
  156.                 ForceUpdateOverlay(&m_paDestRects[0], &m_paSrcRects[0], HX_OVER_HIDE|HX_OVER_KEYDEST);
  157.                 ForceGDIMode(TRUE);
  158.             }
  159.         }
  160.         if (pItem->pAlphaList)
  161.         {
  162.             delete [] pItem->pAlphaList;
  163.         }
  164.         SetEvent(m_hFallbackEmpty);
  165.     }
  166.     else
  167.     {
  168.         INT32 nLastGdiSurface = m_nLastGdiSurface;
  169.         // If no src rect is specified, use surface
  170.         if (!pItem->rcSrc.right && !pItem->rcSrc.bottom)
  171.         {
  172.             pItem->rcSrc.right = m_allocatedGdiSize.cx;
  173.             pItem->rcSrc.bottom = m_allocatedGdiSize.cy;
  174.         }
  175.         // If no src rect is specified, use surface
  176.         if (!pItem->rcDst.right && !pItem->rcDst.bottom)
  177.         {
  178.             m_pSite->GetSize(rcSize);
  179.             pItem->rcDst.right = rcSize.cx;
  180.             pItem->rcDst.bottom = rcSize.cy;
  181.         }
  182.         SetLastScale(&pItem->rcSrc, &pItem->rcDst);
  183.         if (bVisibleSite && !m_bFlushing)
  184.         {
  185.             m_nLastBltMode = HX_BASIC_BLT;
  186.             // Setup new src and dest rects....
  187.             _ConstructRects( pItem->rcSrc,
  188.                              pItem->rcDst,
  189.                              FALSE,
  190.                              nNumRects,
  191.                              &m_paSrcRects,
  192.                              &m_paDestRects);
  193.             // Do a gdi blt for each display rect
  194.             for( int j=0 ; j<nNumRects ; j++ )
  195.             {
  196.                 hr = WinDrawSurface_Blt(pWindraw, &m_GDIsurface, (RECT*)&m_paDestRects[j], (RECT*)&m_paSrcRects[j], pItem->nIndex);
  197.             }
  198.             if (HX_OVERLAY_BLT == m_nBltMode)
  199.             {
  200.                 m_bDisableFillColorKey = TRUE;
  201.                 m_bDisableFillColorKey = TRUE;
  202.                 ForceUpdateOverlay(&m_paDestRects[0], &m_paSrcRects[0], HX_OVER_HIDE|HX_OVER_KEYDEST);
  203.                 ForceGDIMode(TRUE);
  204.             }
  205.         }
  206.         m_nLastGdiSurface = pItem->nIndex;
  207.         // Release the lock on this surface after we updated it.  We keep around the last
  208.         // image for refreshing.
  209.         if (nLastGdiSurface >= 0)
  210.         {
  211.             SetEvent(m_GDIsurface.gdi.lpGDIBackBuffer[nLastGdiSurface]->hEmpty);
  212.         }
  213.     }
  214.     //We are done blt'ing all our rects. Lets notify everyone that
  215.     //might be interested in alpha blending that we changed.
  216.     int nTot = m_pSite->m_AlphaBlendNotifiers.GetCount();
  217.     if( nTot>0 && !m_pSite->IsCompositionMode() && m_bOffBecauseofShinking)
  218.     {
  219.         //XXXgfw Once we have optimized YUV blenders, do even bother
  220.         //calling this as YUV blends from the bottom up and all this
  221.         //has already been done.
  222.         if( m_pSite && m_pSite->m_pTopLevelSite )
  223.             m_pSite->m_pTopLevelSite->ScheduleCallback(REDRAW_ALL, 0);
  224.     }
  225.     m_pSite->_TLSUnlock();
  226.     if (DDERR_WRONGMODE == hr)
  227.         hr = HXR_OK;
  228.     // Update blt stats
  229.     if (HXR_OK == hr && !m_bFlushing)
  230.     {
  231.         UpdateBltStats(&pItem->rcDst);
  232.     }
  233.     return hr;
  234. }
  235. DWORD WINAPI CWinSurface2::ThreadProc(CWinSurface2* pThis)
  236. {
  237.     return pThis->RenThread();
  238. }
  239. DWORD CWinSurface2::RenThread()
  240. {
  241.     BOOL    bMeasureJitter = FALSE;
  242.     HRESULT hr;
  243.     tFrameElement *pItem;
  244.     HANDLE  aObjects[2] = {m_hFrameSem, m_hAbort},
  245.     aRenderObjects[2] = {m_hForceRender, m_hAbort};
  246.     UINT32  nResolution = SCHEDULE_GRANULE;
  247.     tFrameElement lastItem;
  248. #ifdef ENABLE_ERROR_TRACE
  249.     g_ulFrameCount = 0;
  250.     g_ulSleepCount = 0;
  251. #endif // ENABLE_ERROR_TRACE
  252.     // Read some preferences
  253.     IHXPreferences*    pPreferences    = NULL;
  254.     IHXBuffer*         pBuffer         = NULL;
  255. #if !defined(_GOLD) && 0
  256.     CTimeSample  sample;
  257.     sample.Init(m_pContext, (void*)this);
  258. #endif
  259.     if (HXR_OK == m_pContext->QueryInterface(IID_IHXPreferences,(void**)&pPreferences))
  260.     {
  261.         // Use vblank flags for flipping
  262.         if (pPreferences->ReadPref("VideoBoost\MeasureJitter", pBuffer) == HXR_OK)
  263.             bMeasureJitter = ::atoi((char*) pBuffer->GetBuffer());
  264.         HX_RELEASE(pBuffer);
  265.         if (pPreferences->ReadPref("VideoBoost\SchedulerResolution", pBuffer) == HXR_OK)
  266.             nResolution = ::atoi((char*) pBuffer->GetBuffer());
  267.         if (pPreferences->ReadPref("VideoBoost\IgnorePresentIfReady", pBuffer) == HXR_OK)
  268.             m_bIngnorePresentIfReady = ::atoi((char*) pBuffer->GetBuffer());
  269.         HX_RELEASE(pPreferences);
  270.     }
  271.     CWinBaseRootSurface *pSurface = NULL;
  272.     WINDRAW *pWindraw = NULL;
  273.     pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  274.     if (pSurface)
  275.     {
  276.         pWindraw = pSurface->GetWinDraw();
  277.         pWindraw->nSchedulerResolution = nResolution;
  278.     }
  279. #ifdef HARDCODE_GRANULE
  280.     if (nResolution)
  281.         timeBeginPeriod(nResolution);
  282. #endif //HARDCODE_GRANULE
  283.     // Make sure timeline is active. If Wait returns and error,
  284.     // an abort message work it up, so check if our thread is
  285.     // supposed to keep running, and if so, wait again.
  286.     while (HXR_OK != WaitForTimeLine(0) && m_bCont && !m_bFlushing)
  287.         continue;
  288.     while (m_bCont)
  289.     {
  290.         m_nLastDisplayTime = -1;
  291.         // Wait for a frame or an abort
  292.         hr = WaitForMultipleObjects(2, aObjects, FALSE, INFINITE);
  293.         if (hr - WAIT_OBJECT_0 == 0 || hr - WAIT_OBJECT_0 == 1)
  294.         {
  295.             if (m_pListOfFrames->GetCount())
  296.             {
  297.                 // Grab the first frame off the list
  298.                 EnterCriticalSection(&m_csList);
  299.                 pItem = (tFrameElement*)m_pListOfFrames->GetHead();
  300.                 LeaveCriticalSection(&m_csList);
  301.                 EnterCriticalSection(&m_csDisplay);
  302. TIME_AND_BLT_AGAIN:
  303.                 pItem->dwDDFlags = 0;
  304.                 pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  305.                 HX_ASSERT(pSurface);
  306.                 // The root surface may have been destroyed
  307.                 if (pSurface)
  308.                 {
  309.                     pWindraw = pSurface->GetWinDraw();
  310.                     if (m_bQueryMonitorFreq)
  311.                     {
  312.                         HX_ASSERT(pWindraw->dRefreshRate != 0);
  313.                         HX_ASSERT(pWindraw->dwReportedHeight);
  314.                     }
  315.                     // Blocks until display time
  316.                     _ScheduleFrameForDisplay(pWindraw, pItem, nResolution);
  317.                     // Preserve our frame descriptor
  318.                     lastItem = *pItem;
  319.                     hr = DisplayFrame(pItem);
  320.                     // Check if the root surface was destroyed during the scheduling
  321.                     pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  322.                     if (pSurface)
  323.                         pWindraw = pSurface->GetWinDraw();
  324.                     // Need to try again
  325.                     if (DDERR_WASSTILLDRAWING == hr)
  326.                     {
  327.                         // Restore our frame descriptor
  328.                         *pItem = lastItem;
  329.                         WaitForMultipleObjects(2, aRenderObjects, FALSE, 10);
  330.                         goto TIME_AND_BLT_AGAIN;
  331.                     }
  332.                     // Probably can not async flip, so turn it off
  333.                     else if (DDERR_INVALIDPARAMS == hr && m_bUseVBlankFlip)
  334.                     {
  335.                         // Restore our frame descriptor
  336.                         *pItem = lastItem;
  337.                         m_bUseVBlankFlip = FALSE;
  338.                         goto TIME_AND_BLT_AGAIN;
  339.                     }
  340.                     else if (DD_OK != hr)
  341.                     {
  342.                         // Need to discard the overlay
  343.                         if (pItem->nBltMode == HX_OVERLAY_BLT && pSurface)
  344.                         {
  345.                             WinDraw_DisplaySurface(pWindraw, &m_surface, pItem->dwDDFlags, pItem->nIndex, TRUE);
  346.                         }
  347.                         hr = DD_OK;
  348.                     }
  349.                     if (m_bQueryMonitorFreq &&
  350.                         DD_OK == hr &&
  351.                         pSurface)
  352.                     {
  353.                         m_bQueryMonitorFreq = FALSE;
  354.                         WinDraw2_GetMonitorProperties(pWindraw);
  355.                     }
  356.                     if (HXR_OK == hr)
  357.                     {
  358.                         // Delete the frame element
  359.                         EnterCriticalSection(&m_csList);
  360.                         pItem = (tFrameElement*)m_pListOfFrames->RemoveHead();
  361.                         LeaveCriticalSection(&m_csList);
  362.                         delete pItem;
  363.                         pItem = NULL;
  364.                     }
  365.                 }
  366.                 LeaveCriticalSection(&m_csDisplay);
  367.             }
  368.         }
  369.     }
  370. #ifdef ENABLE_ERROR_TRACE
  371.     // Calculate mean and std. dev:
  372.     double dSum = 0;
  373.     double dAbsSum = 0;
  374.     double dMin = 1000000;
  375.     double dMax = -1000000;
  376.     UINT32 i;
  377.     // Skip first and last ten frames:
  378.     for (i = 10; i < min(g_ulFrameCount - 10, 10000); i++)
  379.     {
  380.         dSum += g_error[i][1];
  381.         dAbsSum += abs(g_error[i][1]);
  382.         if (g_error[i][1] < dMin)
  383.         {
  384.             dMin = g_error[i][1];
  385.         }
  386.         if (g_error[i][1] > dMax)
  387.         {
  388.             dMax = g_error[i][1];
  389.         }
  390.     }
  391.     HX_TRACE("Min:t%fn", dMin);
  392.     HX_TRACE("Max:t%fn", dMax);
  393.     double dMean = dSum / min(g_ulFrameCount - 20, 10000);
  394.     HX_TRACE("Mean:t%fn", dMean);
  395.     HX_TRACE("Abs. Mean:t%fn", dAbsSum / min(g_ulFrameCount - 20, 10000));
  396.     double dStdDev = 0;
  397.     for (i = 10; i < min(g_ulFrameCount - 10, 10000); i++)
  398.     {
  399.         dStdDev += pow(dMean - g_error[i][1], 2);
  400.     }
  401.     dStdDev /= min(g_ulFrameCount -20, 10000) - 1;
  402.     dStdDev = sqrt(dStdDev);
  403.     HX_TRACE("Std. dev:t%fn", dStdDev);
  404.     // Calculate alternate mean and std. dev:
  405.     dSum = 0;
  406.     dMin = 1000000;
  407.     dMax = -1000000;
  408.     for (i = 10; i < min(g_ulFrameCount - 10, 10000); i++)
  409.     {
  410.         dSum += g_alternateError[i];
  411.         if (g_alternateError[i] < dMin)
  412.         {
  413.             dMin = g_alternateError[i];
  414.         }
  415.         if (g_alternateError[i] > dMax)
  416.         {
  417.             dMax = g_alternateError[i];
  418.         }
  419.     }
  420.     HX_TRACE("Alternate min:t%fn", dMin);
  421.     HX_TRACE("Alternate Max:t%fn", dMax);
  422.     dMean = dSum / min(g_ulFrameCount - 20, 10000);
  423.     HX_TRACE("Alternate mean:t%fn", dMean);
  424.     dStdDev = 0;
  425.     for (i = 10; i < min(g_ulFrameCount - 10, 10000); i++)
  426.     {
  427.         dStdDev += pow(dMean - g_alternateError[i], 2);
  428.     }
  429.     dStdDev /= min(g_ulFrameCount - 20, 10000) - 1;
  430.     dStdDev = sqrt(dStdDev);
  431.     HX_TRACE("Alternate std. dev:t%fn", dStdDev);
  432.     DumpErrorEntries();
  433. #endif // ENABLE_ERROR_TRACE
  434. #ifdef ENABLE_SYNC_TRACE
  435.     DumpSyncEntries();
  436. #endif // ENABLE_SYNC_TRACE
  437. #ifdef HARDCODE_GRANULE
  438.     if (nResolution)
  439.         timeEndPeriod(nResolution);
  440. #endif //HARDCODE_GRANULE
  441.     return 0;
  442. }
  443. BOOL CWinSurface2::GetColorConverter(int cIdIn, int cIdOut)
  444. {
  445.     //grab the non padded converters...
  446.     BOOL bConverter = zm_pColorAcc->CheckColorConverter(cIdIn, cIdOut);
  447.     m_pSite->ColorConverterRequest(cIdIn, cIdOut, bConverter);
  448.     return bConverter;
  449. }
  450. BOOL CWinSurface2::GetColorConverter2(int cIdIn, int cIdOut)
  451. {
  452.     //grab the padded converters...
  453.     BOOL bConverter = zm_pColorAcc->CheckColorConverter2(cIdIn, cIdOut);
  454.     m_pSite->ColorConverterRequest(cIdIn, cIdOut, bConverter);
  455.     return bConverter;
  456. }
  457. int CWinSurface2::ColorConvert(INT32 cidOut, unsigned char *dest_ptr,
  458.                                int dest_width, int dest_height,
  459.                                int dest_pitch, int dest_x, int dest_y,
  460.                                int dest_dx, int dest_dy,
  461.                                INT32 cidIn, unsigned char *src_ptr,
  462.                                int src_width, int src_height,
  463.                                int src_pitch, int src_x, int src_y,
  464.                                int src_dx, int src_dy)
  465. {
  466.     return zm_pColorAcc->ColorConvert(cidOut, dest_ptr,
  467.                                       dest_width, dest_height,
  468.                                       dest_pitch, dest_x, dest_y,
  469.                                       dest_dx, dest_dy,
  470.                                       cidIn, src_ptr,
  471.                                       src_width, src_height,
  472.                                       src_pitch, src_x, src_y,
  473.                                       src_dx, src_dy);
  474. }
  475. int CWinSurface2::ColorConvert2(INT32 cidOut, unsigned char *dest_ptr,
  476.                                 int dest_width, int dest_height,
  477.                                 int dest_pitch, int dest_x, int dest_y,
  478.                                 int dest_dx, int dest_dy,
  479.                                 INT32 cidIn, unsigned char *pY,
  480.                                 unsigned char *pU, unsigned char *pV,
  481.                                 int src_width, int src_height,
  482.                                 int yPitch, int uPitch, int vPitch,
  483.                                 int src_x, int src_y, int src_dx, int src_dy)
  484. {
  485.     return zm_pColorAcc->ColorConvert2(cidOut, dest_ptr,
  486.                                        dest_width, dest_height,
  487.                                        dest_pitch, dest_x, dest_y,
  488.                                        dest_dx, dest_dy,
  489.                                        cidIn, pY, pU, pV,
  490.                                        src_width, src_height,
  491.                                        yPitch, uPitch, vPitch,
  492.                                        src_x, src_y, src_dx, src_dy);
  493. }
  494. HX_RESULT CWinSurface2::RelinquishOverlay()
  495. {
  496.     // Prevent access to video memory while we tear down our surfaces
  497.     WaitForSingleObject(m_hSurfaceMutex, INFINITE);
  498.     m_bSwitchingingOverlay = TRUE;
  499.     WaitForQueuedFrames();
  500.     HX_RESULT res = CWinSurface::RelinquishOverlay();
  501.     if (res == HXR_OK)
  502.     {
  503.         // Create a fallback and always use it
  504.         if (m_bVideoSurface2)
  505.         {
  506.             CreateFallbackSurface(m_nFallbackSurfaceCID, &m_allocatedFallbackSize);
  507.             m_bMultipleOverlay = TRUE;
  508.         }
  509.         // Force the renderer who lost overlay to redraw to cover the colorkey
  510.         HXxRect dirty = {m_pSite->m_topleft.x,
  511.                          m_pSite->m_topleft.y,
  512.                          m_pSite->m_topleft.x+m_pSite->m_size.cx,
  513.                          m_pSite->m_topleft.y+m_pSite->m_size.cy};
  514.         m_pSite->m_pTopLevelSite->_RecursiveDamageRect(&dirty, TRUE);
  515.         m_pSite->m_pTopLevelSite->ScheduleCallback(REPAINT, 0);
  516.     }
  517.     m_bSwitchingingOverlay = FALSE;
  518.     ReleaseMutex(m_hSurfaceMutex);
  519.     return res;
  520. }
  521. HX_RESULT CWinSurface2::AcquireOverlay()
  522. {
  523.     m_bSwitchingingOverlay = TRUE;
  524.     HX_RESULT res = HXR_FAIL;
  525.     if (m_bVideoSurface2)
  526.     {
  527.         _ReleaseSurface();
  528.         ReInitSurfaces();
  529.         res = HXR_OK;
  530.     }
  531.     else
  532.         res = CWinSurface::AcquireOverlay();
  533.     m_bSwitchingingOverlay = FALSE;
  534.     return res;
  535. }
  536. HX_RESULT CWinSurface2::CreateFallbackSurface(int nSurfaceCID, HXxSize* pSize, int *pcidList, int nListSize)
  537. {
  538.     if (m_bFallbackSurfaceCreated)
  539.     {
  540.         if (pSize->cx == m_allocatedFallbackSize.cx &&
  541.             pSize->cy == m_allocatedFallbackSize.cy)
  542.         {
  543.             return HXR_OK;
  544.         }
  545.         else
  546.         {
  547.             DestroyFallbackSurface();
  548.         }
  549.     }
  550.     //Get our windraw object from the root surface
  551.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  552.     if( !pSurface )
  553.         return HXR_FAIL;
  554.     EnterCriticalSection(&m_csFallback);
  555.     pSurface->OpenWindraw();
  556.     WINDRAW* pWindraw = pSurface->GetWinDraw();
  557.     BMI bmi;
  558.     memset(&bmi, 0, sizeof(BMI));
  559.     BOOL    bSuccess = FALSE;
  560.     int     fFlags = WINDRAWSURFACE_DIRECTDRAW | WINDRAWSURFACE_VIDEOMEMORY;
  561.     int     acid[4] = {nSurfaceCID, CID_YV12, CID_YUY2, CID_UYVY};
  562.     int     dwId;
  563.     if (!pcidList)
  564.     {
  565.         pcidList = &acid[0];
  566.         nListSize = sizeof(acid)/sizeof(acid[0]);
  567.     }
  568.     // Try video memory, then system memory
  569.     for (int j=0; j<2; j++, fFlags = WINDRAWSURFACE_DIRECTDRAW)
  570.     {
  571.         // If the dd driver can do color space conversion blts, create a yuv surface
  572.         if (pWindraw->dd.m_caps.dwCaps & DDCAPS_BLTFOURCC)
  573.         {
  574.             // Try to create an offscreen yuv surface
  575.             for (int i=0; i<nListSize && IsYUV(pcidList[i]); i++)
  576.             {
  577.                 MakeBitmap((LPBITMAPINFO)&bmi, sizeof(BMI), pcidList[i], pSize->cx, pSize->cy, NULL, NULL);
  578.                 memset(&m_fallbackSurface, 0, sizeof(m_fallbackSurface));
  579.                 if (NOERROR == WinDraw2_CreateSurface(pWindraw, &m_fallbackSurface, &bmi, fFlags, 0, 0))
  580.                 {
  581.                     // Test if blitting to the primary works (but don't let the user see it)
  582.                     RECT rcSrc = {0,0,pSize->cx, pSize->cy};
  583.                     RECT rcDst = {-pSize->cx, -pSize->cy, 0, 0};
  584.                     if (NOERROR == WinDrawSurface_Blt(pWindraw, &m_fallbackSurface, &rcDst, &rcSrc))
  585.                     {
  586.                         bSuccess = TRUE;
  587.                         dwId = pcidList[i];
  588. #ifdef _DEBUG
  589.                         char szTmp[128]; /* Flawfinder: ignore */
  590.                         char cid[6][5] = {{"I420"}, {"YV12"}, {"YVU9"}, {"YUY2"}, {"UYVY"}, {"DVPF"}}; /* Flawfinder: ignore */
  591.                         if (dwId == CID_DVPF)
  592.                             dwId = 5;
  593.                         wsprintf(szTmp, "CreateFallbackSurface Created 1 %s buffersn", cid[dwId]);
  594.                         OutputDebugString(szTmp);
  595. #endif
  596.                         break;
  597.                     }
  598.                 }
  599.             }
  600.         }
  601.         // Try to create an offscreen surface matching the primary format if
  602.         // yuv surface failed.
  603.         if (!bSuccess)
  604.         {
  605.             memset(&bmi, 0, sizeof(BMI));
  606.             WinDraw2_GetDisplayFormat(pWindraw, &bmi);
  607.             int cid = GetBitmapColor((LPBITMAPINFO)&bmi);
  608.             MakeBitmap((LPBITMAPINFO)&bmi, sizeof(BMI), cid, m_pOptimizedFormat->biWidth, m_pOptimizedFormat->biHeight, NULL, NULL);
  609.             // Don't use hardware rgb...it kills performance on some cards
  610.             fFlags = WINDRAWSURFACE_DIRECTDRAW;
  611.             if (NOERROR == WinDraw2_CreateSurface(pWindraw, &m_fallbackSurface, &bmi, fFlags, 0, 0))
  612.             {
  613.                 bSuccess = TRUE;
  614.                 dwId = cid;
  615. #ifdef _DEBUG
  616.                 OutputDebugString("Created RGB offscreen surfacen");
  617. #endif
  618.             }
  619.         }
  620.         if (bSuccess)
  621.         {
  622.             m_allocatedFallbackSize.cx = pSize->cx;
  623.             m_allocatedFallbackSize.cy = pSize->cy;
  624.             m_nFallbackSurfaceCID = dwId;
  625.             m_bFallbackSurfaceCreated = TRUE;
  626.             if (!m_nBitsPerPixel ||
  627.                 !m_nHozRes ||
  628.                 !m_nVertRes)
  629.             {
  630.                 // Store the display mode we were created in.
  631.                 m_pSite->_GetDeviceCaps(NULL, m_nBitsPerPixel, m_nHozRes, m_nVertRes);
  632.             }
  633.             if (m_hRenThread)
  634.             {
  635.                 // We create our surface, start servicing GetVidMem calls
  636.                 SetEvent(m_hReinit);
  637.             }
  638.             LeaveCriticalSection(&m_csFallback);
  639.             return HXR_OK;
  640.         }
  641.     }
  642. #if 1
  643.     LeaveCriticalSection(&m_csFallback);
  644.     return HXR_FAIL;
  645. #else
  646.     // Result to sys mem buffers
  647.     return CreateSysMemSurface(nSurfaceCID, pSize, 1);
  648. #endif
  649. }
  650. HX_RESULT CWinSurface2::DestroyFallbackSurface()
  651. {
  652.     if (!m_bFallbackSurfaceCreated)
  653.         return HXR_OK;
  654.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  655.     if (!pSurface)
  656.         return HXR_FAIL;
  657.     WINDRAW* pWindraw = pSurface->GetWinDraw();
  658.     if (!pWindraw)
  659.         return HXR_FAIL;
  660.     EnterCriticalSection(&m_csFallback);
  661.     WinDraw2_ReleaseSurface(pWindraw, &m_fallbackSurface);
  662.     m_bFallbackSurfaceCreated = FALSE;
  663.     LeaveCriticalSection(&m_csFallback);
  664.     return HXR_OK;
  665. }
  666. HX_RESULT CWinSurface2::LockFallbackSurface(UCHAR* &pVidMem, INT32 &nPitch, BOOL bBlock)
  667. {
  668.     if (!bBlock)
  669.     {
  670.         if (WAIT_OBJECT_0 != WaitForSingleObject(m_hFallbackEmpty, 0))
  671.             return HXR_BUFFER_NOT_AVAILABLE;
  672.     }
  673.     HANDLE  aObjects[2] = {m_hFallbackEmpty, m_hAbort};
  674.     if (WaitForMultipleObjects(2, aObjects, FALSE, INFINITE) - WAIT_OBJECT_0 == 0)
  675.     {
  676.         HRESULT hr;
  677.         CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  678.         WINDRAW* pWindraw = pSurface->GetWinDraw();
  679.         HXxSize rcSize = {m_surfaceSize.cx,m_surfaceSize.cy};
  680.         if (HXR_OK != CreateFallbackSurface(m_nSurfaceCID, &rcSize))
  681.             return HXR_FAIL;
  682.         LONG lPitch;
  683.         hr = WinDrawSurface_Lock (pWindraw, &m_fallbackSurface, 0, (void**)&pVidMem, &lPitch);
  684.         if (hr != HXR_OK)
  685.             return hr;
  686.         m_bScratchSurface = TRUE;
  687.         nPitch = lPitch;
  688.     }
  689.     else
  690.         return HXR_FAIL;
  691.     return HXR_OK;
  692. }
  693. HX_RESULT CWinSurface2::TryNewFallback()
  694. {
  695.     int nNewCID = 0;
  696.     int acid[5] = {m_nFallbackSurfaceCID, 0,0,0,0};
  697.     for (int i=0; i<5; i++)
  698.     {
  699.         // Try a new format for our offscreen buffer ending in rgb
  700.         switch (acid[i])
  701.         {
  702.            case CID_I420:  acid[i+1] = CID_YV12; nNewCID++; break;
  703.            case CID_YV12:  acid[i+1] = CID_YUY2; nNewCID++; break;
  704.            case CID_YUY2:  acid[i+1] = CID_UYVY; nNewCID++; break;
  705.            case CID_UYVY:  acid[i+1] = CID_RGB32; nNewCID++; break;
  706.            default:
  707.                i=5;    // jump out of loop
  708.         }
  709.     }
  710.     if (!nNewCID)
  711.         return HXR_FAIL;
  712.     EnterCriticalSection(&m_csFallback);
  713.     DestroyFallbackSurface();
  714.     HRESULT hr = CreateFallbackSurface(acid[1], &m_allocatedFallbackSize, &acid[1], nNewCID);
  715.     LeaveCriticalSection(&m_csFallback);
  716.     return hr;
  717. }
  718. HX_RESULT CWinSurface2::CreateSysMemSurface(int nSurfaceCID,
  719.                                             HXxSize* pSize,
  720.                                             int nBuffers)
  721. {
  722.     // Do we need to create new buffers?
  723.     if (m_pSysMemSurf)
  724.     {
  725.         if (nBuffers == m_nSysMemSurfCount &&
  726.             pSize->cx == m_bmi.biWidth &&
  727.             pSize->cy == m_bmi.biHeight)
  728.         {
  729.             return HXR_OK;
  730.         }
  731.         DestroySysMemSurface();
  732.     }
  733.     // Calculate the size of each frame buffer
  734.     m_nSysMemSurfSize = pSize->cx * pSize->cy * GetBitsPerPixel(CID_I420) / 8;
  735.     // Allocate the surface list
  736.     m_pSysMemSurf = new tSysMemSurf[nBuffers];
  737.     if (!m_pSysMemSurf)
  738.         return HXR_OUTOFMEMORY;
  739.     memset(m_pSysMemSurf, 0, sizeof(tSysMemSurf)*nBuffers);
  740.     // Allocate each buffer
  741.     for (int i=0; i<nBuffers; i++)
  742.     {
  743.         m_pSysMemSurf[i].pBuffer = new UCHAR[m_nSysMemSurfSize + 31 & ~31];
  744.         if (!m_pSysMemSurf[i].pBuffer)
  745.         {
  746.             DestroySysMemSurface();
  747.             return HXR_OUTOFMEMORY;
  748.         }
  749.         m_pSysMemSurf[i].hEmpty = CreateEvent(NULL, TRUE, TRUE, NULL);
  750.         ++m_nSysMemSurfCount;
  751.     }
  752.     m_allocatedSysMemSurfSize = *pSize;
  753.     m_nSysMemSurfID = CID_I420;
  754.     m_bUseSysMemSurface = TRUE;
  755.     m_nSysMemSurfPitch = pSize->cx;
  756.     if (!m_nBitsPerPixel ||
  757.         !m_nHozRes ||
  758.         !m_nVertRes)
  759.     {
  760.         // Store the display mode we were created in.
  761.         m_pSite->_GetDeviceCaps(NULL, m_nBitsPerPixel, m_nHozRes, m_nVertRes);
  762.     }
  763.     return HXR_OK;
  764. }
  765. HX_RESULT CWinSurface2::LockSysMemSurface(UCHAR* &pVidMem, INT32 &nPitch, BOOL bBlock)
  766. {
  767.     HXxSize rcSize = {m_bmi.biWidth,m_bmi.biHeight};
  768.     if (HXR_OK != CreateSysMemSurface(m_nSurfaceCID, &rcSize, 1))
  769.         return HXR_FAIL;
  770.     if (!bBlock)
  771.     {
  772.         if (WAIT_OBJECT_0 != WaitForSingleObject(m_pSysMemSurf[m_nNextSysMemBuffer].hEmpty, 0))
  773.             return HXR_BUFFER_NOT_AVAILABLE;
  774.     }
  775.     HANDLE  aWait[2] = {m_pSysMemSurf[m_nNextSysMemBuffer].hEmpty, m_hAbort};
  776.     if (WaitForMultipleObjects(2, aWait, FALSE, INFINITE) - WAIT_OBJECT_0 == 0)
  777.     {
  778.         pVidMem = m_pSysMemSurf[m_nNextSysMemBuffer].pBuffer;
  779.         nPitch = m_nSysMemSurfPitch;
  780.         return HXR_OK;
  781.     }
  782.     else
  783.         return HXR_FAIL;
  784. }
  785. HX_RESULT CWinSurface2::DestroySysMemSurface()
  786. {
  787.     if (!m_pSysMemSurf)
  788.         return HXR_OK;
  789.     for (int i=0; i<m_nSysMemSurfCount; i++)
  790.     {
  791.         if (m_pSysMemSurf[i].pBuffer)
  792.         {
  793.             delete [] m_pSysMemSurf[i].pBuffer;
  794.             m_pSysMemSurf[i].pBuffer = NULL;
  795.         }
  796.         if (m_pSysMemSurf[i].hEmpty)
  797.         {
  798.             CloseHandle(m_pSysMemSurf[i].hEmpty);
  799.             m_pSysMemSurf[i].hEmpty = 0;
  800.         }
  801.     }
  802.     delete [] m_pSysMemSurf;
  803.     m_pSysMemSurf = NULL;
  804.     m_nSysMemSurfSize = 0;
  805.     m_nSysMemSurfCount = 0;
  806.     m_nNextSysMemBuffer = 0;
  807.     m_nSysMemSurfPitch = 0;
  808.     m_bUseSysMemSurface = FALSE;
  809.     return HXR_OK;
  810. }
  811. INT32 CWinSurface2::GetBitsPerPixel(int nSurfaceID)
  812. {
  813.     switch (nSurfaceID)
  814.     {
  815.        case CID_YV12:
  816.        case CID_I420:
  817.            return 12;
  818.        case CID_YUY2:
  819.        case CID_UYVY:
  820.            return 16;
  821.        default:
  822.            return 24;
  823.     }
  824. }
  825. HX_RESULT CWinSurface2::CreateGdiSurface(HXxSize* pSize)
  826. {
  827.     HX_RESULT hr = HXR_OK;
  828.     if (m_bGdiSurfaceCreated)
  829.         return hr;
  830.     // Create GDI buffers
  831.     BMI bmi;
  832.     memset(&bmi, 0, sizeof(BMI));
  833.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  834.     WINDRAW* pWindraw = pSurface->GetWinDraw();
  835.     WinDraw2_GetDisplayFormat(pWindraw, &bmi);
  836.     int cid = GetBitmapColor((LPBITMAPINFO)&bmi);
  837.     memset(&bmi, 0, sizeof(BMI));
  838.     MakeBitmap((LPBITMAPINFO)&bmi, sizeof(BMI), cid, pSize->cx, pSize->cy, NULL, NULL);
  839.     for (int nBuffers = m_nOverlayBackBuffersCreated; nBuffers; nBuffers--)
  840.     {
  841.         hr = WinDraw2_CreateSurface(pWindraw, &m_GDIsurface, &bmi, 0, nBuffers, 0);
  842.         if (NOERROR == hr)
  843.         {
  844.             m_allocatedGdiSize = *pSize;
  845.             m_nGdiSurfaceCID = cid;
  846.             m_nGdiSurfaceCount = nBuffers+1;
  847.             m_bGdiSurfaceCreated = TRUE;
  848.             m_nLastGdiSurface = -1;
  849.             if (m_hRenThread)
  850.                 SetEvent(m_hReinit);
  851.             break;
  852.         }
  853.     }
  854.     return hr;
  855. }
  856. HX_RESULT CWinSurface2::LockGdiSurface(UCHAR* &pVidMem, INT32 &nPitch, BOOL bBlock)
  857. {
  858.     HX_RESULT hr = HXR_FAIL;
  859.     // Create the gdi surface if necessary
  860.     if (!m_bGdiSurfaceCreated)
  861.     {
  862.         HXxSize size = {m_pOptimizedFormat->biWidth,
  863.                         m_pOptimizedFormat->biHeight};
  864.         hr = CreateGdiSurface(&size);
  865.         if (HXR_OK != hr)
  866.             return hr;
  867.     }
  868.     // Do we have a surface available
  869.     if (!bBlock)
  870.     {
  871.         if (WAIT_OBJECT_0 != WaitForSingleObject(m_GDIsurface.gdi.lpGDIBackBuffer[m_nNextGdiSurface]->hEmpty, 0))
  872.             return HXR_BUFFER_NOT_AVAILABLE;
  873.     }
  874.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  875.     WINDRAW* pWindraw = pSurface->GetWinDraw();
  876.     // Wait for the next surface
  877.     HANDLE  aWait[2] = {m_GDIsurface.gdi.lpGDIBackBuffer[m_nNextGdiSurface]->hEmpty, m_hAbort};
  878.     if (WaitForMultipleObjects(2, aWait, FALSE, INFINITE) - WAIT_OBJECT_0 == 0)
  879.     {
  880.         LPVOID  pTemp = NULL;
  881.         LONG    lPitch = 0;
  882.         hr = WinDrawSurface_Lock(pWindraw, &m_GDIsurface, m_nNextGdiSurface, &pTemp, &lPitch);
  883.         if (HXR_OK == hr)
  884.         {
  885.             pVidMem = (UCHAR*)pTemp;
  886.             nPitch = lPitch;
  887.             m_bGDISurface = TRUE;
  888.         }
  889.     }
  890.     return hr;
  891. }
  892. HX_RESULT CWinSurface2::DestroyGdiSurface()
  893. {
  894.     if (m_bGdiSurfaceCreated)
  895.     {
  896.         CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  897.         WINDRAW* pWindraw = pSurface->GetWinDraw();
  898.         if (m_allocatedGdiSize.cx && m_allocatedGdiSize.cy)
  899.         {
  900.             WinDraw2_ReleaseSurface(pWindraw, &m_GDIsurface);
  901.             memset(&m_GDIsurface,0,sizeof(m_GDIsurface));
  902.             memset(&m_allocatedGdiSize,0,sizeof(m_allocatedGdiSize));
  903.             m_nGdiSurfaceCID = 0;
  904.         }
  905.         m_bGdiSurfaceCreated = FALSE;
  906.         m_nLastGdiSurface = -1;
  907.     }
  908.     return HXR_OK;
  909. }
  910. void CWinSurface2::SetLastScale(HXxRect *pSrc, HXxRect *pDest)
  911. {
  912.     EnterCriticalSection(&m_csScale);
  913.     m_dLastXScale = (((double)pDest->right - (double)pDest->left) /
  914.                      ((double)pSrc->right - (double)pSrc->left));
  915.     m_dLastYScale = (((double)pDest->bottom - (double)pDest->top) /
  916.                      ((double)pSrc->bottom - (double)pSrc->top));
  917.     LeaveCriticalSection(&m_csScale);
  918. }
  919. int CWinSurface2::GetBestBltMode()
  920. {
  921.     // Here is our blt mode prority
  922.     // 1. DD overlay
  923.     // 2. DD offscreen (yuv then rgb)
  924.     // 3. GDI
  925.     BOOL    bSub1x = FALSE;
  926.     int     nBltMode = HX_OVERLAY_BLT;
  927.     int     nPreferredBltMode = nBltMode;
  928.     if (IsShrinking() && !_AllowsOverlayShrinking())
  929.         bSub1x = TRUE;
  930.     // Drop to yuv stretch blts if
  931.     // sub1x OR
  932.     // another app has the overlay
  933.     if (bSub1x | m_bMultipleOverlay)
  934.     {
  935.         nBltMode = HX_BLT_YUV_STRETCH;
  936.     }
  937.     // Drop to GDI if
  938.     // DD not available
  939.     if (m_bLostHWAcceleration)
  940.     {
  941.         nPreferredBltMode = nBltMode;
  942.         nBltMode = HX_BASIC_BLT;
  943.     }
  944.     // Can we restore DirectDraw
  945.     /*if (m_bLostHWAcceleration)
  946.     {
  947.         LPWINDRAWSURFACE lpwds = NULL;
  948.         switch(nPreferredBltMode)
  949.         {
  950.             case HX_OVERLAY_BLT: lpwds = &m_surface; break;
  951.             case HX_BLT_YUV_STRETCH: lpwds = &m_fallbackSurface; break;
  952.             default: lpwds = &m_GDIsurface;
  953.         }
  954.         CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  955.         m_bLostHWAcceleration = !pSurface->_IsHardwareAccelerationAvail(lpwds);
  956.         if (!m_bLostHWAcceleration)
  957.         {
  958.             if (HXR_OK != WaitForQueuedFrames())
  959.                 Flush();
  960.             DestroyGdiSurface();
  961.             pSurface->_AcquireHardwareAcceleration();
  962.             ReInitSurfaces();
  963.         }
  964.     }*/
  965.     return nBltMode;
  966. }
  967. BOOL CWinSurface2::IsShrinking()
  968. {
  969.     BOOL bShrink = FALSE;
  970.     EnterCriticalSection(&m_csScale);
  971.     if (m_dLastXScale != 0.0 && m_dLastYScale != 0.0 &&
  972.         (m_dLastXScale < 1.0 || m_dLastYScale < 1.0))
  973.     {
  974.         bShrink = TRUE;
  975.     }
  976.     LeaveCriticalSection(&m_csScale);
  977.     return bShrink;
  978. }
  979. void CWinSurface2::_WaitForFlush()
  980. {
  981.     m_bWaitingForFlush = TRUE;
  982.     // In the transition for VideoSurface2 to VideoSurface1, wait
  983.     // until all frames are displayed.
  984.     if (m_bWasInVidSurf2 && m_pListOfFrames)
  985.     {
  986.         while (m_pListOfFrames->GetCount())
  987.         {
  988.             Sleep(5);
  989.         }
  990.         // When switching to vidsurf1, set the backbuffer
  991.         // to NULL so we do not flip the overlay.  The flipping
  992.         // chain seems to get out of whack in the transition from
  993.         // vidsurf1 to 2.
  994.         m_surface.dd.lpDDBackBuffer = NULL;
  995.     }
  996.     m_bWaitingForFlush = FALSE;
  997. }
  998. HX_RESULT CWinSurface2::ForceUpdateOverlay(HXxRect *pDst, HXxRect *pSrc, DWORD dwFlags, BOOL bCheckPos)
  999. {
  1000.     HXxRect destRect,
  1001.     srcRect = *pSrc;
  1002.     BOOL bUpdate = FALSE;
  1003.     if (HX_OVER_SHOW | dwFlags)
  1004.     {
  1005.         memset( &destRect, 0, sizeof(HXxRect) );
  1006.         _GetWindowDeviceCords(&destRect);
  1007.         destRect.right = destRect.left + pDst->right;
  1008.         destRect.bottom = destRect.top + pDst->bottom;
  1009.         destRect.left += pDst->left;
  1010.         destRect.top += pDst->top;
  1011.         // Ensure we limit update coordinates to screen res
  1012.         UINT16 uBitesPerPixel;
  1013.         UINT16 uHorzRes;
  1014.         UINT16 uVertRes;
  1015.         m_pSite->_GetDeviceCaps(NULL, uBitesPerPixel, uHorzRes, uVertRes);
  1016.         double ratio;
  1017.         if (destRect.left < 0)
  1018.         {
  1019.             ratio = ((double)abs(destRect.left)) / (double)(destRect.right - destRect.left);
  1020.             destRect.left = 0;
  1021.             srcRect.left = (int) (((double) m_surfaceSize.cx) * ratio);
  1022.         }
  1023.         if (destRect.right> uHorzRes)
  1024.         {
  1025.             ratio = ((double)(destRect.right - uHorzRes)) / (double)(destRect.right - destRect.left);
  1026.             destRect.right = uHorzRes;
  1027.             srcRect.right = (int) (((double) m_surfaceSize.cx) * (1.0 - ratio));
  1028.         }
  1029.         if (destRect.top < 0)
  1030.         {
  1031.             ratio = ((double)abs(destRect.top)) / (double)(destRect.bottom - destRect.top);
  1032.             destRect.top = 0;
  1033.             srcRect.top = (int) (((double) m_surfaceSize.cy) * ratio);
  1034.         }
  1035.         if (destRect.bottom > uVertRes)
  1036.         {
  1037.             ratio = ((double)(destRect.bottom - uVertRes)) / (double)(destRect.bottom - destRect.top);
  1038.             destRect.bottom = uVertRes;
  1039.             srcRect.bottom = (int) (((double) m_surfaceSize.cy) * (1.0 - ratio));
  1040.         }
  1041.         if (uBitesPerPixel != m_oldOverlayColorDepth)
  1042.         {
  1043.             m_oldOverlayColorDepth = uBitesPerPixel;
  1044.             // XXXAH Probably do not need this, but keeping it to make sure.
  1045.             m_convertedOverlayColor = _InsureColorMatch(GetOverlayColor());
  1046.         }
  1047.         if (bCheckPos)
  1048.         {
  1049.             CWinBaseRootSurface *pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  1050.             WINDRAW *pWindraw = pSurface->GetWinDraw();
  1051.             // If the overlay is invisible or if it nees to be
  1052.             // moved update its position.
  1053.             if (!WinDraw2_IsSurfaceVisible(pWindraw, &m_surface) ||
  1054.                 ((m_lastUpdateDestRect.left   != destRect.left)   |
  1055.                  (m_lastUpdateDestRect.right  != destRect.right)  |
  1056.                  (m_lastUpdateDestRect.top    != destRect.top)    |
  1057.                  (m_lastUpdateDestRect.bottom != destRect.bottom) |
  1058.                  (m_lastUpdateSrcRect.left    != srcRect.left)    |
  1059.                  (m_lastUpdateSrcRect.right   != srcRect.right)   |
  1060.                  (m_lastUpdateSrcRect.top     != srcRect.top)     |
  1061.                  (m_lastUpdateSrcRect.bottom  != srcRect.bottom)))
  1062.             {
  1063.                 bUpdate = TRUE;
  1064.             }
  1065.         }
  1066.         else
  1067.         {
  1068.             bUpdate = TRUE;
  1069.         }
  1070.         memcpy(&m_lastUpdateDestRect, &destRect, sizeof(HXxRect)); /* Flawfinder: ignore */
  1071.         memcpy(&m_lastUpdateSrcRect,  &srcRect,  sizeof(HXxRect)); /* Flawfinder: ignore */
  1072.     }
  1073.     if (bUpdate)
  1074.     {
  1075.         _SetColorKey(m_convertedOverlayColor, m_convertedOverlayColor);
  1076.         _UpdateOverlay(&destRect, &srcRect, dwFlags);
  1077.     }
  1078.     return HXR_OK;
  1079. }
  1080. HX_RESULT CWinSurface2::HandleDisplayModeChange()
  1081. {
  1082.     UINT16  nBitDepth = 0,
  1083.         nHozRes = 0,
  1084.         nVertRes = 0;
  1085.     m_pSite->_GetDeviceCaps(NULL, nBitDepth, nHozRes, nVertRes);
  1086.     // The site handles surface reinit when bitdepth and
  1087.     // dimensions change.  If the mode changed in some other
  1088.     // way (like refresh rate), handle it here.
  1089.     if (m_pSite->zm_bInFullScreenTest ||
  1090.         (nBitDepth == m_nBitsPerPixel &&
  1091.          nHozRes == m_nHozRes &&
  1092.          nVertRes == m_nVertRes &&
  1093.          WAIT_OBJECT_0 == WaitForSingleObject(m_hReinit, 0)))
  1094.     {
  1095.         // Wait for display buffers to render
  1096.         Flush();
  1097.         DestroySurfaces();
  1098.         ReInitSurfaces();
  1099.         m_bQueryMonitorFreq = TRUE;
  1100.     }
  1101.     else
  1102.     {
  1103.         // Wait on the next GetVidMem call for new surface creation
  1104.         ResetEvent(m_hReinit);
  1105.         m_nBitsPerPixel = nBitDepth;
  1106.         m_nHozRes = nHozRes;
  1107.         m_nVertRes = nVertRes;
  1108.     }
  1109.     return HXR_OK;
  1110. }
  1111. BOOL CWinSurface2::HandleDirectDrawLoss(BOOL bLockedTLSMutex)
  1112. {
  1113.     BOOL bRet = FALSE;
  1114.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  1115.     m_bLostHWAcceleration = !pSurface->_IsHardwareAccelerationAvail();
  1116.     if (m_bLostHWAcceleration)
  1117.     {
  1118.         if (bLockedTLSMutex)
  1119.             m_pSite->_TLSUnlock();
  1120.         DestroySurfaces();
  1121.         pSurface->_LoseHardwareAcceleration();
  1122.         // RGB blitting is expensive, so drop the render thread priority
  1123.         if (m_bBoostRenderThread)
  1124.             SetThreadPriority(m_hRenThread, THREAD_PRIORITY_NORMAL);
  1125.         bRet = TRUE;
  1126.     }
  1127.     return bRet;
  1128. }
  1129. HX_RESULT CWinSurface2::ReleaseSurface(VideoMemStruct* pVidStruct, BOOL bDiscard, BOOL bDeleteAlphaList)
  1130. {
  1131.     UCHAR* pVidMem = pVidStruct->pVidMem;
  1132.     if (pVidStruct->pAlphaList && bDeleteAlphaList)
  1133.     {
  1134.         delete [] pVidStruct->pAlphaList;
  1135.     }
  1136.     m_bFrameHasHWAlphaBlend = FALSE;
  1137.     CWinBaseRootSurface* pSurface = (CWinBaseRootSurface*)m_pSite->GetRootSurface();
  1138.     WINDRAW* pWindraw = pSurface->GetWinDraw();
  1139.     if (!m_bUseSysMemSurface)
  1140.     {
  1141.         if (m_bScratchSurface)
  1142.         {
  1143.             if (!bDiscard && m_pSite->HasFocusRect())
  1144.             {
  1145.                 pSurface->DrawFocusRect(//&m_fallbackSurface,
  1146.                     m_nFallbackSurfaceCID,
  1147.                     &m_allocatedFallbackSize,
  1148.                     pVidMem,
  1149.                     m_pSite);
  1150.             }
  1151.             WinDrawSurface_Unlock (pWindraw, &m_fallbackSurface, 0);
  1152.             if (bDiscard)
  1153.                 SetEvent(m_hFallbackEmpty);
  1154.             m_bScratchSurface = FALSE;
  1155.         }
  1156.         else if (m_bGDISurface)
  1157.         {
  1158.             if (!bDiscard && m_pSite->HasFocusRect())
  1159.             {
  1160.                 pSurface->DrawFocusRect(//&m_GDIsurface,
  1161.                     m_nGdiSurfaceCID,
  1162.                     &m_allocatedGdiSize,
  1163.                     pVidMem,
  1164.                     m_pSite);
  1165.             }
  1166.             WinDrawSurface_Unlock (pWindraw, &m_GDIsurface, m_nNextGdiSurface);
  1167.             if (!bDiscard)
  1168.             {
  1169.                 ResetEvent(m_GDIsurface.gdi.lpGDIBackBuffer[m_nNextGdiSurface]->hEmpty);
  1170.                 if (++m_nNextGdiSurface == m_nGdiSurfaceCount)
  1171.                     m_nNextGdiSurface = 0;
  1172.             }
  1173.             m_bGDISurface = FALSE;
  1174.         }
  1175.         else
  1176.         {
  1177.             if (m_pHwMemObj)
  1178.             {
  1179.                 pVidMem = (UCHAR*)m_pHwMemObj->RendererToDevice(pVidMem);
  1180.                 m_bFrameHasHWAlphaBlend = FALSE;
  1181.             }
  1182.             WinDraw_ReleaseLockedSurface (pWindraw, &m_surface, pVidMem, bDiscard);
  1183.         }
  1184.     }
  1185.     // Unlocked the surface
  1186.     ReleaseMutex(m_hSurfaceMutex);
  1187.     m_pSite->_TLSUnlock();
  1188.     return HXR_OK;
  1189. }
  1190. HX_RESULT CWinSurface2::WaitForTimeLine(INT32 lTimeStamp)
  1191. {
  1192.     HX_RESULT hr = HXR_OK;
  1193.     if (m_pTimeLine)
  1194.     {
  1195.         DWORD dwRet = 0;
  1196.         UINT32 ulTime = 0;
  1197.         HX_RESULT hrTimeLine = m_pTimeLine->GetTimeLineValue(ulTime);
  1198.         while (HXR_TIMELINE_SUSPENDED == hrTimeLine &&
  1199.                m_bCont &&
  1200.                !m_bFlushing &&
  1201.                !m_bWaitingForFlush)
  1202.         {
  1203.             dwRet = WaitForSingleObject(m_hAbort, 5);
  1204.             if (WAIT_TIMEOUT != dwRet)
  1205.             {
  1206.                 hr = HXR_FAIL;
  1207.                 break;
  1208.             }
  1209.             hrTimeLine = m_pTimeLine->GetTimeLineValue(ulTime);
  1210.         }
  1211.     }
  1212.     return hr;
  1213. }
  1214. HX_RESULT CWinSurface2::WaitForQueuedFrames()
  1215. {
  1216.     if (m_pTimeLine)
  1217.     {
  1218.         UINT32 ulTime = 0;
  1219.         if (HXR_TIMELINE_SUSPENDED == m_pTimeLine->GetTimeLineValue(ulTime))
  1220.             return HXR_FAIL;
  1221.     }
  1222.     // Wait until our queue count reaches 0
  1223.     int nCount = m_pListOfFrames->GetCount();
  1224.     while (nCount)
  1225.     {
  1226.         Sleep(5);
  1227.         nCount = m_pListOfFrames->GetCount();
  1228.     }
  1229.     return HXR_OK;
  1230. }
  1231. void CWinSurface2::CreateAlphaList(VideoMemStruct* pVidStruct)
  1232. {
  1233.     _SetUpBlendRects();
  1234.     if(m_imageBlocks.GetCount())
  1235.     {
  1236.         UCHAR*  pSysBuf = NULL;
  1237.         INT32   nPitch = 0;
  1238.         HRESULT hr = LockSysMemSurface(pSysBuf, nPitch, TRUE);
  1239.         // yuck..."sys mem" mode means we are passing system memory
  1240.         // buffers for the video but here we are using it for alpha blending,
  1241.         // so we need to set it to false.
  1242.         m_bUseSysMemSurface = FALSE;
  1243.         if (HXR_OK == hr)
  1244.         {
  1245.             ImageBlock* pBlock = NULL;
  1246.             // Create an alpha struct for every region rect
  1247.             pVidStruct->ulCount = m_imageBlocks.GetCount();
  1248.             pVidStruct->pAlphaList = new AlphaStruct[pVidStruct->ulCount];
  1249.             // Set each alpha struct rect as a pointer to a sys mem buffer
  1250.             // the size of one video frame.  rcImageRect is the subrect
  1251.             // we need copied.
  1252.             CHXSimpleList::Iterator j = m_imageBlocks.Begin();
  1253.             for (int i=0; j != m_imageBlocks.End(); ++i, ++j)
  1254.             {
  1255.                 pBlock = (ImageBlock*)*j;
  1256.                 pVidStruct->pAlphaList[i].rcImageRect = pBlock->rect;
  1257.                 pVidStruct->pAlphaList[i].ulImageWidth = m_allocatedSysMemSurfSize.cx;
  1258.                 pVidStruct->pAlphaList[i].ulImageHeight = m_allocatedSysMemSurfSize.cy;
  1259.                 pVidStruct->pAlphaList[i].ulFourCC = HX_I420;
  1260.                 pVidStruct->pAlphaList[i].lPitch = m_nSysMemSurfPitch;
  1261.                 pVidStruct->pAlphaList[i].pBuffer = pSysBuf;
  1262.                 // The alpha source is greater than our video...yikes
  1263.                 if (pBlock->rect.right > m_allocatedSysMemSurfSize.cx ||
  1264.                     pBlock->rect.bottom > m_allocatedSysMemSurfSize.cy ||
  1265.                     pBlock->rect.right-pBlock->rect.left > m_allocatedSysMemSurfSize.cx ||
  1266.                     pBlock->rect.bottom-pBlock->rect.top > m_allocatedSysMemSurfSize.cy)
  1267.                 {
  1268.                     pVidStruct->ulCount = 0;
  1269.                     HX_VECTOR_DELETE(pVidStruct->pAlphaList);
  1270.                     return;
  1271.                 }
  1272.             }
  1273.         }
  1274.     }
  1275.     m_bImageBlocksGood = TRUE;
  1276. }
  1277. void CWinSurface2::YuvAlphaBlend(AlphaStruct* pList,
  1278.                                  UINT32 ulCount,
  1279.                                  UCHAR* pDest,
  1280.                                  UINT32 ulFourCC,
  1281.                                  INT32  lPitch,
  1282.                                  HXxSize* pDestDim)
  1283. {
  1284.     // Alpha blend each list entry and blt on the video frame
  1285.     if (m_bImageBlocksGood)
  1286.     {
  1287.         if( _BlendYUVRects(pList, ulCount, HX_I420) )
  1288.         {
  1289.             BOOL bConverter;
  1290.             INT32 ulDestCID = MapFourCCtoCID(ulFourCC);
  1291.             if (CID_UNKNOWN == ulDestCID)
  1292.                 ulDestCID = ulFourCC;
  1293.             CHXSimpleList::Iterator gg = m_imageBlocks.Begin();
  1294.             for (int i=0; gg != m_imageBlocks.End(); ++i, ++gg)
  1295.             {
  1296.                 ImageBlock* pBlock = (ImageBlock*)*gg;
  1297.                 Image*      pTmp   = pBlock->pImage;
  1298.                 // Get a converter
  1299.                 bConverter = GetColorConverter(MapFourCCtoCID(pList[i].ulFourCC), ulDestCID);
  1300.                 if (bConverter)
  1301.                 {
  1302.                     ColorConvert( ulDestCID,
  1303.                                   pDest,
  1304.                                   pDestDim->cx,
  1305.                                   pDestDim->cy,
  1306.                                   lPitch,
  1307.                                   pBlock->rect.left,
  1308.                                   pBlock->rect.top,
  1309.                                   pBlock->rect.right-pBlock->rect.left,
  1310.                                   pBlock->rect.bottom-pBlock->rect.top,
  1311.                                   MapFourCCtoCID(pList[i].ulFourCC),
  1312.                                   pTmp->pucImage,
  1313.                                   pTmp->bmiImage.biWidth,
  1314.                                   pTmp->bmiImage.biHeight,
  1315.                                   GETBITMAPPITCH(&pTmp->bmiImage),
  1316.                                   0,
  1317.                                   0,
  1318.                                   pBlock->rect.right-pBlock->rect.left,
  1319.                                   pBlock->rect.bottom-pBlock->rect.top);
  1320.                 }
  1321.             }
  1322.         }
  1323.     }
  1324. }
  1325. /************************************************************************
  1326.  *  Method:
  1327.  *      _ScheduleFrameForDisplay
  1328.  *  Purpose:
  1329.  */
  1330. HX_RESULT CWinSurface2::_ScheduleFrameForDisplay(void* pOsData,
  1331.                                                  tFrameElement* pItem,
  1332.                                                  UINT32 nResolution)
  1333. {
  1334.     // Display immediately when we do not have a clock
  1335.     if (!m_pTimeLine)
  1336.         return HXR_OK;
  1337.     HX_RESULT   hr = HXR_OK;
  1338.     UINT32      ulTime = 0;
  1339.     HANDLE      aWaitObjects[2] = {m_hForceRender, m_hAbort};
  1340.     // Number of ms the frame is ahead of the clock
  1341.     INT32       nTimeAhead = 0;
  1342.     // Use default scheduler
  1343.     if (!m_bOptimalVideoScheduler)
  1344.     {
  1345.         if (HXR_OK != CWinSurface::_ScheduleFrameForDisplay(pOsData, pItem, nResolution))
  1346.         {
  1347.             m_pTimeLine->GetTimeLineValue(ulTime);
  1348.             nTimeAhead = pItem->lTimeStamp - ulTime;
  1349.             // Ignore scheduling during a flush
  1350.             if (!m_bFlushing &&
  1351.                 hr != HXR_TIMELINE_SUSPENDED &&
  1352.                 nTimeAhead > 0)
  1353.             {
  1354.                 m_nLastDisplayTime = ulTime + nTimeAhead;
  1355.                 if (nResolution)
  1356.                     timeBeginPeriod(nResolution);
  1357.                 WaitForMultipleObjects(2, aWaitObjects, FALSE, nTimeAhead);
  1358.                 if (nResolution)
  1359.                     timeEndPeriod(nResolution);
  1360.                 m_nLastDisplayTime = -1;
  1361.             }
  1362.         }
  1363.         pItem->dTimeAvailable = GetMSTickDouble32() + 15;
  1364.         return HXR_OK;
  1365.     }
  1366.     WINDRAW*    pWindraw = (WINDRAW*)pOsData;
  1367.     double      dTickAtStreamTime = 0;
  1368.     double      dPreemptionCheckTick = 0;
  1369.     // Number of ms to the next vertical retrace
  1370.     double      dMsToNextVBlank = 0;
  1371.     double      dCurrentError = 0;
  1372.     // Number of vblanks the display device can schedule the blt
  1373.     INT32       nMaxVBlanksPerSchedule = 0;
  1374.     // The display device's current vertical scan line
  1375.     UINT32      dwScanLine = 0;
  1376.     double      dFilteredScanLine = 0.0;
  1377.     // Number of vblanks until we need to display the frame
  1378.     double      dVblanksToWait = 0.0;
  1379.     double      dIdealVBlank = 0.0;
  1380.     INT32       nVblanksToWait = 0;
  1381.     // Fraction of a vertical trace the video starts on
  1382.     double      dWindowPosScanLine = 0;
  1383.     // Final window placement:
  1384.     HXxRect     windowRect = { 0, 0, 0, 0 };
  1385.     // Window of error for picking a vblank to flip on.
  1386.     double      dWindowOfError = .2;
  1387.     if (pItem->nBltMode == HX_OVERLAY_BLT)
  1388.     {
  1389.         // Some cards can schedule an overlay flip 4 vblanks in advance
  1390.         if (m_bUseVBlankFlip)
  1391.             nMaxVBlanksPerSchedule = 4;
  1392.         else
  1393.             nMaxVBlanksPerSchedule = 1;
  1394.     }
  1395.     while (1)
  1396.     {
  1397.         dTickAtStreamTime = GetMSTickDouble32();
  1398.         hr = m_pTimeLine->GetTimeLineValue(ulTime);
  1399.         dPreemptionCheckTick = GetMSTickDouble32();
  1400.         // Calculate how far the video is ahead of the clock in ms
  1401.         UINT32 i;
  1402.         for (i = 0; (dPreemptionCheckTick - dTickAtStreamTime > OS_THREAD_QUANTUM / 5.0)
  1403.                            && i < MAX_PREEMPTION_CHECK_ATTEMPTS; ++i)
  1404.         {
  1405.             HX_TRACE("Preemption!n");
  1406.             dTickAtStreamTime = GetMSTickDouble32();
  1407.             hr = m_pTimeLine->GetTimeLineValue(ulTime);
  1408.             dPreemptionCheckTick = GetMSTickDouble32();
  1409.         }
  1410.         nTimeAhead = pItem->lTimeStamp - ulTime;
  1411.         WinDraw2_GetScanLine(pWindraw, &dwScanLine);
  1412.         // GetScanLine is terribly noisy on the G400 - one can get better
  1413.         // results by using high precision timers!
  1414.         // dFilteredScanLine = FilterScanLine(dwScanLine, dTickAtStreamTime - dVblankTime, pWindraw);
  1415.         dFilteredScanLine = dwScanLine;
  1416.         HX_ASSERT(dFilteredScanLine < pWindraw->dwMaxScanLine + 1);
  1417. #ifdef ENABLE_SYNC_TRACE
  1418.         syncTraceArray[ulSyncTraceIdx % MAX_SYNC_TRACE_ENTRIES][0] = dTickAtStreamTime;
  1419.         syncTraceArray[ulSyncTraceIdx % MAX_SYNC_TRACE_ENTRIES][1] = dwScanLine;
  1420.         syncTraceArray[ulSyncTraceIdx++ % MAX_SYNC_TRACE_ENTRIES][2] = GetMSTickDouble32() - dPreemptionCheckTick;
  1421. #endif // ENABLE_SYNC_TRACE
  1422.         _GetWindowDeviceCords(&windowRect);
  1423.         dWindowPosScanLine = windowRect.top / (double) (pWindraw->dwMaxScanLine + 1);
  1424.         // How many ms until the next vblank
  1425.         dMsToNextVBlank = (1.0 - (dFilteredScanLine / (double) (pWindraw->dwMaxScanLine + 1))) * pWindraw->dMsPerVBlank;
  1426.         // How many vblanks after the current one, until display time
  1427.         dVblanksToWait = (nTimeAhead - dMsToNextVBlank) / pWindraw->dMsPerVBlank;
  1428. #ifdef KAYA_CODE
  1429.         // Pick the appropriate vblank to display our frame.  First truncate
  1430.         // dVblanksToWait then round up and down and pick the smallest error.
  1431.         // In the rounding code, use nWindowPosScanLine to increase the a/v sync
  1432.         // accuracy.  We want to draw the first line of video as close to
  1433.         // the time give to us in pItem.
  1434.         double dPrevVBlank = ((INT32) dVblanksToWait) + dWindowPosScanLine - 1;
  1435.         double dCurrentVBlank = dPrevVBlank + 1;
  1436.         double dNextVBlank = dCurrentVBlank + 1;
  1437.         dIdealVBlank = fabs(dPrevVBlank - dVblanksToWait)
  1438.             < fabs(dCurrentVBlank - dVblanksToWait) ? dPrevVBlank : dCurrentVBlank;
  1439.         dIdealVBlank = fabs(dIdealVBlank - dVblanksToWait)
  1440.             < fabs(dNextVBlank - dVblanksToWait) ? dIdealVBlank : dNextVBlank;
  1441.         // If the refresh rate is a close multiple of the frame rate, we may
  1442.         // see rapid +/- oscillation of choice of vblanks due to timing error.
  1443.         // We only want to snap once per beat, so bias to the previous frame's
  1444.         // error in this case.
  1445.         dCurrentError = dVblanksToWait - (((INT32) dIdealVBlank <= 0 ? 0 : (INT32) dIdealVBlank)
  1446.                   + dWindowPosScanLine);
  1447.         if (fabs(dCurrentError) > TIME_JITTER_FILTER_THRESHOLD)
  1448.         {
  1449.             if ((m_dLastBlitError < 0) && (dCurrentError > 0))
  1450.             {
  1451.                 //HX_TRACE("Error sign change: %fn", dCurrentError);
  1452.                 // Decrease error:
  1453.                 dIdealVBlank++;
  1454.             }
  1455.             else if ((m_dLastBlitError > 0) && (dCurrentError < 0))
  1456.             {
  1457.                 //HX_TRACE("Error sign change: %fn", dCurrentError);
  1458.                 // Increase error:
  1459.                 dIdealVBlank--;
  1460.             }
  1461.             // An error of zero indicates an unitialized value on
  1462.             // start of playback or an unlikely coincidence.  Don't dampen
  1463.             // arbitrarily on the first frame to reduce the odds
  1464.             // of an initial, preventable snap; coincidences are harmless
  1465.         }
  1466.         nVblanksToWait = (INT32) dIdealVBlank;
  1467.         if (nVblanksToWait < 0)
  1468.         {
  1469.             nVblanksToWait = 0;
  1470.         }
  1471. #else
  1472.         // Determine the appropriate time to schedule this frame for display.
  1473.         // The basic idea is to map the time stamp with a vertical retrace.
  1474.         // When the refresh rate is evenly divisible by video frame rate there
  1475.         // will be an even map but the rest of the time we must approximate.
  1476.         //
  1477.         // The approximation is simple, find the vtrace the time stamps maps
  1478.         // to, calculate the time of this vtrace and compare this value with
  1479.         // the next vtrace.  Select the one that is closest to the time stamp.
  1480.         double dBltTime1 = pItem->lTimeStamp - (dVblanksToWait-(INT32)dVblanksToWait)*pWindraw->dMsPerVBlank;
  1481.         double dBltTime2 = dBltTime1 + pWindraw->dMsPerVBlank;
  1482.         double dBltTime;
  1483.         if ( fabs(dBltTime1-pItem->lTimeStamp) < fabs( dBltTime2-pItem->lTimeStamp))
  1484.         {
  1485.             dBltTime = dBltTime1;
  1486.             nVblanksToWait = (INT32)dVblanksToWait;
  1487.         }
  1488.         else
  1489.         {
  1490.             dBltTime = dBltTime2;
  1491.             nVblanksToWait = (INT32)(dVblanksToWait + 1);
  1492.         }
  1493.         INT32 nScheduleTime = dBltTime - nMaxVBlanksPerSchedule*pWindraw->dMsPerVBlank;
  1494.         // Ignore scheduling when the clock stops updating to avoid an infinite loop
  1495.         if (m_bFlushing || hr == HXR_TIMELINE_SUSPENDED)
  1496.         {
  1497.             nVblanksToWait = max(min(nVblanksToWait,nMaxVBlanksPerSchedule-1), 0);
  1498.             ulTime = nScheduleTime+1;
  1499.         }
  1500. #endif //KAYA_CODE
  1501.         // If the clock is within our allowed scheduling time, schedule the blt
  1502.         if (ulTime > nScheduleTime)
  1503.         {
  1504.             #ifdef LOG_JITTER_DATA
  1505.             FILE *fp = fopen(JITTER_LOG_FILE, "a+");
  1506.             if (fp)
  1507.             {
  1508.                 fprintf(fp, "Ready to flip: ts %ld clock %ld scan line %ld mstvb %.3f vbw %.3f jitter %ldn",
  1509.                              pItem->lTimeStamp, ulTime, dwScanLine, dMsToNextVBlank, dVblanksToWait, (INT32)(pItem->lTimeStamp-(ulTime+dMsToNextVBlank+(INT32)nVblanksToWait*pWindraw->dMsPerVBlank)));
  1510.                 fclose(fp);
  1511.             }
  1512.             #endif //LOG_JITTER_DATA
  1513.             m_dLastBlitError = pItem->lTimeStamp-(ulTime+dMsToNextVBlank+(INT32)nVblanksToWait*pWindraw->dMsPerVBlank);
  1514.             nVblanksToWait = 0;
  1515.             break;
  1516.         }
  1517.         else
  1518.         {
  1519.             // We want to wake up as soon as we can display the frame
  1520.             long lSleep = nScheduleTime - ulTime + 1;
  1521.             m_nLastDisplayTime = ulTime + lSleep;
  1522.             #ifdef LOG_JITTER_DATA
  1523.             INT32 lB4Sleep = GetBetterTickCount();
  1524.             #endif //LOG_JITTER_DATA
  1525.             if (lSleep > 0)
  1526.             {
  1527.                 #ifndef HARDCODE_GRANULE
  1528.                 if (nResolution)
  1529.                     timeBeginPeriod(nResolution);
  1530.                 #endif //HARDCODE_GRANULE
  1531.                 WaitForMultipleObjects(2, aWaitObjects, FALSE, lSleep);
  1532.                 #ifndef HARDCODE_GRANULE
  1533.                 if (nResolution)
  1534.                     timeEndPeriod(nResolution);
  1535.                 #endif //HARDCODE_GRANULE
  1536.             }
  1537.             m_nLastDisplayTime = -1;
  1538.             #ifdef LOG_JITTER_DATA
  1539.             FILE *fp = fopen(JITTER_LOG_FILE, "a+");
  1540.             if (fp)
  1541.             {
  1542.                 fprintf(fp, "ts %ld clock %ld scan line %ld mstvb %.3f vbw %.3f sleep %ld sleep dur %ldn",
  1543.                               pItem->lTimeStamp, ulTime, dwScanLine, dMsToNextVBlank, dVblanksToWait, lSleep, GetBetterTickCount()-lB4Sleep);
  1544.                 fclose(fp);
  1545.             }
  1546.             #endif //LOG_JITTER_DATA
  1547.             if (lSleep < 0)
  1548.                 break;
  1549.         }
  1550.     }
  1551. #ifdef ENABLE_ERROR_TRACE
  1552.     //char szTmp[1000];
  1553.     //HX_TRACE("%lut:: blit error: %fn", pItem->lTimeStamp, (dIdealVBlank - dVblanksToWait)*pWindraw->dMsPerVBlank);
  1554.     //sprintf(szTmp, "Timing error: %fn", (dIdealVBlank - dVblanksToWait)*pWindraw->dMsPerVBlank);
  1555.     g_error[g_ulFrameCount % 10000][0] = dTickAtStreamTime;
  1556.     g_error[g_ulFrameCount % 10000][1] = m_dLastBlitError*pWindraw->dMsPerVBlank;
  1557.     g_error[g_ulFrameCount % 10000][2] = dIdealVBlank;
  1558.     g_alternateError[g_ulFrameCount++ % 10000] = pItem->lTimeStamp - (INT32) ulTime;
  1559.     // Get the DC and render this to the screen:
  1560.     //OutputDebugString(szTmp);
  1561. #endif // ENABLE_ERROR_TRACE
  1562.     // Set the minimum time this frame needs to be displayed (1 vblank)
  1563.     pItem->dTimeAvailable = dTickAtStreamTime + dMsToNextVBlank + (nVblanksToWait+1)*pWindraw->dMsPerVBlank + 1;
  1564.     HX_ASSERT(pItem->dTimeAvailable);
  1565.     // Set the DD flags for interval flipping
  1566.     if (pItem->nBltMode == HX_OVERLAY_BLT && m_bUseVBlankFlip)
  1567.     {
  1568.         switch((INT32)nVblanksToWait+1)
  1569.         {
  1570.             case 4: pItem->dwDDFlags = DDFLIP_INTERVAL4; break;
  1571.             case 3: pItem->dwDDFlags = DDFLIP_INTERVAL3; break;
  1572.             case 2: pItem->dwDDFlags = DDFLIP_INTERVAL2; break;
  1573.             default:pItem->dwDDFlags = 0;
  1574.         }
  1575.     }
  1576.     return hr;
  1577. }
  1578. double CWinSurface2::FilterScanLine(UINT32 ulScanLine, double dTickAtStreamTime,
  1579.                                     WINDRAW* pWindraw, BOOL bResetFilter)
  1580. {
  1581. #ifdef FILTER_SCAN_LINE
  1582.     // No mutex needed (for now) - this function is only called from the
  1583.     // render thread.
  1584.     // On reset, wait for vertical blank and reset m_ulScanLineFilterDepth:
  1585.     if (bResetFilter)
  1586.     {
  1587.         m_dMaxRegression = 0;
  1588.         m_ulScanLineFilterDepth = 0;
  1589.         return 0;
  1590.     }
  1591.     // This filter should adjust the max scan line (i.e. vertical refresh time),
  1592.     // refresh rate, and current scan line.  It is critical that we at least get
  1593.     // the phase (scan line) accurate.
  1594.     double currentRefresh = ulScanLine / pWindraw->dMsPerVBlank;
  1595.     UINT32 ulSamplesUsed = 0;
  1596.     double m;
  1597.     double b;
  1598.     // Ignore both zero and max scan line; some drivers play games with these.
  1599.     if (ulScanLine == 0 && ulScanLine != pWindraw->dwMaxScanLine)
  1600.     {
  1601.         // Add to filter:
  1602.         m_scanLineFilter[m_ulScanLineFilterDepth % SCAN_LINE_FILTER_DEPTH][0] = dTickAtStreamTime;
  1603.         m_scanLineFilter[m_ulScanLineFilterDepth++ % SCAN_LINE_FILTER_DEPTH][1]= currentRefresh;
  1604. #ifdef _DEBUG
  1605.         double dLastPhaseError;
  1606. #endif // _DEBUG
  1607.         // If we assume our refresh + scan line error is +/- 5%, then our
  1608.         // phase error should be monotonic to 20 past vblanks.
  1609.         // Perform a linear regression to correct our sample, if needed.
  1610.         double  sumX,
  1611.                 sumY,
  1612.                 sumXY,
  1613.                 sumXSquared,
  1614.                 sumYSquared = 0;
  1615.         for (int i = 1; i < m_ulScanLineFilterDepth && i < SCAN_LINE_FILTER_DEPTH; ++i)
  1616.         {
  1617.             double elapsedTime = m_scanLineFilter[(m_ulScanLineFilterDepth - i - 1) % SCAN_LINE_FILTER_DEPTH][0] -
  1618.                                  m_scanLineFilter[(m_ulScanLineFilterDepth - i) % SCAN_LINE_FILTER_DEPTH][0];
  1619.             if (elapsedTime >= 10*pWindraw->dMsPerVBlank)
  1620.             {
  1621.                 continue;
  1622.             }
  1623. #ifdef _DEBUG
  1624.             // Monotonic?
  1625. #endif // _DEBUG
  1626.             ulSamplesUsed++;
  1627.             double refresh = (m_scanLineFilter[(m_ulScanLineFilterDepth - i - 1) % SCAN_LINE_FILTER_DEPTH][1] / pWindraw->dMsPerVBlank) + fmod(elapsedTime, pWindraw->dMsPerVBlank);
  1628.             refresh = refresh - (INT32) refresh;
  1629.             double error = m_scanLineFilter[(m_ulScanLineFilterDepth - i) % SCAN_LINE_FILTER_DEPTH][1] - refresh;
  1630.             //HX_TRACE("terror : %lfn", error);
  1631.             sumX += elapsedTime;
  1632.             sumY += error;
  1633.             sumXY = elapsedTime*error;
  1634.             sumXSquared += elapsedTime*elapsedTime;
  1635.             sumYSquared += error*error;
  1636.         }
  1637.         if (ulSamplesUsed < 100)
  1638.         {
  1639.             //HX_TRACE("skipn");
  1640.             goto nofilter;
  1641.         }
  1642.         double meanX = sumX / ulSamplesUsed;
  1643.         double meanY = sumY / ulSamplesUsed;
  1644.         double sumSquaredErrorX = 0;
  1645.         double sumSquaredErrorY = 0;
  1646.         double sumErrorProduct = 0;
  1647.         for (i = 1; i < m_ulScanLineFilterDepth && i < SCAN_LINE_FILTER_DEPTH; ++i)
  1648.         {
  1649.             double elapsedTime = m_scanLineFilter[(m_ulScanLineFilterDepth - i - 1) % SCAN_LINE_FILTER_DEPTH][0] -
  1650.                                  m_scanLineFilter[(m_ulScanLineFilterDepth - i) % SCAN_LINE_FILTER_DEPTH][0];
  1651.             if (elapsedTime >= 10*pWindraw->dMsPerVBlank)
  1652.             {
  1653.                 continue;
  1654.             }
  1655.             double refresh = (m_scanLineFilter[(m_ulScanLineFilterDepth - i - 1) % SCAN_LINE_FILTER_DEPTH][1] / pWindraw->dMsPerVBlank) + fmod(elapsedTime, pWindraw->dMsPerVBlank);
  1656.             refresh = refresh - (INT32) refresh;
  1657.             double error = m_scanLineFilter[(m_ulScanLineFilterDepth - i) % SCAN_LINE_FILTER_DEPTH][1] - refresh;
  1658.             sumSquaredErrorX += (elapsedTime - meanX)*(elapsedTime - meanX);
  1659.             sumSquaredErrorY += (error - meanY)*(error - meanY);
  1660.             sumErrorProduct += (elapsedTime - meanX)*(error - meanY);
  1661.         }
  1662.         double rho = sumErrorProduct / sqrt(sumSquaredErrorX*sumSquaredErrorY);
  1663.         //double rho = (sumXY - ((sumX*sumY) / ulSamplesUsed)) /
  1664.         //             sqrt((sumXSquared - ((sumX*sumX) / ulSamplesUsed))*(sumYSquared - ((sumY*sumY) / ulSamplesUsed)));
  1665.         double stdDevX = sumSquaredErrorX / ulSamplesUsed - 1;
  1666.         double stdDevY = sumSquaredErrorY / ulSamplesUsed - 1;
  1667.         m = rho*stdDevY/stdDevX;
  1668.         b = meanY - (m*meanX);
  1669.         //HX_TRACE("current phase error: %lfn");
  1670.         //HX_TRACE("current refresh error: %lfn");
  1671.         // Do we have enough data to update our phase point
  1672. #if 0
  1673.         if (rho >= MIN_ALLOWED_REGRESSION)
  1674.         {
  1675.             m_dMaxRegression = rho;
  1676.             HX_TRACE("current rho: %lfn", rho);
  1677.             HX_TRACE("current m: %lfn", m);
  1678.             HX_TRACE("current b: %lfn", b);
  1679.             // Regression still has a sample delay; let's not worry about it for
  1680.             // now; nor any error due to an inaccurate max scan line.
  1681.             // Update refresh rate:
  1682.             // A negative slope = error decreasing back in time, increasing forwards in time.
  1683.             // Refresh rate should increase.
  1684.             // Positive slope = error increasing back in time, decreasing forwards in time.
  1685.             // Refresh rate should decrease.
  1686.             pWindraw->dRefreshRate -= m*1000;
  1687.             pWindraw->dMsPerVBlank = 1 / pWindraw->dRefreshRate;
  1688.             HX_TRACE("new refresh: %lfn", pWindraw->dRefreshRate);
  1689.             // Update phase point:
  1690.             currentRefresh -= b;
  1691.             if (currentRefresh > 0)
  1692.             {
  1693.                 m_dPhasePoint = dTickAtStreamTime - (currentRefresh)/pWindraw->dMsPerVBlank;
  1694.             }
  1695.             else
  1696.             {
  1697.                 m_dPhasePoint = dTickAtStreamTime - ((currentRefresh)+1)/pWindraw->dMsPerVBlank;
  1698.             }
  1699.         }
  1700. #endif // 0
  1701.     }
  1702.     //if (m_dMaxRegression >= MIN_ALLOWED_REGRESSION)
  1703.     {
  1704.         double dRefreshes = (dTickAtStreamTime - m_dPhasePoint) / pWindraw->dMsPerVBlank;
  1705.         HX_TRACE("current b: %lfn", b);
  1706.         dRefreshes -= b;
  1707.         if (dRefreshes < 0)
  1708.         {
  1709.             dRefreshes++;
  1710.         }
  1711.         double dScanLine = (dRefreshes - ((UINT32) dRefreshes))*(pWindraw->dwMaxScanLine + 1);
  1712.         // If we're off by less than 15%, let it slide?
  1713.         return fabs(dScanLine - ulScanLine) / (pWindraw->dwMaxScanLine + 1) > 15
  1714.             ? dScanLine : ulScanLine;
  1715.     }
  1716. #endif // FILTER_SCAN_LINE
  1717. #ifdef FILTER_SCAN_LINE
  1718. nofilter:
  1719. #endif
  1720.     return ulScanLine;
  1721. }