helldrg Опубликовано 9 октября, 2016 Поделиться Опубликовано 9 октября, 2016 (изменено) Здравствуйте! Об этом много написано с применением DirectX и Opengl, но вот с WinAPI я один раз встречал на англоязычном стриме. Выкладываю код класса, возможности: установка фпс приложения и вывод некоторой информации. Имеется не большой баг, что фпс колеблется, но так наверно везде устроено. Может кому то пригодится, меня вот раньше напрягало, когда пустой цикл нагружал процессор на 12 -15%. Если есть идеи как можно улучшить класс с точки зрения производительности, логики и т.д. и т.п. или же есть какая то ошибка недочет пишите! Долой быдло код и необразованность!!! Вот скриншот вывода информации: Скрытый текст Код: Скрытый текст #if !defined(VSYNCCLASS_H) #include <Windows.h> #include <stdio.h> #pragma comment(lib, "winmm.lib") class VSyncClass { public: VSyncClass(); void Begin(int fps); // In front of while void End(bool printInfo); // End while // Additional function float GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end); LARGE_INTEGER GetCounter(); LARGE_INTEGER GetFrequency(); private: LARGE_INTEGER m_perfCountFrequency; float m_targetSecondsPerFrame = 0.0f; LARGE_INTEGER m_lastCounter = {}; INT64 m_lastCycleCount = 0; bool m_sleepIsGranular = false; }; #define VSYNCCLASS_H #endif Скрытый текст #include "vsyncclass.h" VSyncClass::VSyncClass() { m_perfCountFrequency = {}; m_targetSecondsPerFrame = 0.0f; m_lastCounter = {}; m_lastCycleCount = 0; m_sleepIsGranular = false; } void VSyncClass::Begin(int fps) { QueryPerformanceFrequency(&m_perfCountFrequency); m_targetSecondsPerFrame = (1.0f / (float)fps); UINT DesiredSchedulerMS = 1; m_sleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR); m_lastCounter = GetCounter(); m_lastCycleCount = __rdtsc(); } void VSyncClass::End(bool printInfo) { float secondsElapsedForFrame = GetSecondsElapsed(m_lastCounter, GetCounter()); if (secondsElapsedForFrame < m_targetSecondsPerFrame) { if (m_sleepIsGranular) { DWORD sleepMS = (DWORD)(1000.0f * (m_targetSecondsPerFrame - secondsElapsedForFrame)); if (sleepMS > 0) { Sleep(sleepMS); } } while (secondsElapsedForFrame < m_targetSecondsPerFrame) { secondsElapsedForFrame = GetSecondsElapsed(m_lastCounter, GetCounter()); } } LARGE_INTEGER endCounter = GetCounter(); INT64 counterElapsed = endCounter.QuadPart - m_lastCounter.QuadPart; INT64 endCycleCount = __rdtsc(); INT64 cyclesElapsed = endCycleCount - m_lastCycleCount; if (printInfo == true) { double FPS = (double)m_perfCountFrequency.QuadPart / (double)counterElapsed; double MSPerFrame = 1000.0f * GetSecondsElapsed(m_lastCounter, endCounter); double MCPF = ((double)cyclesElapsed / (1000.0f * 1000.0f)); char Buffer[256]; _snprintf_s(Buffer, sizeof(Buffer), "%.02fms/f, %.02ff/s, %.02fmc/f\n", MSPerFrame, FPS, MCPF); OutputDebugStringA(Buffer); } m_lastCounter = endCounter; m_lastCycleCount = endCycleCount; } float VSyncClass::GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) { float result = ((float)(end.QuadPart - start.QuadPart) / (float)m_perfCountFrequency.QuadPart); return result; } LARGE_INTEGER VSyncClass::GetCounter() { LARGE_INTEGER result; QueryPerformanceCounter(&result); return result; } LARGE_INTEGER VSyncClass::GetFrequency() { LARGE_INTEGER result; QueryPerformanceFrequency(&result); return result; } В проект добавляется так: Скрытый текст VSyncClass VSync; VSync.Begin(30);// Обязательно перед циклом while (globalRunning) { if (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&message); DispatchMessage(&message); } ............................................................ VSync.End(true);//обязательно в конце цикла } Изменено 9 октября, 2016 пользователем helldrg 2 Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения