diff --git a/Makefile b/Makefile index e69de29..e4acf8a 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,77 @@ +################################################################################ +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Define the compiler and flags +NVCC = /usr/local/cuda/bin/nvcc +CXX = g++ +CXXFLAGS = -std=c++11 -I/usr/local/cuda/include -Iinclude +LDFLAGS = -L/usr/local/cuda/lib64 -lcudart -lnppc -lnppial -lnppicc -lnppidei -lnppif -lnppig -lnppim -lnppist -lnppisu -lnppitc + +# Define directories +SRC_DIR = src +BIN_DIR = bin +DATA_DIR = data +LIB_DIR = lib + +# Define source files and target executable +SRC = $(SRC_DIR)/imageRotationNPP.cpp +TARGET = $(BIN_DIR)/imageRotationNPP + +# Define the default rule +all: $(TARGET) + +# Rule for building the target executable +$(TARGET): $(SRC) + mkdir -p $(BIN_DIR) + $(NVCC) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS) + +# Rule for running the application +run: $(TARGET) + ./$(TARGET) --input $(DATA_DIR)/Lena.png --output $(DATA_DIR)/Lena_rotated.png + +# Clean up +clean: + rm -rf $(BIN_DIR)/* + +# Installation rule (not much to install, but here for completeness) +install: + @echo "No installation required." + +# Help command +help: + @echo "Available make commands:" + @echo " make - Build the project." + @echo " make run - Run the project." + @echo " make clean - Clean up the build files." + @echo " make install- Install the project (if applicable)." + @echo " make help - Display this help message." diff --git a/README.md b/README.md index 3751f2f..965169c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -# CUDAatScaleForTheEnterpriseCourseProjectTemplate -This is a template for the course project for the CUDA at Scale for the Enterprise +# Image Rotation using NVIDIA NPP with CUDA -## Project Description +## Overview -Beyond just being a template for course members, this project can be used by non-course members as the general structure for CUDA projects. +This project demonstrates the use of NVIDIA Performance Primitives (NPP) library with CUDA to perform image rotation. The goal is to utilize GPU acceleration to efficiently rotate a given image by a specified angle, leveraging the computational power of modern GPUs. The project is a part of the CUDA at Scale for the Enterprise course and serves as a template for understanding how to implement basic image processing operations using CUDA and NPP. ## Code Organization @@ -29,4 +28,96 @@ This file should hold the human-readable set of instructions for installing the There should be some rudimentary scripts for building your project's code in an automatic fashion. ```run.sh``` -An optional script used to run your executable code, either with or without command-line arguments. \ No newline at end of file +An optional script used to run your executable code, either with or without command-line arguments. + +## Key Concepts + +Performance Strategies, Image Processing, NPP Library + +## Supported SM Architectures + +[SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) + +## Supported OSes + +Linux, Windows + +## Supported CPU Architecture + +x86_64, ppc64le, armv7l + +## CUDA APIs involved + +## Dependencies needed to build/run +[FreeImage](../../README.md#freeimage), [NPP](../../README.md#npp) + +## Prerequisites + +Download and install the [CUDA Toolkit 11.4](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Make sure the dependencies mentioned in [Dependencies]() section above are installed. + +## Build and Run + +### Windows +The Windows samples are built using the Visual Studio IDE. Solution files (.sln) are provided for each supported version of Visual Studio, using the format: +``` +*_vs.sln - for Visual Studio +``` +Each individual sample has its own set of solution files in its directory: + +To build/examine all the samples at once, the complete solution files should be used. To build/examine a single sample, the individual sample solution files should be used. +> **Note:** Some samples require that the Microsoft DirectX SDK (June 2010 or newer) be installed and that the VC++ directory paths are properly set up (**Tools > Options...**). Check DirectX Dependencies section for details." + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le, armv7l. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
`$ make TARGET_ARCH=armv7l`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + + +## Running the Program +After building the project, you can run the program using the following command: + +```bash +Copy code +make run +``` + +This command will execute the compiled binary, rotating the input image (Lena.png) by 45 degrees, and save the result as Lena_rotated.png in the data/ directory. + +If you wish to run the binary directly with custom input/output files, you can use: + +```bash +- Copy code +./bin/imageRotationNPP --input data/Lena.png --output data/Lena_rotated.png +``` + +- Cleaning Up +To clean up the compiled binaries and other generated files, run: + + +```bash +- Copy code +make clean +``` + +This will remove all files in the bin/ directory. diff --git a/data/Lena.png b/data/Lena.png new file mode 100644 index 0000000..cd90c5a Binary files /dev/null and b/data/Lena.png differ diff --git a/src/imageRotationNPP.cpp b/src/imageRotationNPP.cpp new file mode 100644 index 0000000..c88422b --- /dev/null +++ b/src/imageRotationNPP.cpp @@ -0,0 +1,210 @@ +/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define WINDOWS_LEAN_AND_MEAN +#define NOMINMAX +#include +#pragma warning(disable : 4819) +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +bool printfNPPinfo(int argc, char *argv[]) +{ + const NppLibraryVersion *libVer = nppGetLibVersion(); + + printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, + libVer->build); + + int driverVersion, runtimeVersion; + cudaDriverGetVersion(&driverVersion); + cudaRuntimeGetVersion(&runtimeVersion); + + printf(" CUDA Driver Version: %d.%d\n", driverVersion / 1000, + (driverVersion % 100) / 10); + printf(" CUDA Runtime Version: %d.%d\n", runtimeVersion / 1000, + (runtimeVersion % 100) / 10); + + // Min spec is SM 1.0 devices + bool bVal = checkCudaCapabilities(1, 0); + return bVal; +} + +int main(int argc, char *argv[]) +{ + printf("%s Starting...\n\n", argv[0]); + + try + { + std::string sFilename; + char *filePath; + + findCudaDevice(argc, (const char **)argv); + + if (printfNPPinfo(argc, argv) == false) + { + exit(EXIT_SUCCESS); + } + + if (checkCmdLineFlag(argc, (const char **)argv, "input")) + { + getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath); + } + else + { + filePath = sdkFindFilePath("Lena.pgm", argv[0]); + } + + if (filePath) + { + sFilename = filePath; + } + else + { + sFilename = "Lena.pgm"; + } + + // if we specify the filename at the command line, then we only test + // sFilename[0]. + int file_errors = 0; + std::ifstream infile(sFilename.data(), std::ifstream::in); + + if (infile.good()) + { + std::cout << "nppiRotate opened: <" << sFilename.data() + << "> successfully!" << std::endl; + file_errors = 0; + infile.close(); + } + else + { + std::cout << "nppiRotate unable to open: <" << sFilename.data() << ">" + << std::endl; + file_errors++; + infile.close(); + } + + if (file_errors > 0) + { + exit(EXIT_FAILURE); + } + + std::string sResultFilename = sFilename; + + std::string::size_type dot = sResultFilename.rfind('.'); + + if (dot != std::string::npos) + { + sResultFilename = sResultFilename.substr(0, dot); + } + + sResultFilename += "_rotate.pgm"; + + if (checkCmdLineFlag(argc, (const char **)argv, "output")) + { + char *outputFilePath; + getCmdLineArgumentString(argc, (const char **)argv, "output", + &outputFilePath); + sResultFilename = outputFilePath; + } + + // declare a host image object for an 8-bit grayscale image + npp::ImageCPU_8u_C1 oHostSrc; + // load gray-scale image from disk + npp::loadImage(sFilename, oHostSrc); + // declare a device image and copy construct from the host image, + // i.e. upload host to device + npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc); + + // create struct with the ROI size + NppiSize oSrcSize = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()}; + NppiPoint oSrcOffset = {0, 0}; + NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()}; + + // Calculate the bounding box of the rotated image + NppiRect oBoundingBox; + double angle = 45.0; // Rotation angle in degrees + NPP_CHECK_NPP(nppiGetRotateBound(oSrcSize, angle, &oBoundingBox)); + + // allocate device image for the rotated image + npp::ImageNPP_8u_C1 oDeviceDst(oBoundingBox.width, oBoundingBox.height); + + // Set the rotation point (center of the image) + NppiPoint oRotationCenter = {(int)(oSrcSize.width / 2), (int)(oSrcSize.height / 2)}; + + // run the rotation + NPP_CHECK_NPP(nppiRotate_8u_C1R( + oDeviceSrc.data(), oSrcSize, oDeviceSrc.pitch(), oSrcOffset, + oDeviceDst.data(), oDeviceDst.pitch(), oBoundingBox, angle, oRotationCenter, + NPPI_INTER_NN)); + + // declare a host image for the result + npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size()); + // and copy the device result data into it + oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch()); + + saveImage(sResultFilename, oHostDst); + std::cout << "Saved image: " << sResultFilename << std::endl; + + nppiFree(oDeviceSrc.data()); + nppiFree(oDeviceDst.data()); + + exit(EXIT_SUCCESS); + } + catch (npp::Exception &rException) + { + std::cerr << "Program error! The following exception occurred: \n"; + std::cerr << rException << std::endl; + std::cerr << "Aborting." << std::endl; + + exit(EXIT_FAILURE); + } + catch (...) + { + std::cerr << "Program error! An unknown type of exception occurred. \n"; + std::cerr << "Aborting." << std::endl; + + exit(EXIT_FAILURE); + return -1; + } + + return 0; +}