{"id":56035,"date":"2011-11-11T16:01:00","date_gmt":"2011-11-11T16:01:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2011\/11\/11\/how-to-use-c-amp-from-c-using-winrt\/"},"modified":"2011-11-11T16:01:00","modified_gmt":"2011-11-11T16:01:00","slug":"how-to-use-c-amp-from-c-using-winrt","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/how-to-use-c-amp-from-c-using-winrt\/","title":{"rendered":"How to use C++ AMP from C# using WinRT"},"content":{"rendered":"<p><em>[Updated 5\/17\/2012 for Visual Studio 11 Beta]<\/em><\/p>\n<p>In a previous article, <a title=\"How to use C++ AMP to C#\" href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2011\/09\/21\/10214538.aspx\">How to use C++ AMP to C#<\/a>, we described how you can use P\/Invoke to call into C++ AMP and accelerate your C# apps on GPUs and other heterogeneous hardware. In this post, we&#8217;ll take a look at how the same task becomes easier in Windows 8 using WinRT.<\/p>\n<p>Before attempting to call C++ AMP from C#, make sure that you have C++ AMP working on your machine. For example, please verify that you can run the <a href=\"https:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2012\/03\/04\/quot-hello-world-quot-in-c-amp.aspx\">C++ AMP &#8220;Hello, World&#8221; example<\/a>.<\/p>\n<h2>The short story<\/h2>\n<p>Once you have C++ AMP working on your machine, the easiest way to start using it from C# via WinRT is to open <a href=\"https:\/\/devblogs.microsoft.com\/00\/00\/01\/04\/99\/2021.HelloWorldCSharpWinRT.zip\">this sample project<\/a> in Visual Studio 11 and begin experimenting with the code.<\/p>\n<h2>The long story<\/h2>\n<p>If you have an existing Metro style app that you&rsquo;d like to modify to use C++ AMP &ndash; or you&rsquo;d like to understand how the sample is set up &ndash; you can follow the steps below. In summary, you need to take the following steps:<\/p>\n<ul>\n<li>Step 1: Open or create a C# Metro style project in Visual Studio 11<\/li>\n<ul>\n<li>Choose the platform target as X86 (if you plan to write 32-bit C++ AMP code).<\/li>\n<\/ul>\n<li>Step 2: Create a C++ WinRT Component DLL project<\/li>\n<ul>\n<li>DO NOT build the project before completing step 3<\/li>\n<\/ul>\n<li>Step 3: Add the C++ project as a reference to the C# project.<\/li>\n<li>Step 4: Write the C++ AMP and the C# code<\/li>\n<\/ul>\n<h3>Step 1: Open or create a&nbsp;C# Metro style&nbsp;project<\/h3>\n<p>First, you need to open or create a C# Metro style application project. The rest of the article assumes that the project is named HelloWorldCSharpWinRT:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/7711.image1_.png\"><img decoding=\"async\" border=\"0\" alt=\"\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/7711.image1_.png\" \/><\/a><\/p>\n<p>Also, set the &#8220;Platform target&#8221; of the project to &#8220;X86&#8221;.<\/p>\n<h3>Step 2: Create a C++ WinRT Component DLL project<\/h3>\n<p>Now, you can add a Visual C++ WinRT component&nbsp; that will contain the C++ AMP code. Simply create a project named &#8220;HelloWorldLib&#8221; from the &#8220;WinRT Component DLL&#8221; template:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/7288.image2_.png\"><img decoding=\"async\" border=\"0\" alt=\"\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/7288.image2_.png\" \/><\/a><\/p>\n<p><strong><span style=\"color: #ff0000\">WARNING:<\/span><\/strong> Do not build the project yet! Due to a bug in the Visual Studio 11 Developer Preview, building the project before completing step 3 will cause problems, and you may be stuck having to delete and&nbsp;recreate the C++ WinRT&nbsp;project.<\/p>\n<h3>Step 3: Add reference from HelloWorldCSharpWinRT to HelloWorldLib<\/h3>\n<p>With WinRT, you can simply add HelloWorldLib as a reference to HelloWorldCSharpWinRT. No more manual editing of the csproj file is necessary, as it was with P\/Invoke! Just right-click HelloWorldCSharpWinRT, choose &#8220;Add Reference&#8230;&#8221; and select the HelloWorldLib project:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/2287.image3_.png\"><img decoding=\"async\" border=\"0\" alt=\"\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/21\/2011\/11\/2287.image3_.png\" \/><\/a><\/p>\n<h3>Step 4. Write the C++ AMP and the C# code<\/h3>\n<p>Now, we just need to write the C++ AMP code and call it from C#.<\/p>\n<p>Since a C++ AMP kernel may take a long time to execute, the WinRT guidelines state that the kernel should be exposed as an asynchronous operation. A convenient way to expose asynchronous operations in C++ is via create_async, currently available in the&nbsp;<a href=\"http:\/\/code.msdn.microsoft.com\/windowsapps\/Windows-8-Asynchronous-08009a0d\">PPL Sample Pack<\/a>&nbsp;(for details on how this works, see <a href=\"https:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2011\/10\/27\/try-it-now-use-ppl-to-produce-windows-8-asynchronous-operations.aspx\">Try It Now: Use PPL to Produce Windows 8 Asynchronous Operations<\/a>)<span><span lang=\"\">.<\/span><\/span><\/p>\n<p>Delete WinRTComponent.h.<\/p>\n<p>Modify WinRTComponent.cpp as follows:<\/p>\n<p><span style=\"font-family: courier new,courier\">#include &lt;pch.h&gt;<br \/>#include &lt;amp.h&gt;<br \/>#include &lt;ppltasks.h&gt;<br \/>#include &lt;collection.h&gt;<br \/>#include &lt;vector&gt;<br \/><\/span>&nbsp;<br \/><span style=\"font-family: courier new,courier\">using namespace concurrency;<\/span><br \/><span style=\"font-family: courier new,courier\">using namespace Windows::Foundation;<\/span><br \/><span style=\"font-family: courier new,courier\">using namespace Windows::Foundation::Collections;<\/span><br \/>&nbsp;<br \/><span style=\"font-family: courier new,courier\">namespace HelloWorldLib<\/span><br \/><span style=\"font-family: courier new,courier\">{<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; public ref class WinRTComponent sealed<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; public:<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IAsyncOperation&lt;IVectorView&lt;float&gt;^&gt;^ square_array_async(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IVectorView&lt;float&gt;^ input)<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Synchronously copy input data from host to device<\/span><br \/><span style=\"font-family: courier new,courier\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>int size = input-&gt;Size;<\/span><br \/><span style=\"font-family: courier new,courier\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>array&lt;float, 1&gt; *dataPt = new array&lt;float, 1&gt;(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size, begin(input), end(input));<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>\/\/ Asynchronously perform the computation on the GPU<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return create_async( [=]() -&gt; IVectorView&lt;float&gt;^<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ <\/span><span style=\"font-family: courier new,courier\">Array objects can only be captured by Reference<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array&lt;float,1&gt; &amp;arr = *dataPt;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Run the kernel on the GPU<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parallel_for_each(arr.extent, [&amp;arr] (index&lt;1&gt; idx) mutable restrict(amp)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arr[idx] = arr[idx] * arr[idx];<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<\/span><br \/>&nbsp;<br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Copy outputs from device to host<\/span><br \/><span style=\"font-family: courier new,courier\"><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>std::vector&lt;float&gt; vec = std::vector&lt;float&gt;(size);<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy((*dataPt), vec.begin());<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete dataPt;<\/span><\/p>\n<p><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Return the outputs as a VectorView&lt;float&gt;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ref new Platform::Collections::VectorView&lt;float&gt;(vec);<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; };<\/span><br \/><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<\/p>\n<p>Notice that the square-array operation is exposed via an asynchronous API. In WinRT, operations that may be long-running should be exposed via asynchronous APIs, and GPU operations may take a relatively long time to execute.<\/p>\n<p>That is all that we need on the C++ side. Now, we&#8217;ll add a button to the C# project. Modify MainPage.xaml as follows:<\/p>\n<p><span style=\"font-family: courier new,courier\">&lt;UserControl x:Class=&#8221;HelloWorldCSharpWinRT.MainPage&#8221;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; xmlns=&#8221;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation&#8221;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; xmlns:x=&#8221;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml&#8221;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; xmlns:d=&#8221;http:\/\/schemas.microsoft.com\/expression\/blend\/2008&#8243;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; xmlns:mc=&#8221;http:\/\/schemas.openxmlformats.org\/markup-compatibility\/2006&#8243;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; mc:Ignorable=&#8221;d&#8221;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; d:DesignHeight=&#8221;768&#8243; d:DesignWidth=&#8221;1366&#8243;&gt;<\/span><br \/>&nbsp;&nbsp;&nbsp; <br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; &lt;Grid x:Name=&#8221;LayoutRoot&#8221; Background=&#8221;#FF0C0C0C&#8221;&gt;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Button x:Name=&#8221;Button_Example&#8221; Content=&#8221;Click&#8221;&nbsp; Click=&#8221;Button_Example_Click&#8221; HorizontalAlignment=&#8221;Center&#8221;\/&gt;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; &lt;\/Grid&gt;<\/span><br \/><span style=\"font-family: courier new,courier\">&lt;\/UserControl&gt;<\/span><\/p>\n<p>When the user clicks the button, we&#8217;ll call into C++ AMP. Modify MainPage.xaml.cs as follows:<\/p>\n<p><span style=\"font-family: courier new,courier\">using System;<\/span><br \/><span style=\"font-family: courier new,courier\">using System.Collections.Generic;<\/span><br \/><span style=\"font-family: courier new,courier\">using Windows.UI.Popups;<\/span><br \/><span style=\"font-family: courier new,courier\">using Windows.UI.Xaml;<\/span><br \/><span style=\"font-family: courier new,courier\">using HelloWorldLib;<br \/><\/span><span style=\"font-family: courier new,courier\"><br \/>namespace HelloWorldCSharpWinRT<\/span><br \/><span style=\"font-family: courier new,courier\">{<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; partial class MainPage<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public MainPage()<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InitializeComponent();<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pr<\/span><span style=\"font-family: courier new,courier\">ivate async void Button_Example_Click(<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object sender, RoutedEventArgs e)<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Button_Example.IsEnabled = false;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var arr = new [] { 1.0f, 2.0f, 3.0f, 4.0f };<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;float&gt; inputs = new List&lt;float&gt;(arr);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><span style=\"font-family: courier new,courier\">IReadOnlyList&lt;float&gt; outputs =&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <\/span><span style=\"font-family: courier new,courier\">await new WinRTComponent()<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; .square_array_async(inputs);<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><span style=\"font-family: courier new,courier\">await new MessageDialog(string.Join(&#8220;,&#8221;, outputs)).ShowAsync();<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Button_Example.IsEnabled = true;<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/span><br \/><span style=\"font-family: courier new,courier\">&nbsp;&nbsp;&nbsp; }<\/span><br \/><span style=\"font-family: courier new,courier\">}<\/span><\/p>\n<\/p>\n<p>&hellip; and that&rsquo;s it!<\/p>\n<p>Note that this is a very simple example that demonstrates how to call a C++ AMP function from C#. The example is too na&iuml;ve to demonstrate speedup &ndash; it contains too little work per data element and in total to benefit from GPU acceleration. An example of a workload that does demonstrate speedup is matrix multiplication, and here is a link to <a href=\"https:\/\/www.danielmoth.com\/Blog\/Matrix-Multiplication-With-C-AMP.aspx\">C++ AMP code for Matrix Multiplication<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/00\/00\/01\/04\/99\/2021.HelloWorldCSharpWinRT.zip\">https:\/\/blogs.msdn.com\/cfs-file.ashx\/__key\/communityserver-blogs-components-weblogfiles\/00-00-01-04-99\/2021.HelloWorldCSharpWinRT.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>[Updated 5\/17\/2012 for Visual Studio 11 Beta] In a previous article, How to use C++ AMP to C#, we described how you can use P\/Invoke to call into C++ AMP and accelerate your C# apps on GPUs and other heterogeneous hardware. In this post, we&#8217;ll take a look at how the same task becomes easier [&hellip;]<\/p>\n","protected":false},"author":481,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[46],"class_list":["post-56035","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-c"],"acf":[],"blog_post_summary":"<p>[Updated 5\/17\/2012 for Visual Studio 11 Beta] In a previous article, How to use C++ AMP to C#, we described how you can use P\/Invoke to call into C++ AMP and accelerate your C# apps on GPUs and other heterogeneous hardware. In this post, we&#8217;ll take a look at how the same task becomes easier [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56035","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/481"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=56035"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56035\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=56035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56035"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}