Thông báo về ComputeSharp 2.0 — chạy C# trên GPU một cách dễ dàng thông qua DirectX 12 và D2D1!

Nov 30 2022
Sau hơn 2 năm làm việc, tôi vui mừng thông báo rằng ComputeSharp 2.0 cuối cùng đã có sẵn! Đây là bản viết lại hoàn chỉnh của thư viện, có hỗ trợ cho cả .

Sau hơn 2 năm làm việc, tôi vui mừng thông báo rằng ComputeSharp 2.0 cuối cùng đã có sẵn! Đây là bản viết lại hoàn chỉnh của thư viện, có tính năng hỗ trợ cho cả .NET Standard 2.0 và .NET 6, trình tạo nguồn mới để thay thế hoàn toàn việc tạo mã thời gian chạy, nhiều API mới, hỗ trợ hoàn toàn mới cho trình đổ bóng pixel D2D1, điều khiển XAML cho UWP và WinUI 3, v.v.!

Rất nhiều nỗ lực đã được đưa vào bản phát hành này và phạm vi của toàn bộ dự án đã tăng lên rất nhiều theo thời gian, nhiều hơn những gì tôi dự đoán ban đầu. Trong bài đăng trên blog này, tôi muốn giới thiệu thư viện với những người chưa quen thuộc với nó, nêu bật một số tính năng mới và hiển thị một vài ví dụ về những gì có thể được thực hiện với nó.

Đối với những người thích dạng video, đây là liên kết đến bài nói chuyện của tôi về ComputeSharp tại .NET Conf 2022 và đối với những người chỉ muốn nhảy thẳng vào mã, đây cũng là liên kết đến repo GitHub . Hãy bắt đầu với ComputeSharp 2.0!

Hãy bắt đầu với phần giới thiệu nâng cao cho thư viện: ComputeSharp là thư viện .NET để chạy mã C# song song trên GPU thông qua DX12, D2D1 và các trình tạo bóng điện toán HLSL được tạo động, với mục tiêu làm cho điện toán GPU dễ sử dụng cho tất cả . NET! Nó cho phép bạn viết các trình đổ bóng (tức là mã có thể chạy trên GPU) bằng C#, sau đó nó thực hiện tất cả các công việc nặng nhọc để chuyển đổi mã đó và thực sự gửi nó trên GPU đang sử dụng trên máy của bạn. Điều này có thể được sử dụng để tăng tốc phần cứng cho tất cả các loại khối lượng công việc — xử lý hình ảnh, tính toán song song, tạo hoạt ảnh lạ mắt, bạn có thể đặt tên cho nó! Và tất cả mà bạn không cần phải tìm hiểu sâu về các API cụ thể của nền tảng cần thiết để thực hiện bất kỳ công việc nào trong số này, cũng như tìm hiểu cách thực sự viết HLSL, ngôn ngữ lập trình mà DirectX sử dụng cho các trình đổ bóng.

Đối với một ví dụ thực tế, đây là Ứng dụng mẫu ComputeSharp đang hoạt động:

Tại đây, bạn có thể thấy một trong các điều khiển XAML mà ComputeSharp cung cấp cho UWP và WinUI 3 đang được sử dụng để hiển thị một số trình đổ bóng điện toán động, trong trường hợp này là chạy trong ứng dụng WinUI 3. Toàn bộ mã nguồn có sẵn trên GitHub và tất cả các trình tạo bóng mà bạn thấy đã được chuyển từ trình tạo bóng GLSL từ shadertoy sang chỉ C# và tất cả đều được cung cấp bởi ComputeSharp và chạy bằng trình tạo bóng điện toán DirectX 12.

Và đây là một ví dụ khác về ComputeSharp đang hoạt động:

Paint.NET 5.0 giới thiệu hiệu ứng làm mờ Boong do ComputeSharp cung cấp

