Compare commits

...

3 Commits

Author SHA1 Message Date
Dustin Howett
4ba0df58fa TopLeft -> full Padding (to pass to the user shader!) 2023-08-16 13:14:46 -05:00
Leonard Hecker
682370fad9 Offset background texture and use Sample() instead of Load() 2023-08-12 02:04:48 +02:00
Dustin L. Howett
bc2a169590 WIP: Put padding in the atlas engine
TODO:
- [ ] the background texture gets rendered in the wrong place
- [ ] clean up the weird "updatedpi" thing
- [ ] handle Leonard's request to move the add after the M to get FMA
- [ ] actually use it in TermControl lel
2023-08-11 10:32:34 -05:00
11 changed files with 107 additions and 28 deletions

View File

@@ -176,6 +176,12 @@ constexpr HRESULT vec2_narrow(U x, U y, vec2<T>& out) noexcept
if (_api.s->font->dpi != newDPI)
{
_api.s.write()->font.write()->dpi = newDPI;
_api.s.write()->misc.write()->padding = {
.x = _api.paddingInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.y = _api.paddingInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.z = _api.paddingInDip.z * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.w = _api.paddingInDip.w * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
};
}
return S_OK;
@@ -778,3 +784,18 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
fontMetrics->overline = { 0, underlineWidthU16 };
}
}
void AtlasEngine::SetPadding(float left, float top, float right, float bottom) noexcept
{
f32x4 newPadding{ left, top, right, bottom };
if (_api.paddingInDip != newPadding)
{
_api.paddingInDip = newPadding;
_api.s.write()->misc.write()->padding = {
.x = _api.paddingInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.y = _api.paddingInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.z = _api.paddingInDip.z * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.w = _api.paddingInDip.w * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
};
}
}

View File

@@ -78,6 +78,7 @@ namespace Microsoft::Console::Render::Atlas
[[nodiscard]] HRESULT SetWindowSize(til::size pixels) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept override;
void UpdateHyperlinkHoveredId(uint16_t hoveredId) noexcept override;
void SetPadding(float left, float top, float right, float bottom) noexcept override;
private:
// AtlasEngine.cpp
@@ -164,6 +165,9 @@ namespace Microsoft::Console::Render::Atlas
u16r invalidatedCursorArea = invalidatedAreaNone;
range<u16> invalidatedRows = invalidatedRowsNone; // x is treated as "top" and y as "bottom"
i16 scrollOffset = 0;
// SetPadding()
f32x4 paddingInDip{ 0.f, 0.f, 0.f, 0.f };
} _api;
};
}

View File

