dotnet C# 使用 Vortice 支持 Direct2D1 離屏渲染

来源:https://www.cnblogs.com/lindexi/archive/2022/10/10/16774416.html
-Advertisement-
Play Games

一:背景 1.講故事 最近分享了好幾篇關於 非托管記憶體泄漏 的文章,有時候就是這麼神奇,來求助的都是這類型的dump,一飲一啄,莫非前定。讓我被迫加深對 NT堆, 頁堆 的理解,這一篇就給大家再帶來一篇記憶體泄漏。 前段時間有位朋友找到我,說他的程式出現了非托管泄漏,某一塊的操作會導致非托管記憶體上漲的 ...


本文告訴大家如何使用 Vortice 進行 D2D 的離屏渲染功能,本文將在一個純控制台無視窗的應用下,使用 Direct2D1 進行離屏繪製,將繪製結果保存為本地圖片文件

本文屬於使用 Vortice 調用 DirectX 系列博客,也屬於 DirectX 系列博客,本文屬於入門級博客,但在閱讀本文之前,期望大家瞭解了 DirectX 的基礎概念

本文使用的 Vortice 是 SharpDx 的代替品,是對 DirectX 的底層 C# 封裝。使用 Vortice 底層庫,能讓 C# 代碼比較方便的和 DirectX 對接。儘管本文使用的是 Vortice 庫來調用 DirectX 相關的介面,但不代表著只有 Vortice 庫能做此實現,可以將 Vortice 換成其他的對 DirectX 封裝的庫,例如 SharpDx 或者是 Silk.NET 等,更換之後只是調用的方法或者是參數等稍微有點不相同,但是實現思路都是相同的

使用 Direct2D1 離屏渲染技術,可以進行脫離具體的視窗調用渲染,可以不需要占用主線程的時間,採用後臺線程驅動執行渲染。可以實現在某些性能敏感的業務上,預先準備好渲染內容,從而提升性能等

新建一個 dotnet 6 的控制台項目,咱將在此新建的項目裡面完成一個簡單的 Direct2D1 離屏渲染的控制台應用。本文不會貼所有的代碼,如果按照本文給出的代碼構建不通過或者遇到其他問題,還請到本文末尾獲取所有源代碼,將源代碼拉到本地構建

按照慣例,在開始之前,先通過 NuGet 安裝必要的庫。在 dotnet 6 項目里,採用 SDK 風格的 csproj 項目文件格式,可以通過編輯項目文件的方式快速安裝 NuGet 庫。可以在 VisualStudio 里,右擊項目,點擊編輯項目文件,或者雙擊項目都可以,替換項目文件為以下代碼即可完成安裝

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Vortice.Direct2D1" Version="2.1.32" />
    <PackageReference Include="Vortice.Win32" Version="1.6.2" />
  </ItemGroup>
</Project>

以上代碼安裝了 Vortice.Direct2D1 庫用來對接 Direct2D1 的邏輯,安裝了 Vortice.Win32 用來輔助處理雜項邏輯

打開 Program.cs 文件,開始編寫離線渲染邏輯。開始編寫代碼之前,先引用命名空間

using Vortice.Mathematics;
using Vortice.WIC;
using D2D = Vortice.Direct2D1;
using PixelFormat = Vortice.DCommon.PixelFormat;

大家都知道,使用 D2D 時,最重要的就是獲取到 ID2D1RenderTarget 用來作為繪製的畫布。創建 ID2D1RenderTarget 的方法有很多個,本文是通過 ID2D1Factory1 工廠調用 CreateWicBitmapRenderTarget 方法,從一個 IWICBitmap 創建的

也就是說想要獲取到 ID2D1RenderTarget 進行繪製,就需要能先拿到 IWICBitmap 類型的對象。創建 IWICBitmap 類型的對象需要通過 WIC 工廠進行創建。於是先創建工廠

        using var wicImagingFactory = new IWICImagingFactory();

