winsurf2.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:135k
源码类别:

Symbian

开发平台:

C/C++

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