417 lines
12 KiB
C++
417 lines
12 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "WddmConRenderer.hpp"
|
|
|
|
#include "main.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Default non-bright white.
|
|
//
|
|
|
|
#define DEFAULT_COLOR_ATTRIBUTE (0xC)
|
|
|
|
#define DEFAULT_FONT_WIDTH (8)
|
|
#define DEFAULT_FONT_HEIGHT (12)
|
|
|
|
using namespace Microsoft::Console::Render;
|
|
|
|
WddmConEngine::WddmConEngine() :
|
|
RenderEngineBase(),
|
|
_hWddmConCtx(INVALID_HANDLE_VALUE),
|
|
_displayHeight(0),
|
|
_displayWidth(0),
|
|
_displayState(nullptr),
|
|
_currentLegacyColorAttribute(DEFAULT_COLOR_ATTRIBUTE)
|
|
{
|
|
}
|
|
|
|
void WddmConEngine::FreeResources(ULONG displayHeight)
|
|
{
|
|
if (_displayState)
|
|
{
|
|
for (ULONG i = 0; i < displayHeight; i++)
|
|
{
|
|
if (_displayState[i])
|
|
{
|
|
if (_displayState[i]->Old)
|
|
{
|
|
free(_displayState[i]->Old);
|
|
}
|
|
if (_displayState[i]->New)
|
|
{
|
|
free(_displayState[i]->New);
|
|
}
|
|
|
|
free(_displayState[i]);
|
|
}
|
|
}
|
|
|
|
free(_displayState);
|
|
}
|
|
|
|
if (_hWddmConCtx != INVALID_HANDLE_VALUE)
|
|
{
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
_hWddmConCtx = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
WddmConEngine::~WddmConEngine()
|
|
{
|
|
FreeResources(_displayHeight);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Initialize() noexcept
|
|
{
|
|
HRESULT hr;
|
|
RECT DisplaySize;
|
|
CD_IO_DISPLAY_SIZE DisplaySizeIoctl;
|
|
|
|
if (_hWddmConCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = WDDMConCreate(&_hWddmConCtx);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = WDDMConGetDisplaySize(_hWddmConCtx, &DisplaySizeIoctl);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DisplaySize.top = 0;
|
|
DisplaySize.left = 0;
|
|
DisplaySize.bottom = (LONG)DisplaySizeIoctl.Height;
|
|
DisplaySize.right = (LONG)DisplaySizeIoctl.Width;
|
|
|
|
_displayState = (PCD_IO_ROW_INFORMATION*)calloc(DisplaySize.bottom, sizeof(PCD_IO_ROW_INFORMATION));
|
|
|
|
if (_displayState != nullptr)
|
|
{
|
|
for (LONG i = 0; i < DisplaySize.bottom; i++)
|
|
{
|
|
_displayState[i] = (PCD_IO_ROW_INFORMATION)calloc(1, sizeof(CD_IO_ROW_INFORMATION));
|
|
if (_displayState[i] == nullptr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
|
|
_displayState[i]->Index = (SHORT)i;
|
|
_displayState[i]->Old = (PCD_IO_CHARACTER)calloc(DisplaySize.right, sizeof(CD_IO_CHARACTER));
|
|
_displayState[i]->New = (PCD_IO_CHARACTER)calloc(DisplaySize.right, sizeof(CD_IO_CHARACTER));
|
|
|
|
if (_displayState[i]->Old == nullptr || _displayState[i]->New == nullptr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_displayHeight = DisplaySize.bottom;
|
|
_displayWidth = DisplaySize.right;
|
|
}
|
|
else
|
|
{
|
|
FreeResources(DisplaySize.bottom);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WDDMConDestroy(_hWddmConCtx);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_HANDLE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
bool WddmConEngine::IsInitialized()
|
|
{
|
|
return _hWddmConCtx != INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Enable() noexcept
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
return WDDMConEnableDisplayAccess((PHANDLE)_hWddmConCtx, TRUE);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Disable() noexcept
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
return WDDMConEnableDisplayAccess((PHANDLE)_hWddmConCtx, FALSE);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Invalidate(const SMALL_RECT* const /*psrRegion*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateCursor(const COORD* const /*pcoordCursor*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateSystem(const RECT* const /*prcDirtyClient*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateSelection(const std::vector<SMALL_RECT>& /*rectangles*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateScroll(const COORD* const /*pcoordDelta*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateAll() noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
|
|
{
|
|
*pForcePaint = false;
|
|
return S_FALSE;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
|
|
{
|
|
*pForcePaint = false;
|
|
return S_FALSE;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::StartPaint() noexcept
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
return WDDMConBeginUpdateDisplayBatch(_hWddmConCtx);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::EndPaint() noexcept
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
return WDDMConEndUpdateDisplayBatch(_hWddmConCtx);
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Used to perform longer running presentation steps outside the lock so the other threads can continue.
|
|
// - Not currently used by WddmConEngine.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - S_FALSE since we do nothing.
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::Present() noexcept
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::ScrollFrame() noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBackground() noexcept
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
PCD_IO_CHARACTER OldChar;
|
|
PCD_IO_CHARACTER NewChar;
|
|
|
|
for (LONG rowIndex = 0; rowIndex < _displayHeight; rowIndex++)
|
|
{
|
|
for (LONG colIndex = 0; colIndex < _displayWidth; colIndex++)
|
|
{
|
|
OldChar = &_displayState[rowIndex]->Old[colIndex];
|
|
NewChar = &_displayState[rowIndex]->New[colIndex];
|
|
|
|
OldChar->Character = NewChar->Character;
|
|
OldChar->Atribute = NewChar->Atribute;
|
|
|
|
NewChar->Character = L' ';
|
|
NewChar->Atribute = 0x0;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
|
const COORD coord,
|
|
const bool /*trimLeft*/) noexcept
|
|
{
|
|
try
|
|
{
|
|
RETURN_IF_HANDLE_INVALID(_hWddmConCtx);
|
|
|
|
PCD_IO_CHARACTER OldChar;
|
|
PCD_IO_CHARACTER NewChar;
|
|
|
|
for (size_t i = 0; i < clusters.size() && i < (size_t)_displayWidth; i++)
|
|
{
|
|
OldChar = &_displayState[coord.Y]->Old[coord.X + i];
|
|
NewChar = &_displayState[coord.Y]->New[coord.X + i];
|
|
|
|
OldChar->Character = NewChar->Character;
|
|
OldChar->Atribute = NewChar->Atribute;
|
|
|
|
NewChar->Character = clusters.at(i).GetTextAsSingle();
|
|
NewChar->Atribute = _currentLegacyColorAttribute;
|
|
}
|
|
|
|
return WDDMConUpdateDisplay(_hWddmConCtx, _displayState[coord.Y], FALSE);
|
|
}
|
|
CATCH_RETURN();
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintBufferGridLines(GridLines const /*lines*/,
|
|
COLORREF const /*color*/,
|
|
size_t const /*cchLine*/,
|
|
COORD const /*coordTarget*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintSelection(const SMALL_RECT /*rect*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::PaintCursor(const IRenderEngine::CursorOptions& /*options*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateDrawingBrushes(COLORREF const /*colorForeground*/,
|
|
COLORREF const /*colorBackground*/,
|
|
const WORD legacyColorAttribute,
|
|
const ExtendedAttributes /*extendedAttrs*/,
|
|
bool const /*isSettingDefaultBrushes*/) noexcept
|
|
{
|
|
_currentLegacyColorAttribute = legacyColorAttribute;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept
|
|
{
|
|
return GetProposedFont(fiFontInfoDesired, fiFontInfo, USER_DEFAULT_SCREEN_DPI);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateDpi(int const /*iDpi*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// Method Description:
|
|
// - This method will update our internal reference for how big the viewport is.
|
|
// Does nothing for WDDMCon.
|
|
// Arguments:
|
|
// - srNewViewport - The bounds of the new viewport.
|
|
// Return Value:
|
|
// - HRESULT S_OK
|
|
[[nodiscard]] HRESULT WddmConEngine::UpdateViewport(const SMALL_RECT /*srNewViewport*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::GetProposedFont(const FontInfoDesired& /*fiFontInfoDesired*/,
|
|
FontInfo& fiFontInfo,
|
|
int const /*iDpi*/) noexcept
|
|
{
|
|
COORD coordSize = { 0 };
|
|
LOG_IF_FAILED(GetFontSize(&coordSize));
|
|
|
|
fiFontInfo.SetFromEngine(fiFontInfo.GetFaceName(),
|
|
fiFontInfo.GetFamily(),
|
|
fiFontInfo.GetWeight(),
|
|
fiFontInfo.IsTrueTypeFont(),
|
|
coordSize,
|
|
coordSize);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
SMALL_RECT WddmConEngine::GetDirtyRectInChars()
|
|
{
|
|
SMALL_RECT r;
|
|
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
|
|
r.Top = 0;
|
|
r.Left = 0;
|
|
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
|
|
|
|
return r;
|
|
}
|
|
|
|
RECT WddmConEngine::GetDisplaySize()
|
|
{
|
|
RECT r;
|
|
r.top = 0;
|
|
r.left = 0;
|
|
r.bottom = _displayHeight;
|
|
r.right = _displayWidth;
|
|
|
|
return r;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept
|
|
{
|
|
// In order to retrieve the font size being used by DirectX, it is necessary
|
|
// to modify the API set that defines the contract for WddmCon. However, the
|
|
// intention is to subsume WddmCon into ConhostV2 directly once the issue of
|
|
// building in the OneCore 'depot' including DirectX headers and libs is
|
|
// resolved. The font size has no bearing on the behavior of the console
|
|
// since it is used to determine the invalid rectangle whenever the console
|
|
// buffer changes. However, given that no invalidation logic exists for this
|
|
// renderer, the value returned by this function is irrelevant.
|
|
//
|
|
// TODO: MSFT 11851921 - Subsume WddmCon into ConhostV2 and remove the API
|
|
// set extension.
|
|
COORD c;
|
|
c.X = DEFAULT_FONT_WIDTH;
|
|
c.Y = DEFAULT_FONT_HEIGHT;
|
|
|
|
*pFontSize = c;
|
|
return S_OK;
|
|
}
|
|
|
|
[[nodiscard]] HRESULT WddmConEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const pResult) noexcept
|
|
{
|
|
*pResult = false;
|
|
return S_OK;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Updates the window's title string.
|
|
// Does nothing for WddmCon.
|
|
// Arguments:
|
|
// - newTitle: the new string to use for the title of the window
|
|
// Return Value:
|
|
// - S_OK
|
|
[[nodiscard]] HRESULT WddmConEngine::_DoUpdateTitle(_In_ const std::wstring& /*newTitle*/) noexcept
|
|
{
|
|
return S_OK;
|
|
}
|