Представляем ComputeSharp 2.0 — с легкостью запускайте C# на графическом процессоре с помощью DirectX 12 и D2D1!

Nov 30 2022
После более чем двух лет работы я рад сообщить, что ComputeSharp 2.0 наконец-то доступен! Это полностью переписанная библиотека с поддержкой обоих форматов .

После более чем двух лет работы я рад сообщить, что ComputeSharp 2.0 наконец-то доступен! Это полностью переписанная библиотека с поддержкой как .NET Standard 2.0, так и .NET 6, новые генераторы исходного кода для полной замены генерации кода во время выполнения, множество новых API, совершенно новая поддержка пиксельных шейдеров D2D1, элементы управления XAML для UWP и WinUI 3 и многое другое!

В этот выпуск было вложено много усилий, и объем всего проекта со временем значительно вырос, намного больше, чем я изначально ожидал. В этом сообщении блога я хочу представить библиотеку тем, кто с ней не знаком, выделить некоторые новые функции и показать несколько примеров того, что с ней можно сделать.

Для тех, кто предпочитает форму видео, вот ссылка на мой доклад о ComputeSharp на .NET Conf 2022 , а для тех, кто просто хочет сразу перейти к коду, вот ссылка на репозиторий GitHub . Давайте перейдем к ComputeSharp 2.0!

Начнем с описания библиотеки: ComputeSharp — это библиотека .NET для параллельного выполнения кода C# на графическом процессоре с помощью DX12, D2D1 и динамически генерируемых вычислительных шейдеров HLSL с целью сделать вычисления на графическом процессоре простыми в использовании для всех . НЕТ разработчики! Он позволяет вам писать шейдеры (то есть код, который может работать на графическом процессоре) с использованием C#, а затем выполняет всю тяжелую работу по преобразованию этого кода и фактической отправке его на графический процессор, используемый на вашем компьютере. Это можно использовать для аппаратного ускорения всех видов рабочих нагрузок — обработки изображений, параллельных вычислений, создания причудливых анимаций и так далее! И все это без необходимости глубоко погружаться в специфичные для платформы API, необходимые для выполнения какой-либо из этих операций, или изучать, как на самом деле писать HLSL, который является языком программирования, который DirectX использует для шейдеров.

В качестве практического примера, вот пример приложения ComputeSharp в действии:

Здесь вы можете увидеть, как один из элементов управления XAML, которые ComputeSharp предлагает для UWP и WinUI 3, используется для отрисовки нескольких анимированных вычислительных шейдеров, в данном случае запускаемых в приложении WinUI 3. Весь исходный код доступен на GitHub , и все шейдеры, которые вы видите, были перенесены из шейдеров GLSL с shapertoy только на C#, и все они основаны на ComputeSharp и работают с использованием вычислительных шейдеров DirectX 12.

А вот еще один пример ComputeSharp в действии:

Paint.NET 5.0 демонстрирует эффект размытия боке на базе ComputeSharp

Последние несколько месяцев я также добавлял поддержку Direct2D в ComputeSharp, который теперь является основным компонентом грядущей версии Paint.NET 5.0 . ComputeSharp.D2D1 (версия библиотеки для пиксельных шейдеров D2D1) используется для реализации десятков графических эффектов в приложении, полностью написанном на C# и ускоренном графическим процессором благодаря мощности D2D. Это позволило Рику Брюстеру , разработчику Paint.NET, значительно увеличить количество эффектов, которые он мог запускать на графическом процессоре, и в то же время значительно снизить сложность приложения по отношению к эффектам графического процессора D2D, поскольку больше не было необходимость вручную писать эффекты на HLSL и компилировать их с помощью пользовательского шага сборки — ComputeSharp делает всю эту работу за кулисами!

Забавный факт: размытие боке, показанное на снимке экрана Paint.NET выше, является портом Рика моего образца размытия боке ComputeSharp.D2D1 , который сам является портом моего примера размытия боке ComputeSharp , который является портом из версии C#, которую я написал. для ImageSharp , который является портом из версии Python, которую профессор Майк Паунд написал для своего видео Computerphile об эффектах размытия боке . Иди проверь!

