Beispiel #1
0
static void swapBuffersWGL(_GLFWwindow* window)
{
    // HACK: Use DwmFlush when desktop composition is enabled
    if (_glfwIsCompositionEnabledWin32() && !window->monitor)
    {
        int count = abs(window->context.wgl.interval);
        while (count--)
            DwmFlush();
    }

    SwapBuffers(window->context.wgl.dc);
}
Beispiel #2
0
static void swapBuffersWGL(_GLFWwindow* window)
{
    if (!window->monitor)
    {
        if (IsWindowsVistaOrGreater())
        {
            BOOL enabled;

            // HACK: Use DwmFlush when desktop composition is enabled
            if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
            {
                int count = abs(window->context.wgl.interval);
                while (count--)
                    DwmFlush();
            }
        }
    }

    SwapBuffers(window->context.wgl.dc);
}
Beispiel #3
0
static bool compositor_active(MPGLContext *ctx)
{
    // For Windows 7.
    BOOL enabled = 0;
    if (FAILED(DwmIsCompositionEnabled(&enabled)) || !enabled)
        return false;

    // This works at least on Windows 8.1: it returns an error in fullscreen,
    // which is also when we get consistent timings without DwmFlush. Might
    // be cargo-cult.
    DWM_TIMING_INFO info = { .cbSize = sizeof(DWM_TIMING_INFO) };
    if (FAILED(DwmGetCompositionTimingInfo(0, &info)))
        return false;

    // Test if a program is running in exclusive fullscreen mode. If so, it's
    // probably this one, so it's not getting redirected by the compositor.
    if (mp_w32_is_in_exclusive_mode())
        return false;

    return true;
}

static void w32_swap_buffers(MPGLContext *ctx)
{
    struct w32_context *w32_ctx = ctx->priv;
    SwapBuffers(w32_ctx->hdc);

    // default if we don't DwmFLush
    int new_swapinterval = w32_ctx->opt_swapinterval;

    if (ctx->dwm_flush_opt >= 0) {
        if ((ctx->dwm_flush_opt == 1 && !ctx->vo->opts->fullscreen) ||
            (ctx->dwm_flush_opt == 2) ||
            (ctx->dwm_flush_opt == 0 && compositor_active(ctx)))
        {
            if (DwmFlush() == S_OK)
                new_swapinterval = 0;
        }
    }

    if (new_swapinterval != w32_ctx->current_swapinterval &&
        w32_ctx->real_wglSwapInterval)
    {
        w32_ctx->real_wglSwapInterval(new_swapinterval);
        MP_VERBOSE(ctx->vo, "set SwapInterval(%d)\n", new_swapinterval);
    }
    w32_ctx->current_swapinterval = new_swapinterval;
}

static int w32_control(MPGLContext *ctx, int *events, int request, void *arg)
{
    return vo_w32_control(ctx->vo, events, request, arg);
}