@@ -38,12 +38,15 @@ void BackendD2D::Render(RenderingPayload& p)
_handleSettingsUpdate(p);
}
const D2D1_MATRIX_3X2_F worldTransform{ _getDefaultTransform(p) };
_renderTarget->BeginDraw();
#if ATLAS_DEBUG_SHOW_DIRTY || ATLAS_DEBUG_DUMP_RENDER_TARGET
// Invalidating the render target helps with spotting Present1() bugs.
_renderTarget->Clear();
#endif
_drawBackground(p);
_renderTarget->SetTransform(&worldTransform);
_drawCursorPart1(p);
_drawText(p);
_drawCursorPart2(p);
@@ -265,7 +268,7 @@ void BackendD2D::_drawText(RenderingPayload& p)
if (row->lineRendition != LineRendition::SingleWidth)
{
_drawTextResetLineRendition(row);
_drawTextResetLineRendition(p, row);
}
if (p.invalidatedRows.contains(y))
@@ -287,17 +290,15 @@ void BackendD2D::_drawText(RenderingPayload& p)
f32 BackendD2D::_drawTextPrepareLineRendition(const RenderingPayload& p, const ShapedRow* row, f32 baselineY) const noexcept
{
const auto lineRendition = row->lineRendition;
D2D1_MATRIX_3X2_F transform{
.m11 = 2.0f,
.m22 = 1.0f,
};
D2D1_MATRIX_3X2_F transform{ _getDefaultTransform(p) };
transform.m11 = 2.0f; // scale horizontally by 2.0
if (lineRendition >= LineRendition::DoubleHeightTop)
{
D2D1_RECT_F clipRect{ 0, 0, static_cast<f32>(p.s->targetSize.x), static_cast<f32>(p.s->targetSize.y) };
transform.m22 = 2.0f;
transform.dy = -1.0f * (baselineY + p.s->font->descender);
transform.dy += -1.0f * (baselineY + p.s->font->descender);
// If you print the top half of a double height row (DECDHL), the expectation is that only
// the top half is visible, which requires us to keep the clip rect at the bottom of the row.
@@ -321,9 +322,9 @@ f32 BackendD2D::_drawTextPrepareLineRendition(const RenderingPayload& p, const S
return baselineY;
}
void BackendD2D::_drawTextResetLineRendition(const ShapedRow* row) const noexcept
void BackendD2D::_drawTextResetLineRendition(const RenderingPayload& p, const ShapedRow* row) const noexcept
{
static constexpr D2D1_MATRIX_3X2_F identity{ .m11 = 1, .m22 = 1 };
const auto identity{ _getDefaultTransform(p) };
_renderTarget->SetTransform(&identity);
if (row->lineRendition >= LineRendition::DoubleHeightTop)
@@ -684,4 +685,14 @@ void BackendD2D::_fillRectangle(const D2D1_RECT_F& rect, u32 color)
_renderTarget->FillRectangle(&rect, brush);
}
D2D_MATRIX_3X2_F BackendD2D::_getDefaultTransform(const RenderingPayload& p) const noexcept
{
return {
.m11 = 1.f,
.m22 = 1.f,
.dx = p.s->misc->padding.x,
.dy = p.s->misc->padding.y,
};
}
TIL_FAST_MATH_END

View File

@@ -20,7 +20,7 @@ namespace Microsoft::Console::Render::Atlas
void _drawBackground(const RenderingPayload& p) noexcept;
void _drawText(RenderingPayload& p);
ATLAS_ATTR_COLD f32 _drawTextPrepareLineRendition(const RenderingPayload& p, const ShapedRow* row, f32 baselineY) const noexcept;
ATLAS_ATTR_COLD void _drawTextResetLineRendition(const ShapedRow* row) const noexcept;
ATLAS_ATTR_COLD void _drawTextResetLineRendition(const RenderingPayload& p, const ShapedRow* row) const noexcept;
ATLAS_ATTR_COLD f32r _getGlyphRunDesignBounds(const DWRITE_GLYPH_RUN& glyphRun, f32 baselineX, f32 baselineY);
ATLAS_ATTR_COLD void _drawGridlineRow(const RenderingPayload& p, const ShapedRow* row, u16 y);
void _drawCursorPart1(const RenderingPayload& p);
@@ -34,6 +34,8 @@ namespace Microsoft::Console::Render::Atlas
ATLAS_ATTR_COLD ID2D1SolidColorBrush* _brushWithColorUpdate(u32 color);
void _fillRectangle(const D2D1_RECT_F& rect, u32 color);
D2D_MATRIX_3X2_F _getDefaultTransform(const RenderingPayload& p) const noexcept;
wil::com_ptr<ID2D1DeviceContext> _renderTarget;
wil::com_ptr<ID2D1DeviceContext4> _renderTarget4; // Optional. Supported since Windows 10 14393.
wil::com_ptr<ID2D1StrokeStyle> _dottedStrokeStyle;

View File

@@ -524,23 +524,52 @@ void BackendD3D::_recreateBackgroundColorBitmap(const RenderingPayload& p)
_backgroundBitmapGeneration = {};
}
void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const
void BackendD3D::_recreateConstBuffer(const RenderingPayload& p)
{
{
VSConstBuffer data{};
data.positionScale = { 2.0f / p.s->targetSize.x, -2.0f / p.s->targetSize.y };
data.positionScale = {
2.0f / p.s->targetSize.x,
-2.0f / p.s->targetSize.y,
};
data.positionOffset = {
data.positionScale.x * p.s->misc->padding.x - 1.0f,
data.positionScale.y * p.s->misc->padding.y + 1.0f,
};
p.deviceContext->UpdateSubresource(_vsConstantBuffer.get(), 0, nullptr, &data, 0, 0);
}
{
PSConstBuffer data{};
data.backgroundColor = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor);
data.backgroundCellSize = { static_cast<f32>(p.s->font->cellSize.x), static_cast<f32>(p.s->font->cellSize.y) };
data.backgroundCellCount = { static_cast<f32>(p.s->viewportCellCount.x), static_cast<f32>(p.s->viewportCellCount.y) };
data.backgroundScale = {
1.0f / (p.s->font->cellSize.x * p.s->viewportCellCount.x),
1.0f / (p.s->font->cellSize.y * p.s->viewportCellCount.y),
};
data.backgroundOffset = {
data.backgroundScale.x * -p.s->misc->padding.x,
data.backgroundScale.y * -p.s->misc->padding.y,
};
DWrite_GetGammaRatios(_gamma, data.gammaRatios);
data.enhancedContrast = p.s->font->antialiasingMode == AntialiasingMode::ClearType ? _cleartypeEnhancedContrast : _grayscaleEnhancedContrast;
data.underlineWidth = p.s->font->underline.height;
p.deviceContext->UpdateSubresource(_psConstantBuffer.get(), 0, nullptr, &data, 0, 0);
}
{
const auto color = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor);
const D3D11_SAMPLER_DESC desc{
.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT,
.AddressU = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressV = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressW = D3D11_TEXTURE_ADDRESS_BORDER,
.MipLODBias = 0,
.MaxAnisotropy = 1,
.ComparisonFunc = D3D11_COMPARISON_NEVER,
.BorderColor = { color.x, color.y, color.z, color.w },
//.BorderColor = { 1.0f, 0.2f, 0.2f, 1.0f },
.MinLOD = -FLT_MAX,
.MaxLOD = FLT_MAX,
};
THROW_IF_FAILED(p.device->CreateSamplerState(&desc, _backgroundSampler.put()));
}
}
void BackendD3D::_setupDeviceContextState(const RenderingPayload& p)
@@ -569,6 +598,7 @@ void BackendD3D::_setupDeviceContextState(const RenderingPayload& p)
p.deviceContext->PSSetShader(_pixelShader.get(), nullptr, 0);
p.deviceContext->PSSetConstantBuffers(0, 1, _psConstantBuffer.addressof());
p.deviceContext->PSSetShaderResources(0, 2, &resources[0]);
p.deviceContext->PSSetSamplers(0, 1, _backgroundSampler.addressof());
// OM: Output Merger
p.deviceContext->OMSetBlendState(_blendState.get(), nullptr, 0xffffffff);
@@ -931,6 +961,10 @@ void BackendD3D::_drawBackground(const RenderingPayload& p)
_appendQuad() = {
.shadingType = ShadingType::Background,
.position = {
static_cast<i16>(lrintf(-p.s->misc->padding.x)),
static_cast<i16>(lrintf(-p.s->misc->padding.x)),
},
.size = p.s->targetSize,
};
}
@@ -2092,10 +2126,11 @@ void BackendD3D::_executeCustomShader(RenderingPayload& p)
.time = std::chrono::duration<f32>(std::chrono::steady_clock::now() - _customShaderStartTime).count(),
.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),
static_cast<f32>(_viewportCellCount.y * p.s->font->cellSize.y),
static_cast<f32>(p.s->targetSize.x),
static_cast<f32>(p.s->targetSize.y),
},
.background = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor),
.padding = p.s->misc->padding,
};
D3D11_MAPPED_SUBRESOURCE mapped{};
@@ -2150,7 +2185,7 @@ void BackendD3D::_executeCustomShader(RenderingPayload& p)
p.deviceContext->PSSetShader(_pixelShader.get(), nullptr, 0);
p.deviceContext->PSSetConstantBuffers(0, 1, _psConstantBuffer.addressof());
p.deviceContext->PSSetShaderResources(0, 2, &resources[0]);
p.deviceContext->PSSetSamplers(0, 0, nullptr);
p.deviceContext->PSSetSamplers(0, 1, _backgroundSampler.addressof());
// OM: Output Merger
p.deviceContext->OMSetBlendState(_blendState.get(), nullptr, 0xffffffff);