И это также доступно для авторов плагинов, а это означает, что теперь любой может также использовать ComputeSharp.D2D1 для написания полностью настраиваемых эффектов с ускорением на графическом процессоре для интеграции в Paint.NET. То, что раньше требовало знания внутреннего устройства HLSL и D2D, теперь легко доступно всем разработчикам C# с помощью всего нескольких строк кода и дружественных API высокого уровня.

Если вам интересно посмотреть, как выглядит шейдер ComputeSharp, вот очень простой: шейдер hello world, который просто отображает анимированный цветовой градиент, меняющийся со временем. Вот код С# для этого:

Вычислительный шейдер DirectX 12, написанный на C# с помощью ComputeSharp.

Вы можете видеть, что шейдер представляет собой просто тип структуры C#, который захватывает некоторые значения (в данном случае число с плавающей запятой для обозначения прошедшего времени), а затем выполняет некоторые вычисления для вычисления цвета, отображаемого на выходе. Это весь шейдер, который ComputeSharp затем позаботится об обработке во время сборки с помощью генератора исходного кода, чтобы преобразовать его в HLSL, а также сгенерировать дополнительный код для поддержки его выполнения.

Вот как выглядит полученный HLSL-код для этого шейдера:

Транспилированный шейдер HLSL для типа C#

Нетрудно увидеть некоторые преобразования, которые ComputeSharp сделал за кулисами: шейдер теперь имеет постоянный буфер, который используется для маршалирования захваченных значений в GPU, он имеет аннотации размера потока для управления диспетчеризацией шейдера, автоматические проверки границ был добавлен, и шейдер также неявно захватывает выходную текстуру и присваивает ей результирующий пиксель. Как разработчик C#, использующий ComputeSharp, вам никогда не придется беспокоиться ни о чем из этого: генератор исходного кода в комплекте с ComputeSharp позаботится обо всей этой тяжелой работе, пока вы можете писать на C# и пользоваться IntelliSense и всеми замечательными инструментами, которые предлагает C#.

Я также хочу показать пару полных примеров того, как выглядит работающий код на графическом процессоре с использованием ComputeSharp. Мы видели, как вы можете написать шейдер, но вам может быть интересно, действительно ли его диспетчеризация сложна или нет. Это не так! И есть также несколько способов сделать это, поэтому вы можете выбрать тот, который лучше всего соответствует вашим потребностям.

ComputeSharp предлагает режим быстрого выполнения и режим вычислительного графа. Первый особенно полезен, если вы только начинаете работать с библиотекой, хотите попробовать что-то новое или вам просто нужно запустить какой-нибудь простой скрипт и не хотите беспокоиться о настройке более сложного конвейера выполнения. Вот как вы можете запустить очень простой тестовый шейдер:

Режим нетерпеливого выполнения в ComputeSharp

Это все, что вам нужно сделать, чтобы запустить код C# на графическом процессоре! Вы можете видеть, что у нас есть очень простой шейдер, который просто умножает все значения в текстуре на 2, а затем мы распределяем их по доступному для записи буферу, который мы выделили на графическом процессоре, с некоторыми случайными значениями в нем. После отправки шейдера мы также можем скопировать этот буфер графического процессора обратно в ЦП, чтобы прочитать его содержимое. ComputeSharp предоставляет десятки очень простых в использовании API-интерфейсов для выполнения подобных операций, которые можно адаптировать ко всем сценариям, от простых минимальных сценариев до более сложных архитектур.

Давайте также рассмотрим пример с использованием режима вычислительного графика:

Режим вычислительного графа в ComputeSharp

