%% Integrating GPU Coder(TM) into Simulink(R)
%
% This example shows how to integrate GPU Coder(TM) into Simulink(R). GPU
% Coder is not supported for Simulink blocks, but 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 by using
% <docid:coder_ref#bt050gk-1 coder.ExternalDependency> APIs.
% Sobel edge detection is used as an example to demonstrate this concept.

%   Copyright 2017-2019 The MathWorks, Inc.

%% Prerequisites
% * CUDA enabled NVIDIA(R) GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * Simulink to create the model in Simulink.
% * Computer Vision Toolbox(TM) to use the video reader and viewer used
% in the example.
% * Environment variables for the compilers and libraries. For information 
% on the supported versions of the compilers and libraries, see 
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff
% Third-Party Products>. For setting up the environment variables, see 
% <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% Environment Variables>.

%% Create a 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 GPU Environment
% To verify that the compilers and libraries necessary for running this example
% are set up correctly, use the <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278 coder.checkGpuInstall>
% function.
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%% The Sobel Edge Detection Entry-Point Function
% The <matlab:edit(fullfile(matlabroot,'toolbox','gpucoder','gpucoderdemos','gpucoderdemo_in_simulink','sobelEdge.m')) sobelEdge.m>
% function takes an image (represented as a single matrix) and returns an image with the edges detected.
type sobelEdge

%% Generate a Dynamic Library for the Function
% To run this function on the GPU from Simulink, generate a shared
% library by using GPU Coder. Call the generated code (library) from Simulink by using
% <docid:coder_ref#bt050gk-1 coder.ExternalDependency> APIs.
% Copy the generated library to top level folder.
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, first test the MEX function in
% MATLAB(R) 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 <matlab:edit(fullfile(matlabroot,'toolbox','gpucoder','gpucoderdemos','gpucoderdemo_in_simulink','SobelAPI.m')) SobelAPI.m>
% is a class that defines the API to invoke the generated dynamic library. Most of this
% function is a standard template. The method of interest is SobelAPI.sobelEdge,
% which is called to execute the dynamic library. This function invokes the
% sobelEdge dynamic library through a <docid:coder_ref#br49spw-1 coder.ceval> call.
type SobelAPI

%% Create a Simulink Model That Integrates the API to the DLL
% In Simulink, create a MATLAB function block that calls
% SobelAPI.sobelEdge. This step is equivalent to executing the GPU Coder generated
% DLL code. When the MATLAB function block executes, this dynamic library 
% runs on your host machine's GPU. And similarly for code-generation from Simulink, the CUDA
% code is 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.

close_system('gpucoder_sobelEdge');
cleanup

displayEndOfDemoMessage(mfilename)