Tôi cũng đã dành vài tháng qua để bổ sung hỗ trợ Direct2D cho ComputeSharp, hiện là thành phần cơ bản của bản phát hành Paint.NET 5.0 sắp tới . ComputeSharp.D2D1 (phiên bản của thư viện dành cho trình đổ bóng pixel D2D1) đang được sử dụng để triển khai hàng chục hiệu ứng hình ảnh trong ứng dụng, được viết hoàn toàn bằng C# và GPU được tăng tốc nhờ sức mạnh của D2D. Điều này cho phép Rick Brewster , nhà phát triển Paint.NET, tăng đáng kể số lượng hiệu ứng mà anh ta có thể chạy trên GPU, đồng thời giảm đáng kể độ phức tạp của ứng dụng đối với các hiệu ứng GPU D2D, vì không còn nhu cầu viết các hiệu ứng trong HLSL theo cách thủ công và biên dịch chúng bằng một bước xây dựng tùy chỉnh — ComputeSharp đang thực hiện tất cả công việc này ở hậu trường!

Sự thật thú vị — hiệu ứng làm mờ hiệu ứng bokeh được hiển thị trong ảnh chụp màn hình Paint.NET ở trên là cổng của Rick trong mẫu hiệu ứng làm mờ hiệu ứng bokeh trên ComputeSharp.D2D1 của tôi , bản thân nó cũng là một cổng tôi đã thực hiện trong mẫu hiệu ứng làm mờ hiệu ứng bokeh trên ComputeSharp của mình , là một cổng từ phiên bản C# mà tôi đã viết cho ImageSharp , đây là bản chuyển thể từ phiên bản Python mà giáo sư Mike Pound đã viết cho video Computerphile của ông về hiệu ứng mờ nhòe . Đi kiểm tra nó ra!

Và điều này cũng có sẵn cho các tác giả plugin, nghĩa là giờ đây bất kỳ ai cũng có thể sử dụng ComputeSharp.D2D1 để viết các hiệu ứng tăng tốc GPU và tùy chỉnh hoàn toàn để tích hợp vào Paint.NET. Tất cả các nhà phát triển C# đều có thể dễ dàng truy cập những gì từng yêu cầu kiến ​​thức về nội bộ HLSL và D2D, chỉ với một vài dòng mã và các API cấp cao, thân thiện.

Nếu bạn tò mò muốn biết trình đổ bóng ComputeSharp trông như thế nào, thì đây là một thứ rất đơn giản: trình tạo bóng hello world, chỉ hiển thị một dải màu động thay đổi theo thời gian. Đây là mã C# cho nó:

Trình đổ bóng điện toán DirectX 12 được viết bằng C# với ComputeSharp

Bạn có thể thấy trình đổ bóng chỉ đơn giản là một kiểu cấu trúc C#, nắm bắt một số giá trị (trong trường hợp này là dấu phẩy động để biểu thị thời gian đã trôi qua), sau đó thực hiện một số tính toán để tính toán màu sẽ hiển thị ở đầu ra. Đây là toàn bộ trình đổ bóng, sau đó ComputeSharp sẽ đảm nhiệm việc xử lý tại thời điểm xây dựng thông qua một trình tạo nguồn, để chuyển đổi nó thành HLSL và cũng tạo mã bổ sung để hỗ trợ quá trình thực thi của nó.

Đây là mã HLSL kết quả trông như thế nào đối với trình đổ bóng này:

Trình tạo bóng HLSL được dịch mã cho loại C#

Thật dễ dàng để thấy một số biến đổi mà ComputeSharp đã thực hiện đằng sau hậu trường: trình đổ bóng hiện có bộ đệm không đổi, được sử dụng để sắp xếp các giá trị đã chụp cho GPU, nó có chú thích kích thước luồng để kiểm soát việc gửi trình đổ bóng, kiểm tra giới hạn tự động có đã được thêm vào và trình đổ bóng cũng đang ngầm nắm bắt kết cấu đầu ra và gán pixel kết quả cho nó. Là nhà phát triển C# sử dụng ComputeSharp, bạn sẽ không bao giờ phải lo lắng về bất kỳ vấn đề nào trong số này: trình tạo nguồn đi kèm với ComputeSharp sẽ đảm nhận tất cả công việc nặng nhọc này trong khi bạn có thể viết C# và hưởng lợi từ IntelliSense cũng như tất cả các công cụ tuyệt vời mà C# cung cấp.

