@@ -31,7 +31,6 @@ using namespace Microsoft::Console::Render;
3131try
3232{
3333 _adjustAtlasSize ();
34- _reserveScratchpadSize (_r.maxEncounteredCellCount );
3534 _processGlyphQueue ();
3635
3736 if (WI_IsFlagSet (_r.invalidations , RenderInvalidations::Cursor))
8685}
8786catch (const wil::ResultException& exception)
8887{
88+ // TODO: this writes to _api.
8989 return _handleException (exception);
9090}
9191CATCH_RETURN ()
@@ -159,7 +159,7 @@ void AtlasEngine::_adjustAtlasSize()
159159 desc.ArraySize = 1 ;
160160 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
161161 desc.SampleDesc = { 1 , 0 };
162- desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
162+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET ;
163163 THROW_IF_FAILED (_r.device ->CreateTexture2D (&desc, nullptr , atlasBuffer.addressof ()));
164164 THROW_IF_FAILED (_r.device ->CreateShaderResourceView (atlasBuffer.get (), nullptr , atlasView.addressof ()));
165165 }
@@ -184,38 +184,8 @@ void AtlasEngine::_adjustAtlasSize()
184184 _r.atlasView = std::move (atlasView);
185185 _setShaderResources ();
186186
187- WI_SetFlagIf (_r.invalidations , RenderInvalidations::Cursor, !copyFromExisting);
188- }
189-
190- void AtlasEngine::_reserveScratchpadSize (u16 minWidth)
191- {
192- if (minWidth <= _r.scratchpadCellWidth )
193- {
194- return ;
195- }
196-
197- // The new size is the greater of ... cells wide:
198- // * 2
199- // * minWidth
200- // * current size * 1.5
201- const auto newWidth = std::max<UINT>(std::max<UINT>(2 , minWidth), _r.scratchpadCellWidth + (_r.scratchpadCellWidth >> 1 ));
202-
203- _r.d2dRenderTarget .reset ();
204- _r.atlasScratchpad .reset ();
205-
206- {
207- D3D11_TEXTURE2D_DESC desc{};
208- desc.Width = _r.cellSize .x * newWidth;
209- desc.Height = _r.cellSize .y ;
210- desc.MipLevels = 1 ;
211- desc.ArraySize = 1 ;
212- desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
213- desc.SampleDesc = { 1 , 0 };
214- desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
215- THROW_IF_FAILED (_r.device ->CreateTexture2D (&desc, nullptr , _r.atlasScratchpad .put ()));
216- }
217187 {
218- const auto surface = _r.atlasScratchpad .query <IDXGISurface>();
188+ const auto surface = _r.atlasBuffer .query <IDXGISurface>();
219189
220190 wil::com_ptr<IDWriteRenderingParams1> renderingParams;
221191 DWrite_GetRenderParams (_sr.dwriteFactory .get (), &_r.gamma , &_r.cleartypeEnhancedContrast , &_r.grayscaleEnhancedContrast , renderingParams.addressof ());
@@ -243,8 +213,8 @@ void AtlasEngine::_reserveScratchpadSize(u16 minWidth)
243213 _r.brush = brush.query <ID2D1Brush>();
244214 }
245215
246- _r.scratchpadCellWidth = _r.maxEncounteredCellCount ;
247216 WI_SetAllFlags (_r.invalidations , RenderInvalidations::ConstBuffer);
217+ WI_SetFlagIf (_r.invalidations , RenderInvalidations::Cursor, !copyFromExisting);
248218}
249219
250220void AtlasEngine::_processGlyphQueue ()
@@ -254,10 +224,12 @@ void AtlasEngine::_processGlyphQueue()
254224 return ;
255225 }
256226
227+ _r.d2dRenderTarget ->BeginDraw ();
257228 for (const auto & pair : _r.glyphQueue )
258229 {
259230 _drawGlyph (pair);
260231 }
232+ THROW_IF_FAILED (_r.d2dRenderTarget ->EndDraw ());
261233
262234 _r.glyphQueue .clear ();
263235}
@@ -280,7 +252,7 @@ void AtlasEngine::_drawGlyph(const AtlasQueueItem& item) const
280252 textLayout->SetTypography (_r.typography .get (), { 0 , charsLength });
281253 }
282254
283- auto options = D2D1_DRAW_TEXT_OPTIONS_NONE ;
255+ auto options = D2D1_DRAW_TEXT_OPTIONS_CLIP ;
284256 // D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT enables a bunch of internal machinery
285257 // which doesn't have to run if we know we can't use it anyways in the shader.
286258 WI_SetFlagIf (options, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT, coloredGlyph);
@@ -294,31 +266,29 @@ void AtlasEngine::_drawGlyph(const AtlasQueueItem& item) const
294266 _r.d2dRenderTarget ->SetTextAntialiasMode (coloredGlyph ? D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE : D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
295267 }
296268
297- _r.d2dRenderTarget ->BeginDraw ();
298- // We could call
299- // _r.d2dRenderTarget->PushAxisAlignedClip(&rect, D2D1_ANTIALIAS_MODE_ALIASED);
300- // now to reduce the surface that needs to be cleared, but this decreases
301- // performance by 10% (tested using debugGlyphGenerationPerformance).
302- _r.d2dRenderTarget ->Clear ();
303- _r.d2dRenderTarget ->DrawTextLayout ({}, textLayout.get (), _r.brush .get (), options);
304- THROW_IF_FAILED (_r.d2dRenderTarget ->EndDraw ());
305-
306269 for (u32 i = 0 ; i < cells; ++i)
307270 {
308- // Specifying NO_OVERWRITE means that the system can assume that existing references to the surface that
309- // may be in flight on the GPU will not be affected by the update, so the copy can proceed immediately
310- // (avoiding either a batch flush or the system maintaining multiple copies of the resource behind the scenes).
311- //
312- // Since our shader only draws whatever is in the atlas, and since we don't replace glyph tiles that are in use,
313- // we can safely (?) tell the GPU that we don't overwrite parts of our atlas that are in use.
314- _copyScratchpadTile (i, coords[i], D3D11_COPY_NO_OVERWRITE);
271+ const auto coord = coords[i];
272+
273+ D2D1_RECT_F rect;
274+ rect.left = static_cast <float >(coord.x ) * static_cast <float >(USER_DEFAULT_SCREEN_DPI) / static_cast <float >(_r.dpi );
275+ rect.top = static_cast <float >(coord.y ) * static_cast <float >(USER_DEFAULT_SCREEN_DPI) / static_cast <float >(_r.dpi );
276+ rect.right = rect.left + _r.cellSizeDIP .x ;
277+ rect.bottom = rect.top + _r.cellSizeDIP .y ;
278+
279+ D2D1_POINT_2F origin;
280+ origin.x = rect.left - i * _r.cellSizeDIP .x ;
281+ origin.y = rect.top ;
282+
283+ _r.d2dRenderTarget ->PushAxisAlignedClip (&rect, D2D1_ANTIALIAS_MODE_ALIASED);
284+ _r.d2dRenderTarget ->Clear ();
285+ _r.d2dRenderTarget ->DrawTextLayout (origin, textLayout.get (), _r.brush .get (), options);
286+ _r.d2dRenderTarget ->PopAxisAlignedClip ();
315287 }
316288}
317289
318290void AtlasEngine::_drawCursor ()
319291{
320- _reserveScratchpadSize (1 );
321-
322292 // lineWidth is in D2D's DIPs. For instance if we have a 150-200% zoom scale we want to draw a 2px wide line.
323293 // At 150% scale lineWidth thus needs to be 1.33333... because at a zoom scale of 1.5 this results in a 2px wide line.
324294 const auto lineWidth = std::max (1 .0f , static_cast <float >((_r.dpi + USER_DEFAULT_SCREEN_DPI / 2 ) / USER_DEFAULT_SCREEN_DPI * USER_DEFAULT_SCREEN_DPI) / static_cast <float >(_r.dpi ));
@@ -377,19 +347,4 @@ void AtlasEngine::_drawCursor()
377347 }
378348
379349 THROW_IF_FAILED (_r.d2dRenderTarget ->EndDraw ());
380-
381- _copyScratchpadTile (0 , {});
382- }
383-
384- void AtlasEngine::_copyScratchpadTile (uint32_t scratchpadIndex, u16x2 target, uint32_t copyFlags) const noexcept
385- {
386- D3D11_BOX box;
387- box.left = scratchpadIndex * _r.cellSize .x ;
388- box.top = 0 ;
389- box.front = 0 ;
390- box.right = box.left + _r.cellSize .x ;
391- box.bottom = _r.cellSize .y ;
392- box.back = 1 ;
393- #pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function '...' which may throw exceptions (f.6).
394- _r.deviceContext ->CopySubresourceRegion1 (_r.atlasBuffer .get (), 0 , target.x , target.y , 0 , _r.atlasScratchpad .get (), 0 , &box, copyFlags);
395350}
0 commit comments