通過 IWICImagingFactory 工廠創建 IWICBitmap 對象,需要調用 CreateBitmap 方法,傳入尺寸和顏色格式。顏色格式裡面只有一些是 D2D 支持的,本文這裡採用常用的 PixelFormat32bppPBGRA 格式

        using IWICBitmap wicBitmap =
            wicImagingFactory.CreateBitmap(1000, 1000, Win32.Graphics.Imaging.Apis.GUID_WICPixelFormat32bppPBGRA);

獲取到 IWICBitmap 類型的對象,即可開始通過 D2D 工廠創建 ID2D1RenderTarget 畫布。先創建 D2D 工廠

        using D2D.ID2D1Factory1 d2DFactory = D2D.D2D1.D2D1CreateFactory<D2D.ID2D1Factory1>();

接著設置渲染參數

        var renderTargetProperties = new D2D.RenderTargetProperties(PixelFormat.Premultiplied);

創建 ID2D1RenderTarget 對象

        D2D.ID2D1RenderTarget d2D1RenderTarget =
            d2DFactory.CreateWicBitmapRenderTarget(wicBitmap, renderTargetProperties);

以上就是最核心的步驟了,獲取到 ID2D1RenderTarget 對象,即可開始 D2D 的繪製邏輯,如下麵代碼,修改畫布顏色

        using var renderTarget = d2D1RenderTarget;
        // 開始繪製邏輯
        renderTarget.BeginDraw();

        // 隨意創建顏色
        var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
            (byte) Random.Shared.Next(255));
        renderTarget.Clear(color);

        renderTarget.EndDraw();

如此即可將內容繪製到 IWICBitmap 上

接下來是將 IWICBitmap 的內容保存到本地的圖片,保存 IWICBitmap 需要先對 IWICBitmap 進行編碼,編碼時需要使用 WIC 工廠創建編碼器,接著傳入編碼的格式和編碼的輸出

先打開一個文件用來存放編碼的輸出

        var file = @"D2D.png";
        using (var fileStream = File.OpenWrite(file))
        {
            // 忽略代碼
        }

通過 WIC 工廠創建編碼器,設置編碼的格式是 png 格式

            using var wicBitmapEncoder =
                wicImagingFactory.CreateEncoder(Win32.Graphics.Imaging.Apis.GUID_ContainerFormatPng);

設置編碼的輸出到文件

            wicBitmapEncoder.Initialize(fileStream);

從編碼器創建出一張圖片

            using var wicFrameEncode = wicBitmapEncoder.CreateNewFrame(out var _);
            wicFrameEncode.Initialize();

將上文完成繪製的 IWICBitmap 輸入到編碼器裡面

            wicFrameEncode.WriteSource(wicBitmap);

完成邏輯之後提交一下

            wicFrameEncode.Commit();
            wicBitmapEncoder.Commit();

如此執行完成,即可將繪製的內容保存到本地文件里。這就是本文的採用 D2D 進行離屏繪製的方法

想不開的話,可以測試一下調用渲染時是否能跑滿 GPU 資源,稍微更改一下渲染的代碼,從原本的調用 Clear 修改顏色,修改為以下邏輯

        using var renderTarget = d2D1RenderTarget;
        var stopwatch = Stopwatch.StartNew();
        while (true)
        {
            // 開始繪製邏輯
            renderTarget.BeginDraw();

            // 隨意創建顏色
            var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
                (byte) Random.Shared.Next(255));
            renderTarget.Clear(color);
            color = new Color4(GetRandom(), GetRandom(), GetRandom());
            using var brush = renderTarget.CreateSolidColorBrush(color);

            for (int i = 0; i < 1000; i++)
            {
                renderTarget.DrawEllipse(new D2D.Ellipse(new Vector2(GetRandom(), GetRandom()), 5, 5), brush, 2);
            }

            stopwatch.Stop();
            Console.WriteLine($"Draw: {stopwatch.ElapsedMilliseconds}");
            stopwatch.Restart();

            renderTarget.EndDraw();

            stopwatch.Stop();
            Console.WriteLine($"EndDraw: {stopwatch.ElapsedMilliseconds}");
            stopwatch.Restart();

            byte GetRandom() => (byte) Random.Shared.Next(255);
        }