Tôi cũng muốn hiển thị một vài ví dụ đầy đủ từ đầu đến cuối về mã đang chạy trên GPU bằng ComputeSharp trông như thế nào. Chúng tôi đã thấy cách bạn có thể viết một shader, nhưng bạn có thể tự hỏi liệu việc gửi nó có thực sự khó khăn hay không. Nó không phải! Và cũng có một số cách để làm điều đó, vì vậy bạn cũng có thể chọn cách phù hợp nhất với nhu cầu của mình.

ComputeSharp cung cấp chế độ thực thi háo hức và chế độ đồ thị tính toán. Cái trước đặc biệt hữu ích nếu bạn mới bắt đầu với thư viện, muốn thử mọi thứ hoặc chỉ cần chạy một số tập lệnh đơn giản và không muốn phải lo lắng về việc thiết lập một quy trình thực thi phức tạp hơn. Đây là cách bạn có thể chạy một shader thử nghiệm rất đơn giản:

Chế độ thực thi háo hức trong ComputeSharp

Đó là tất cả những gì bạn cần làm để chạy mã C# trên GPU! Bạn có thể thấy cách chúng tôi có một trình tạo bóng rất đơn giản, chỉ nhân tất cả các giá trị trong một kết cấu với 2, sau đó chúng tôi gửi nó qua một bộ đệm có thể ghi mà chúng tôi đã phân bổ trên GPU với một số giá trị ngẫu nhiên trong đó. Sau khi gửi shader, chúng tôi cũng có thể sao chép bộ đệm GPU đó trở lại CPU để có thể đọc nội dung của nó. ComputeSharp hiển thị hàng chục API rất dễ sử dụng để thực hiện các hoạt động phổ biến như thế này, có thể thích ứng với tất cả các tình huống từ các tập lệnh tối thiểu đơn giản đến các kiến ​​trúc phức tạp hơn.

Chúng ta cũng hãy xem một ví dụ sử dụng chế độ đồ thị tính toán:

Chế độ đồ thị tính toán trong ComputeSharp

Chế độ này là hoàn hảo nếu bạn muốn tạo một quy trình thực thi được tùy chỉnh hoàn toàn, chế độ này cũng có thể tận dụng tối đa hiệu suất của GPU. Trong chế độ này, trước tiên chúng ta tạo một ComputeContext , một đối tượng cho phép chúng ta xếp hàng các hoạt động trên GPU. Sau đó, chúng tôi đang tạo quy trình của mình (bao gồm các hoạt động như gửi trình đổ bóng, kiểm soát quá trình chuyển đổi để đồng bộ hóa quyền truy cập vào tài nguyên được chia sẻ, v.v.) và cuối cùng, chúng tôi sẽ gửi điều đó trên GPU khi đi ra ngoài phạm vi của ngữ cảnh. Bạn cũng có thể thấy ở đây chúng ta đang tận dụng cú pháp chờ đợi như thế nào để thực thi tất cả công việc này một cách không đồng bộ trên GPU, vì vậy chúng ta không chặn luồng hiện tại cho đến khi GPU xử lý xong yêu cầu của chúng ta.

Còn hỗ trợ XAML thì sao? ComputeSharp cung cấp hai điều khiển ( ComputeShaderPanelAnimatedComputeShaderPanel ), giúp tích hợp hiệu ứng do ComputeSharp hỗ trợ vào ứng dụng UWP hoặc WinUI 3 trở nên cực kỳ dễ dàng: chỉ cần đặt điều khiển XAML vào dạng xem của bạn, chỉ định một đối tượng chạy đổ bóng cho nó, và bạn' tốt để đi!

ComputeShaderPanel được sử dụng trong chế độ xem XAML

Đây là cách một ComputeShaderPanel có thể dễ dàng được khai báo trong một dạng xem. Sau đó, nó chỉ cần một phiên bản IShaderRunner để biết cách hiển thị từng khung hình. Đối với các trường hợp đơn giản, chẳng hạn như khi chúng ta chỉ muốn hiển thị hoạt ảnh đổ bóng, thì loại ShaderRunner<T> tích hợp sẵn là quá đủ:

