{"id":500,"date":"2023-05-23T10:23:11","date_gmt":"2023-05-23T15:23:11","guid":{"rendered":"https:\/\/davidwdrell.net\/wordpress\/?p=500"},"modified":"2023-05-23T10:23:48","modified_gmt":"2023-05-23T15:23:48","slug":"calling-cuda-functions-from-c","status":"publish","type":"post","link":"https:\/\/davidwdrell.net\/wordpress\/?p=500","title":{"rendered":"Calling Cuda functions from C#"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This is a demonstration of creating a C# wrapper for a Cuda function.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The example Cuda function is &#8216;invertImageCuda()&#8217; and it is contained in a Cuda dll called &#8216;image_processor.dll&#8217;. This dll file must exist in the same directory as the C# exe or in the path.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The C# File<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In a C# file, create a C# entry point called &#8216;Invert()&#8217;. This entry point is a standard C# function and can be passed in any complex C# object type.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    \/\/\/ &lt;summary&gt;\n    \/\/\/ Takes an array of float values, assumed to be pixels ranging from 0,1. Applies 'pixel = 1 - pixel' to all pixels in parallel Cuda operations.\n    \/\/\/ Original array is un-changed, inverted image is returned in a new array. \n    \/\/\/ &lt;\/summary&gt;\n    \/\/\/ &lt;param name=\"SrcPixels\"&gt;&lt;\/param&gt;\n    \/\/\/ &lt;param name=\"srcWidth\"&gt;&lt;\/param&gt;\n    \/\/\/ &lt;param name=\"srcHeight\"&gt;&lt;\/param&gt;\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\n    public static float&#91;] Invert(float&#91;] SrcPixels, int srcWidth, int srcHeight)\n    {\n        float&#91;] DstPixels = new float&#91;srcWidth * srcHeight];\n\n        unsafe\n        {\n            GCHandle handleSrcImage = GCHandle.Alloc(SrcPixels, GCHandleType.Pinned);\n            float* srcPtr = (float*)handleSrcImage.AddrOfPinnedObject();\n\n            GCHandle handleDstImage = GCHandle.Alloc(DstPixels, GCHandleType.Pinned);\n            float* dstPtr = (float*)handleDstImage.AddrOfPinnedObject();\n\n       \n            \/\/ call a local function that takes c style raw pointers\n            \/\/ this local function will in turn call the Cuda function\n            invert(srcPtr, dstPtr, srcWidth, srcHeight);\n\n            handleSrcImage.Free();\n            handleDstImage.Free();\n            GC.Collect();\n        }\n        return DstPixels;\n    }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The &#8216;unsafe&#8217; block tells C# that we are intentionally using raw c-style pointers. In the Visual Studio project properties editor, we must also check the box that allows un-safe code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The GCHandle.Alloc() call creates a  pinned pointer to a float[] so that the garbage collector cannot move the memory while the Cuda program is accessing it. We need to create a pinned pointer (GCHandle) for both the source and destination arrays.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The AddrOfPinnedObject() returns the pinned pointer that was allocated in the Alloc() function. We need c-style raw pointers to pass into the Cuda program.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A local function, invert(), will be called passing in only simple objects of pointers and int-s.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the same C# file, create the Cuda wrapper function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        &#91;DllImport(\"image_processor.dll\")]\n        unsafe static extern int invertImageCuda(float* src, float* dst, Int32 width, Int32 sheight); \n        unsafe static int invert(float* src, float* dst, Int32 width, Int32 height)\n        {\n            return invertImageCuda(src, dst, width, height);\n        }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The DllImport() line must be immediately above the Cuda function extern declaration and tells the compiler to look for invertImageCuda() in the dll. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The &#8216;invert()&#8217; function is a local static, unsafe, function that accepts raw c-style pointers and then calls into the Cuda function, returning the value returned from Cuda (which is a success\/error int value). The dst pointer is used by the Cuda function as the location to write the output values. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Cuda File<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In a separate Cuda file, in Cuda dll project, create the entry point:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/invertimage.h\n#ifndef INVERTIMAGE_H\n#define INVERTIMAGE_H\n#include \"cuda_runtime.h\"\n#include \"device_launch_parameters.h\"\n\n\/\/ public\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define CUDA_CLIB_EXPORTS\n#ifdef CUDA_CLIB_EXPORTS\n#define CUDA_CLIB_API __declspec(dllexport) \n#else\n#define CUDA_CLIB_API __declspec(dllimport) \n#endif\n\n    CUDA_CLIB_API cudaError_t invertImageCuda(float* src, float* dst, unsigned int width, unsigned int height);\n\n#ifdef __cplusplus\n}\n#endif\n\n\/\/private\n\n__global__ void invertImageKernel(float* src, float* dst, unsigned int width, unsigned int height);\n\n\n\n#endif\n\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This c header will not be read or used by the C# program, but rather, the C# compiler will rely on the invertImageCuda() matching declaration in the C# file. But this header with the CUDA_CLIB_API __declspec(dllexport) will tell the Cuda build to export this function as a public function.  The CUDA_CLIB_EXPORTS  preprocessor variable is defined locally because the cuda compiler of invert.cu will be the only compiler to see this code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a demonstration of creating a C# wrapper for a Cuda function. The example Cuda function is &#8216;invertImageCuda()&#8217; and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[8],"tags":[],"class_list":["post-500","post","type-post","status-publish","format-standard","hentry","category-cuda"],"_links":{"self":[{"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/500","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=500"}],"version-history":[{"count":4,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/500\/revisions"}],"predecessor-version":[{"id":504,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/500\/revisions\/504"}],"wp:attachment":[{"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=500"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=500"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/davidwdrell.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=500"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}