summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-10-17 16:49:31 -0400
committerJonathan Bradley <jcb@pikum.xyz>2023-10-17 16:49:31 -0400
commiteff34c523b4816bb06ffbc19e6d368cac35f538c (patch)
tree26678623a8b854c99598da149e14e183087e9670
parentf5917baf1f3f7f1766ae3730727f83f7a708439c (diff)
large refactor for tick rate and handling vkPresentMode
-rw-r--r--src/game-settings.hpp9
-rw-r--r--src/game.cpp13
-rw-r--r--src/main.cpp61
-rw-r--r--src/window.cpp55
-rw-r--r--src/window.hpp1
5 files changed, 96 insertions, 43 deletions
diff --git a/src/game-settings.hpp b/src/game-settings.hpp
index a624bd6..cc20233 100644
--- a/src/game-settings.hpp
+++ b/src/game-settings.hpp
@@ -7,20 +7,23 @@
struct GameSettings {
bool isGameRunning = true;
bool isGamePaused = false;
- bool isFramerateUnlocked = true;
bool isShowingEditor = true;
bool isRenderingDebug = false;
std::chrono::steady_clock steadyClock;
int64_t targetFPS = 144;
int64_t minFPS = 20;
- double deltaPerFrame = 1 / double(targetFPS);
- double minimumDeltaPerFrame = 1 / double(minFPS);
+ double deltaPerFrame = 1.0 / double(targetFPS);
+ double minimumDeltaPerFrame = 1.0 / double(minFPS);
struct {
bool isShowingConsole = true;
bool isShowingEntityList = true;
bool isShowingSceneEditor = true;
bool isShowingUBO = true;
} editorSettings;
+ struct {
+ bool isFramerateUnlocked = false;
+ bool isWaitingForVsync = true;
+ } graphicsSettings;
};
extern GameSettings pkeSettings;
diff --git a/src/game.cpp b/src/game.cpp
index 5863ecc..a0be182 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -387,6 +387,17 @@ void RecordImGuiEditorWrapper() {
}
if (ImGui::BeginMenu("Debug")) {
ImGui::Checkbox("Show Debug Hitboxes", &pkeSettings.isRenderingDebug);
+ if (ImGui::Checkbox("Uncap Framerate", &pkeSettings.graphicsSettings.isFramerateUnlocked)) {
+ shouldRecreateSwapchain = true;
+ }
+ if (ImGui::Checkbox("wait for v-sync", &pkeSettings.graphicsSettings.isWaitingForVsync)) {
+ shouldRecreateSwapchain = true;
+ }
+ // ImGui::Checkbox("Uncap Tickrate", &pkeSettings.isTickrateUnlocked);
+
+ ImGuiIO &io = ImGui::GetIO();
+ ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
@@ -622,8 +633,6 @@ void RecordImGuiSceneEditor() {
ImGui::End();
return;
}
- ImGuiIO &io = ImGui::GetIO();
- ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
if (ImGui::Button("Create Entity Type")) {
ImGui::OpenPopup("CreateEntityType");
}
diff --git a/src/main.cpp b/src/main.cpp
index bd9dee0..fcddf80 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -16,7 +16,7 @@
#include "window.hpp"
void signal_handler(int signal_num) {
- printf("Received signal: %d - shutting down\n", signal_num);
+ fprintf(stdout, "Received signal: %d - shutting down\n", signal_num);
pkeSettings.isGameRunning = false;
}
@@ -29,7 +29,7 @@ void Tick(double delta) {
int main() {
signal(SIGTERM, signal_handler);
- printf("PKE ENTERING\n");
+ fprintf(stdout, "PKE ENTERING\n");
try {
AM_Init();
Game_Init();
@@ -49,8 +49,10 @@ int main() {
glfwPollEvents();
+ int64_t nsAheadHolder = 0.0;
if (nsAhead > 0) {
- std::this_thread::sleep_until(lastTimePoint + GameTimeDuration(nsAhead + 1));
+ nsAheadHolder = nsAhead;
+ std::this_thread::sleep_for(GameTimeDuration(nsAhead));
nsAhead = 0;
}
if (vidMode.refreshRate != pkeSettings.targetFPS) {
@@ -59,23 +61,23 @@ int main() {
}
GameTimePoint currentTimePoint = pkeSettings.steadyClock.now();
- double deltaThisTick = (currentTimePoint - lastTimePoint).count() / NANO_DENOM_DOUBLE;
+ double deltaThisTick = ((currentTimePoint - lastTimePoint).count() - nsAheadHolder) / NANO_DENOM_DOUBLE;
deltaThisTick = std::min(deltaThisTick, pkeSettings.minimumDeltaPerFrame);
- deltaTillNextRender -= deltaThisTick;
- bool shouldRender = deltaTillNextRender < deltaThisTick;
lastTimePoint = currentTimePoint;
- if (shouldRender) {
- if (deltaTillNextRender > 0.0 && deltaThisTick < pkeSettings.deltaPerFrame) {
- /*
- * We are ahead of schedule && the current tick is faster than our target FPS.
- * Simulate the extra time we are ahead and prepare to sleep the difference
- * before the next tick.
- */
- nsAhead = std::ceil(deltaTillNextRender * NANO_DENOM_DOUBLE);
- deltaThisTick += deltaTillNextRender;
- }
- deltaTillNextRender += pkeSettings.deltaPerFrame;
+ deltaTillNextRender -= deltaThisTick;
+ bool shouldRender = pkeSettings.graphicsSettings.isFramerateUnlocked || deltaTillNextRender <= 0.0;
+
+ if (deltaTillNextRender > 0.0 && deltaTillNextRender - deltaThisTick <= 0.0) {
+ /*
+ * We are ahead of the render schedule
+ * && the current tick's speed would put us behind schedule next tick.
+ * Simulate the extra time we are ahead and prepare to sleep the difference
+ * before the next tick.
+ */
+ nsAhead = std::ceil(deltaTillNextRender * NANO_DENOM_DOUBLE);
+ deltaThisTick += deltaTillNextRender;
+ shouldRender = true;
}
tickCount += 1;
@@ -83,11 +85,22 @@ int main() {
if (shouldRender) {
Render();
+ double msBehind = deltaTillNextRender * -1000;
+ int64_t behindCount = 0;
+ while (deltaTillNextRender < pkeSettings.deltaPerFrame) {
+ behindCount += 1;
+ deltaTillNextRender += pkeSettings.deltaPerFrame;
+ }
+ if (behindCount > 2) {
+ fprintf(stderr, "[PKE::main] late render - simulated ahead: %fms - delta behind: %fms - missed frames:%ld\n", nsAheadHolder / (NANO_DENOM_DOUBLE / 1000), msBehind, behindCount - 1);
+ fflush(stderr);
+ }
}
- if (shouldRender == false && (currentTimePoint - lastLogTimePoint).count() > std::chrono::nanoseconds::period::den) {
+ if ((currentTimePoint - lastLogTimePoint).count() > std::chrono::nanoseconds::period::den) {
lastLogTimePoint = currentTimePoint;
- printf("TPS: ~%ld - actual:%ld\n", int64_t(1 / deltaThisTick), tickCount);
+ fprintf(stdout, "TPS: ~%ld - actual:%ld\n", int64_t(1 / deltaThisTick), tickCount);
+ fflush(stdout);
tickCount = 0;
}
@@ -97,13 +110,13 @@ int main() {
vkDeviceWaitIdle(vkDevice);
} catch (const std::exception &exc) {
- printf("EXCEPTION: %s\n", exc.what());
+ fprintf(stdout, "EXCEPTION: %s\n", exc.what());
} catch (const char *err) {
- printf("UNHANDLED EXCEPTION: %s\n", err);
+ fprintf(stdout, "UNHANDLED EXCEPTION: %s\n", err);
} catch (...) {
- printf("UNHANDLED EXCEPTION\n");
+ fprintf(stdout, "UNHANDLED EXCEPTION\n");
}
- printf("PKE SHUTDOWN INITIATED\n");
+ fprintf(stdout, "PKE SHUTDOWN INITIATED\n");
Game_Teardown();
Event_Teardown();
EntityType_Teardown();
@@ -112,6 +125,6 @@ int main() {
AM_Teardown();
DestroyWindow();
Pke_DebugPrint();
- printf("PKE EXITING\n");
+ fprintf(stdout, "PKE EXITING\n");
return 0;
}
diff --git a/src/window.cpp b/src/window.cpp
index 2a1b905..6655c88 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -51,12 +51,11 @@ unsigned int transferFamilyIndex;
bool shouldRecreateSwapchain = false;
unsigned int CURRENT_FRAME = 0;
unsigned int selectedSurfaceIndex = -1u;
-unsigned int selectedPresentIndex = -1u;
unsigned int swapchainLength = 0u;
VkSwapchainKHR vkSwapchainKHR = VK_NULL_HANDLE;
VkSurfaceFormatKHR vkSurfaceFormatKHR;
VkFormat depthFormat;
-VkPresentModeKHR vkPresentModeKHR;
+VkPresentModeKHR vkPresentModeKHR = VK_PRESENT_MODE_FIFO_KHR;
VkExtent2D extent;
VkImage *swapchainImages = nullptr;
VkImageView *swapchainImageViews = nullptr;
@@ -604,22 +603,46 @@ void CreateSwapchain() {
height = extent.height < surfaceCapabilities.minImageExtent.height ? surfaceCapabilities.minImageExtent.height : extent.height;
extent.height = height > surfaceCapabilities.maxImageExtent.height ? surfaceCapabilities.maxImageExtent.height : height;
- if (selectedPresentIndex == -1u) {
+ vkPresentModeKHR = VK_PRESENT_MODE_FIFO_KHR;
+ if (pkeSettings.graphicsSettings.isWaitingForVsync == false || pkeSettings.graphicsSettings.isFramerateUnlocked == true) {
unsigned int presentModeCount = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, vkSurfaceKHR, &presentModeCount, nullptr);
VkPresentModeKHR *presentModes = Pke_New<VkPresentModeKHR>(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, vkSurfaceKHR, &presentModeCount, presentModes);
- unsigned long mailboxIndex = -1;
- unsigned long fifoRelaxedIndex = -1;
+ uint32_t immediateIndex = -1;
+ uint32_t fifoRelaxedIndex = -1;
+ /*
+ uint32_t mailboxIndex = -1;
+ uint32_t fifoIndex = -1;
+ */
for (long i = 0; i < presentModeCount; ++i) {
- if (presentModes[i] != VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR) {
- mailboxIndex = i;
- } else if (presentModes[i] != VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
+ if (presentModes[i] == VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR) {
+ immediateIndex = i;
+ }
+ else if (presentModes[i] == VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
fifoRelaxedIndex = i;
}
+ /*
+ // TODO returns 5 swapchain images, which causes other unhandled issues
+ else if (presentModes[i] == VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR) {
+ mailboxIndex = i;
+ }
+ else if (presentModes[i] == VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR) {
+ fifoIndex = i;
+ }
+ */
+ }
+ if (fifoRelaxedIndex != -1) {
+ vkPresentModeKHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
+ }
+ /*
+ if (mailboxIndex != -1) {
+ vkPresentModeKHR = VK_PRESENT_MODE_MAILBOX_KHR;
+ } else
+ */
+ if (immediateIndex != -1) {
+ vkPresentModeKHR = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
- selectedPresentIndex = mailboxIndex != -1ul ? mailboxIndex : fifoRelaxedIndex;
- vkPresentModeKHR = presentModes[selectedPresentIndex];
Pke_Delete<VkPresentModeKHR>(presentModes, presentModeCount);
}
@@ -654,7 +677,8 @@ void CreateSwapchain() {
vkSwapchainCreateInfo.queueFamilyIndexCount = 0;
}
- vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, vkAllocator, &vkSwapchainKHR);
+ VkResult vkResult = vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, vkAllocator, &vkSwapchainKHR);
+ assert(vkResult == VK_SUCCESS);
VkImageSubresourceRange vkImageSubresourceRange;
vkImageSubresourceRange.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT;
@@ -686,13 +710,16 @@ void CreateSwapchain() {
assert(depthImages == nullptr || depthImages == CAFE_BABE(VkImage));
assert(depthImageViews == nullptr || depthImageViews == CAFE_BABE(VkImageView));
- vkGetSwapchainImagesKHR(vkDevice, vkSwapchainKHR, &swapchainLength, nullptr);
+ vkResult = vkGetSwapchainImagesKHR(vkDevice, vkSwapchainKHR, &swapchainLength, nullptr);
+ assert(vkResult == VK_SUCCESS);
swapchainImages = Pke_New<VkImage>(swapchainLength);
- vkGetSwapchainImagesKHR(vkDevice, vkSwapchainKHR, &swapchainLength, swapchainImages);
+ vkResult = vkGetSwapchainImagesKHR(vkDevice, vkSwapchainKHR, &swapchainLength, swapchainImages);
+ assert(vkResult == VK_SUCCESS);
swapchainImageViews = Pke_New<VkImageView>(swapchainLength);
for (long i = 0; i < swapchainLength; ++i) {
vkImageViewCreateInfo.image = swapchainImages[i];
- vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &swapchainImageViews[i]);
+ vkResult = vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &swapchainImageViews[i]);
+ assert(vkResult == VK_SUCCESS);
}
// render target items
diff --git a/src/window.hpp b/src/window.hpp
index ab07a8b..e94598b 100644
--- a/src/window.hpp
+++ b/src/window.hpp
@@ -20,6 +20,7 @@
// TODO replace me with something more elegant
const unsigned int MAX_FRAMES_IN_FLIGHT = 3;
+extern bool shouldRecreateSwapchain;
extern GLFWwindow *window;
extern GLFWmonitor *monitor;
extern GLFWvidmode vidMode;