This example shows how to integrate GPU Coder™ into Simulink®. While GPU Coder is not supported for Simulink blocks, you can still leverage GPUs in Simulink by generating a dynamic linked library (dll) using GPU Coder and then integrating it into a Simulink block using coder.ExternalDependency APIs. Sobel edge detection is used as an example to demonstrate this concept.

Prerequisites

  • CUDA-enabled NVIDIA® GPU with compute capability 3.0 or higher.

  • NVIDIA CUDA toolkit.

  • Environment variables for the compilers and libraries. For more information see Environment Variables.

  • Simulink to create the model in Simulink.

  • Computer Vision Toolbox™ to use the video reader and viewer used in the example.

Create a New Folder and Copy Relevant Files

The following line of code creates a folder in your current working folder (pwd), and copies all the relevant files into this folder. If you do not want to perform this operation or if you cannot generate files in this folder, change your current working folder.

gpucoderdemo_setup('gpucoderdemo_in_simulink');

Verify the GPU Environment

Use the coder.checkGpuInstall function and verify that the compilers and libraries needed for running this example are set up correctly.

envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

Sobel edge detection

The sobelEdge.m function takes an image (represented as a single matrix) and returns an image with the edges detected.

type sobelEdge
function [ magnitude ] = sobelEdge( Image )
%#codegen

%   Copyright 2017 The MathWorks, Inc.


maskX = single([-1 0 1 ; -2 0 2; -1 0 1]);
maskY = single([-1 -2 -1 ; 0 0 0 ; 1 2 1]);

coder.gpu.kernelfun();



resX = conv2(Image, maskX, 'same');
resY = conv2(Image, maskY, 'same');

magnitude = sqrt(resX.^2 + resY.^2);
thresh = magnitude < 0.4;
magnitude(thresh) = 0;

end

Generate a DLL for the function

To run this function on the GPU from Simulink, generate a shared library by using GPU Coder and call the generated code (library) from Simulink by using coder.ExternalDependency APIs. Copy the generated library to top level directory.

Isize = single(zeros(240, 320));
cfg = coder.gpuConfig('dll');
codegen -args {Isize} -config cfg sobelEdge
if ispc
    copyfile(fullfile(pwd, 'codegen','dll', 'sobelEdge','sobelEdge.dll'), pwd);
else
    copyfile(fullfile(pwd, 'codegen','dll', 'sobelEdge','sobelEdge.so'), pwd);
end

Before generating C/CUDA code, you should first test the MEX function in MATLAB® to ensure that it is functionally equivalent to the original MATLAB code and that no run-time errors occur.

Define coder.ExternalDependency API to Invoke the Generated Code

The SobelAPI.m is a class that defines the API to invoke the generated DLL. Most of this function is a standard template. The method of interest is SobelAPI.sobelEdge, which is called to execute the DLL. This function simply invokes the sobelEdge DLL through a coder.ceval call.

type SobelAPI

%   Copyright 2017 The MathWorks, Inc.

classdef SobelAPI < coder.ExternalDependency
    %#codegen
    
    methods (Static)
        
        function bName = getDescriptiveName(~)
            bName = 'SobelAPI';
        end
        
        function tf = isSupportedContext(ctx)
            if  ctx.isMatlabHostTarget()
                tf = true;
            else
                error('sobel library not available for this target');
            end
        end
        
        function updateBuildInfo(buildInfo, ctx)
            [~, linkLibExt, execLibExt, ~] = ctx.getStdLibInfo();
            
            % Header files
            hdrFilePath = fullfile(pwd, 'codegen', 'dll', 'sobelEdge');
            buildInfo.addIncludePaths(hdrFilePath);
            
            % Link files
            linkFiles = strcat('sobelEdge', linkLibExt);
            linkPath = hdrFilePath;
            linkPriority = '';
            linkPrecompiled = true;
            linkLinkOnly = true;
            group = '';
            buildInfo.addLinkObjects(linkFiles, linkPath, ...
                linkPriority, linkPrecompiled, linkLinkOnly, group);
            
            % Non-build files
            nbFiles = 'sobelEdge';
            nbFiles = strcat(nbFiles, execLibExt);
            buildInfo.addNonBuildFiles(nbFiles,'','');
        end
        
        %API for library function 'sobelEdge'
        function c = sobelEdge(I)
            % running in generated code, call library function
            coder.cinclude('sobelEdge.h');
            
            c = coder.nullcopy(I);
            coder.ceval('sobelEdge', coder.rref(I), coder.wref(c));
        end
    end
end

% LocalWords:  sobel

Create a Simulink Model that Integrates the API to the DLL

In Simulink, create a MATLAB function block that calls SobelAPI.sobelEdge. This is equivalent to executing the GPU coder generated DLL code. Thus, when the MATLAB function block executes, this DLL will run on your host machine's GPU. And similarly for code-generation from Simulink, the CUDA code will be invoked. The Simulink model uses a video reader and a video display to show the effect of the algorithm.

open_system('gpucoder_sobelEdge');
set_param('gpucoder_sobelEdge', 'SimulationCommand', 'update');

Run the Simulink Model (The Sobel Filter)

Run simulation to see the effect of the Sobel algorithm.

sim('gpucoder_sobelEdge', 'timeout', 30);

Cleanup

Remove files and return to the original folder

Run Command: Cleanup

close_system('gpucoder_sobelEdge');
cleanup