Этот режим идеально подходит, если вы хотите создать полностью настраиваемый конвейер выполнения, который также может выжать максимальную производительность из графического процессора. В этом режиме мы сначала создаем ComputeContext — объект, который позволяет нам ставить операции в очередь на GPU. Затем мы создаем наш конвейер (включая такие операции, как отправка шейдеров, управление переходами для синхронизации доступа к общим ресурсам и т. д.), и, наконец, мы отправляем их на GPU, когда выходим за рамки контекста. Вы также можете увидеть, как здесь мы используем синтаксис await using для асинхронного выполнения всей этой работы на графическом процессоре, поэтому мы не блокируем текущий поток, пока графический процессор не завершит обработку нашего запроса.

Как насчет поддержки XAML? ComputeSharp предлагает два элемента управления ( ComputeShaderPanel и AnimatedComputeShaderPanel ), которые упрощают интеграцию эффекта на основе ComputeSharp в приложение UWP или WinUI 3: просто вставьте элемент управления XAML в свое представление, назначьте ему объект запуска шейдера, и вы Хорошо идти!

ComputeShaderPanel, используемый в представлении XAML

Вот как можно легко объявить ComputeShaderPanel в представлении. Затем ему просто нужен экземпляр IShaderRunner , чтобы знать, как визуализировать каждый кадр. Для простых случаев, например, когда мы просто хотим отобразить анимацию шейдера, встроенного типа ShaderRunner<T> более чем достаточно:

ShaderRunner присваивается ComputeShaderPanel

Вот и все! Панель будет использовать бегун шейдеров для отрисовки каждого кадра и позаботится обо всей настройке, необходимой для фактического отображения каждого сгенерированного кадра. Для более сложных сценариев вы также можете реализовать средство запуска шейдеров самостоятельно, что дает вам полный контроль над синхронизацией кадров, графом вычислений, используемым для создания каждого отображаемого изображения, и многим другим!

Наконец, я также хочу показать пример пиксельного шейдера D2D1. Это шейдеры, которые использует Paint.NET, и они также являются частью инфраструктуры, над которой я сейчас работаю, чтобы разрешить их использование в приложениях UWP и WinUI 3 через библиотеку Win2D (вы также можете увидеть мое предложение по этому поводу здесь ). ). Они сильно отличаются от вычислительных шейдеров DirectX 12, но благодаря инфраструктуре ComputeSharp их так же легко реализовать, и их также можно запустить без особых усилий, используя встроенный эффект пиксельного шейдера, который включает ComputeSharp.D2D1.

Вот пример эффекта пикселизации от Paint.NET:

Пиксельный шейдер D2D1 от Paint.NET.

Вы заметите, что между этим шейдером и шейдером DX12, показанным выше, есть некоторые различия, но опыт разработчика в основном такой же: вам просто нужно создать тип C#, использовать доступные проекции HLSL и API, которые включает ComputeSharp, пусть IntelliSense направляет вам, а затем позвольте ComputeSharp сделать всю остальную работу за вас во время компиляции.

Давайте также посмотрим на транспилированный код этого шейдера:

Пиксельный эффект, перенесенный в HLSL

И снова тип C# был преобразован в соответствии с необходимыми соглашениями HLSL, в данном случае специально для пиксельных шейдеров D2D1. Мы объявили поля для сопоставления с различными захваченными значениями в C#, все встроенные функции были перенаправлены на их эквиваленты HLSL, обновлен синтаксис шейдера и многое другое. И все эти шейдеры, как и DX12, также могут быть предварительно скомпилированы во время сборки, что означает, что ваши приложения могут иметь молниеносную скорость запуска и вообще не нужно вызывать или связывать компилятор шейдеров после развертывания!

В ComputeSharp доступно гораздо больше, и это также только самый первый стабильный выпуск после перезаписи — есть множество новых функций и улучшений, над которыми я уже работаю и которые я планирую включить в будущие выпуски! Вы можете проверить репозиторий на GitHub , попробовать библиотеку ( вы можете найти ее на NuGet! ), а также оставить отзывы и идеи!

И если вы используете его и что-то строите — поделитесь, пожалуйста! Мне очень нравится видеть все классные вещи, которые люди могут создавать с помощью ComputeSharp!

Удачного кодирования!