嘗試運行代碼,看看任務管理器裡面,顯示當前進程是否有用到 GPU 資源,以及占用了多少 GPU 資源

本文的代碼放在githubgitee 歡迎訪問

可以通過如下方式獲取本文的源代碼,先創建一個空文件夾,接著使用命令行 cd 命令進入此空文件夾,在命令行裡面輸入以下代碼,即可獲取到本文的代碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin bb1f1f3db2cf7317341e830d1e3adb14df67a71e

以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令行繼續輸入以下代碼

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin bb1f1f3db2cf7317341e830d1e3adb14df67a71e

獲取代碼之後,進入 WakolerwhaKanicabirem 文件夾

渲染部分,關於 SharpDx 使用,包括入門級教程,請參閱:

在 WPF 框架的渲染部分,請參閱: WPF 底層渲染_lindexi_gd的博客-CSDN博客

更多關於我博客請參閱 博客導航

交流 Vortice 技術,歡迎加群: 622808968

博客園博客只做備份,博客發佈就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

知識共用許可協議
本作品採用知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名[林德熙](https://www.cnblogs.com/lindexi)(包含鏈接:https://www.cnblogs.com/lindexi ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我[聯繫](mailto:[email protected])。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說說你對@Configuration的理解? 定義 @Configuration這個註解是一個類註解,加在類上,標識該類是一個配置類,讓這個類的功能等同於一個bean xml配置文件。 @Configuration public class SpringConfig { } 上面代碼類似於下麵的xm ...
  • Docker 部署 Kibana 本篇主要介紹 使用 Docker 部署 kibana 用於操作 Elasticsearch 使用. 1. 前置準備 1.1 Elasticsearch 準備 可以先準備一個 Elasticsearch 服務 後續用於使用Kibana 去連接它操作,本篇就不展開了 1 ...
  • 文章的添加 博客園打開需要拷貝的文章,右鍵檢查--》選擇cnblogs_post_body這一個div,然後複製outer HTML到admin後臺文章表裡面 最後需要在文章詳情頁的文章內容那一行添加一個|safe 點贊點踩製作 前端樣式: 不會寫,直接拷貝博客園的點贊點踩html和css樣式 {# ...
  • 泛型除了KTV,還有一個讓人比較疑惑的玩意,而且它就是用來表達疑惑的:? 雖然通過泛型已經達到我們想要的效果了,例如: List<String> list = new ArrayList<String>(); 這樣就可以放心地存取String類型的數據。 但是(抱歉,凡事總有個但是),應用的場景總是 ...
  • 現在的關係型資料庫例如PostgreSQL/MySQL, 都已經對 JSON 類型提供相當豐富的功能, 項目中對於不需要檢索但是又需要結構化的存儲, 會在資料庫中產生很多 JSON 類型的欄位, 與 Jackson 做對象的序列化和反序列化配合非常方便. 如果 JSON 在 Java 代碼中是定義為... ...
  • 目錄 什麼是應用服務雪崩 雪崩效應產生的幾種場景 緩存雪崩的解決方案 雪崩的整體解決方案 熔斷設計 隔離設計 超時機制設計 如何提前發現雪崩 什麼是應用服務雪崩 雪崩問題 分散式系統都存在這樣一個問題,由於網路的不穩定性,決定了任何一個服務的可用性都不是 100% 的。當網路不穩定的時候,作為服務的 ...
  • 一、前言 MyBatis 創建時的一個思想是:資料庫不可能永遠是你所想或所需的那個樣子。 我們希望每個資料庫都具備良好的第三範式或 BCNF 範式,可惜它們並不都是那樣。 如果能有一種資料庫映射模式,完美適配所有的應用程式,那就太好了,但可惜也沒有。 而 ResultMap 就是 MyBatis 對 ...
  • > cat /etc/kylin-build Kylin-Desktop V10-SP1 Build 20220316 > cat /etc/.kyinfo [dist] name=Kylin milestone=Desktop-V10-SP1-General-RC6-Build21-2203 ar ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...