mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 11:44:21 -04:00
Settings: add FPS cap (#532)
* settings: add fpsCap * fpsCap: convert to nanos correctly * main.zig: use specific names for lastBeginRendering and frameTime * physics/fps window: use real time between frames * graphics menu: add fps slider * fpsCap: round slider + fix formatter * fpsCap: prevent overflow * fpsCap: remove debug spam * fpsCap setting: add 'Limit' * debug menu: note fps limit * fpsCap formatter: dupe constant string to prevent free failure * debug menu: remove contradictory (vsync) (unlimited) * debug menu: fix mem leak in fps format * debug manu: simplify fps limit text allocation
This commit is contained in:
parent
3956f07556
commit
ad9cad6270
@ -25,7 +25,14 @@ pub var window = GuiWindow {
|
||||
pub fn render() void {
|
||||
draw.setColor(0xffffffff);
|
||||
var y: f32 = 0;
|
||||
draw.print("fps: {d:.0} Hz{s}", .{1.0/main.lastFrameTime.load(.monotonic), if(main.settings.vsync) @as([]const u8, " (vsync)") else ""}, 0, y, 8, .left);
|
||||
const fpsCapText = if(main.settings.fpsCap) |fpsCap| std.fmt.allocPrint(main.stackAllocator.allocator, " (limit: {d:.0} Hz)", .{fpsCap}) catch unreachable else "";
|
||||
defer main.stackAllocator.allocator.free(fpsCapText);
|
||||
const fpsLimit = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}{s}", .{
|
||||
fpsCapText,
|
||||
if(main.settings.vsync) " (vsync)" else "",
|
||||
}) catch unreachable;
|
||||
defer main.stackAllocator.allocator.free(fpsLimit);
|
||||
draw.print("fps: {d:.0} Hz{s}", .{1.0/main.lastDeltaTime.load(.monotonic), fpsLimit}, 0, y, 8, .left);
|
||||
y += 8;
|
||||
draw.print("frameTime: {d:.1} ms", .{main.lastFrameTime.load(.monotonic)*1000.0}, 0, y, 8, .left);
|
||||
y += 8;
|
||||
@ -57,4 +64,4 @@ pub fn render() void {
|
||||
draw.print("Opaque faces: {}, Transparent faces: {}", .{main.renderer.chunk_meshing.quadsDrawn, main.renderer.chunk_meshing.transparentQuadsDrawn}, 0, y, 8, .left);
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,27 @@ const anisotropy = [_]u8{1, 2, 4, 8, 16};
|
||||
|
||||
const resolutions = [_]u16{25, 50, 100};
|
||||
|
||||
fn fpsCapRound(newValue: f32) ?u32 {
|
||||
if(newValue < 144.0) {
|
||||
return @as(u32, @intFromFloat(newValue/5.0))*5;
|
||||
} else if (newValue < 149.0) {
|
||||
return 144;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn fpsCapFormatter(allocator: main.utils.NeverFailingAllocator, value: f32) []const u8 {
|
||||
const cap = fpsCapRound(value);
|
||||
if(cap == null)
|
||||
return allocator.dupe(u8, "#ffffffFPS: Unlimited");
|
||||
return std.fmt.allocPrint(allocator.allocator, "#ffffffFPS Limit: {d:.0}", .{cap.?}) catch unreachable;
|
||||
}
|
||||
|
||||
fn fpsCapCallback(newValue: f32) void {
|
||||
settings.fpsCap = fpsCapRound(newValue);
|
||||
}
|
||||
|
||||
fn renderDistanceCallback(newValue: u16) void {
|
||||
settings.renderDistance = newValue + renderDistances[0];
|
||||
}
|
||||
@ -64,6 +85,7 @@ fn resolutionScaleCallback(newValue: u16) void {
|
||||
|
||||
pub fn onOpen() void {
|
||||
const list = VerticalList.init(.{padding, 16 + padding}, 300, 16);
|
||||
list.add(ContinuousSlider.init(.{0, 0}, 128, 10.0, 154.0, @floatFromInt(settings.fpsCap orelse 144), &fpsCapCallback, &fpsCapFormatter));
|
||||
list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffRender Distance: ", "{}", &renderDistances, settings.renderDistance - renderDistances[0], &renderDistanceCallback));
|
||||
list.add(ContinuousSlider.init(.{0, 0}, 128, 40.0, 120.0, settings.fov, &fovCallback, &fovFormatter));
|
||||
list.add(CheckBox.init(.{0, 0}, 128, "Bloom", settings.bloom, &bloomCallback));
|
||||
@ -80,4 +102,4 @@ pub fn onClose() void {
|
||||
if(window.rootComponent) |*comp| {
|
||||
comp.deinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
src/main.zig
31
src/main.zig
@ -347,7 +347,10 @@ pub const KeyBoard = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// Records gpu time per frame.
|
||||
pub var lastFrameTime = std.atomic.Value(f64).init(0);
|
||||
/// Measures time between different frames' beginnings.
|
||||
pub var lastDeltaTime = std.atomic.Value(f64).init(0);
|
||||
|
||||
pub fn main() void {
|
||||
seed = @bitCast(std.time.milliTimestamp());
|
||||
@ -428,7 +431,7 @@ pub fn main() void {
|
||||
c.glDepthFunc(c.GL_LESS);
|
||||
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
|
||||
Window.GLFWCallbacks.framebufferSize(undefined, Window.width, Window.height);
|
||||
var lastTime = std.time.nanoTimestamp();
|
||||
var lastBeginRendering = std.time.nanoTimestamp();
|
||||
|
||||
if(settings.developerAutoEnterWorld.len != 0) {
|
||||
// Speed up the dev process by entering the world directly.
|
||||
@ -448,17 +451,27 @@ pub fn main() void {
|
||||
std.time.sleep(16_000_000);
|
||||
}
|
||||
|
||||
const endRendering = std.time.nanoTimestamp();
|
||||
const frameTime = @as(f64, @floatFromInt(endRendering -% lastBeginRendering))/1e9;
|
||||
if(settings.developerGPUInfiniteLoopDetection and frameTime > 5) { // On linux a process that runs 10 seconds or longer on the GPU will get stopped. This allows detecting an infinite loop on the GPU.
|
||||
std.log.err("Frame got too long with {} seconds. Infinite loop on GPU?", .{frameTime});
|
||||
std.posix.exit(1);
|
||||
}
|
||||
lastFrameTime.store(frameTime, .monotonic);
|
||||
|
||||
if(settings.fpsCap) |fpsCap| {
|
||||
const minFrameTime = @divFloor(1000*1000*1000, fpsCap);
|
||||
const sleep = @min(minFrameTime, @max(0, minFrameTime - (endRendering -% lastBeginRendering)));
|
||||
std.time.sleep(sleep);
|
||||
}
|
||||
const begin = std.time.nanoTimestamp();
|
||||
const deltaTime = @as(f64, @floatFromInt(begin -% lastBeginRendering))/1e9;
|
||||
lastDeltaTime.store(deltaTime, .monotonic);
|
||||
lastBeginRendering = begin;
|
||||
|
||||
Window.handleEvents();
|
||||
file_monitor.handleEvents();
|
||||
|
||||
const newTime = std.time.nanoTimestamp();
|
||||
const deltaTime = @as(f64, @floatFromInt(newTime -% lastTime))/1e9;
|
||||
if(settings.developerGPUInfiniteLoopDetection and deltaTime > 5) { // On linux a process that runs 10 seconds or longer on the GPU will get stopped. This allows detecting an infinite loop on the GPU.
|
||||
std.log.err("Frame got too long with {} seconds. Infinite loop on GPU?", .{deltaTime});
|
||||
std.posix.exit(1);
|
||||
}
|
||||
lastFrameTime.store(deltaTime, .monotonic);
|
||||
lastTime = newTime;
|
||||
if(game.world != null) { // Update the game
|
||||
game.update(deltaTime);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ pub var cpuThreads: ?u64 = null;
|
||||
pub var anisotropicFiltering: u8 = 4.0;
|
||||
|
||||
|
||||
pub var fpsCap: ?u32 = null;
|
||||
|
||||
pub var fov: f32 = 70;
|
||||
|
||||
pub var mouseSensitivity: f32 = 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user