【不完全翻譯】Direct2D介紹

https://bell0bytes.eu/direct2d-a-revision/

Drawing Text in Direct2D

Direct2D文本渲染可以分爲兩部分。第一部分暴露爲DrawText和DrawTextLayout方法,允許我們傳遞一個字符串或者文本進去。

第二個部分是渲染文字,使用到了ID2D1RenderTarget::DrawGlyphRun方法。

Layout vs Glyphs

DrawText非常容易使用。它使用了Unicode字符串,一個前景畫刷,一個Format物體和一個目的矩形。將文字放進矩形裏面,然後裁剪它。

DrawTextLayout

DrawTextLayout is a bit more advanced than the simple DrawText method. By creating an IDWriteTextLayout object, it is possible to measure and arrange text as desired. With text layouts, multiple fonts, styles, underlines and strikethroughs are supported as well.

DrawTextLayOut比DrawText稍微先進一些。當創建了IDWriteTextLayout物體後,就可以測量和管理文本了。當然可以支持多種字體,風格和下劃線。

當使用Text Layouts的時候,此Glyph Position將在Layout上創建一個緩存,意味着當多次使用DrawCalls,如果能夠多次使用同樣的Layout物體後,將節省非常多的性能。

DrawGlyphRun

Finally, it is possible to implement the IDWriteTextRenderer interface and to call DrawGlyphRun and FillRectangle manually.


效率

DrawTextLayout把已經存在的DWriteTextLayout物體繪製到RenderTarget上,此時DrawText首先已經通過傳入的參數創建了一個DirectWrite的Layout。如果要將相同的文本內容繪製多次,那麼用DrawTextLayout將更加高效,因爲DrawText每次都會創建一個Layout。

抗鋸齒

使用抗鋸齒模式 D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE 非常有效。效果與 ClearType 有一比,但是更高效。我們可以用DeviceContext來在全局設置這個。

devCon->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);


DXGI

As we have seen, Direct2D interoperates seamlessly with Direct3D surfaces. When rendering to a DXGI surface, Direct2D saves the state of the Direct3D devices while rendering and restores it when rendering is completed. Every time that a batch of Direct2D rendering is completed, the cost of this save and restore and the cost of flushing all the 2D operations are paid, and yet, the Direct3D device is not flushed. Therefore, to increase performance, the number of rendering switches between Direct2D and Direct3D must be limited.

正如我們看到的,D2D能無縫銜接D3D界面。當渲染DXGI表面時,D2D會在D3D渲染時保存狀態,在D3D渲染完成後重新讀取。爲了提高性能,我們必須限制D2D和D3D之間的切換。因此我們需要更改PrintFPS函數。

void Direct2D::printFPS(const Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> brush)
{
	if (dxApp->showFPS && textLayoutFPS)
	{
		// draw the text
		devCon->DrawTextLayout(D2D1::Point2F(2.5f, 5.0f), textLayoutFPS.Get(), brush.Get());
	}
}

我們需要在D2D繪製塊調用printFPS方法。

util::Expected<int> DirectXGame::render(double /*farSeer*/)
{
	// clear the back buffer and the depth/stencil buffer
	d3d->clearBuffers();

	////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////// Direct2D /////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////
	d2d->devCon->BeginDraw();

	// print FPS information
	d2d->printFPS(d2d->blackBrush.Get());

	if(FAILED(d2d->devCon->EndDraw()))
		return std::runtime_error("Failed to draw 2D graphics!");
	
	////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////// Direct3D /////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////
	
	// present the scene
	if (!d3d->present().wasSuccessful())
		return std::runtime_error("Failed to present the scene!");

	// return success
	return 0;
}

從Win10開始,D2D開始支持創建並渲染Sprite Batches。與通常的繪製圖像的方法相比,SpriteBatchesSprite批處理產生的每個映像CPU開銷大大減少。這讓其成爲渲染成百上千圖像的旋轉,比如粒子系統。

D2D現在爲Gradient Meshes提供新的Primitive。

 

在WIN10下,D2D爲加載圖像提供了一套新的API,即ID2D1ImageSource。圖像源改進了現有圖像加載API,包括CreateBitmapFromWicBitmap,位圖源效果和YCbCr效果。

Direct2D圖像源將這些API的功能與對任意大圖像的支持,與打印和效果的輕鬆集成以及衆多優化(包括YCbCr JPEG和索引JPEG)相結合。

Ink Rendering

在Win10上,D2D提供一種新的Primitve來表現ink Strokes。這個Ink Strokes由貝塞爾曲線定義。