View File

@@ -30,15 +30,15 @@ namespace Microsoft::Console::Render::Atlas
// * bool will probably not work the way you want it to,
// because HLSL uses 32-bit bools and C++ doesn't.
alignas(sizeof(f32x2)) f32x2 positionScale;
alignas(sizeof(f32x2)) f32x2 positionOffset;
#pragma warning(suppress : 4324) // 'VSConstBuffer': structure was padded due to alignment specifier
};
// WARNING: Same rules as for VSConstBuffer above apply.
struct alignas(16) PSConstBuffer
{
alignas(sizeof(f32x4)) f32x4 backgroundColor;
alignas(sizeof(f32x2)) f32x2 backgroundCellSize;
alignas(sizeof(f32x2)) f32x2 backgroundCellCount;
alignas(sizeof(f32x2)) f32x2 backgroundScale;
alignas(sizeof(f32x2)) f32x2 backgroundOffset;
alignas(sizeof(f32x4)) f32 gammaRatios[4]{};
alignas(sizeof(f32)) f32 enhancedContrast = 0;
alignas(sizeof(f32)) f32 underlineWidth = 0;
@@ -52,6 +52,7 @@ namespace Microsoft::Console::Render::Atlas
alignas(sizeof(f32)) f32 scale = 0;
alignas(sizeof(f32x2)) f32x2 resolution;
alignas(sizeof(f32x4)) f32x4 background;
alignas(sizeof(f32x4)) f32x4 padding;
#pragma warning(suppress : 4324) // 'CustomConstBuffer': structure was padded due to alignment specifier
};
@@ -199,7 +200,7 @@ namespace Microsoft::Console::Render::Atlas
void _recreateCustomShader(const RenderingPayload& p);
void _recreateCustomRenderTargetView(const RenderingPayload& p);
void _recreateBackgroundColorBitmap(const RenderingPayload& p);
void _recreateConstBuffer(const RenderingPayload& p) const;
void _recreateConstBuffer(const RenderingPayload& p);
void _setupDeviceContextState(const RenderingPayload& p);
void _debugUpdateShaders(const RenderingPayload& p) noexcept;
void _debugShowDirty(const RenderingPayload& p);
@@ -254,6 +255,7 @@ namespace Microsoft::Console::Render::Atlas
wil::com_ptr<ID3D11Texture2D> _backgroundBitmap;
wil::com_ptr<ID3D11ShaderResourceView> _backgroundBitmapView;
wil::com_ptr<ID3D11SamplerState> _backgroundSampler;
til::generation_t _backgroundBitmapGeneration;
wil::com_ptr<ID3D11Texture2D> _glyphAtlas;