ShaderRunner được gán cho một ComputeShaderPanel

Và thế là xong! Bảng điều khiển sẽ sử dụng trình đổ bóng để vẽ từng khung hình và sẽ đảm nhận toàn bộ thiết lập cần thiết để thực sự hiển thị từng khung hình được tạo. Đối với các kịch bản nâng cao hơn, bạn cũng có thể tự triển khai trình chạy đổ bóng, cho phép bạn kiểm soát hoàn toàn thời gian của khung hình, biểu đồ tính toán được sử dụng để tạo từng hình ảnh để hiển thị, v.v.!

Cuối cùng, tôi cũng muốn đưa ra một ví dụ về trình đổ bóng pixel D2D1. Đây là những shader mà Paint.NET sử dụng và chúng cũng là một phần của cơ sở hạ tầng mà tôi hiện đang làm việc để cho phép sử dụng chúng trong các ứng dụng UWP và WinUI 3 thông qua thư viện Win2D (bạn cũng có thể xem đề xuất của tôi về điều đó tại đây ). Chúng khác rất nhiều so với các trình đổ bóng điện toán DirectX 12, nhưng nhờ cơ sở hạ tầng của ComputeSharp, chúng rất dễ triển khai và cũng có thể chạy mà không cần quá nhiều nỗ lực bằng cách tận dụng hiệu ứng đổ bóng pixel tích hợp sẵn trong ComputeSharp.D2D1.

Đây là một ví dụ về hiệu ứng pixelate từ Paint.NET:

Trình đổ bóng pixel pixelate D2D1, từ Paint.NET

Bạn sẽ nhận thấy có một số khác biệt giữa trình tạo bóng này và trình tạo bóng DX12 được trình bày ở trên, nhưng trải nghiệm của nhà phát triển hầu như giống nhau: bạn chỉ cần tạo một loại C#, sử dụng các phép chiếu HLSL và API có sẵn mà ComputeSharp bao gồm, hãy để IntelliSense hướng dẫn bạn, sau đó để ComputeSharp thực hiện tất cả công việc còn lại cho bạn tại thời điểm biên dịch.

Chúng ta cũng hãy xem mã được dịch mã cho trình đổ bóng này:

Hiệu ứng pixelate được chuyển thành HLSL

Một lần nữa, loại C# đã được chuyển đổi khi cần thiết để tuân theo các quy ước HLSL cần thiết, trong trường hợp này là dành riêng cho trình đổ bóng pixel D2D1. Chúng tôi đã khai báo các trường để ánh xạ tới các giá trị được chụp khác nhau trong C#, tất cả nội tại đã được chuyển tiếp tới các giá trị tương đương HLSL của chúng, cú pháp đổ bóng đã được cập nhật, v.v. Và tất cả các trình đổ bóng này, giống như các trình đổ bóng DX12, cũng có thể được biên dịch trước khi xây dựng, nghĩa là các ứng dụng của bạn có thể có hiệu suất khởi động cực nhanh và không cần phải gọi hoặc đóng gói trình biên dịch đổ bóng sau khi triển khai!

Còn nhiều tính năng khác có sẵn trong ComputeSharp và đây cũng chỉ là bản phát hành ổn định đầu tiên sau khi viết lại — có rất nhiều tính năng và cải tiến mới mà tôi đang nghiên cứu và tôi dự định đưa vào các bản phát hành trong tương lai! Bạn có thể kiểm tra kho lưu trữ trên GitHub , dùng thử thư viện ( bạn có thể tìm thấy nó trên NuGet! ) và để lại phản hồi cũng như ý tưởng!

Và nếu bạn sử dụng nó và xây dựng thứ gì đó — hãy chia sẻ nó! Tôi thực sự thích xem tất cả những điều thú vị mà mọi người có thể xây dựng bằng ComputeSharp!

Chúc mừng mã hóa!