資源包括筆刷,位圖,在D2D裏,可以在硬件或軟件上創建。但在硬件上刪除,則需要大量的開銷。

在D2D中,所有的渲染指令,都在BeginDraw和EndDraw兩個調用中。當BeginDraw被調用後,將建立一系列渲染指令,但將在一些狀態爲真後才執行這些指令。

  • EndDraw被調用後,會讓所有Batched的繪製操作取完成並且返回這些操作的狀態。
  • Flush將會被明確地調用,讓被執行的batch和所有等待狀態的指令都發布。
  • 保存渲染指令的緩存滿了。如果保存渲染指令的緩存在上面上面兩個指令滿足之前就滿了,那麼這些渲染指令將被Flushed Out。

在Primitive被flush之前,D2D將一直保持對資源的引用,比如bitmaps和brushed。

Reuse Resources

正如之前提到的,創建和刪除資源在硬件上非常昂貴,所以應當儘量複用資源。

比如位圖,在遊戲一開始就創建了所有不同種類的位圖,以便之後使用,而不是重新創建。丹青注意當窗口縮放時,有些與窗口尺寸有關的資源比如Compatible render target則需要重新創建,因爲保證渲染場景的整體質量是非常重要的。

Don't Flush (too often)

因爲Flush方法會讓所有batched的渲染指令被執行,我們推薦你別去用它,而是把資源管理交給D2D。

Large Bitmaps

顯卡通常有一個最小的內存分配大小限制。如果一個分配請求要比這個還小,那麼其餘的內存空間將會被浪費無法做任何事。

那麼如果你有一系列很小的位圖,那麼最好是把它們一起放在一張大位圖上。【原來是這樣】。這個也被叫做一個Atlas,可以減少創建位圖的開銷和內存的浪費。推薦位圖儘量大於64kb而不去使用小於4kb的位圖。

同樣,顯卡內存也有最大內存分配大小限制,取決於適配器。D2D從WIN8開始就開始支持Atlas了。

Shared Bitmaps

創建Shared Bitmaps允許更高級調用,即創建D2D位圖物體,可以被已存在的物體烘焙,也可以與Render Target兼容。這可以避免創建多個表面並且幫助減少開銷。

Shared bitmaps are usually limited to software targets or to targets interoperable with DXGI. The CreateBitmapFromDxgiSurface, CreateBitmapFromWicBitmap, and CreateSharedBitmap methods can be used to create shared bitmaps.

Copying Bitmaps

創建DXGI表面是非常昂貴的操作,所以重新使用已存在的表面吧。渲染通常要比複製更昂貴,因爲爲了提高緩存性能,bitmap在硬件上的位置通常會被打亂。因此CopyFrom*方法可以用於從一個Source複製矩形到D2D位圖。

Caching

當要把同一個東西渲染很多遍的時候,最好能夠緩存它。

Full scene caching using a color bitmap

When rendering static content, in scenarios like animation, creating another full colour bitmap instead of writing directly to the screen bitmap is a lot more efficient.

Per primitive caching using an A8 bitmap and the FillOpacityMask method

當一個場景不是靜態的時候,但卻包含很多靜態元素比如幾何體和Text,Per primitive緩存技術可以被用上。這個技術保持抗鋸齒的Primitive和Brush types。位圖是A8的,即Alpha通道使用了8bits。

當不透明的物體必須改變時,儘量去改變它的Mask而不是物體本身。

Per-primitive caching using geometry realizations

https://docs.microsoft.com/en-us/windows/win32/direct2d/geometry-realizations-overview

簡單來說,就是如果你的場景裏有一些不怎麼改變的幾何體,那麼每一幀都去Tesselation,渲染效率太低了。

於是大家想到一種方法,把這些幾何體緩存成位圖,這樣就可以節省大量資源。

但是一旦這個幾何體有所改變,又要重新緩存成位圖,這不好。

於是就有了Geometry Realization,就是把幾何體緩存成頂點數據。

 


Geometries

Primitives over Geometries

When drawing geometries, it is more efficient to call DrawRectangle than DrawGeometry, as with DrawRectangle, the geometry is already known so rendering is faster.

當要繪製幾何形狀時,使用DrawRectangle要比DrawGeometry更快,因爲前者已經知道了要繪製什麼形狀。


Multithreading

With the

D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS

flag (which we set when we created our device), Direct2D will distribute rendering across all of the logical cores present on the system, which can significantly decrease overall rendering time.

Note though that as of Windows 8.1 this only affects path geometries.

 

Pixel Formats

如果Render Target不使用Alpha通道,那麼應該用D2D1_ALPHA_MODE_IGNORE模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章