View File

@@ -379,6 +379,7 @@ namespace Microsoft::Console::Render::Atlas
u32 selectionColor = 0x7fffffff;
std::wstring customPixelShaderPath;
bool useRetroTerminalEffect = false;
f32x4 padding{ 0.f, 0.f, 0.f, 0.f };
};
struct Settings

View File

@@ -6,14 +6,14 @@
cbuffer ConstBuffer : register(b0)
{
float4 backgroundColor;
float2 backgroundCellSize;
float2 backgroundCellCount;
float2 backgroundScale;
float2 backgroundOffset;
float4 gammaRatios;
float enhancedContrast;
float underlineWidth;
}
SamplerState backgroundSampler;
Texture2D<float4> background : register(t0);
Texture2D<float4> glyphAtlas : register(t1);
@@ -34,8 +34,7 @@ Output main(PSData data) : SV_Target
{
case SHADING_TYPE_TEXT_BACKGROUND:
{
const float2 cell = data.position.xy / backgroundCellSize;
color = all(cell < backgroundCellCount) ? background[cell] : backgroundColor;
color = background.Sample(backgroundSampler, data.position.xy * backgroundScale + backgroundOffset);
weights = float4(1, 1, 1, 1);
break;
}

View File

@@ -6,6 +6,7 @@
cbuffer ConstBuffer : register(b0)
{
float2 positionScale;
float2 positionOffset;
}
// clang-format off
@@ -17,8 +18,8 @@ PSData main(VSData data)
output.shadingType = data.shadingType;
// positionScale is expected to be float2(2.0f / sizeInPixel.x, -2.0f / sizeInPixel.y). Together with the
// addition below this will transform our "position" from pixel into normalized device coordinate (NDC) space.
output.position.xy = (data.position + data.vertex.xy * data.size) * positionScale + float2(-1.0f, 1.0f);
output.position.xy = (data.vertex * data.size + data.position) * positionScale + positionOffset;
output.position.zw = float2(0, 1);
output.texcoord = data.texcoord + data.vertex.xy * data.size;
output.texcoord = data.vertex * data.size + data.texcoord;
return output;
}

View File

@@ -158,6 +158,7 @@ namespace Microsoft::Console::Render
int _dpi;
float _scale;
float _prevScale;
DirectX::XMFLOAT4 _padding;
std::function<void(const HANDLE)> _pfn;
std::function<void(const HRESULT)> _pfnWarningCallback;
@@ -279,6 +280,7 @@ namespace Microsoft::Console::Render
float Scale;
DirectX::XMFLOAT2 Resolution;
DirectX::XMFLOAT4 Background;
DirectX::XMFLOAT4 Padding;
#pragma warning(suppress : 4324) // structure was padded due to __declspec(align())
} _pixelShaderSettings;

View File

@@ -111,6 +111,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT SetWindowSize(const til::size pixels) noexcept { return E_NOTIMPL; }
[[nodiscard]] virtual HRESULT UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept { return E_NOTIMPL; }
virtual void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept {}
virtual void SetPadding(float left, float top, float right, float bottom) noexcept {}
};
}
#pragma warning(pop)