%% Package Generated Code Using the GPU Coder
% This example shows how to package generated code into a zip file for relocation using the Package option in the GPU Coder app. The example uses a Sobel edge detection application to demonstrate this concept. By default, GPU Coder creates the zip file in the current working folder.
%% Prerequisites
% NVIDIA® CUDA® hardware, compilers, and libraries. For information on the supported versions of the compilers and libraries, see  Third-party Products. For setting up the environment variables, see  Environment Variables.
%% The Sobel Edge Detection Entry-Point Function
% In the Sobel edge detection algorithm, a 2-D spatial gradient operation on a grayscale image is performed. This operation emphasizes the high spatial frequency regions which corresponds to edges.

type sobelEdge.m

% The Sobel edge algorithm computes the horizontal gradient (resX) and the vertical gradient (resY) of the input image by using two orthogonal filter kernels (maskX and maskY). After the filtering operation, the algorithm computes the gradient magnitude and applies a threhold to find the regions of the images that are considered to be edges.
%% Run Sobel Edge Detection Algorithm on Test Image
% The Sobel filtering algorithm operates on grayscale images. Convert the color image to an equivalent grayscale image with normalized values (0.0 for black, 1.0 for white).

im = imread('hello.jpg');
imGray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
imSize = size(imGray);
figure();
image(im);
title('Test Image');

%
% Write the matrix gray into the imputImage.csv file using the writematrix command. The Sobel edge detection application reads in this CSV file.

writematrix(reshape(imGray,1,[]),'inputImage.csv');
imOut = sobelEdge(double(imGray));

%
% To display the edge detected image, reformat the matrix imOut with the function repmat so that you can pass it to the image command.

figure();
image(repmat(imOut,[1 1 3]));
title('Edge Detected Image in MATLAB');

%
%% Create Custom Main Function for sobelEdge.m
% This example uses a custom main file, main_sobel.cu and its associdated header file main_sobel.h. This custom main file reads the input image from the inputImage.csv file, calls the sobelEdge function in the generated sobelEdge.cu file, and saves the data from the edge detected image into the outputMag.csv file.
%% Package Generated Code Using the GPU Coder App
% Open the GPU Coder app. On the MATLAB Toolstrip Apps tab, under Code Generation, click the GPU Coder app icon.
% On the Select Source Files page, enter the name of the entry-point function sobelEdge.m. Click Next to go to the Define Input Types page.
% Specify that the input Image is of double data type and variable size with upper bound of 1024. To specify variable size with an upper bound of 1024, select :1024. Click Next to go to the Check for Run-Time Issues page.
%
%
%
% Check for run-time issues. In the Check for Run-Time Issues dialog box, enter code that calls sobelEdge with double input. For example,  sobelEdge(ones(648,484)). Click Check for Issues. To check for run-time issues, the app generates and runs a MEX function. The app does not find issues for sobelEdge. Click Next to go to the Generate Code page.
% In the Generate dialog box, set the Build Type to Executable. You can also package the code generated for Source Code, Static Library, or Dynamic Library targets. You cannot package the code generated for MEX targets. Click More Settings.
% On the Custom Code tab, under Custom C Code for Generated Files, set Additional source files to main_sobel.cu. Click Close to go to the Generate Code page.
%
%
%
% Click Generate. Click Next to go to the Finish Workflow page. On the Finish Workflow page, click Package.
%
%
%
% In the Package dialog box, specify the package file name and packaging type. By default, the app derives the name of the package file from the project name. The app saves the file in the current working folder. By default, the app packages the generated files as a single, flat folder. For this example, use the default values, and then click Save.
% This zip file contains the CUDA C++ code and header files required for relocation. It does not contain:
% Compile flags
% Defines
% Makefiles
% Example main files, unless you configure code generation to generate and compile the example main function.
% Inspect the contents of sobelEdge_pkg.zip in your working folder to verify that it is ready for relocation to the destination system. Depending on the zip tool that you use, you can potentially open and inspect the file without unpacking it. You can now relocate the resulting zip file to the desired development environment and unpack the file.
%% Package Generated Code at the Command Line
% To generate a CUDA executable for the sobelEdge function, create a GPU code configuration object and run the codegen command.

cfg = coder.gpuConfig('exe');
cfg.GenerateReport = true;
cfg.CustomSource = 'main_sobel.cu';
codegen -config cfg sobelEdge -args {coder.typeof(0,[1024 1024],[1 1])}

%
% To package the generated code into a zip file, load the BuildInfo object. The BuildInfo object contains information for compiling and linking generated code, including the list of all the source and include files and their paths.

buildInfoFile = fullfile(pwd,'codegen','exe','sobelEdge','buildInfo.mat');
load(buildInfoFile);

%
% Create the zip file by using the packNGo function.

packNGo(buildInfo,'packType','flat','nestedZipFiles',true,...
    'minimalHeaders',false,'includeReport',false);

%
% The packNGo function creates the sobelEdge.zip file in the current working folder. This zip file contains the CUDA C++ code and header files required for relocation. It does not contain:
% Compile flags
% Defines
% Makefiles
% Example main files, unless you configure code generation to generate and compile the example main function.
% Inspect the contents of sobelEdge.zip in your working folder to verify that it is ready for relocation to the destination system. Depending on the zip tool that you use, you can potentially open and inspect the file without unpacking it. You can now relocate the resulting zip file to the desired development environment and unpack the file.
%% Standalone Code Execution
% When you execute the generated standalone executable, the output magnitudeData is computed and written to a comma-separated file. Read this output back in MATLAB and use the image function to visualize the edge detected image.

if ispc
    system('sobelEdge.exe');
else
    system('./sobelEdge');
end

imOutGPU = reshape(readmatrix('outputMag.csv'),imSize);
edgeImg = repmat(imOutGPU,[1 1 3]);
figure();
image(edgeImg);
title('Edge Detected Image on the GPU');

% Copyright 2019 The MathWorks, Inc.