mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
AtlasEngine: Fix custom shader time imprecision (#17104)
Since floats are imprecise we need to constrain the time value into a range that can be accurately represented. Assuming a monitor refresh rate of 1000 Hz, we can still easily represent 1000 seconds accurately (roughly 16 minutes). So to solve this, we'll simply treat the shader time modulo 1000s. This may lead to some unexpected jank every 16min but it keeps any ongoing animation smooth otherwise.
This commit is contained in:
parent
a590a1bff0
commit
daffb2dbbf
@ -47,6 +47,20 @@ using namespace Microsoft::Console::Render::Atlas;
|
||||
static constexpr D2D1_MATRIX_3X2_F identityTransform{ .m11 = 1, .m22 = 1 };
|
||||
static constexpr D2D1_COLOR_F whiteColor{ 1, 1, 1, 1 };
|
||||
|
||||
static u64 queryPerfFreq() noexcept
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency(&li);
|
||||
return std::bit_cast<u64>(li.QuadPart);
|
||||
}
|
||||
|
||||
static u64 queryPerfCount() noexcept
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
return std::bit_cast<u64>(li.QuadPart);
|
||||
}
|
||||
|
||||
BackendD3D::BackendD3D(const RenderingPayload& p)
|
||||
{
|
||||
THROW_IF_FAILED(p.device->CreateVertexShader(&shader_vs[0], sizeof(shader_vs), nullptr, _vertexShader.addressof()));
|
||||
@ -485,7 +499,14 @@ void BackendD3D::_recreateCustomShader(const RenderingPayload& p)
|
||||
THROW_IF_FAILED(p.device->CreateSamplerState(&desc, _customShaderSamplerState.put()));
|
||||
}
|
||||
|
||||
_customShaderStartTime = std::chrono::steady_clock::now();
|
||||
// Since floats are imprecise we need to constrain the time value into a range that can be accurately represented.
|
||||
// Assuming a monitor refresh rate of 1000 Hz, we can still easily represent 1000 seconds accurately (roughly 16 minutes).
|
||||
// 10000 seconds would already result in a 50% error. So to avoid this, we use queryPerfCount() modulo _customShaderPerfTickMod.
|
||||
// The use of a power of 10 is intentional, because shaders are often periodic and this makes any decimal multiplier up to 3 fractional
|
||||
// digits not break the periodicity. For instance, with a wraparound of 1000 seconds sin(1.234*x) is still perfectly periodic.
|
||||
const auto freq = queryPerfFreq();
|
||||
_customShaderPerfTickMod = freq * 1000;
|
||||
_customShaderSecsPerPerfTick = 1.0f / freq;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2111,8 +2132,12 @@ void BackendD3D::_debugDumpRenderTarget(const RenderingPayload& p)
|
||||
void BackendD3D::_executeCustomShader(RenderingPayload& p)
|
||||
{
|
||||
{
|
||||
// See the comment in _recreateCustomShader() which initializes the two members below and explains what they do.
|
||||
const auto now = queryPerfCount();
|
||||
const auto time = static_cast<int>(now % _customShaderPerfTickMod) * _customShaderSecsPerPerfTick;
|
||||
|
||||
const CustomConstBuffer data{
|
||||
.time = std::chrono::duration<f32>(std::chrono::steady_clock::now() - _customShaderStartTime).count(),
|
||||
.time = time,
|
||||
.scale = static_cast<f32>(p.s->font->dpi) / static_cast<f32>(USER_DEFAULT_SCREEN_DPI),
|
||||
.resolution = {
|
||||
static_cast<f32>(_viewportCellCount.x * p.s->font->cellSize.x),
|
||||
|
||||
@ -248,7 +248,8 @@ namespace Microsoft::Console::Render::Atlas
|
||||
wil::com_ptr<ID3D11SamplerState> _customShaderSamplerState;
|
||||
wil::com_ptr<ID3D11Texture2D> _customShaderTexture;
|
||||
wil::com_ptr<ID3D11ShaderResourceView> _customShaderTextureView;
|
||||
std::chrono::steady_clock::time_point _customShaderStartTime;
|
||||
u64 _customShaderPerfTickMod = 0;
|
||||
f32 _customShaderSecsPerPerfTick = 0;
|
||||
|
||||
wil::com_ptr<ID3D11Texture2D> _backgroundBitmap;
|
||||
wil::com_ptr<ID3D11ShaderResourceView> _backgroundBitmapView;
|
||||
|
||||
@ -146,6 +146,8 @@ namespace Microsoft::Console::Render::Atlas
|
||||
using i32x4 = vec4<i32>;
|
||||
using i32r = rect<i32>;
|
||||
|
||||
using u64 = uint64_t;
|
||||
|
||||
using f32 = float;
|
||||
using f32x2 = vec2<f32>;
|
||||
using f32x4 = vec4<f32>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user