const struct mpgl_driver mpgl_driver_w32 = {
    .name           = "w32",
    .priv_size      = sizeof(struct w32_context),
    .init           = w32_init,
    .reconfig       = w32_reconfig,
    .swap_buffers   = w32_swap_buffers,
    .control        = w32_control,
    .uninit         = w32_uninit,
};
Beispiel #4
0
static LRESULT CALLBACK ShieldWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int left, top, width, height;
    static HDC whiteCtx, blackCtx;
    static HBITMAP white, black;
    static uint8_t* buffer;

    switch (message)
    {
    case WM_CREATE:
    {
        CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
        HDC desktop = GetDC(NULL);

        buffer = cs->lpCreateParams;
        left = cs->x;
        top = cs->y;
        width = cs->cx;
        height = cs->cy;

        /* These bitmaps will be used to store the light and dark
           screenshots */
        whiteCtx = CreateCompatibleDC(desktop);
        white = CreateCompatibleBitmap(desktop, width, height);
        blackCtx = CreateCompatibleDC(desktop);
        black = CreateCompatibleBitmap(desktop, width, height);
        ReleaseDC(NULL, desktop);

        if (!whiteCtx || !white || !blackCtx || !black)
            return -1;

        SetTimer(window, 101, 0, NULL);

        return 0;
    }
    case WM_TIMER:
    {
        HDC desktop = GetDC(NULL);

        KillTimer(window, 101);
        DwmFlush();

        /* The shield window is created with a white background, so take
           the first screenshot */
        SelectObject(whiteCtx, white);
        BitBlt(whiteCtx, 0, 0, width, height, desktop, left, top, SRCCOPY | CAPTUREBLT);

        /* Change the window background to black and update it */
        SetClassLongPtr(window, GCLP_HBRBACKGROUND, (long)GetStockObject(BLACK_BRUSH));
        InvalidateRect(window, NULL, TRUE);
        UpdateWindow(window);
        DwmFlush();

        /* Now take the second screenshot */
        SelectObject(blackCtx, black);
        BitBlt(blackCtx, 0, 0, width, height, desktop, left, top, SRCCOPY | CAPTUREBLT);

        ReleaseDC(NULL, desktop);
        DestroyWindow(window);

        return 0;
    }
    case WM_DESTROY:
    {
        size_t pitch = width * 4,
               size = height * pitch;
        uint8_t* blackBuf = xmalloc(size);

        GetBits(buffer, width, height, white, whiteCtx);
        DeleteDC(whiteCtx);
        DeleteObject(white);

        GetBits(blackBuf, width, height, black, blackCtx);
        DeleteDC(blackCtx);
        DeleteObject(black);

        /* Get an image with an alpha channel from both bitmaps */
        ProcessAlpha(buffer, blackBuf, size);
        free(blackBuf);

        /* Exit this modal message loop so the program can continue */
        PostQuitMessage(0);
        return 0;
    }
    }

    return DefWindowProc(window, message, wParam, lParam);
}
/** Blocks the CPU to synchronize with vblank by communicating with DWM. */
void FD3D11Viewport::PresentWithVsyncDWM()
{
#if D3D11_WITH_DWMAPI
	LARGE_INTEGER Cycles;
	DWM_TIMING_INFO TimingInfo;

	// Find out how long since we last flipped and query DWM for timing information.
	QueryPerformanceCounter(&Cycles);
	FMemory::MemZero(TimingInfo);
	TimingInfo.cbSize = sizeof(DWM_TIMING_INFO);
	DwmGetCompositionTimingInfo(WindowHandle, &TimingInfo);

	uint64 QpcAtFlip = Cycles.QuadPart;
	uint64 CyclesSinceLastFlip = Cycles.QuadPart - LastFlipTime;
	float CPUTime = FPlatformTime::ToMilliseconds(CyclesSinceLastFlip);
	float GPUTime = FPlatformTime::ToMilliseconds(TimingInfo.qpcFrameComplete - LastCompleteTime);
	float DisplayRefreshPeriod = FPlatformTime::ToMilliseconds(TimingInfo.qpcRefreshPeriod);

	// Find the smallest multiple of the refresh rate that is >= 33ms, our target frame rate.
	float RefreshPeriod = DisplayRefreshPeriod;
	if (RHIConsoleVariables::bForceThirtyHz && RefreshPeriod > 1.0f)
	{
		while (RefreshPeriod - (1000.0f / 30.0f) < -1.0f)
		{
			RefreshPeriod *= 2.0f;
		}
	}

	// If the last frame hasn't completed yet, we don't know how long the GPU took.
	bool bValidGPUTime = (TimingInfo.cFrameComplete > LastFrameComplete);
	if (bValidGPUTime)
	{
		GPUTime /= (float)(TimingInfo.cFrameComplete - LastFrameComplete);
	}

	// Update the sync counter depending on how much time it took to complete the previous frame.
	float FrameTime = FMath::Max<float>(CPUTime, GPUTime);
	if (FrameTime >= RHIConsoleVariables::SyncRefreshThreshold * RefreshPeriod)
	{
		SyncCounter--;
	}
	else if (bValidGPUTime)
	{
		SyncCounter++;
	}
	SyncCounter = FMath::Clamp<int32>(SyncCounter, 0, RHIConsoleVariables::MaxSyncCounter);

	// If frames are being completed quickly enough, block for vsync.
	bool bSync = (SyncCounter >= RHIConsoleVariables::SyncThreshold);
	if (bSync)
	{
		// This flushes the previous present call and blocks until it is made available to DWM.
		D3DRHI->GetDeviceContext()->Flush();
		DwmFlush();

		// We sleep a percentage of the remaining time. The trick is to get the
		// present call in after the vblank we just synced for but with time to
		// spare for the next vblank.
		float MinFrameTime = RefreshPeriod * RHIConsoleVariables::RefreshPercentageBeforePresent;
		float TimeToSleep;
		do 
		{
			QueryPerformanceCounter(&Cycles);
			float TimeSinceFlip = FPlatformTime::ToMilliseconds(Cycles.QuadPart - LastFlipTime);
			TimeToSleep = (MinFrameTime - TimeSinceFlip);
			if (TimeToSleep > 0.0f)
			{
				FPlatformProcess::Sleep(TimeToSleep * 0.001f);
			}
		}
		while (TimeToSleep > 0.0f);
	}

	// Present.
	PresentChecked(/*SyncInterval=*/ 0);

	// If we are forcing <= 30Hz, block the CPU an additional amount of time if needed.
	// This second block is only needed when RefreshPercentageBeforePresent < 1.0.
	if (bSync)
	{
		LARGE_INTEGER LocalCycles;
		float TimeToSleep;
		bool bSaveCycles = false;
		do 
		{
			QueryPerformanceCounter(&LocalCycles);
			float TimeSinceFlip = FPlatformTime::ToMilliseconds(LocalCycles.QuadPart - LastFlipTime);
			TimeToSleep = (RefreshPeriod - TimeSinceFlip);
			if (TimeToSleep > 0.0f)
			{
				bSaveCycles = true;
				FPlatformProcess::Sleep(TimeToSleep * 0.001f);
			}
		}
		while (TimeToSleep > 0.0f);

		if (bSaveCycles)
		{
			Cycles = LocalCycles;
		}
	}

	// If we are dropping vsync reset the counter. This provides a debounce time
	// before which we try to vsync again.
	if (!bSync && bSyncedLastFrame)
	{
		SyncCounter = 0;
	}

	if (bSync != bSyncedLastFrame || UE_LOG_ACTIVE(LogRHI,VeryVerbose))
	{
		UE_LOG(LogRHI,Verbose,TEXT("BlockForVsync[%d]: CPUTime:%.2fms GPUTime[%d]:%.2fms Blocked:%.2fms Pending/Complete:%d/%d"),
			bSync,
			CPUTime,
			bValidGPUTime,
			GPUTime,
			FPlatformTime::ToMilliseconds(Cycles.QuadPart - QpcAtFlip),
			TimingInfo.cFramePending,
			TimingInfo.cFrameComplete);
	}

	// Remember if we synced, when the frame completed, etc.
	bSyncedLastFrame = bSync;
	LastFlipTime = Cycles.QuadPart;
	LastFrameComplete = TimingInfo.cFrameComplete;
	LastCompleteTime = TimingInfo.qpcFrameComplete;
#endif	//D3D11_WITH_DWMAPI
}
Beispiel #6
0
void  VSyncWin::VSyncLoop()
{
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);

	DWM_TIMING_INFO vblankTime;
	// Make sure to init the cbSize, otherwise GetCompositionTiming will fail
	vblankTime.cbSize = sizeof(DWM_TIMING_INFO);

	LARGE_INTEGER frequency;
	QueryPerformanceFrequency(&frequency);
	TimeStamp vsync = Now();
	// On Windows 10, DwmGetCompositionInfo returns the upcoming vsync.
	// See GetAdjustedVsyncTimestamp.
	// On start, set mPrevVsync to the "next" vsync
	// So we'll use this timestamp on the 2nd loop iteration.
	mPrevVsync = vsync + mSoftwareVsyncRate;

	for (;;) {

#if !USING_DWM_FLUSH
		TimeStamp here = Now();

		::QueryPerformanceCounter(&gSS);
		//Sleep(1);
		//Sleep(200);

		
		m_pOutput->WaitForVBlank();

		
		//Sleep(1);
		
		m_pSwapChain->Present(0, 0);
		//DwmFlush();

		//Gdi: NtGdiDdDDIWaitForVerticalBlankEvent()
		//TimerBlit();
		//gS = gSS;
		//::PostMessageA(gHwnd, WM_BLIT_REQUEST, 0, 0);
		//TimerBlit();
		FILE *f;
		fopen_s(&f, "C:\\VSyncThread", "rb");
		//char buf[200];
		LARGE_INTEGER fi;
		char buf[200];
		::QueryPerformanceFrequency(&fi);
		sprintf_s(buf, "\n+++++ %d", int((Now() - here) * 1000000 / fi.QuadPart));
		OutputDebugStringA(buf);
#else
		::QueryPerformanceCounter(&gS);

		gTS = vsync;


		/*mWork = CreateThreadpoolWork(BlittingThread,
		(void*)&gTS,
		&mCallBackEnviron);

		SubmitThreadpoolWork(mWork);*/

		//mVSyncTimeStamp.store(vsync);
		
		char buf[1000];
		LARGE_INTEGER fi;
		//::QueryPerformanceFrequency(&fi);
		//sprintf_s(buf, "\n+++++%d", int((vsync - here) * 1000000 / fi.QuadPart));
		//OutputDebugStringA(buf);

		// Use a combination of DwmFlush + DwmGetCompositionTimingInfoPtr
		// Using WaitForVBlank, the whole system dies :/
		//m_pSwapChain->Present(0, 0);
		//::PostMessageA(gHwnd, WM_BLIT_REQUEST, 0, 0);
		//m_pSwapChain->Present(1, 0);
		//TimerBlit();
		
		HRESULT hr;
		
		hr = DwmFlush();//WinUtils::dwmFlushProcPtr();
		if (!SUCCEEDED(hr)) {
		//	// We don't actually know how long we had to wait on DWMFlush
		//	// Instead of trying to calculate how long DwmFlush actually took
		//	// Fallback to software vsync.
		//	//-->ScheduleSoftwareVsync(Now());

			return;
		}

		//dwmflush does not exactly return at next vblank 
		//TimerBlit();

		hr = DwmGetCompositionTimingInfo(0, &vblankTime);


		/*vsync = SUCCEEDED(hr) ?
		GetAdjustedVsyncTimeStamp(frequency, vblankTime.qpcVBlank) :
		Now();*/
		vsync = vblankTime.qpcVBlank;// +vblankTime.qpcRefreshPeriod;
		mVSyncTimeStamp.store(vsync);
		mBlit = true;
		////char buf[200];
		//LARGE_INTEGER l;
		//

		//QueryPerformanceFrequency(&l);
		////if (((vsync - Now()) * 1000000 / l.QuadPart) > 10000)
		//	//continue;
		///*LARGE_INTEGER le, lf;
		//QueryPerformanceCounter(&le);
		//QueryPerformanceFrequency(&lf);*/
		//sprintf_s(buf, "\nvblank Time  Now =  %u", (vsync - Now()) * 1000000 / l.QuadPart);
		//OutputDebugStringA(buf);
		//sprintf_s(buf, "\n****** ---- %llu --", vsync);
		//OutputDebugStringA(buf);
		/*sprintf_s(buf, "\nv Timed %d ", ((le.QuadPart - gS.QuadPart) * 1000000 / lf.QuadPart));
		OutputDebugStringA(buf);*/
#endif
	} // end for

}