Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite AtlasEngine to allow arbitrary overhangs #14959

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f24a9ea
A minor AtlasEngine refactoring
lhecker Mar 6, 2023
6ba233a
Fix transparency, scrolling, dirty rects
lhecker Mar 7, 2023
7ddddfe
Improve performance, Fix OOM when drawing whitespace
lhecker Mar 8, 2023
1eafcd4
Fix glyph rounding error, Fix custom shaders
lhecker Mar 8, 2023
01e596c
Adapter selection, Overlapping gridlines, QuadInstance simplification
lhecker Mar 15, 2023
c270284
Better dirty rect tracking and partial rerendering (WIP)
lhecker Mar 15, 2023
339b892
Mostly fix dirty rects, Reduce memory/PCIe usage
lhecker Mar 16, 2023
d44974a
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Mar 20, 2023
694daa7
Fix dirty area calculation, Add ATLAS_DEBUG_SHOW_DIRTY
lhecker Mar 20, 2023
badbd49
Finally fix broken rendering in BackendD3D
lhecker Mar 21, 2023
0d44fe4
Fix dirty rects in BackendD2D, Investigate broken support for hinted …
lhecker Mar 21, 2023
6232dfd
Implement line renditions for BackendD2D
lhecker Mar 23, 2023
da40a01
Fix D2D emoji rendering, Add support for line renditions
lhecker Mar 25, 2023
5d16e7e
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Mar 25, 2023
4879a36
Fix glyph measurements, Fix font axis support, Begin implementing sof…
lhecker Mar 27, 2023
2c06f8b
Fix glyph retry crash, Hyperlink hovering, Swap chain startup crash, …
lhecker Mar 28, 2023
c32bfec
Silence spell check
lhecker Mar 28, 2023
f068688
Simplify dxgi adapter invalidation, Fix dirty rect on backend recreation
lhecker Mar 28, 2023
f95d435
DWM folks said to test for IsCurrent(), Added basic soft font support
lhecker Mar 30, 2023
0f3b1d3
Implement line renditions for soft fonts
lhecker Mar 30, 2023
ec5f208
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Mar 30, 2023
20cb489
Fix AuditMode failures
lhecker Mar 30, 2023
4caf341
Fix background opacity in BackendD2D
lhecker Mar 31, 2023
d0fcc5b
Slightly reduce memory usage, Clean up AntialiasingMode, Document IDW…
lhecker Mar 31, 2023
4803617
Fix line endings, Remove weird IDWriteFontFace_SoftFont, Add flat_set…
lhecker Apr 2, 2023
4ef2b3f
Implement inverted cursors for D2D, Make _appendQuad a prettier & fas…
lhecker Apr 3, 2023
4aa71a1
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Apr 3, 2023
f8f0ea1
Fix background color alpha
lhecker Apr 3, 2023
2e03220
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Apr 4, 2023
7f1707b
Integrate changes to linear_flat_set from main
lhecker Apr 4, 2023
2602fa3
Fix AuditMode failures
lhecker Apr 4, 2023
d9b66ab
Some cleanup, Ligature per-cell coloring
lhecker Apr 6, 2023
b60bbc9
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Apr 7, 2023
da93dbd
Improve vertical coloring of overhangs, Fix hyperlink underline
lhecker Apr 7, 2023
1b9cd8d
Fix overlap split for double width glyphs
lhecker Apr 7, 2023
039e27f
Fix AuditMode, Fix DRCS baseline, Fix DECDWL color bitmaps
lhecker Apr 7, 2023
93722f8
Lots and lots and lots of fixes
lhecker Apr 11, 2023
9a5a8ec
Move swap chain responsibility from backends to AtlasEngine
lhecker Apr 15, 2023
26a5ab3
Merge remote-tracking branch 'origin/main' into dev/lhecker/atlas-eng…
lhecker Apr 21, 2023
270c1ba
Begin writing documentation, Fix some ATLAS_ATTR_COLD on BackendD2D
lhecker Apr 21, 2023
900b6a9
Change the inverted cursor rendering approach
lhecker Apr 25, 2023
b1590cc
Improve inverted cursor via hole punching
lhecker Apr 25, 2023
990f57a
Fix hole punching algorithm, Implement semi-reverse cursors
lhecker Apr 26, 2023
ab13e16
Add an Emoji shortcut
lhecker Apr 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/host/CursorBlinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void CursorBlinker::SettingsChanged() noexcept
{
KillCaretTimer();
_uCaretBlinkTime = dwCaretBlinkTime;
//SetCaretTimer();
SetCaretTimer();
}
}

Expand All @@ -66,7 +66,7 @@ void CursorBlinker::FocusEnd() const noexcept

void CursorBlinker::FocusStart() const noexcept
{
//SetCaretTimer();
SetCaretTimer();
}

// Routine Description:
Expand Down
2 changes: 2 additions & 0 deletions src/inc/til/small_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#pragma warning(disable : 26459) // You called an STL function '...' with a raw pointer parameter at position '...' that may be unsafe ... (stl.1).
// small_vector::_data references potentially uninitialized data and so we can't pass it regular iterators which reference initialized data.
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
// small_vector::_buffer is explicitly uninitialized, because we manage it's initialization manually.
#pragma warning(disable : 26495) // Variable '...' is uninitialized. Always initialize a member variable (type.6).

namespace til
{
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/atlas/AtlasEngine.r.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ void AtlasEngine::WaitUntilCanRender() noexcept
{
_b->WaitUntilCanRender();
}
if constexpr (ATLAS_DEBUG_RENDER_DELAY)
{
Sleep(ATLAS_DEBUG_RENDER_DELAY);
}
}

#pragma endregion
Expand Down
21 changes: 20 additions & 1 deletion src/renderer/atlas/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@

namespace Microsoft::Console::Render::Atlas
{
// If set to 1, this will cause the entire viewport to be invalidated at all times.
// Helpful for benchmarking our text shaping code based on DirectWrite.
#define ATLAS_DEBUG_DISABLE_PARTIAL_INVALIDATION 0

// Redraw at display refresh rate at all times. This helps with shader debugging.
#define ATLAS_DEBUG_CONTINUOUS_REDRAW 0

// Disables the use of DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT.
// This helps with benchmarking the application as it'll run beyond display refresh rate.
#define ATLAS_DEBUG_DISABLE_FRAME_LATENCY_WAITABLE_OBJECT 0
#define ATLAS_DEBUG_DISABLE_PARTIAL_INVALIDATION 0

// Forces the use of Direct2D for text rendering (= BackendD2D).
#define ATLAS_DEBUG_FORCE_D2D_MODE 0

// Adds an artificial delay before every render pass. In milliseconds.
#define ATLAS_DEBUG_RENDER_DELAY 0

// Shows the dirty rects as given to IDXGISwapChain2::Present1() during each frame.
#define ATLAS_DEBUG_SHOW_DIRTY 0

// Dumps the contents of the swap chain on each render pass into the given directory as PNG.
// I highly recommend setting ATLAS_DEBUG_RENDER_DELAY to 250 or similar if this is used.
#define ATLAS_DEBUG_DUMP_RENDER_TARGET 0
#define ATLAS_DEBUG_DUMP_RENDER_TARGET_PATH LR"(%USERPROFILE%\Downloads\AtlasEngine)"

struct SwapChainManager
{
void UpdateSwapChainSettings(const RenderingPayload& p, IUnknown* device, auto&& prepareRecreate, auto&& prepareResize)
Expand Down
30 changes: 29 additions & 1 deletion src/renderer/atlas/BackendD2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include "pch.h"
#include "BackendD2D.h"

#if ATLAS_DEBUG_SHOW_DIRTY
#include "colorbrewer.h"
#endif

TIL_FAST_MATH_BEGIN

// Disable a bunch of warnings which get in the way of writing performant code.
Expand Down Expand Up @@ -34,6 +38,9 @@ void BackendD2D::Render(RenderingPayload& p)
_drawGridlines(p);
_drawCursor(p);
_drawSelection(p);
#if ATLAS_DEBUG_SHOW_DIRTY
_debugShowDirty(p);
#endif
THROW_IF_FAILED(_renderTarget->EndDraw());

_swapChainManager.Present(p);
Expand Down Expand Up @@ -208,7 +215,7 @@ void BackendD2D::_drawText(RenderingPayload& p)
}
} while (it != end);
}

if (y >= p.invalidatedRows.x && y < p.invalidatedRows.y)
{
dirtyTop = std::min(dirtyTop, row->top);
Expand Down Expand Up @@ -486,6 +493,27 @@ void BackendD2D::_drawSelection(const RenderingPayload& p)
}
}

void BackendD2D::_debugShowDirty(RenderingPayload& p)
{
_presentRects[_presentRectsPos] = p.dirtyRectInPx;
_presentRectsPos = (_presentRectsPos + 1) % std::size(_presentRects);

for (size_t i = 0; i < std::size(_presentRects); ++i)
{
if (const auto& rect = _presentRects[i])
{
const D2D1_RECT_F rectF{
static_cast<f32>(rect.left),
static_cast<f32>(rect.top),
static_cast<f32>(rect.right),
static_cast<f32>(rect.bottom),
};
const auto color = 0x1f000000 | colorbrewer::pastel1[i];
lhecker marked this conversation as resolved.
Show resolved Hide resolved
_fillRectangle(rectF, color);
}
}
}

ID2D1Brush* BackendD2D::_brushWithColor(u32 color)
{
if (_brushColor != color)
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/atlas/BackendD2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace Microsoft::Console::Render::Atlas
void _drawGridlineRow(const RenderingPayload& p, const ShapedRow* row, u16 y);
void _drawCursor(const RenderingPayload& p);
void _drawSelection(const RenderingPayload& p);
void _debugShowDirty(RenderingPayload& p);
ID2D1Brush* _brushWithColor(u32 color);
void _fillRectangle(const D2D1_RECT_F& rect, u32 color);

Expand All @@ -46,5 +47,10 @@ namespace Microsoft::Console::Render::Atlas
til::generation_t _generation;
til::generation_t _fontGeneration;
u16x2 _cellCount;

#if ATLAS_DEBUG_SHOW_DIRTY
til::rect _presentRects[9]{};
size_t _presentRectsPos = 0;
#endif
};
}
98 changes: 68 additions & 30 deletions src/renderer/atlas/BackendD3D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@

#include "dwrite.h"

#if ATLAS_DEBUG_SHOW_DIRTY
#include "colorbrewer.h"
#endif

#if ATLAS_DEBUG_DUMP_RENDER_TARGET
#include "wic.h"
#endif

TIL_FAST_MATH_BEGIN

Expand Down Expand Up @@ -290,44 +296,33 @@ void BackendD3D::Render(RenderingPayload& p)
// After a Present() the render target becomes unbound.
_deviceContext->OMSetRenderTargets(1, _renderTargetView.addressof(), nullptr);

// Invalidating the render target helps with spotting invalid quad instances and Present1() bugs.
#if ATLAS_DEBUG_SHOW_DIRTY || ATLAS_DEBUG_DUMP_RENDER_TARGET
{
static constexpr f32 clearColor[4]{};
_deviceContext->ClearView(_renderTargetView.get(), &clearColor[0], nullptr, 0);
}
#endif

_drawBackground(p);
_drawCursorPart1(p);
_drawText(p);
_drawGridlines(p);
_drawCursorPart2(p);
_drawSelection(p);

#if ATLAS_DEBUG_SHOW_DIRTY
{
_presentRects[_presentRectsPos] = p.dirtyRectInPx;
_presentRectsPos = (_presentRectsPos + 1) % std::size(_presentRects);

for (size_t i = 0; i < std::size(_presentRects); ++i)
{
if (const auto& rect = _presentRects[i])
{
const i16x2 position{
static_cast<i16>(rect.left),
static_cast<i16>(rect.top),
};
const u16x2 size{
static_cast<u16>(rect.right - rect.left),
static_cast<u16>(rect.bottom - rect.top),
};
const auto color = 0x3f000000 | colorbrewer::pastel1[i];
_appendQuad(position, size, color, ShadingType::SolidFill);
}
}
}
_debugShowDirty(p);
#endif

_flushQuads(p);

if (_customPixelShader)
{
_executeCustomShader(p);
}

#if ATLAS_DEBUG_DUMP_RENDER_TARGET
_debugDumpRenderTarget(p);
#endif
_swapChainManager.Present(p);
}

Expand Down Expand Up @@ -403,11 +398,6 @@ void BackendD3D::_handleSettingsUpdate(const RenderingPayload& p)
_miscGeneration = p.s->misc.generation();
_targetSize = p.s->targetSize;
_cellCount = p.s->cellCount;

#if ATLAS_DEBUG_SHOW_DIRTY
std::ranges::fill(_presentRects, til::rect{});
_presentRectsPos = 0;
#endif
}

void BackendD3D::_recreateCustomShader(const RenderingPayload& p)
Expand Down Expand Up @@ -747,7 +737,7 @@ void BackendD3D::_d2dEndDrawing()
}
}

void BackendD3D::_handleFontChangedResetGlyphAtlas(RenderingPayload& p)
void BackendD3D::_handleFontChangedResetGlyphAtlas(const RenderingPayload& p)
{
_fontChangedResetGlyphAtlas = false;
_resetGlyphAtlasAndBeginDraw(p);
Expand Down Expand Up @@ -860,7 +850,13 @@ void BackendD3D::_appendQuad(i16x2 position, u16x2 size, u16x2 texcoord, u32 col

void BackendD3D::_bumpInstancesSize()
{
_instances = Buffer<QuadInstance>{ std::max<size_t>(1024, _instances.size() << 1) };
const auto newSize = std::max<size_t>(256, _instances.size() * 2);
Expects(newSize > _instances.size());

auto newInstances = Buffer<QuadInstance>{ newSize };
std::copy_n(_instances.data(), _instances.size(), newInstances.data());

_instances = std::move(newInstances);
}

void BackendD3D::_flushQuads(const RenderingPayload& p)
Expand Down Expand Up @@ -1383,6 +1379,48 @@ void BackendD3D::_drawSelection(const RenderingPayload& p)
}
}

#if ATLAS_DEBUG_SHOW_DIRTY
void BackendD3D::_debugShowDirty(RenderingPayload& p)
{
_presentRects[_presentRectsPos] = p.dirtyRectInPx;
_presentRectsPos = (_presentRectsPos + 1) % std::size(_presentRects);

for (size_t i = 0; i < std::size(_presentRects); ++i)
{
if (const auto& rect = _presentRects[i])
{
const i16x2 position{
static_cast<i16>(rect.left),
static_cast<i16>(rect.top),
};
const u16x2 size{
static_cast<u16>(rect.right - rect.left),
static_cast<u16>(rect.bottom - rect.top),
};
const auto color = 0x1f000000 | colorbrewer::pastel1[i];
_appendQuad(position, size, color, ShadingType::SolidFill);
}
}
}
#endif

#if ATLAS_DEBUG_DUMP_RENDER_TARGET
void BackendD3D::_debugDumpRenderTarget(RenderingPayload& p)
{
const auto n = _dumpRenderTargetCounter.fetch_add(1, std::memory_order_relaxed);

if (n == 0)
{
ExpandEnvironmentStringsW(ATLAS_DEBUG_DUMP_RENDER_TARGET_PATH, &_dumpRenderTargetBasePath[0], std::size(_dumpRenderTargetBasePath));
std::filesystem::create_directories(_dumpRenderTargetBasePath);
}

wchar_t path[MAX_PATH];
swprintf_s(path, L"%s\\%u_%08u.png", &_dumpRenderTargetBasePath[0], GetCurrentProcessId(), n);
SaveTextureToPNG(_deviceContext.get(), _swapChainManager.GetBuffer().get(), p.s->font->dpi, &path[0]);
}
#endif

