diff --git a/msvc/hexgame.vcxproj b/msvc/hexgame.vcxproj index 48da8a3..fa04d07 100644 --- a/msvc/hexgame.vcxproj +++ b/msvc/hexgame.vcxproj @@ -22,7 +22,7 @@ 15.0 {A20061AD-7985-4275-96C6-A25215941A26} Win32Proj - 10.0.16299.0 + 10.0.17134.0 @@ -100,20 +100,22 @@ - D:\dev\lib\glm;D:\dev\lib\gl3w\include;D:\dev\projects\hexgame\ext\imgui;D:\dev\projects\hexgame\ext\aixlog\include;D:\dev\lib\SDL2-2.0.8\include;D:\dev\lib\SDL2_image-2.0.3\include;D:\dev\lib\Assimp\include;%(AdditionalIncludeDirectories) + C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\shared;C:\Program Files %28x86%29\Windows Kits\10\Include\10.0.17134.0\km;D:\dev\lib\glm;D:\dev\lib\gl3w\include;D:\dev\projects\hexgame\ext\imgui;D:\dev\projects\hexgame\ext\aixlog\include;D:\dev\lib\SDL2-2.0.8\include;D:\dev\lib\SDL2_image-2.0.3\include;D:\dev\lib\Assimp\include;%(AdditionalIncludeDirectories) D:\dev\lib\Assimp\lib\x64;D:\dev\lib\SDL2_image-2.0.3\lib\x64;D:\dev\lib\SDL2-2.0.8\lib\x64;%(AdditionalLibraryDirectories) SDL2.lib;SDL2_image.lib;Opengl32.lib;assimp-vc140-mt.lib;%(AdditionalDependencies) + NotSet - D:\dev\lib\glm;D:\dev\lib\gl3w\include;D:\dev\projects\hexgame\ext\imgui;D:\dev\projects\hexgame\ext\aixlog\include;D:\dev\lib\SDL2-2.0.8\include;D:\dev\lib\SDL2_image-2.0.3\include;D:\dev\lib\Assimp\include;%(AdditionalIncludeDirectories) + C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\shared;C:\Program Files %28x86%29\Windows Kits\10\Include\10.0.17134.0\km;D:\dev\lib\glm;D:\dev\lib\gl3w\include;D:\dev\projects\hexgame\ext\imgui;D:\dev\projects\hexgame\ext\aixlog\include;D:\dev\lib\SDL2-2.0.8\include;D:\dev\lib\SDL2_image-2.0.3\include;D:\dev\lib\Assimp\include;%(AdditionalIncludeDirectories) D:\dev\lib\Assimp\lib\x64;D:\dev\lib\SDL2_image-2.0.3\lib\x64;D:\dev\lib\SDL2-2.0.8\lib\x64;%(AdditionalLibraryDirectories) SDL2.lib;SDL2_image.lib;Opengl32.lib;assimp-vc140-mt.lib;%(AdditionalDependencies) + NotSet diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 2366c93..cd6b225 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -25,6 +25,7 @@ #define VIEWPORT_WIDTH 1920 #define VIEWPORT_HEIGHT 1080 #define CONE_ANGLE 30 +#define VSYNC_ENABLED true #include @@ -39,6 +40,11 @@ #include +// TODO: replace aixlog with simpler logging +#if defined(_WIN32) +#pragma warning(push) +#pragma warning(disable : 4003) +#endif #include "aixlog.hpp" #include "util.h" @@ -47,6 +53,7 @@ #include "renderer.h" #include "gooey.h" #include "mesh.h" +#include "platform_wait_for_vblank.h" using std::vector; @@ -562,19 +569,26 @@ int main(int argc, char* argv[]) LOG(ERROR) << "Fooey, No Gooey!\n"; return 1; } - + + if (!platform_init(handles.window)) { + LOG(ERROR) << "Couldn't get SDL platform info, exiting\n"; + return 1; + } + // main loop while (processSDLEvents()) { - // TODO: remove hack to not peg CPU. replace with an actual frame timer +#if defined(_WIN32) + // sort-of fixed in windows with platform_wait_for_vblank() +#else + LOG(DEBUG) << "TODO: Implement better frame timer on linux\n"; // should notice this SDL_Delay(16); // ~60hz +#endif game_state* g = g_game_state; render_state* r = g_render_state; moveCamera(g->is_moveup, g->is_moveleft, g->is_movedown, g->is_moveright, g->is_moveforward, g->is_movebackward); - rollCamera(g->is_rotateCW, g->is_rotateCCW); - renderFrame(g->hex_array, g_render_state->entities, g_render_state->entity_count); if (r->is_debug_draw && g->draw_mode == CONE_FILL) @@ -584,6 +598,8 @@ int main(int argc, char* argv[]) g->current_hex, g->is_selecting, getCameraPosition()); SDL_GL_SwapWindow(handles.window); + + platform_wait_for_vblank(VSYNC_ENABLED); } cleanUp(handles); diff --git a/src/platform_wait_for_vblank.h b/src/platform_wait_for_vblank.h new file mode 100644 index 0000000..d11a353 --- /dev/null +++ b/src/platform_wait_for_vblank.h @@ -0,0 +1,102 @@ + +// attempt to fix vsync with opengl on windows +// https://bugs.chromium.org/p/chromium/issues/detail?id=467617 +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/d3dkmthk/nf-d3dkmthk-d3dkmtwaitforverticalblankevent +// NOTE: requires installing windows driver kit addon for msvc +// TODO: not working with hdc provided by SDL, try enumerating display devices as described here: +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/d3dkmthk/nf-d3dkmthk-d3dkmtopenadapterfromhdc +// NOTE: the above seems to make some difference in lowering cpu usage, but cpu stays at max frequency even when relatively idle. + +// TODO: if d3dkmt... doensn't work, try DWMFlush() https://docs.microsoft.com/en-us/windows/desktop/api/dwmapi/nf-dwmapi-dwmflush +// glfw uses this https://github.com/glfw/glfw/blob/master/src/wgl_context.c +// +// if that doesn't work... https://docs.microsoft.com/en-us/windows/desktop/api/timeapi/nf-timeapi-timebeginperiod +// to increase schedular granularity. can then use sleep(1) for 1ms resolution + +#pragma once + +#include + +#include "SDL_syswm.h" + +#if defined(_WIN32) +#include "windows.h" +#include "d3dkmthk.h" + +typedef uint32_t D3DKMT_HANDLE; +typedef struct { + D3DKMT_HANDLE hAdapter = NULL; + UINT vidID = 0; +} platform_win_device_handles; +platform_win_device_handles g_platform_win_device_handles; + +#endif // _WIN32 + + +inline bool +platform_init(SDL_Window* window) +{ +#if defined(_WIN32) + D3DKMT_HANDLE hAdapter = NULL; + UINT vidID = 0; + D3DKMT_OPENADAPTERFROMHDC OpenAdapterData; + DISPLAY_DEVICE dd; + HDC hdc; + + memset(&dd, 0, sizeof(dd)); + dd.cb = sizeof dd; + + for (int i = 0; EnumDisplayDevicesA(NULL, i, &dd, 0); ++i) { + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + break; + } + + hdc = CreateDC(NULL, dd.DeviceName, NULL, NULL); + if (hdc == NULL) + return false; + + OpenAdapterData.hDc = hdc; + if ((D3DKMTOpenAdapterFromHdc(&OpenAdapterData)) >= 0) { + DeleteDC(hdc); + g_platform_win_device_handles.hAdapter = OpenAdapterData.hAdapter; + g_platform_win_device_handles.vidID = OpenAdapterData.VidPnSourceId; + return true; + } + + DeleteDC(hdc); + return false; +#endif // _WIN32 + + return true; +} + +inline void +platform_wait_for_vblank(bool wait=true) +{ + if (!wait) return; + +#if defined(_WIN32) + _D3DKMT_WAITFORVERTICALBLANKEVENT waitForVBlankData; + memset(&waitForVBlankData, 0, sizeof(waitForVBlankData)); + waitForVBlankData.hAdapter = g_platform_win_device_handles.hAdapter; + waitForVBlankData.VidPnSourceId = g_platform_win_device_handles.vidID; + NTSTATUS ret = D3DKMTWaitForVerticalBlankEvent(&waitForVBlankData); + + switch (ret) { + case 0x00000000: // STATUS_SUCCESS + //OutputDebugString("Success\r\n"); + break; + //case STATUS_DEVICE_REMOVED: + // OutputDebugString("STATUS_DEVICE_REMOVED\r\n"); + // break; + case STATUS_INVALID_PARAMETER: + OutputDebugString("STATUS_INVALID_PARAMETER\r\n"); + break; + default: + OutputDebugString("????"); + } +#endif // _WIN32 + + // TODO: implement/test for linux +} + diff --git a/src/renderer.cpp b/src/renderer.cpp index 6a0a892..49f74a5 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -224,18 +224,27 @@ initRenderer(SDL_Handles &handles, v2i vpDims) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetSwapInterval(1); // vsync SDL_GetCurrentDisplayMode(0, &handles.currentDisplayMode); handles.window = SDL_CreateWindow("hexgame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, vpDims.x, vpDims.y, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); + + if (!handles.window) { + LOG(ERROR) << "Error creating window: " << SDL_GetError() << "\n"; + return false; + } - if (handles.window == NULL) { - LOG(ERROR) << SDL_GetError() << "\n"; + handles.glContext = SDL_GL_CreateContext(handles.window); + + if (!handles.glContext) { + LOG(ERROR) << "Error creating glContext: " << SDL_GetError() << "\n"; return false; } - handles.glContext = SDL_GL_CreateContext(handles.window); + if (SDL_GL_SetSwapInterval(1) != 0) { // vsync + LOG(ERROR) << "SDL Errors: " << SDL_GetError() << "\n"; + return false; + } if (gl3wInit()) { // TODO: decide on extension library LOG(ERROR) << "failed to initialize OpenGL\n";