Skip to content

Commit

Permalink
Scale retro terminal scan lines (#4716)
Browse files Browse the repository at this point in the history
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
- Scale the retro terminal effects (#3468) scan lines with the screen's DPI.
- Remove artifacts from sampling wrap around.

Before & after, with my display scale set to 350%:
![Scaling scan lines](https://user-images.githubusercontent.com/38924837/75214566-df0f4780-5742-11ea-9bdc-3430eb24ccca.png)

Before & after showing artifact removal, with my display scale set to 100%, and image enlarged to 400%:
![Sampling artifacts annotated](https://user-images.githubusercontent.com/38924837/75214618-05cd7e00-5743-11ea-9060-f4eba257ea56.png)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #4362
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Requires documentation to be updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

Adds a constant buffer, which could be used for other settings for the retro terminal pixel shader.

I haven't touched C++ in over a decade before this change, and this is the first time I've played with DirectX, so please assume my code isn't exactly best practice. 🙂

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Changed display scale with experimental.retroTerminalEffect enabled, enjoyed scan lines on high resolution monitors.
- Enabled experimental.retroTerminalEffect, turned the setting off, changed display scale. Retro tabs still scale scan lines.
  • Loading branch information
dotpaul authored Feb 26, 2020
1 parent 8a5407c commit de5e72f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 15 deletions.
61 changes: 50 additions & 11 deletions src/renderer/dx/DxRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,24 @@ HRESULT DxEngine::_SetupTerminalEffects()

RETURN_IF_FAILED(_d3dDevice->CreateBuffer(&bd, &InitData, &_screenQuadVertexBuffer));

D3D11_BUFFER_DESC pixelShaderSettingsBufferDesc{};
pixelShaderSettingsBufferDesc.Usage = D3D11_USAGE_DEFAULT;
pixelShaderSettingsBufferDesc.ByteWidth = sizeof(_pixelShaderSettings);
pixelShaderSettingsBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

_ComputePixelShaderSettings();

D3D11_SUBRESOURCE_DATA pixelShaderSettingsInitData{};
pixelShaderSettingsInitData.pSysMem = &_pixelShaderSettings;

RETURN_IF_FAILED(_d3dDevice->CreateBuffer(&pixelShaderSettingsBufferDesc, &pixelShaderSettingsInitData, &_pixelShaderSettingsBuffer));

// Sampler state is needed to use texture as input to shader.
D3D11_SAMPLER_DESC samplerDesc{};
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
Expand All @@ -308,6 +320,22 @@ HRESULT DxEngine::_SetupTerminalEffects()
return S_OK;
}

// Routine Description:
// - Puts the correct values in _pixelShaderSettings, so the struct can be
// passed the GPU.
// Arguments:
// - <none>
// Return Value:
// - <none>
void DxEngine::_ComputePixelShaderSettings() noexcept
{
// Retro scan lines alternate every pixel row at 100% scaling.
_pixelShaderSettings.ScaledScanLinePeriod = _scale * 1.0f;

// Gaussian distribution sigma used for blurring.
_pixelShaderSettings.ScaledGaussianSigma = _scale * 2.0f;
}

// Routine Description;
// - Creates device-specific resources required for drawing
// which generally means those that are represented on the GPU and can
Expand Down Expand Up @@ -1097,18 +1125,18 @@ void DxEngine::_InvalidOr(RECT rc) noexcept
// - S_OK on success, E_PENDING to indicate a retry or a relevant DirectX error
[[nodiscard]] HRESULT DxEngine::Present() noexcept
{
if (_retroTerminalEffects)
if (_presentReady)
{
const HRESULT hr2 = _PaintTerminalEffects();
if (FAILED(hr2))
if (_retroTerminalEffects)
{
_retroTerminalEffects = false;
LOG_HR_MSG(hr2, "Failed to paint terminal effects. Disabling.");
const HRESULT hr2 = _PaintTerminalEffects();
if (FAILED(hr2))
{
_retroTerminalEffects = false;
LOG_HR_MSG(hr2, "Failed to paint terminal effects. Disabling.");
}
}
}

if (_presentReady)
{
try
{
HRESULT hr = S_OK;
Expand Down Expand Up @@ -1492,6 +1520,7 @@ try
_d3dDeviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
_d3dDeviceContext->PSSetShaderResources(0, 1, shaderResource.GetAddressOf());
_d3dDeviceContext->PSSetSamplers(0, 1, _samplerState.GetAddressOf());
_d3dDeviceContext->PSSetConstantBuffers(0, 1, _pixelShaderSettingsBuffer.GetAddressOf());
_d3dDeviceContext->Draw(ARRAYSIZE(_screenQuadVertices), 0);

return S_OK;
Expand Down Expand Up @@ -1589,6 +1618,16 @@ CATCH_RETURN()

RETURN_IF_FAILED(InvalidateAll());

if (_retroTerminalEffects && _d3dDeviceContext && _pixelShaderSettingsBuffer)
{
_ComputePixelShaderSettings();
try
{
_d3dDeviceContext->UpdateSubresource(_pixelShaderSettingsBuffer.Get(), 0, NULL, &_pixelShaderSettings, 0, 0);
}
CATCH_RETURN();
}

return S_OK;
}

Expand Down
10 changes: 10 additions & 0 deletions src/renderer/dx/DxRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,23 @@ namespace Microsoft::Console::Render
::Microsoft::WRL::ComPtr<ID3D11PixelShader> _pixelShader;
::Microsoft::WRL::ComPtr<ID3D11InputLayout> _vertexLayout;
::Microsoft::WRL::ComPtr<ID3D11Buffer> _screenQuadVertexBuffer;
::Microsoft::WRL::ComPtr<ID3D11Buffer> _pixelShaderSettingsBuffer;
::Microsoft::WRL::ComPtr<ID3D11SamplerState> _samplerState;
::Microsoft::WRL::ComPtr<ID3D11Texture2D> _framebufferCapture;

D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode;

// DirectX constant buffers need to be a multiple of 16; align to pad the size.
__declspec(align(16)) struct
{
float ScaledScanLinePeriod;
float ScaledGaussianSigma;
#pragma warning(suppress : 4324) // structure was padded due to __declspec(align())
} _pixelShaderSettings;

[[nodiscard]] HRESULT _CreateDeviceResources(const bool createSwapChain) noexcept;
HRESULT _SetupTerminalEffects();
void _ComputePixelShaderSettings() noexcept;

[[nodiscard]] HRESULT _PrepareRenderTarget() noexcept;

Expand Down
12 changes: 8 additions & 4 deletions src/renderer/dx/ScreenPixelShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ const char screenPixelShaderString[] = R"(
Texture2D shaderTexture;
SamplerState samplerState;

cbuffer PixelShaderSettings
{
float ScaledScanLinePeriod;
float ScaledGaussianSigma;
};

#define SCANLINE_FACTOR 0.5
#define SCANLINE_PERIOD 1

static const float M_PI = 3.14159265f;

Expand All @@ -26,7 +31,6 @@ float4 Blur(Texture2D input, float2 tex_coord, float sigma)
float texelHeight = 1.0f/height;

float4 color = { 0, 0, 0, 0 };
float factor = 1;

int sampleCount = 13;

Expand All @@ -49,7 +53,7 @@ float4 Blur(Texture2D input, float2 tex_coord, float sigma)

float SquareWave(float y)
{
return 1 - (floor(y / SCANLINE_PERIOD) % 2) * SCANLINE_FACTOR;
return 1 - (floor(y / ScaledScanLinePeriod) % 2) * SCANLINE_FACTOR;
}

float4 Scanline(float4 color, float4 pos)
Expand All @@ -74,7 +78,7 @@ float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET

// TODO:GH#3930 Make these configurable in some way.
float4 color = input.Sample(samplerState, tex);
color += Blur(input, tex, 2)*0.3;
color += Blur(input, tex, ScaledGaussianSigma)*0.3;
color = Scanline(color, pos);

return color;
Expand Down

0 comments on commit de5e72f

Please sign in to comment.