void BackendD3D::_executeCustomShader(RenderingPayload& p)
{
{
Expand Down
11 changes: 9 additions & 2 deletions src/renderer/atlas/BackendD3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ namespace Microsoft::Console::Render::Atlas
void _recreateConstBuffer(const RenderingPayload& p);
void _setupDeviceContextState(const RenderingPayload& p);
void _debugUpdateShaders(const RenderingPayload& p) noexcept;
void _debugShowDirty(RenderingPayload& p);
void _debugDumpRenderTarget(RenderingPayload& p);
void _d2dBeginDrawing() noexcept;
void _d2dEndDrawing();
void _handleFontChangedResetGlyphAtlas(RenderingPayload& p);
void _handleFontChangedResetGlyphAtlas(const RenderingPayload& p);
void _resetGlyphAtlasAndBeginDraw(const RenderingPayload& p);
void _markStateChange(ID3D11BlendState* blendState);
QuadInstance& _getLastQuad() noexcept;
Expand Down Expand Up @@ -226,12 +228,17 @@ namespace Microsoft::Console::Render::Atlas
til::small_vector<CursorRect, 6> _cursorRects;

bool _requiresContinuousRedraw = false;

#if ATLAS_DEBUG_SHOW_DIRTY
til::rect _presentRects[9]{};
size_t _presentRectsPos = 0;
#endif

#if ATLAS_DEBUG_DUMP_RENDER_TARGET
std::atomic<uint32_t> _dumpRenderTargetCounter;
wchar_t _dumpRenderTargetBasePath[MAX_PATH];
#endif

#ifndef NDEBUG
std::filesystem::path _sourceDirectory;
wil::unique_folder_change_reader_nothrow _sourceCodeWatcher;
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/atlas/colorbrewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

#pragma once

namespace Microsoft::Console::Render::Atlas::colorbrewer {
namespace Microsoft::Console::Render::Atlas::colorbrewer
{
// The following list of colors is only used as a debug aid and not part of the final product.
// They're licensed under:
//
Expand Down
35 changes: 1 addition & 34 deletions src/renderer/atlas/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ namespace Microsoft::Console::Render::Atlas
{
}

#pragma warning(suppress : 26432) // If you define or delete any default operation in the type '...', define or delete them all (c.21).
Buffer& operator=(Buffer&& other) noexcept
{
destroy();
Expand All @@ -181,40 +182,6 @@ namespace Microsoft::Console::Render::Atlas
return *this;
}

#if 0
Buffer(const Buffer& other) noexcept :
_data{ allocate(other._size) },
_size{ other._size }
{
#pragma warning(suppress : 26459) // You called an STL function '...' with a raw pointer parameter at position '...' that may be unsafe [...].
std::uninitialized_copy_n(other._data, other._size, _data);
}

Buffer& operator=(const Buffer& other) noexcept
{
destroy();
_data = nullptr;
_size = 0;

_data = allocate(other._size);
_size = other._size;

#pragma warning(suppress : 26459) // You called an STL function '...' with a raw pointer parameter at position '...' that may be unsafe [...].
std::uninitialized_copy_n(other._data, other._size, _data);
return *this;
}

bool operator==(const Buffer& other) const
{
return memcmp(_data, other._data, _size * sizeof(T)) == 0;
}

bool operator!=(const Buffer& other) const
{
return memcmp(_data, other._data, _size * sizeof(T)) != 0;
}
#endif

explicit operator bool() const noexcept
{
return _data != nullptr;
Expand Down
Loading