Контекст OpenGL и честный счетчик кадров
Пункт ноль плана: клиент теперь просит контекст 3.3 в режиме совместимости, а не тот, что выпадал по умолчанию. Зачем: дальний вид будет писаться шейдером GLSL 330, и контекст должен гарантированно быть не ниже 3.3. В профиле совместимости работают и шейдеры игры (#version 120, их 34 штуки), и наши 330-е. LWJGL 2.9.4 выше 3.3 контекст не заказывает - ограничение в его конструкторе, а не в драйвере. Драйвер при этом дает 4.6, и расширение GL_EXT_gpu_shader4, которое просит FXAA-шейдер игры, в этом контексте на месте. Замер кадров теперь пишется в лог каждую секунду: средний, медиана, 1% и 0.1% low. Одного среднего мало: клиент, который идет со 60 кадрами и дважды в секунду проваливается в 10, в среднем остается 60 и ощущается как slideshow. Медленные кадры - это то, что чувствует игрок, поэтому окно держит все времена кадров и говорит про хвост. Среднее и процентили видны и в HUD, так что их не надо вылавливать из скриншотов. Замер: 307 fps | med 2.9 ms | 1% 6.0 ms | 0.1% 18.1 ms.
This commit is contained in:
@@ -183,6 +183,10 @@ public final class ClientHost {
|
||||
public long frame() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public FrameStats frameStats() {
|
||||
return FrameStats.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/** Names currently registered, for logging and diagnostics. */
|
||||
|
||||
@@ -29,4 +29,7 @@ public interface ClientServices {
|
||||
|
||||
/** Frames drawn, which at a steady frame rate is a better clock than tick. */
|
||||
long frame();
|
||||
|
||||
/** How fast the frames are going, never null. */
|
||||
FrameStats frameStats();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package net.rustnotmc.api.client;
|
||||
|
||||
/**
|
||||
* How fast the frames are going.
|
||||
*
|
||||
* The average is the number everybody quotes and the number that hides the
|
||||
* stutter: a client that runs at sixty frames a second and drops to ten twice
|
||||
* a second has an average of sixty and feels terrible. The slow frames are
|
||||
* what a player actually feels, so the window keeps every frame time and
|
||||
* reports the slow tail as well.
|
||||
*
|
||||
* The percentiles are of the frame time, so a bigger number is worse. The
|
||||
* "one percent low" is the frame time that one frame in a hundred was slower
|
||||
* than, which is the usual way of saying it.
|
||||
*/
|
||||
public final class FrameStats {
|
||||
|
||||
/** The numbers before the first second is over. */
|
||||
public static final FrameStats EMPTY = new FrameStats(0, 0.0D, 0.0D, 0.0D, 0.0D, 0);
|
||||
|
||||
private final int frames;
|
||||
private final double averageFps;
|
||||
private final double medianMillis;
|
||||
private final double onePercentMillis;
|
||||
private final double tenthPercentMillis;
|
||||
private final double worstMillis;
|
||||
|
||||
public FrameStats(int frames, double averageFps, double medianMillis,
|
||||
double onePercentMillis, double tenthPercentMillis,
|
||||
double worstMillis) {
|
||||
this.frames = frames;
|
||||
this.averageFps = averageFps;
|
||||
this.medianMillis = medianMillis;
|
||||
this.onePercentMillis = onePercentMillis;
|
||||
this.tenthPercentMillis = tenthPercentMillis;
|
||||
this.worstMillis = worstMillis;
|
||||
}
|
||||
|
||||
/** Frames drawn in the last second. */
|
||||
public int frames() {
|
||||
return this.frames;
|
||||
}
|
||||
|
||||
/** Frames a second, averaged over the last second. */
|
||||
public double averageFps() {
|
||||
return this.averageFps;
|
||||
}
|
||||
|
||||
/** The middle frame time, in milliseconds. */
|
||||
public double medianMillis() {
|
||||
return this.medianMillis;
|
||||
}
|
||||
|
||||
/** The frame time one frame in a hundred was slower than, in milliseconds. */
|
||||
public double onePercentMillis() {
|
||||
return this.onePercentMillis;
|
||||
}
|
||||
|
||||
/** The frame time one frame in a thousand was slower than, in milliseconds. */
|
||||
public double tenthPercentMillis() {
|
||||
return this.tenthPercentMillis;
|
||||
}
|
||||
|
||||
/** The slowest frame of the last second, in milliseconds. */
|
||||
public double worstMillis() {
|
||||
return this.worstMillis;
|
||||
}
|
||||
|
||||
/** True once there is something to report. */
|
||||
public boolean measured() {
|
||||
return this.frames > 0;
|
||||
}
|
||||
|
||||
/** One line, for a log or an overlay. */
|
||||
public String describe() {
|
||||
if (!measured()) {
|
||||
return "no frames yet";
|
||||
}
|
||||
return String.format(java.util.Locale.ROOT,
|
||||
"%d fps | med %.1f ms | 1%% %.1f ms | 0.1%% %.1f ms | worst %.1f ms",
|
||||
Integer.valueOf((int) Math.round(averageFps)),
|
||||
Double.valueOf(medianMillis),
|
||||
Double.valueOf(onePercentMillis),
|
||||
Double.valueOf(tenthPercentMillis),
|
||||
Double.valueOf(worstMillis));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FrameStats[" + describe() + "]";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user