mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-13 00:08:26 +08:00
CUDA 13.2 samples update (#432)
- Added Python samples for CUDA Python 1.0 release - Renamed top-level `Samples` directory to `cpp` to accommodate Python samples.
This commit is contained in:
16
cpp/8_Platform_Specific/Tegra/CMakeLists.txt
Normal file
16
cpp/8_Platform_Specific/Tegra/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
add_subdirectory(cudaNvSciNvMedia)
|
||||
add_subdirectory(cudaNvSciBufMultiplanar)
|
||||
add_subdirectory(cuDLAErrorReporting)
|
||||
add_subdirectory(cuDLAHybridMode)
|
||||
add_subdirectory(cuDLALayerwiseStatsHybrid)
|
||||
add_subdirectory(cuDLALayerwiseStatsStandalone)
|
||||
add_subdirectory(cuDLAStandaloneMode)
|
||||
add_subdirectory(EGLSync_CUDAEvent_Interop)
|
||||
add_subdirectory(fluidsGLES)
|
||||
add_subdirectory(nbody_opengles)
|
||||
add_subdirectory(simpleGLES)
|
||||
add_subdirectory(simpleGLES_EGLOutput)
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
18
cpp/8_Platform_Specific/Tegra/EGLSync_CUDAEvent_Interop/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/EGLSync_CUDAEvent_Interop/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/EGLSync_CUDAEvent_Interop/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/EGLSync_CUDAEvent_Interop/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(EGLSync_CUDAEvent_Interop LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(EGL)
|
||||
find_package(X11)
|
||||
find_package(OpenGL)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Source file
|
||||
if(${OpenGL_FOUND})
|
||||
if(${EGL_FOUND})
|
||||
if(${X11_FOUND})
|
||||
# Add target for EGLSync_CUDAEvent_Interop
|
||||
add_executable(EGLSync_CUDAEvent_Interop EGLSync_CUDAEvent_Interop.cu)
|
||||
|
||||
target_compile_options(EGLSync_CUDAEvent_Interop PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(EGLSync_CUDAEvent_Interop PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(EGLSync_CUDAEvent_Interop PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(EGLSync_CUDAEvent_Interop PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
${EGL_INCLUDE_DIR}
|
||||
${X11_INCLUDE_DIR}
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(EGLSync_CUDAEvent_Interop
|
||||
CUDA::cuda_driver
|
||||
#CUDA::cudart
|
||||
${EGL_LIBRARY}
|
||||
${X11_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
message(STATUS "X11 libraries not found - will not build sample 'EGLSyncCUDAEvent_Interop'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "EGL not found - will not build sample 'EGLSync_CUDAEvent_Interop'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenGL not found - will not build sample 'EGLSync_CUDAEvent_Interop'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample EGLSync_CUDAEvent_Interop
|
||||
- requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
@@ -0,0 +1,786 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
// Simple interop app demonstrating EGLImage + EGLSync interop with CUDA.
|
||||
// Using EGLSync - CUDA Event interop one can achieve synchronization on GPU
|
||||
// itself for GL-EGL-CUDA operations instead of blocking CPU for
|
||||
// synchronization. This app requires GLES 3.2 or higher
|
||||
|
||||
//---------------------------INCLUDES---------------------------------//
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES3/gl32.h>
|
||||
#include <cuda.h>
|
||||
#include <cudaEGL.h>
|
||||
#include <helper_cuda_drvapi.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "egl_common.h"
|
||||
#include "graphics_interface.h"
|
||||
|
||||
//---------------------------DEFINES---------------------------------//
|
||||
#define MAX_ITR 100
|
||||
|
||||
#define FAILURE 0
|
||||
#define SUCCESS 1
|
||||
#define WAIVED 2
|
||||
|
||||
#define BLOCK_SIZE 16
|
||||
|
||||
#define GL_READ 0
|
||||
#define GL_WRITE 1
|
||||
//---------------------------MACROS---------------------------------//
|
||||
|
||||
// Error-checking wrapper around GL calls
|
||||
#define GL_SAFE_CALL(call) \
|
||||
{ \
|
||||
GLenum err; \
|
||||
call; \
|
||||
err = glGetError(); \
|
||||
if (err != GL_NO_ERROR) { \
|
||||
fprintf(stderr, "%s:%d GL error: %d\n", __FILE__, __LINE__, err); \
|
||||
cleanup(FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GL_SAFE_CALL_NO_CLEANUP(call, err) \
|
||||
{ \
|
||||
GLenum status; \
|
||||
call; \
|
||||
status = glGetError(); \
|
||||
if (status != GL_NO_ERROR) { \
|
||||
fprintf(stderr, "%s:%d GL error: %d\n", __FILE__, __LINE__, status); \
|
||||
err = status; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Error-checking wrapper around CUDA calls (taken from cutil.h)
|
||||
#define CUDA_SAFE_CALL(call) \
|
||||
do { \
|
||||
cudaError err = call; \
|
||||
if (cudaSuccess != err) { \
|
||||
fprintf( \
|
||||
stderr, "Cuda error in file '%s' in line %i : %s.\n", __FILE__, __LINE__, cudaGetErrorString(err)); \
|
||||
cleanup(FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CUDA_SAFE_CALL_NO_CLEANUP(call, err) \
|
||||
do { \
|
||||
cudaError status = call; \
|
||||
if (cudaSuccess != status) { \
|
||||
fprintf( \
|
||||
stderr, "Cuda error in file '%s' in line %i : %s.\n", __FILE__, __LINE__, cudaGetErrorString(status)); \
|
||||
err = status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_DECL)
|
||||
typedef void (*extlst_fnptr_t)(void);
|
||||
static struct
|
||||
{
|
||||
extlst_fnptr_t *fnptr;
|
||||
char const *name;
|
||||
} extensionList[] = {EXTENSION_LIST(EXTLST_ENTRY)};
|
||||
|
||||
int eglSetupExtensions(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < (sizeof(extensionList) / sizeof(*extensionList)); i++) {
|
||||
*extensionList[i].fnptr = eglGetProcAddress(extensionList[i].name);
|
||||
if (*extensionList[i].fnptr == NULL) {
|
||||
printf("Couldn't get address of %s()\n", extensionList[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
|
||||
//------------------------GLOBAL VARIABLES--------------------------//
|
||||
|
||||
// GL texture
|
||||
GLuint tex[2] = {0};
|
||||
|
||||
// Used to catch unexpected termination from GLUT
|
||||
int cleanExit = 0;
|
||||
|
||||
// Use CPU Sync or GPU sync; Default GPU
|
||||
int useGpu = 1;
|
||||
|
||||
// CUDA Resource
|
||||
CUgraphicsResource writeResource = NULL;
|
||||
CUgraphicsResource readResource = NULL;
|
||||
CUarray writeArray, readArray;
|
||||
CUdevice device;
|
||||
CUcontext context;
|
||||
|
||||
// Which device to run on
|
||||
unsigned int dev = 0;
|
||||
|
||||
// Default width, height, and iterations value
|
||||
int width = 2048;
|
||||
int height = 2048;
|
||||
int itr = MAX_ITR;
|
||||
|
||||
// Error check variable
|
||||
__device__ static unsigned int numErrors = 0;
|
||||
|
||||
//-----------------------FUNCTION PROTOTYPES------------------------//
|
||||
|
||||
void checkSync(int argc, char **argv);
|
||||
int parseCmdLine(int argc, char **argv);
|
||||
void printUsage(void);
|
||||
void cleanup(int status);
|
||||
void exitHandler(void);
|
||||
void printStatus(int status);
|
||||
void checkSyncOnCPU(void);
|
||||
void checkSyncOnGPU(EGLDisplay dpy);
|
||||
|
||||
__global__ void
|
||||
verify_and_update_kernel(CUsurfObject write, CUsurfObject read, char expected, char newval, int width, int height);
|
||||
extern "C" cudaError_t cudaGetValueMismatch();
|
||||
|
||||
//-----------------------FUNCTION DEFINITIONS------------------------//
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
parseCmdLine(argc, argv);
|
||||
atexit(exitHandler);
|
||||
|
||||
checkSync(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseCmdLine(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-cpu") == 0) {
|
||||
useGpu = 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
printUsage();
|
||||
cleanup(SUCCESS);
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-width") == 0) {
|
||||
++i;
|
||||
if (i == argc) {
|
||||
printf("width option must be followed by value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
if (sscanf(argv[i], "%d", &width) != 1) {
|
||||
printf("Error: invalid width value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-height") == 0) {
|
||||
++i;
|
||||
if (i == argc) {
|
||||
printf("height option must be followed by value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
if (sscanf(argv[i], "%d", &height) != 1) {
|
||||
printf("Error: invalid height value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
if (strcmp(argv[i], "-itr") == 0) {
|
||||
++i;
|
||||
if (i == argc) {
|
||||
printf("itr option must be followed by iteration value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
if (sscanf(argv[i], "%d", &itr) != 1) {
|
||||
printf("Error: invalid iteration value\n");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void printUsage(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("\t-h\tPrint command line options\n");
|
||||
printf("\t-cpu\tSync on the CPU instead of the GPU\n");
|
||||
printf("\t-width w\tSet the width to w\n");
|
||||
printf("\t-height h\tSet the height to h\n");
|
||||
printf("\t-itr i\tSet number of iterations to i\n");
|
||||
}
|
||||
|
||||
void checkSync(int argc, char **argv)
|
||||
{
|
||||
int x, y;
|
||||
int bufferSize = width * height * 4;
|
||||
unsigned char *pSurf_read = NULL, *pSurf_write = NULL;
|
||||
int integrated;
|
||||
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
CUctxCreateParams ctxCreateParams = {};
|
||||
|
||||
// Init values for variables
|
||||
x = y = 0;
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
}
|
||||
device = findCudaDeviceDRV(argc, (const char **)argv);
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuCtxCreate(&context, &ctxCreateParams, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
}
|
||||
cuCtxPushCurrent(context);
|
||||
|
||||
status = cuDeviceGetAttribute(&integrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, device);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Failed to get device attribute CU_DEVICE_ATTRIBUTE_INTEGRATED\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
if (integrated != 1) {
|
||||
printf("EGLSync_CUDAEvent_Interop does not support dGPU. Waiving sample.\n");
|
||||
cleanup(WAIVED);
|
||||
}
|
||||
|
||||
#if (defined(__arm__) || defined(__aarch64__)) && defined(__linux__)
|
||||
graphics_setup_window(0, 0, width, height, "EGLSync_CUDA_Interop");
|
||||
#endif
|
||||
|
||||
pSurf_read = (unsigned char *)malloc(bufferSize);
|
||||
pSurf_write = (unsigned char *)malloc(bufferSize);
|
||||
if (pSurf_read == NULL || pSurf_write == NULL) {
|
||||
printf("malloc failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
for (y = 0; y < height; y++) {
|
||||
pSurf_read[(y * width + x) * 4] = 1;
|
||||
pSurf_read[(y * width + x) * 4 + 1] = 1;
|
||||
pSurf_read[(y * width + x) * 4 + 2] = 1;
|
||||
pSurf_read[(y * width + x) * 4 + 3] = 1;
|
||||
pSurf_write[(y * width + x) * 4] = 0;
|
||||
pSurf_write[(y * width + x) * 4 + 1] = 0;
|
||||
pSurf_write[(y * width + x) * 4 + 2] = 0;
|
||||
pSurf_write[(y * width + x) * 4 + 3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOP call to error-check the above glut calls
|
||||
GL_SAFE_CALL({});
|
||||
|
||||
// Init texture
|
||||
GL_SAFE_CALL(glGenTextures(2, tex));
|
||||
|
||||
GL_SAFE_CALL(glBindTexture(GL_TEXTURE_2D, tex[GL_READ]));
|
||||
GL_SAFE_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
GL_SAFE_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
GL_SAFE_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pSurf_read));
|
||||
GL_SAFE_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
GL_SAFE_CALL(glBindTexture(GL_TEXTURE_2D, tex[GL_WRITE]));
|
||||
GL_SAFE_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
GL_SAFE_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
GL_SAFE_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pSurf_write));
|
||||
GL_SAFE_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
glFinish();
|
||||
|
||||
EGLDisplay eglDisplayHandle = eglGetCurrentDisplay();
|
||||
if (eglDisplayHandle == EGL_NO_DISPLAY) {
|
||||
printf("eglDisplayHandle failed \n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("eglDisplay Handle created \n");
|
||||
}
|
||||
|
||||
if (!eglSetupExtensions()) {
|
||||
printf("SetupExtentions failed \n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
EGLContext eglCtx = eglGetCurrentContext();
|
||||
if (eglCtx == EGL_NO_CONTEXT) {
|
||||
printf("Context1 create failed with error %d\n", eglGetError());
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// Create the EGL_Image
|
||||
EGLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE};
|
||||
|
||||
EGLImageKHR eglImage1 = eglCreateImageKHR(
|
||||
eglDisplayHandle, eglCtx, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(intptr_t)tex[GL_READ], eglImgAttrs);
|
||||
if (eglImage1 == EGL_NO_IMAGE_KHR) {
|
||||
printf("EGLImage create failed for read texture with error %d\n", eglGetError());
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("EGLImage1 created \n");
|
||||
}
|
||||
|
||||
EGLImageKHR eglImage2 = eglCreateImageKHR(
|
||||
eglDisplayHandle, eglCtx, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(intptr_t)tex[GL_WRITE], eglImgAttrs);
|
||||
if (eglImage2 == EGL_NO_IMAGE_KHR) {
|
||||
printf("EGLImage create failed for write texture with error %d\n", eglGetError());
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("EGLImage2 created \n");
|
||||
}
|
||||
|
||||
glFinish();
|
||||
|
||||
status = cuGraphicsEGLRegisterImage(&writeResource, eglImage1, CU_GRAPHICS_REGISTER_FLAGS_NONE);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("cuGraphicsEGLRegisterImage failed with Texture 1\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("cuGraphicsEGLRegisterImage Passed, writeResource created with texture "
|
||||
"1\n");
|
||||
}
|
||||
|
||||
status = cuGraphicsSubResourceGetMappedArray(&writeArray, writeResource, 0, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("cuGraphicsSubResourceGetMappedArray failed for writeResource with "
|
||||
"texture 1\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
status = cuGraphicsEGLRegisterImage(&readResource, eglImage2, CU_GRAPHICS_REGISTER_FLAGS_NONE);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("cuGraphicsEGLRegisterImage failed for readResource with Texture 2\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("cuGraphicsEGLRegisterImage Passed, readResource created with texture "
|
||||
"2\n");
|
||||
}
|
||||
|
||||
status = cuGraphicsSubResourceGetMappedArray(&readArray, readResource, 0, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("cuGraphicsSubResourceGetMappedArray failed for texture 2\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
if (useGpu) {
|
||||
printf("Using GPU Sync path\n");
|
||||
checkSyncOnGPU(eglDisplayHandle);
|
||||
}
|
||||
else {
|
||||
printf("Using CPU Sync path\n");
|
||||
checkSyncOnCPU();
|
||||
}
|
||||
|
||||
free(pSurf_read);
|
||||
free(pSurf_write);
|
||||
cleanup(SUCCESS);
|
||||
}
|
||||
|
||||
void checkSyncOnCPU(void)
|
||||
{
|
||||
int z = 0;
|
||||
unsigned char expectedData, newData;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
CUDA_RESOURCE_DESC wdsc, rdsc;
|
||||
memset(&wdsc, 0, sizeof(wdsc));
|
||||
memset(&rdsc, 0, sizeof(rdsc));
|
||||
|
||||
expectedData = 0;
|
||||
newData = 1;
|
||||
|
||||
wdsc.resType = CU_RESOURCE_TYPE_ARRAY;
|
||||
wdsc.res.array.hArray = writeArray;
|
||||
CUsurfObject writeSurface;
|
||||
rdsc.resType = CU_RESOURCE_TYPE_ARRAY;
|
||||
rdsc.res.array.hArray = readArray;
|
||||
CUsurfObject readSurface;
|
||||
|
||||
status = cuSurfObjectCreate(&writeSurface, &wdsc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Surface bounding failed with status %d\n", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
status = cuSurfObjectCreate(&readSurface, &rdsc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Surface bounding failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
for (z = 0; z < itr; z++) {
|
||||
// GL call to copy from read texture to write texture
|
||||
GL_SAFE_CALL(glCopyImageSubData(
|
||||
tex[GL_READ], GL_TEXTURE_2D, 0, 0, 0, 0, tex[GL_WRITE], GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1));
|
||||
|
||||
glFinish();
|
||||
|
||||
newData++;
|
||||
expectedData++;
|
||||
|
||||
verify_and_update_kernel<<<(width * height) / 256, 256>>>(
|
||||
writeSurface, readSurface, expectedData, newData, width, height);
|
||||
|
||||
status = cuCtxSynchronize();
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("cuCtxSynchronize failed \n");
|
||||
}
|
||||
}
|
||||
|
||||
cudaError_t err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Value mismatch seen when using CPU sync\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// Clean up CUDA writeResource
|
||||
status = cuGraphicsUnregisterResource(writeResource);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Failed to unregister %d", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("Unregistered writeResource. \n");
|
||||
}
|
||||
|
||||
// Clean up CUDA readResource
|
||||
status = cuGraphicsUnregisterResource(readResource);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Failed to unregister %d", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("Unregistered readResource. \n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Performs same function as checkSyncOnCPU
|
||||
Here instead of glFinish() and cuCtxSynchronize like in checkSyncOnCPU,
|
||||
we make use of EGLSync, CUDA Event and cuStreamWaitEvent, eglWaitSyncKHR to
|
||||
achieve the synchronization due to this CPU is not blocked for any
|
||||
synchronization needed between GL-EGL & CUDA operations all synchronizations
|
||||
happens on the GPU only.
|
||||
*/
|
||||
void checkSyncOnGPU(EGLDisplay dpy)
|
||||
{
|
||||
int z = 0;
|
||||
unsigned char expectedData, newData;
|
||||
cudaError_t err;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
CUstream stream;
|
||||
CUevent timingDisabledEvent;
|
||||
CUDA_RESOURCE_DESC wdsc, rdsc;
|
||||
memset(&wdsc, 0, sizeof(wdsc));
|
||||
memset(&rdsc, 0, sizeof(rdsc));
|
||||
|
||||
expectedData = 0;
|
||||
newData = 1;
|
||||
|
||||
wdsc.resType = CU_RESOURCE_TYPE_ARRAY;
|
||||
wdsc.res.array.hArray = writeArray;
|
||||
CUsurfObject writeSurface;
|
||||
rdsc.resType = CU_RESOURCE_TYPE_ARRAY;
|
||||
rdsc.res.array.hArray = readArray;
|
||||
CUsurfObject readSurface;
|
||||
|
||||
status = cuSurfObjectCreate(&writeSurface, &wdsc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Surface bounding failed with status %d\n", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
status = cuSurfObjectCreate(&readSurface, &rdsc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Surface bounding failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
status = cuStreamCreate(&stream, CU_STREAM_DEFAULT);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Stream creation failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// Creates timing disabled event which uses non-blocking synchronization
|
||||
status = cuEventCreate(&timingDisabledEvent, CU_EVENT_DISABLE_TIMING);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Default event creation failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
1. We perform texture-to-texture copy in GLES which is async function
|
||||
2. Followed by creating EGLSync and a CUDA Event from that EGLSync object
|
||||
3. Using cuStreamWaitEvent() we wait in GPU for the GLES to finish texture
|
||||
copy.
|
||||
4. CUDA kernel verfiy_and_update_kernel verifies if the copied data by
|
||||
GLES is correct, and it updates the buffer with new values.
|
||||
5. This is followed by eglWaitSyncKHR() which waits for the cuda kernel to
|
||||
finish, so that in the next iteration GLES can perform the copying of the
|
||||
updated buffer to write texture,
|
||||
*/
|
||||
for (z = 0; z < itr; z++) {
|
||||
// GL call to copy from read texture to write texture
|
||||
GL_SAFE_CALL(glCopyImageSubData(
|
||||
tex[GL_READ], GL_TEXTURE_2D, 0, 0, 0, 0, tex[GL_WRITE], GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1));
|
||||
|
||||
EGLSyncKHR eglSyncForGL, eglSyncForCuda;
|
||||
EGLBoolean egl_status = EGL_TRUE;
|
||||
EGLAttribKHR eglattrib[] = {EGL_CUDA_EVENT_HANDLE_NV, (EGLAttrib)timingDisabledEvent, EGL_NONE};
|
||||
|
||||
CUevent cudaEGLSyncEvent;
|
||||
|
||||
eglSyncForGL = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
|
||||
|
||||
if (eglSyncForGL == EGL_NO_SYNC_KHR) {
|
||||
printf(" EGL Sync creation failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
status = cuEventCreateFromEGLSync(&cudaEGLSyncEvent, eglSyncForGL, CU_EVENT_DEFAULT);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("CUDA event creation from EGLSync failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// We wait from CUDA in GPU for GL-EGL operation completion
|
||||
status = cuStreamWaitEvent(stream, cudaEGLSyncEvent, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Stream wait for event created from EGLSync failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
egl_status = eglDestroySyncKHR(dpy, eglSyncForGL);
|
||||
if (egl_status != EGL_TRUE) {
|
||||
printf("EGL sync object destruction failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
newData++;
|
||||
expectedData++;
|
||||
|
||||
// Verifies the values in readSurface which is copied by
|
||||
// glCopyImageSubData() And writes value of newData into writeSurface
|
||||
verify_and_update_kernel<<<(width * height) / 256, 256, 0, stream>>>(
|
||||
writeSurface, readSurface, expectedData, newData, width, height);
|
||||
|
||||
status = cuEventDestroy(cudaEGLSyncEvent);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Event Destroy failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
status = cuEventRecord(timingDisabledEvent, stream);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Event Record failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// creating an EGL sync object linked to a CUDA event object
|
||||
eglSyncForCuda = eglCreateSync64KHR(dpy, EGL_SYNC_CUDA_EVENT_NV, eglattrib);
|
||||
|
||||
// We wait from EGL for CUDA operation completion
|
||||
egl_status = eglWaitSyncKHR(dpy, eglSyncForCuda, 0);
|
||||
if (egl_status != EGL_TRUE) {
|
||||
printf("eglWaitSyncKHR failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
egl_status = eglDestroySyncKHR(dpy, eglSyncForCuda);
|
||||
if (egl_status != EGL_TRUE) {
|
||||
printf("EGL sync object destruction failed\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Value mismatch seen when using GPU sync\n");
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
|
||||
// Clean up CUDA writeResource
|
||||
status = cuGraphicsUnregisterResource(writeResource);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Failed to unregister %d", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("Unregistered writeResource. \n");
|
||||
}
|
||||
|
||||
// Clean up CUDA readResource
|
||||
status = cuGraphicsUnregisterResource(readResource);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Failed to unregister %d", status);
|
||||
cleanup(FAILURE);
|
||||
}
|
||||
else {
|
||||
printf("Unregistered readResource. \n");
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies the values in readSurface whether they are expected ones
|
||||
// And writes value of newData into writeSurface
|
||||
__global__ void
|
||||
verify_and_update_kernel(CUsurfObject write, CUsurfObject read, char expected, char newval, int width, int height)
|
||||
{
|
||||
unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
if (x < width && y < height) {
|
||||
uchar4 check;
|
||||
surf2Dread(&check, read, x * 4, y);
|
||||
if (check.x != expected || check.y != expected || check.z != expected || check.w != expected) {
|
||||
printf("Mismatch found in values read[0]= %u read[1]= %u read[2]= %u "
|
||||
"read[3]= %u expected is %u\n",
|
||||
check.x,
|
||||
check.y,
|
||||
check.z,
|
||||
check.w,
|
||||
expected);
|
||||
numErrors++;
|
||||
return;
|
||||
}
|
||||
uchar4 data = make_uchar4(newval, newval, newval, newval);
|
||||
surf2Dwrite(data, write, x * 4, y);
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void getNumErrors(int *numErr) { *numErr = numErrors; }
|
||||
|
||||
extern "C" cudaError_t cudaGetValueMismatch()
|
||||
{
|
||||
int numErr_h;
|
||||
int *numErr_d = NULL;
|
||||
cudaError_t err = cudaSuccess;
|
||||
|
||||
err = cudaMalloc(&numErr_d, sizeof(int));
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMemcpy failed with %s\n", cudaGetErrorString(err));
|
||||
cudaFree(numErr_d);
|
||||
return err;
|
||||
}
|
||||
|
||||
getNumErrors<<<1, 1>>>(numErr_d);
|
||||
err = cudaDeviceSynchronize();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaDeviceSynchronize failed with %s\n", cudaGetErrorString(err));
|
||||
}
|
||||
err = cudaMemcpy(&numErr_h, numErr_d, sizeof(int), cudaMemcpyDeviceToHost);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMemcpy failed with %s\n", cudaGetErrorString(err));
|
||||
cudaFree(numErr_d);
|
||||
return err;
|
||||
}
|
||||
err = cudaFree(numErr_d);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaFree failed with %s\n", cudaGetErrorString(err));
|
||||
return err;
|
||||
}
|
||||
if (numErr_h > 0) {
|
||||
return cudaErrorUnknown;
|
||||
}
|
||||
return cudaSuccess;
|
||||
}
|
||||
|
||||
// Clean up state and exit. If status is SUCCESS, regression success is printed
|
||||
// to stdout. This will happen if the glut timer is triggered. If status is
|
||||
// anything else, the regression failure message is printed.
|
||||
void cleanup(int status)
|
||||
{
|
||||
GLenum glErr = GL_NO_ERROR;
|
||||
cudaError cudaErr = cudaSuccess;
|
||||
int exitStatus = status;
|
||||
|
||||
// Clean up GL
|
||||
if (*tex) {
|
||||
GL_SAFE_CALL_NO_CLEANUP(glDeleteTextures(2, tex), glErr);
|
||||
}
|
||||
|
||||
// Print test status and exit
|
||||
if (glErr != GL_NO_ERROR || cudaErr != cudaSuccess)
|
||||
exitStatus = FAILURE;
|
||||
|
||||
printStatus(exitStatus);
|
||||
|
||||
cleanExit = 1;
|
||||
|
||||
graphics_close_window();
|
||||
|
||||
if (exitStatus == FAILURE)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (exitStatus == WAIVED)
|
||||
exit(EXIT_WAIVED);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void exitHandler(void)
|
||||
{
|
||||
if (!cleanExit) {
|
||||
printf("&&&& EGLSync_CUDAEvent_Interop unexpected failure \n");
|
||||
printStatus(FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Print test success or fail for regression testing
|
||||
void printStatus(int status)
|
||||
{
|
||||
switch (status) {
|
||||
case SUCCESS:
|
||||
printf("&&&& EGLSync_CUDAEvent_Interop PASSED\n");
|
||||
break;
|
||||
case WAIVED:
|
||||
printf("&&&& EGLSync_CUDAEvent_Interop WAIVED\n");
|
||||
break;
|
||||
default:
|
||||
printf("&&&& EGLSync_CUDAEvent_Interop FAILED\n");
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# EGLSync_CUDAEvent_Interop - EGLSync CUDA Event Interop
|
||||
|
||||
## Description
|
||||
|
||||
Demonstrates interoperability between CUDA Event and EGL Sync/EGL Image using which one can achieve synchronization on GPU itself for GL-EGL-CUDA operations instead of blocking CPU for synchronization.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
EGLSync-CUDAEvent Interop, EGLImage-CUDA Interop
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
armv7l
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Driver API](http://docs.nvidia.com/cuda/cuda-driver-api/index.html)
|
||||
cuEventRecord, cuDeviceGetAttribute, cuEventCreate, cuCtxSynchronize, cuEventDestroy, cuGraphicsEGLRegisterImage, cuGraphicsSubResourceGetMappedArray, cuStreamCreate, cuStreamWaitEvent, cuGraphicsUnregisterResource, cuCtxCreate, cuSurfObjectCreate, cuEventCreateFromEGLSync, cuCtxPushCurrent, cuInit
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaMemcpy, cudaGetErrorString, cudaFree, cudaDeviceSynchronize, cudaGetValueMismatch, cudaMalloc
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[EGL](../../../README.md#egl), [EGLSync](../../../README.md#eglsync), [X11](../../../README.md#x11), [OpenGL ES](../../../README.md#opengl-es)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// DESCRIPTION: Common EGL functions header file
|
||||
//
|
||||
|
||||
#ifndef _EGL_COMMON_H_
|
||||
#define _EGL_COMMON_H_
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cuda.h"
|
||||
#include "cudaEGL.h"
|
||||
|
||||
EGLImageKHR eglImage;
|
||||
|
||||
#define EXTENSION_LIST(T) \
|
||||
T(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR) \
|
||||
T(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR) \
|
||||
T(PFNEGLCREATESYNCKHRPROC, eglCreateSyncKHR) \
|
||||
T(PFNEGLDESTROYSYNCKHRPROC, eglDestroySyncKHR) \
|
||||
T(PFNEGLCLIENTWAITSYNCKHRPROC, eglClientWaitSyncKHR) \
|
||||
T(PFNEGLGETSYNCATTRIBKHRPROC, eglGetSyncAttribKHR) \
|
||||
T(PFNEGLCREATESYNC64KHRPROC, eglCreateSync64KHR) \
|
||||
T(PFNEGLWAITSYNCKHRPROC, eglWaitSyncKHR)
|
||||
|
||||
#define eglCreateImageKHR my_eglCreateImageKHR
|
||||
#define eglDestroyImageKHR my_eglDestroyImageKHR
|
||||
#define eglCreateSyncKHR my_eglCreateSyncKHR
|
||||
#define eglDestroySyncKHR my_eglDestroySyncKHR
|
||||
#define eglClientWaitSyncKHR my_eglClientWaitSyncKHR
|
||||
#define eglGetSyncAttribKHR my_eglGetSyncAttribKHR
|
||||
#define eglCreateSync64KHR my_eglCreateSync64KHR
|
||||
#define eglWaitSyncKHR my_eglWaitSyncKHR
|
||||
|
||||
#define EXTLST_DECL(tx, x) tx my_##x = NULL;
|
||||
#define EXTLST_EXTERN(tx, x) extern tx my_##x;
|
||||
#define EXTLST_ENTRY(tx, x) {(extlst_fnptr_t *)&my_##x, #x},
|
||||
|
||||
int eglSetupExtensions(void);
|
||||
#endif
|
||||
@@ -0,0 +1,223 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
Display *display;
|
||||
int screen;
|
||||
Window win = 0;
|
||||
|
||||
void error_exit(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#define GET_GLERROR(ret) \
|
||||
{ \
|
||||
GLenum err = glGetError(); \
|
||||
if (err != GL_NO_ERROR) { \
|
||||
fprintf(stderr, "[%s line %d] OpenGL Error: 0x%x\n", __FILE__, __LINE__, err); \
|
||||
fflush(stderr); \
|
||||
\
|
||||
switch (err) { \
|
||||
case GL_INVALID_ENUM: \
|
||||
printf("GL_INVALID_ENUM\n"); \
|
||||
break; \
|
||||
case GL_INVALID_VALUE: \
|
||||
printf("GL_INVALID_VALUE\n"); \
|
||||
break; \
|
||||
case GL_INVALID_OPERATION: \
|
||||
printf("GL_INVALID_OPERATION\n"); \
|
||||
break; \
|
||||
case GL_OUT_OF_MEMORY: \
|
||||
printf("GL_OUT_OF_MEMORY\n"); \
|
||||
break; \
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION: \
|
||||
printf("GL_INVALID_FRAMEBUFFER_OPERATION\n"); \
|
||||
break; \
|
||||
default: \
|
||||
printf("UKNOWN OPENGL ERROR CODE 0x%x\n", err); \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
EGLContext eglContext = EGL_NO_CONTEXT;
|
||||
|
||||
int graphics_setup_window(int xpos, int ypos, int width, int height, const char *windowname)
|
||||
{
|
||||
EGLint configAttrs[] = {EGL_RED_SIZE,
|
||||
1,
|
||||
EGL_GREEN_SIZE,
|
||||
1,
|
||||
EGL_BLUE_SIZE,
|
||||
1,
|
||||
EGL_DEPTH_SIZE,
|
||||
16,
|
||||
EGL_SAMPLE_BUFFERS,
|
||||
0,
|
||||
EGL_SAMPLES,
|
||||
0,
|
||||
// EGL_CONFORMANT, EGL_OPENGL_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES2_BIT, // 3_BIT_KHR,
|
||||
EGL_NONE};
|
||||
EGLint contextAttrs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||
|
||||
EGLConfig *configList = NULL;
|
||||
EGLint configCount;
|
||||
|
||||
display = XOpenDisplay(NULL);
|
||||
if (!display)
|
||||
error_exit("Error opening X display.\n");
|
||||
|
||||
screen = DefaultScreen(display);
|
||||
|
||||
eglDisplay = eglGetDisplay(0);
|
||||
|
||||
if (eglDisplay == EGL_NO_DISPLAY)
|
||||
error_exit("EGL failed to obtain display\n");
|
||||
|
||||
if (!eglInitialize(eglDisplay, 0, 0))
|
||||
error_exit("EGL failed to initialize\n");
|
||||
|
||||
if (!eglChooseConfig(eglDisplay, configAttrs, NULL, 0, &configCount) || !configCount)
|
||||
error_exit("EGL failed to return any matching configurations\n");
|
||||
|
||||
configList = (EGLConfig *)malloc(configCount * sizeof(EGLConfig));
|
||||
|
||||
if (!eglChooseConfig(eglDisplay, configAttrs, configList, configCount, &configCount) || !configCount)
|
||||
error_exit("EGL failed to populate configuration list\n");
|
||||
|
||||
Window xRootWindow = DefaultRootWindow(display);
|
||||
XSetWindowAttributes xCreateWindowAttributes;
|
||||
xCreateWindowAttributes.event_mask = ExposureMask;
|
||||
win = XCreateWindow(display,
|
||||
xRootWindow,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
CWEventMask,
|
||||
&xCreateWindowAttributes);
|
||||
XMapWindow(display, win);
|
||||
|
||||
Atom netWmStateAtom = XInternAtom(display, "_NET_WM_STATE", false);
|
||||
XEvent xEvent;
|
||||
memset(&xEvent, 0, sizeof(xEvent));
|
||||
xEvent.type = ClientMessage;
|
||||
xEvent.xclient.window = win;
|
||||
xEvent.xclient.message_type = netWmStateAtom;
|
||||
xEvent.xclient.format = 32;
|
||||
xEvent.xclient.data.l[0] = 1;
|
||||
xEvent.xclient.data.l[1] = false;
|
||||
XSendEvent(display, xRootWindow, false, SubstructureNotifyMask, &xEvent);
|
||||
|
||||
XStoreName(display, win, windowname);
|
||||
|
||||
XSelectInput(display,
|
||||
win,
|
||||
ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | KeyReleaseMask
|
||||
| VisibilityChangeMask | PointerMotionMask);
|
||||
|
||||
EGLint windowAttrs[] = {EGL_NONE};
|
||||
|
||||
eglSurface = eglCreateWindowSurface(eglDisplay, configList[0], (EGLNativeWindowType)win, windowAttrs);
|
||||
|
||||
if (!eglSurface)
|
||||
error_exit("EGL couldn't create window\n");
|
||||
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
eglContext = eglCreateContext(eglDisplay, configList[0], NULL, contextAttrs);
|
||||
if (!eglContext)
|
||||
error_exit("EGL couldn't create context\n");
|
||||
|
||||
if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext))
|
||||
error_exit("EGL couldn't make context/surface current\n");
|
||||
|
||||
EGLint Context_RendererType;
|
||||
eglQueryContext(eglDisplay, eglContext, EGL_CONTEXT_CLIENT_TYPE, &Context_RendererType);
|
||||
|
||||
switch (Context_RendererType) {
|
||||
case EGL_OPENGL_API:
|
||||
printf("Using OpenGL API is not supported\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case EGL_OPENGL_ES_API:
|
||||
printf("Using OpenGL ES API\n");
|
||||
break;
|
||||
case EGL_OPENVG_API:
|
||||
error_exit("Context Query Returned OpenVG. This is Unsupported\n");
|
||||
default:
|
||||
error_exit("Unknown Context Type. %04X\n", Context_RendererType);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void graphics_set_windowtitle(const char *windowname) { XStoreName(display, win, windowname); }
|
||||
|
||||
void graphics_swap_buffers() { eglSwapBuffers(eglDisplay, eglSurface); }
|
||||
|
||||
void graphics_close_window()
|
||||
{
|
||||
if (eglDisplay != EGL_NO_DISPLAY) {
|
||||
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (eglContext != EGL_NO_CONTEXT)
|
||||
eglDestroyContext(eglDisplay, eglContext);
|
||||
|
||||
if (eglSurface != EGL_NO_SURFACE)
|
||||
eglDestroySurface(eglDisplay, eglSurface);
|
||||
|
||||
eglTerminate(eglDisplay);
|
||||
}
|
||||
|
||||
if (display) {
|
||||
if (win)
|
||||
XDestroyWindow(display, win);
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
}
|
||||
38
cpp/8_Platform_Specific/Tegra/README.md
Normal file
38
cpp/8_Platform_Specific/Tegra/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 8. Platform_Specific/Tegra
|
||||
|
||||
|
||||
### [cudaNvSciNvMedia](./cudaNvSciNvMedia)
|
||||
This sample demonstrates CUDA-NvMedia interop via NvSciBuf/NvSciSync APIs. Note that this sample only supports cross build from x86_64 to aarch64, aarch64 native build is not supported. For detailed workflow of the sample please check cudaNvSciNvMedia_Readme.pdf in the sample directory.
|
||||
|
||||
### [cudaNvSciBufMultiplanar](./cudaNvSciBufMultiplanar)
|
||||
This sample demonstrates CUDA-NvSciBuf Interop for Multiplanar images. A YUV 420 multiplanar image is flipped and allocated using NvSciBuf APIs and imported into CUDA with CUDA External Resource Interoperability. A CUDA surface is created from the corresponding mapped CUDA array and again bit flipping is performed on the surface. The result is copied back to a YUV image which is compared against the input.
|
||||
|
||||
### [cuDLAErrorReporting](./cuDLAErrorReporting)
|
||||
This sample demonstrates how DLA errors can be detected via CUDA.
|
||||
|
||||
### [cuDLAHybridMode](./cuDLAHybridMode)
|
||||
This sample demonstrates cuDLA hybrid mode wherein DLA can be programmed using CUDA.
|
||||
|
||||
### [cuDLALayerwiseStatsHybrid](./cuDLALayerwiseStatsHybrid)
|
||||
This sample is used to provide layerwise statistics to the application in the cuDLA hybrid mode wherein DLA is programmed using CUDA.
|
||||
|
||||
### [cuDLALayerwiseStatsStandalone](./cuDLALayerwiseStatsStandalone)
|
||||
This sample is used to provide layerwise statistics to the application in cuDLA standalone mode where DLA is programmed without using CUDA.
|
||||
|
||||
### [cuDLAStandaloneMode](./cuDLAStandaloneMode)
|
||||
This sample demonstrates cuDLA standalone mode wherein DLA can be programmed without using CUDA.
|
||||
|
||||
### [EGLSync_CUDAEvent_Interop](./EGLSync_CUDAEvent_Interop)
|
||||
Demonstrates interoperability between CUDA Event and EGL Sync/EGL Image using which one can achieve synchronization on GPU itself for GL-EGL-CUDA operations instead of blocking CPU for synchronization.
|
||||
|
||||
### [fluidsGLES](./fluidsGLES)
|
||||
An example of fluid simulation using CUDA and CUFFT, with OpenGLES rendering.
|
||||
|
||||
### [nbody_opengles](./nbody_opengles)
|
||||
This sample demonstrates efficient all-pairs simulation of a gravitational n-body simulation in CUDA. Unlike the OpenGL nbody sample, there is no user interaction.
|
||||
|
||||
### [simpleGLES](./simpleGLES)
|
||||
Demonstrates data exchange between CUDA and OpenGL ES (aka Graphics interop). The program modifies vertex positions with CUDA and uses OpenGL ES to render the geometry.
|
||||
|
||||
### [simpleGLES_EGLOutput](./simpleGLES_EGLOutput)
|
||||
Demonstrates data exchange between CUDA and OpenGL ES (aka Graphics interop). The program modifies vertex positions with CUDA and uses OpenGL ES to render the geometry, and shows how to render directly to the display using the EGLOutput mechanism and the DRM library.
|
||||
18
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cuDLAErrorReporting LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_library(CUDLA_LIB cudla PATHS ${CUDAToolkit_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CUDLA_LIB)
|
||||
# Source file
|
||||
# Add target for cuDLAErrorReporting
|
||||
add_executable(cuDLAErrorReporting main.cu)
|
||||
|
||||
target_compile_options(cuDLAErrorReporting PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cuDLAErrorReporting PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cuDLAErrorReporting PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cuDLAErrorReporting PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cuDLAErrorReporting
|
||||
${CUDLA_LIB}
|
||||
)
|
||||
else()
|
||||
message(STATUS "CUDLA not found - will not build sample 'cuDLAErrorReporting'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cuDLAErrorReporting - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
32
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/README.md
Normal file
32
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# cuDLAErrorReporting - cuDLA Error Reporting
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates how DLA errors can be detected via CUDA.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
cuDLA, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaStreamCreateWithFlags, cudaStreamDestroy, cudaFree, cudaGetErrorName, cudaSetDevice, cudaStreamSynchronize, cudaMalloc, cudaMemsetAsync, cudaMemcpyAsync
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
|
||||
## References (for more details)
|
||||
423
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/main.cu
Normal file
423
cpp/8_Platform_Specific/Tegra/cuDLAErrorReporting/main.cu
Normal file
@@ -0,0 +1,423 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cuda_runtime.h"
|
||||
#include "cudla.h"
|
||||
|
||||
#define DPRINTF(...) printf(__VA_ARGS__)
|
||||
|
||||
static void printTensorDesc(cudlaModuleTensorDescriptor *tensorDesc)
|
||||
{
|
||||
DPRINTF("\tTENSOR NAME : %s\n", tensorDesc->name);
|
||||
DPRINTF("\tsize: %lu\n", tensorDesc->size);
|
||||
|
||||
DPRINTF("\tdims: [%lu, %lu, %lu, %lu]\n", tensorDesc->n, tensorDesc->c, tensorDesc->h, tensorDesc->w);
|
||||
|
||||
DPRINTF("\tdata fmt: %d\n", tensorDesc->dataFormat);
|
||||
DPRINTF("\tdata type: %d\n", tensorDesc->dataType);
|
||||
DPRINTF("\tdata category: %d\n", tensorDesc->dataCategory);
|
||||
DPRINTF("\tpixel fmt: %d\n", tensorDesc->pixelFormat);
|
||||
DPRINTF("\tpixel mapping: %d\n", tensorDesc->pixelMapping);
|
||||
DPRINTF("\tstride[0]: %d\n", tensorDesc->stride[0]);
|
||||
DPRINTF("\tstride[1]: %d\n", tensorDesc->stride[1]);
|
||||
DPRINTF("\tstride[2]: %d\n", tensorDesc->stride[2]);
|
||||
DPRINTF("\tstride[3]: %d\n", tensorDesc->stride[3]);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
unsigned char *loadableData;
|
||||
cudaStream_t stream;
|
||||
unsigned char *inputBuffer;
|
||||
unsigned char *outputBuffer;
|
||||
void *inputBufferGPU;
|
||||
void *outputBufferGPU;
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc;
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc;
|
||||
} ResourceList;
|
||||
|
||||
void cleanUp(ResourceList *resourceList);
|
||||
|
||||
void cleanUp(ResourceList *resourceList)
|
||||
{
|
||||
if (resourceList->inputTensorDesc != NULL) {
|
||||
free(resourceList->inputTensorDesc);
|
||||
resourceList->inputTensorDesc = NULL;
|
||||
}
|
||||
if (resourceList->outputTensorDesc != NULL) {
|
||||
free(resourceList->outputTensorDesc);
|
||||
resourceList->outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->loadableData != NULL) {
|
||||
free(resourceList->loadableData);
|
||||
resourceList->loadableData = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->moduleHandle != NULL) {
|
||||
cudlaModuleUnload(resourceList->moduleHandle, 0);
|
||||
resourceList->moduleHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->devHandle != NULL) {
|
||||
cudlaDestroyDevice(resourceList->devHandle);
|
||||
resourceList->devHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->inputBufferGPU != 0) {
|
||||
cudaFree(resourceList->inputBufferGPU);
|
||||
resourceList->inputBufferGPU = 0;
|
||||
}
|
||||
if (resourceList->outputBufferGPU != 0) {
|
||||
cudaFree(resourceList->outputBufferGPU);
|
||||
resourceList->outputBufferGPU = 0;
|
||||
}
|
||||
|
||||
if (resourceList->inputBuffer != NULL) {
|
||||
free(resourceList->inputBuffer);
|
||||
resourceList->inputBuffer = NULL;
|
||||
}
|
||||
if (resourceList->outputBuffer != NULL) {
|
||||
free(resourceList->outputBuffer);
|
||||
resourceList->outputBuffer = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->stream != NULL) {
|
||||
cudaStreamDestroy(resourceList->stream);
|
||||
resourceList->stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
cudlaStatus err;
|
||||
FILE *fp = NULL;
|
||||
struct stat st;
|
||||
size_t file_size;
|
||||
size_t actually_read = 0;
|
||||
unsigned char *loadableData = NULL;
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaError_t result;
|
||||
const char *errPtr = NULL;
|
||||
|
||||
ResourceList resourceList;
|
||||
|
||||
memset(&resourceList, 0x00, sizeof(ResourceList));
|
||||
|
||||
if (argc != 2) {
|
||||
DPRINTF("Usage : ./cuDLAErrorReporting <loadable>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read loadable into buffer.
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL) {
|
||||
DPRINTF("Cannot open file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stat(argv[1], &st) != 0) {
|
||||
DPRINTF("Cannot stat file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_size = st.st_size;
|
||||
DPRINTF("The file size = %ld\n", file_size);
|
||||
|
||||
loadableData = (unsigned char *)malloc(file_size);
|
||||
if (loadableData == NULL) {
|
||||
DPRINTF("Cannot Allocate memory for loadable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
actually_read = fread(loadableData, 1, file_size, fp);
|
||||
if (actually_read != file_size) {
|
||||
free(loadableData);
|
||||
DPRINTF("Read wrong size\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
resourceList.loadableData = loadableData;
|
||||
|
||||
// Initialize CUDA.
|
||||
result = cudaFree(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaFree = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
result = cudaSetDevice(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaSetDevice = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaCreateDevice(0, &devHandle, CUDLA_CUDA_DLA);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cuDLA create device = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DPRINTF("Device created successfully\n");
|
||||
resourceList.devHandle = devHandle;
|
||||
|
||||
err = cudlaModuleLoadFromMemory(devHandle, loadableData, file_size, &moduleHandle, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cudlaModuleLoadFromMemory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
DPRINTF("Successfully loaded module\n");
|
||||
}
|
||||
|
||||
resourceList.moduleHandle = moduleHandle;
|
||||
|
||||
// Create CUDA stream.
|
||||
result = cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);
|
||||
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cuda stream = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.stream = stream;
|
||||
|
||||
// Get tensor attributes.
|
||||
uint32_t numInputTensors = 0;
|
||||
uint32_t numOutputTensors = 0;
|
||||
cudlaModuleAttribute attribute;
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_INPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numInputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numInputTensors = attribute.numInputTensors;
|
||||
DPRINTF("numInputTensors = %d\n", numInputTensors);
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_OUTPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numOutputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numOutputTensors = attribute.numOutputTensors;
|
||||
DPRINTF("numOutputTensors = %d\n", numOutputTensors);
|
||||
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numInputTensors);
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numOutputTensors);
|
||||
|
||||
if ((inputTensorDesc == NULL) || (outputTensorDesc == NULL)) {
|
||||
if (inputTensorDesc != NULL) {
|
||||
free(inputTensorDesc);
|
||||
inputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (outputTensorDesc != NULL) {
|
||||
free(outputTensorDesc);
|
||||
outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputTensorDesc = inputTensorDesc;
|
||||
resourceList.outputTensorDesc = outputTensorDesc;
|
||||
|
||||
attribute.inputTensorDesc = inputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_INPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting input tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing input tensor descriptor\n");
|
||||
printTensorDesc(inputTensorDesc);
|
||||
|
||||
attribute.outputTensorDesc = outputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_OUTPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting output tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing output tensor descriptor\n");
|
||||
printTensorDesc(outputTensorDesc);
|
||||
|
||||
// Setup the input and output buffers which will be used as an input to CUDA.
|
||||
unsigned char *inputBuffer = (unsigned char *)malloc(inputTensorDesc[0].size);
|
||||
if (inputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating input memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputBuffer = inputBuffer;
|
||||
|
||||
unsigned char *outputBuffer = (unsigned char *)malloc(outputTensorDesc[0].size);
|
||||
if (outputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating output memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.outputBuffer = outputBuffer;
|
||||
|
||||
memset(inputBuffer, 0x01, inputTensorDesc[0].size);
|
||||
memset(outputBuffer, 0x00, outputTensorDesc[0].size);
|
||||
|
||||
// Allocate memory on GPU.
|
||||
void *inputBufferGPU;
|
||||
void *outputBufferGPU;
|
||||
result = cudaMalloc(&inputBufferGPU, inputTensorDesc[0].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating input memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputBufferGPU = inputBufferGPU;
|
||||
|
||||
result = cudaMalloc(&outputBufferGPU, outputTensorDesc[0].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating output memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.outputBufferGPU = outputBufferGPU;
|
||||
|
||||
// Register the CUDA-allocated buffers.
|
||||
uint64_t *inputBufferRegisteredPtr = NULL;
|
||||
uint64_t *outputBufferRegisteredPtr = NULL;
|
||||
|
||||
err =
|
||||
cudlaMemRegister(devHandle, (uint64_t *)inputBufferGPU, inputTensorDesc[0].size, &inputBufferRegisteredPtr, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering input memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaMemRegister(
|
||||
devHandle, (uint64_t *)outputBufferGPU, outputTensorDesc[0].size, &outputBufferRegisteredPtr, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("ALL MEMORY REGISTERED SUCCESSFULLY\n");
|
||||
|
||||
// Copy data from CPU buffers to GPU buffers.
|
||||
result = cudaMemcpyAsync(inputBufferGPU, inputBuffer, inputTensorDesc[0].size, cudaMemcpyHostToDevice, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memcpy for input\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
result = cudaMemsetAsync(outputBufferGPU, 0, outputTensorDesc[0].size, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memset for output\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enqueue a cuDLA task.
|
||||
cudlaTask task;
|
||||
task.moduleHandle = moduleHandle;
|
||||
task.outputTensor = &outputBufferRegisteredPtr;
|
||||
task.numOutputTensors = 1;
|
||||
task.numInputTensors = 1;
|
||||
task.inputTensor = &inputBufferRegisteredPtr;
|
||||
task.waitEvents = NULL;
|
||||
task.signalEvents = NULL;
|
||||
err = cudlaSubmitTask(devHandle, &task, 1, stream, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in submitting task\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("SUBMIT IS DONE !!!\n");
|
||||
|
||||
// Wait for stream operations to finish and bring output buffer to CPU.
|
||||
result = cudaMemcpyAsync(outputBuffer, outputBufferGPU, outputTensorDesc[0].size, cudaMemcpyDeviceToHost, stream);
|
||||
if (result != cudaSuccess) {
|
||||
if (result != cudaErrorExternalDevice) {
|
||||
DPRINTF("Error in bringing result back to CPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
cudlaStatus hwStatus = cudlaGetLastError(devHandle);
|
||||
if (hwStatus != cudlaSuccess) {
|
||||
DPRINTF("Asynchronous error in HW = %u\n", hwStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = cudaStreamSynchronize(stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in synchronizing stream = %s\n", cudaGetErrorName(result));
|
||||
|
||||
if (result == cudaErrorExternalDevice) {
|
||||
cudlaStatus hwStatus = cudlaGetLastError(devHandle);
|
||||
if (hwStatus != cudlaSuccess) {
|
||||
DPRINTF("Asynchronous error in HW = %u\n", hwStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp(&resourceList);
|
||||
|
||||
DPRINTF("cuDLAErrorReporting DONE !!!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
53
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/CMakeLists.txt
Normal file
53
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/CMakeLists.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cuDLAHybridMode LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_library(CUDLA_LIB cudla PATHS ${CUDAToolkit_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CUDLA_LIB)
|
||||
# Source file
|
||||
# Add target for cuDLAHybridMode
|
||||
add_executable(cuDLAHybridMode main.cu)
|
||||
|
||||
target_compile_options(cuDLAHybridMode PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cuDLAHybridMode PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cuDLAHybridMode PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cuDLAHybridMode PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cuDLAHybridMode
|
||||
${CUDLA_LIB}
|
||||
)
|
||||
else()
|
||||
message(STATUS "CUDLA not found - will not build sample 'cuDLAHybridMode'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cuDLAHybridMode - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
32
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/README.md
Normal file
32
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# cuDLAHybridMode - cuDLA Hybrid Mode
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates cuDLA hybrid mode wherein DLA can be programmed using CUDA.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
cuDLA, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaStreamCreateWithFlags, cudaStreamDestroy, cudaFree, cudaGetErrorName, cudaSetDevice, cudaStreamSynchronize, cudaMalloc, cudaMemsetAsync, cudaMemcpyAsync
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
|
||||
## References (for more details)
|
||||
487
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/main.cu
Normal file
487
cpp/8_Platform_Specific/Tegra/cuDLAHybridMode/main.cu
Normal file
@@ -0,0 +1,487 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cuda_runtime.h"
|
||||
#include "cudla.h"
|
||||
|
||||
#define DPRINTF(...) printf(__VA_ARGS__)
|
||||
|
||||
static void printTensorDesc(cudlaModuleTensorDescriptor *tensorDesc)
|
||||
{
|
||||
DPRINTF("\tTENSOR NAME : %s\n", tensorDesc->name);
|
||||
DPRINTF("\tsize: %lu\n", tensorDesc->size);
|
||||
|
||||
DPRINTF("\tdims: [%lu, %lu, %lu, %lu]\n", tensorDesc->n, tensorDesc->c, tensorDesc->h, tensorDesc->w);
|
||||
|
||||
DPRINTF("\tdata fmt: %d\n", tensorDesc->dataFormat);
|
||||
DPRINTF("\tdata type: %d\n", tensorDesc->dataType);
|
||||
DPRINTF("\tdata category: %d\n", tensorDesc->dataCategory);
|
||||
DPRINTF("\tpixel fmt: %d\n", tensorDesc->pixelFormat);
|
||||
DPRINTF("\tpixel mapping: %d\n", tensorDesc->pixelMapping);
|
||||
DPRINTF("\tstride[0]: %d\n", tensorDesc->stride[0]);
|
||||
DPRINTF("\tstride[1]: %d\n", tensorDesc->stride[1]);
|
||||
DPRINTF("\tstride[2]: %d\n", tensorDesc->stride[2]);
|
||||
DPRINTF("\tstride[3]: %d\n", tensorDesc->stride[3]);
|
||||
}
|
||||
|
||||
static int initializeInputBuffers(char *filePath, cudlaModuleTensorDescriptor *tensorDesc, unsigned char *buf)
|
||||
{
|
||||
// Read the file in filePath and fill up 'buf' according to format
|
||||
// specified by the user.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
unsigned char *loadableData;
|
||||
cudaStream_t stream;
|
||||
unsigned char *inputBuffer;
|
||||
unsigned char *outputBuffer;
|
||||
void *inputBufferGPU;
|
||||
void *outputBufferGPU;
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc;
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc;
|
||||
} ResourceList;
|
||||
|
||||
void cleanUp(ResourceList *resourceList);
|
||||
|
||||
void cleanUp(ResourceList *resourceList)
|
||||
{
|
||||
if (resourceList->inputTensorDesc != NULL) {
|
||||
free(resourceList->inputTensorDesc);
|
||||
resourceList->inputTensorDesc = NULL;
|
||||
}
|
||||
if (resourceList->outputTensorDesc != NULL) {
|
||||
free(resourceList->outputTensorDesc);
|
||||
resourceList->outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->loadableData != NULL) {
|
||||
free(resourceList->loadableData);
|
||||
resourceList->loadableData = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->moduleHandle != NULL) {
|
||||
cudlaModuleUnload(resourceList->moduleHandle, 0);
|
||||
resourceList->moduleHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->devHandle != NULL) {
|
||||
cudlaDestroyDevice(resourceList->devHandle);
|
||||
resourceList->devHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->inputBufferGPU != 0) {
|
||||
cudaFree(resourceList->inputBufferGPU);
|
||||
resourceList->inputBufferGPU = 0;
|
||||
}
|
||||
if (resourceList->outputBufferGPU != 0) {
|
||||
cudaFree(resourceList->outputBufferGPU);
|
||||
resourceList->outputBufferGPU = 0;
|
||||
}
|
||||
|
||||
if (resourceList->inputBuffer != NULL) {
|
||||
free(resourceList->inputBuffer);
|
||||
resourceList->inputBuffer = NULL;
|
||||
}
|
||||
if (resourceList->outputBuffer != NULL) {
|
||||
free(resourceList->outputBuffer);
|
||||
resourceList->outputBuffer = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->stream != NULL) {
|
||||
cudaStreamDestroy(resourceList->stream);
|
||||
resourceList->stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
cudlaStatus err;
|
||||
FILE *fp = NULL;
|
||||
struct stat st;
|
||||
size_t file_size;
|
||||
size_t actually_read = 0;
|
||||
unsigned char *loadableData = NULL;
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaError_t result;
|
||||
const char *errPtr = NULL;
|
||||
|
||||
ResourceList resourceList;
|
||||
|
||||
memset(&resourceList, 0x00, sizeof(ResourceList));
|
||||
|
||||
if (argc != 3) {
|
||||
DPRINTF("Usage : ./cuDLAHybridMode <loadable> <imageFile>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read loadable into buffer.
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL) {
|
||||
DPRINTF("Cannot open file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stat(argv[1], &st) != 0) {
|
||||
DPRINTF("Cannot stat file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_size = st.st_size;
|
||||
DPRINTF("The file size = %ld\n", file_size);
|
||||
|
||||
loadableData = (unsigned char *)malloc(file_size);
|
||||
if (loadableData == NULL) {
|
||||
DPRINTF("Cannot Allocate memory for loadable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
actually_read = fread(loadableData, 1, file_size, fp);
|
||||
if (actually_read != file_size) {
|
||||
free(loadableData);
|
||||
DPRINTF("Read wrong size\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
resourceList.loadableData = loadableData;
|
||||
|
||||
// Initialize CUDA.
|
||||
result = cudaFree(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaFree = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
result = cudaSetDevice(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaSetDevice = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaCreateDevice(0, &devHandle, CUDLA_CUDA_DLA);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cuDLA create device = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DPRINTF("Device created successfully\n");
|
||||
resourceList.devHandle = devHandle;
|
||||
|
||||
err = cudlaModuleLoadFromMemory(devHandle, loadableData, file_size, &moduleHandle, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cudlaModuleLoadFromMemory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
DPRINTF("Successfully loaded module\n");
|
||||
}
|
||||
|
||||
resourceList.moduleHandle = moduleHandle;
|
||||
|
||||
// Create CUDA stream.
|
||||
result = cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);
|
||||
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cuda stream = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.stream = stream;
|
||||
|
||||
// Get tensor attributes.
|
||||
uint32_t numInputTensors = 0;
|
||||
uint32_t numOutputTensors = 0;
|
||||
cudlaModuleAttribute attribute;
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_INPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numInputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numInputTensors = attribute.numInputTensors;
|
||||
DPRINTF("numInputTensors = %d\n", numInputTensors);
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_OUTPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numOutputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numOutputTensors = attribute.numOutputTensors;
|
||||
DPRINTF("numOutputTensors = %d\n", numOutputTensors);
|
||||
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numInputTensors);
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numOutputTensors);
|
||||
|
||||
if ((inputTensorDesc == NULL) || (outputTensorDesc == NULL)) {
|
||||
if (inputTensorDesc != NULL) {
|
||||
free(inputTensorDesc);
|
||||
inputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (outputTensorDesc != NULL) {
|
||||
free(outputTensorDesc);
|
||||
outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputTensorDesc = inputTensorDesc;
|
||||
resourceList.outputTensorDesc = outputTensorDesc;
|
||||
|
||||
attribute.inputTensorDesc = inputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_INPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting input tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing input tensor descriptor\n");
|
||||
printTensorDesc(inputTensorDesc);
|
||||
|
||||
attribute.outputTensorDesc = outputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_OUTPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting output tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing output tensor descriptor\n");
|
||||
printTensorDesc(outputTensorDesc);
|
||||
|
||||
// Setup the input and output buffers which will be used as an input to CUDA.
|
||||
unsigned char *inputBuffer = (unsigned char *)malloc(inputTensorDesc[0].size);
|
||||
if (inputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating input memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputBuffer = inputBuffer;
|
||||
|
||||
unsigned char *outputBuffer = (unsigned char *)malloc(outputTensorDesc[0].size);
|
||||
if (outputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating output memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.outputBuffer = outputBuffer;
|
||||
|
||||
memset(inputBuffer, 0x00, inputTensorDesc[0].size);
|
||||
memset(outputBuffer, 0x00, outputTensorDesc[0].size);
|
||||
|
||||
// Fill up the buffers with data.
|
||||
if (initializeInputBuffers(argv[2], inputTensorDesc, inputBuffer) != 0) {
|
||||
DPRINTF("Error in initializing input buffer\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate memory on GPU.
|
||||
void *inputBufferGPU;
|
||||
void *outputBufferGPU;
|
||||
result = cudaMalloc(&inputBufferGPU, inputTensorDesc[0].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating input memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputBufferGPU = inputBufferGPU;
|
||||
|
||||
result = cudaMalloc(&outputBufferGPU, outputTensorDesc[0].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating output memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.outputBufferGPU = outputBufferGPU;
|
||||
|
||||
// Register the CUDA-allocated buffers.
|
||||
uint64_t *inputBufferRegisteredPtr = NULL;
|
||||
uint64_t *outputBufferRegisteredPtr = NULL;
|
||||
|
||||
err =
|
||||
cudlaMemRegister(devHandle, (uint64_t *)inputBufferGPU, inputTensorDesc[0].size, &inputBufferRegisteredPtr, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering input memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaMemRegister(
|
||||
devHandle, (uint64_t *)outputBufferGPU, outputTensorDesc[0].size, &outputBufferRegisteredPtr, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("ALL MEMORY REGISTERED SUCCESSFULLY\n");
|
||||
|
||||
// Copy data from CPU buffers to GPU buffers.
|
||||
result = cudaMemcpyAsync(inputBufferGPU, inputBuffer, inputTensorDesc[0].size, cudaMemcpyHostToDevice, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memcpy for input\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
result = cudaMemsetAsync(outputBufferGPU, 0, outputTensorDesc[0].size, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memset for output\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enqueue a cuDLA task.
|
||||
cudlaTask task;
|
||||
task.moduleHandle = moduleHandle;
|
||||
task.outputTensor = &outputBufferRegisteredPtr;
|
||||
task.numOutputTensors = 1;
|
||||
task.numInputTensors = 1;
|
||||
task.inputTensor = &inputBufferRegisteredPtr;
|
||||
task.waitEvents = NULL;
|
||||
task.signalEvents = NULL;
|
||||
err = cudlaSubmitTask(devHandle, &task, 1, stream, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in submitting task\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("SUBMIT IS DONE !!!\n");
|
||||
|
||||
// Wait for stream operations to finish and bring output buffer to CPU.
|
||||
result = cudaMemcpyAsync(outputBuffer, outputBufferGPU, outputTensorDesc[0].size, cudaMemcpyDeviceToHost, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in bringing result back to CPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
result = cudaStreamSynchronize(stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in synchronizing stream\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Output is available in outputBuffer.
|
||||
|
||||
// Teardown.
|
||||
err = cudlaMemUnregister(devHandle, inputBufferRegisteredPtr);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in unregistering input memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaMemUnregister(devHandle, outputBufferRegisteredPtr);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("ALL MEMORY UNREGISTERED SUCCESSFULLY\n");
|
||||
|
||||
free(inputTensorDesc);
|
||||
free(outputTensorDesc);
|
||||
free(loadableData);
|
||||
free(inputBuffer);
|
||||
free(outputBuffer);
|
||||
cudaFree(inputBufferGPU);
|
||||
cudaFree(outputBufferGPU);
|
||||
|
||||
resourceList.inputTensorDesc = NULL;
|
||||
resourceList.outputTensorDesc = NULL;
|
||||
resourceList.loadableData = NULL;
|
||||
resourceList.inputBuffer = NULL;
|
||||
resourceList.outputBuffer = NULL;
|
||||
resourceList.inputBufferGPU = 0;
|
||||
resourceList.outputBufferGPU = 0;
|
||||
|
||||
result = cudaStreamDestroy(stream);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in destroying cuda stream = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.stream = NULL;
|
||||
|
||||
err = cudlaModuleUnload(moduleHandle, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cudlaModuleUnload = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
DPRINTF("Successfully unloaded module\n");
|
||||
}
|
||||
|
||||
resourceList.moduleHandle = NULL;
|
||||
|
||||
err = cudlaDestroyDevice(devHandle);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cuDLA destroy device = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Device destroyed successfully\n");
|
||||
|
||||
resourceList.devHandle = NULL;
|
||||
|
||||
DPRINTF("cuDLAHybridMode DONE !!!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cuDLALayerwiseStatsHybrid LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_library(CUDLA_LIB cudla PATHS ${CUDAToolkit_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CUDLA_LIB)
|
||||
# Source file
|
||||
# Add target for cuDLALayerwiseStatsHybrid
|
||||
add_executable(cuDLALayerwiseStatsHybrid main.cu)
|
||||
|
||||
target_compile_options(cuDLALayerwiseStatsHybrid PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cuDLALayerwiseStatsHybrid PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cuDLALayerwiseStatsHybrid PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cuDLALayerwiseStatsHybrid PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cuDLALayerwiseStatsHybrid
|
||||
${CUDLA_LIB}
|
||||
)
|
||||
else()
|
||||
message(STATUS "CUDLA not found - will not build sample 'cuDLALayerwiseStatsHybrid'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cuDLALayerwiseStatsHybrid - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
@@ -0,0 +1,32 @@
|
||||
# cuDLALayerwiseStatsHybrid - cuDLA Layerwise statistics HybridMode
|
||||
|
||||
## Description
|
||||
|
||||
This sample is used to provide layerwise statistics to the application in the cuDLA hybrid mode wherein DLA is programmed using CUDA.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
cuDLA, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaStreamCreateWithFlags, cudaStreamDestroy, cudaFree, cudaGetErrorName, cudaSetDevice, cudaStreamSynchronize, cudaMalloc, cudaMemsetAsync, cudaMemcpyAsync
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
|
||||
## References (for more details)
|
||||
899
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/main.cu
Normal file
899
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsHybrid/main.cu
Normal file
@@ -0,0 +1,899 @@
|
||||
/* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cuda_runtime.h"
|
||||
#include "cudla.h"
|
||||
#include "cudlaExternalEtbl.hpp"
|
||||
|
||||
#define MAX_FILENAME_LEN 200
|
||||
#define RESERVED_SUFFIX_LEN 10
|
||||
|
||||
#define DPRINTF(...) printf(__VA_ARGS__)
|
||||
|
||||
static void printTensorDesc(cudlaModuleTensorDescriptor *tensorDesc)
|
||||
{
|
||||
DPRINTF("\tTENSOR NAME : %s\n", tensorDesc->name);
|
||||
DPRINTF("\tsize: %lu\n", tensorDesc->size);
|
||||
|
||||
DPRINTF("\tdims: [%lu, %lu, %lu, %lu]\n", tensorDesc->n, tensorDesc->c, tensorDesc->h, tensorDesc->w);
|
||||
|
||||
DPRINTF("\tdata fmt: %d\n", tensorDesc->dataFormat);
|
||||
DPRINTF("\tdata type: %d\n", tensorDesc->dataType);
|
||||
DPRINTF("\tdata category: %d\n", tensorDesc->dataCategory);
|
||||
DPRINTF("\tpixel fmt: %d\n", tensorDesc->pixelFormat);
|
||||
DPRINTF("\tpixel mapping: %d\n", tensorDesc->pixelMapping);
|
||||
DPRINTF("\tstride[0]: %d\n", tensorDesc->stride[0]);
|
||||
DPRINTF("\tstride[1]: %d\n", tensorDesc->stride[1]);
|
||||
DPRINTF("\tstride[2]: %d\n", tensorDesc->stride[2]);
|
||||
DPRINTF("\tstride[3]: %d\n", tensorDesc->stride[3]);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
unsigned char *loadableData;
|
||||
cudaStream_t stream;
|
||||
uint32_t numInputTensors;
|
||||
uint32_t numOutputTensors;
|
||||
uint32_t numOutputTaskStatistics;
|
||||
unsigned char **inputBuffer;
|
||||
unsigned char **outputBuffer;
|
||||
unsigned char **statisticsOutputBuffer;
|
||||
void **inputBufferGPU;
|
||||
void **outputBufferGPU;
|
||||
void **outputTaskStatisticsGPU;
|
||||
void **csv;
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc;
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc;
|
||||
cudlaModuleTensorDescriptor *outputTaskStatisticsDesc;
|
||||
uint64_t **inputBufferRegisteredPtr;
|
||||
uint64_t **outputBufferRegisteredPtr;
|
||||
uint64_t **outputTaskStatisticsRegisteredPtr;
|
||||
uint64_t **outputStatisticsBufferRegisteredPtr;
|
||||
} ResourceList;
|
||||
|
||||
void cleanUp(ResourceList *resourceList);
|
||||
|
||||
void cleanUp(ResourceList *resourceList)
|
||||
{
|
||||
uint32_t ii = 0;
|
||||
if (resourceList->inputTensorDesc != NULL) {
|
||||
free(resourceList->inputTensorDesc);
|
||||
resourceList->inputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputTensorDesc != NULL) {
|
||||
free(resourceList->outputTensorDesc);
|
||||
resourceList->outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputTaskStatisticsDesc != NULL) {
|
||||
free(resourceList->outputTaskStatisticsDesc);
|
||||
resourceList->outputTaskStatisticsDesc = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->loadableData != NULL) {
|
||||
free(resourceList->loadableData);
|
||||
resourceList->loadableData = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->moduleHandle != NULL) {
|
||||
cudlaModuleUnload(resourceList->moduleHandle, 0);
|
||||
resourceList->moduleHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->devHandle != NULL) {
|
||||
cudlaDestroyDevice(resourceList->devHandle);
|
||||
resourceList->devHandle = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->inputBufferGPU != NULL) {
|
||||
for (ii = 0; ii < resourceList->numInputTensors; ii++) {
|
||||
if ((resourceList->inputBufferGPU)[ii] != NULL) {
|
||||
cudaFree((resourceList->inputBufferGPU)[ii]);
|
||||
(resourceList->inputBufferGPU)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->inputBufferGPU);
|
||||
resourceList->inputBufferGPU = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputBufferGPU != NULL) {
|
||||
for (ii = 0; ii < resourceList->numOutputTensors; ii++) {
|
||||
if ((resourceList->outputBufferGPU)[ii] != NULL) {
|
||||
cudaFree((resourceList->outputBufferGPU)[ii]);
|
||||
(resourceList->outputBufferGPU)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->outputBufferGPU);
|
||||
resourceList->outputBufferGPU = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputTaskStatisticsGPU != NULL) {
|
||||
for (ii = 0; ii < resourceList->numOutputTaskStatistics; ii++) {
|
||||
if ((resourceList->outputTaskStatisticsGPU)[ii] != NULL) {
|
||||
cudaFree((resourceList->outputTaskStatisticsGPU)[ii]);
|
||||
(resourceList->outputTaskStatisticsGPU)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->outputTaskStatisticsGPU);
|
||||
resourceList->outputTaskStatisticsGPU = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->csv != NULL) {
|
||||
for (ii = 0; ii < resourceList->numOutputTaskStatistics; ii++) {
|
||||
if ((resourceList->csv)[ii] != NULL) {
|
||||
free((resourceList->csv)[ii]);
|
||||
(resourceList->csv)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->csv);
|
||||
resourceList->csv = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->inputBuffer != NULL) {
|
||||
for (ii = 0; ii < resourceList->numInputTensors; ii++) {
|
||||
if ((resourceList->inputBuffer)[ii] != NULL) {
|
||||
free((resourceList->inputBuffer)[ii]);
|
||||
(resourceList->inputBuffer)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->inputBuffer);
|
||||
resourceList->inputBuffer = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputBuffer != NULL) {
|
||||
for (ii = 0; ii < resourceList->numOutputTensors; ii++) {
|
||||
if ((resourceList->outputBuffer)[ii] != NULL) {
|
||||
free((resourceList->outputBuffer)[ii]);
|
||||
(resourceList->outputBuffer)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->outputBuffer);
|
||||
resourceList->outputBuffer = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->statisticsOutputBuffer != NULL) {
|
||||
for (ii = 0; ii < resourceList->numOutputTaskStatistics; ii++) {
|
||||
if ((resourceList->statisticsOutputBuffer)[ii] != NULL) {
|
||||
free((resourceList->statisticsOutputBuffer)[ii]);
|
||||
(resourceList->statisticsOutputBuffer)[ii] = NULL;
|
||||
}
|
||||
}
|
||||
free(resourceList->statisticsOutputBuffer);
|
||||
resourceList->statisticsOutputBuffer = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->stream != NULL) {
|
||||
cudaStreamDestroy(resourceList->stream);
|
||||
resourceList->stream = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->inputBufferRegisteredPtr != NULL) {
|
||||
free(resourceList->inputBufferRegisteredPtr);
|
||||
resourceList->inputBufferRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputBufferRegisteredPtr != NULL) {
|
||||
free(resourceList->outputBufferRegisteredPtr);
|
||||
resourceList->outputBufferRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputTaskStatisticsRegisteredPtr != NULL) {
|
||||
free(resourceList->outputTaskStatisticsRegisteredPtr);
|
||||
resourceList->outputTaskStatisticsRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
if (resourceList->outputStatisticsBufferRegisteredPtr != NULL) {
|
||||
free(resourceList->outputStatisticsBufferRegisteredPtr);
|
||||
resourceList->outputStatisticsBufferRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
resourceList->numInputTensors = 0;
|
||||
resourceList->numOutputTensors = 0;
|
||||
resourceList->numOutputTaskStatistics = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
cudlaDevHandle devHandle;
|
||||
cudlaModule moduleHandle;
|
||||
cudlaStatus err;
|
||||
uint32_t statSupport = 0;
|
||||
uint32_t dlaFreqInMHz = 0;
|
||||
FILE *fp = NULL;
|
||||
struct stat st;
|
||||
size_t file_size;
|
||||
size_t actually_read = 0;
|
||||
unsigned char *loadableData = NULL;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
const char *suffix = ".csv";
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaError_t result;
|
||||
const char *errPtr = NULL;
|
||||
|
||||
ResourceList resourceList;
|
||||
|
||||
memset(&resourceList, 0x00, sizeof(ResourceList));
|
||||
|
||||
if ((argc != 4) && (argc != 5)) {
|
||||
DPRINTF("Usage : ./test_cudla_layerwise_stats_L0_hybrid_test1 <loadable> <freqMHZ> <statSupport> <filename "
|
||||
"prefix>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 5) {
|
||||
if ((strlen(argv[4])) > (MAX_FILENAME_LEN - RESERVED_SUFFIX_LEN)) {
|
||||
DPRINTF("Filename prefix length is too big, greater than maximum permissible prefix length of %u \n",
|
||||
(MAX_FILENAME_LEN - RESERVED_SUFFIX_LEN));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Read loadable into buffer.
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL) {
|
||||
DPRINTF("Cannot open file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stat(argv[1], &st) != 0) {
|
||||
DPRINTF("Cannot stat file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_size = st.st_size;
|
||||
DPRINTF("The file size = %ld\n", file_size);
|
||||
|
||||
dlaFreqInMHz = atoi(argv[2]);
|
||||
statSupport = atoi(argv[3]);
|
||||
|
||||
loadableData = (unsigned char *)malloc(file_size);
|
||||
if (loadableData == NULL) {
|
||||
DPRINTF("Cannot Allocate memory for loadable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
actually_read = fread(loadableData, 1, file_size, fp);
|
||||
if (actually_read != file_size) {
|
||||
free(loadableData);
|
||||
DPRINTF("Read wrong size\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
resourceList.loadableData = loadableData;
|
||||
|
||||
// Initialize CUDA.
|
||||
result = cudaFree(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaFree = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = cudaSetDevice(0);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cudaSetDevice = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = cudlaCreateDevice(0, &devHandle, CUDLA_CUDA_DLA);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cuDLA create device = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DPRINTF("Device created successfully\n");
|
||||
resourceList.devHandle = devHandle;
|
||||
|
||||
err = cudlaModuleLoadFromMemory(devHandle, loadableData, file_size, &moduleHandle, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cudlaModuleLoadFromMemory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
DPRINTF("Successfully loaded module\n");
|
||||
}
|
||||
|
||||
resourceList.moduleHandle = moduleHandle;
|
||||
|
||||
// Create CUDA stream.
|
||||
result = cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);
|
||||
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in creating cuda stream = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.stream = stream;
|
||||
|
||||
// Get tensor attributes.
|
||||
uint32_t numInputTensors = 0;
|
||||
uint32_t numOutputTensors = 0;
|
||||
uint32_t numOutputTaskStatistics = 0;
|
||||
|
||||
cudlaModuleAttribute attribute;
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_INPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numInputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numInputTensors = attribute.numInputTensors;
|
||||
DPRINTF("numInputTensors = %d\n", numInputTensors);
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_OUTPUT_TENSORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numOutputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numOutputTensors = attribute.numOutputTensors;
|
||||
DPRINTF("numOutputTensors = %d\n", numOutputTensors);
|
||||
|
||||
// using the same attributes to get num_output_task_statistics_tensors
|
||||
attribute.numOutputTensors = 0;
|
||||
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_NUM_OUTPUT_TASK_STATISTICS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting numOutputTensors = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
numOutputTaskStatistics = attribute.numOutputTensors;
|
||||
DPRINTF("numOutputTaskStatistics = %d\n", numOutputTaskStatistics);
|
||||
|
||||
if (numOutputTaskStatistics == 0) {
|
||||
DPRINTF("Layerwise stats is not supported for this Loadable \n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.numInputTensors = numInputTensors;
|
||||
resourceList.numOutputTensors = numOutputTensors;
|
||||
resourceList.numOutputTaskStatistics = numOutputTaskStatistics;
|
||||
|
||||
cudlaModuleTensorDescriptor *inputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numInputTensors);
|
||||
cudlaModuleTensorDescriptor *outputTensorDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numOutputTensors);
|
||||
|
||||
if ((inputTensorDesc == NULL) || (outputTensorDesc == NULL)) {
|
||||
if (inputTensorDesc != NULL) {
|
||||
free(inputTensorDesc);
|
||||
inputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
if (outputTensorDesc != NULL) {
|
||||
free(outputTensorDesc);
|
||||
outputTensorDesc = NULL;
|
||||
}
|
||||
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputTensorDesc = inputTensorDesc;
|
||||
resourceList.outputTensorDesc = outputTensorDesc;
|
||||
|
||||
cudlaModuleTensorDescriptor *outputTaskStatisticsDesc =
|
||||
(cudlaModuleTensorDescriptor *)malloc(sizeof(cudlaModuleTensorDescriptor) * numOutputTaskStatistics);
|
||||
if (outputTaskStatisticsDesc == NULL) {
|
||||
free(outputTaskStatisticsDesc);
|
||||
outputTaskStatisticsDesc = NULL;
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.outputTaskStatisticsDesc = outputTaskStatisticsDesc;
|
||||
|
||||
attribute.inputTensorDesc = inputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_INPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting input tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing input tensor descriptor\n");
|
||||
printTensorDesc(inputTensorDesc);
|
||||
|
||||
attribute.outputTensorDesc = outputTensorDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_OUTPUT_TENSOR_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting output tensor descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Printing output tensor descriptor\n");
|
||||
printTensorDesc(outputTensorDesc);
|
||||
|
||||
attribute.outputTensorDesc = outputTaskStatisticsDesc;
|
||||
err = cudlaModuleGetAttributes(moduleHandle, CUDLA_OUTPUT_TASK_STATISTICS_DESCRIPTORS, &attribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in getting task statistics descriptor = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DPRINTF("Printing output task statistics descriptor size\n");
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
DPRINTF("The size of %u descriptor is %lu\n", ii, outputTaskStatisticsDesc[ii].size);
|
||||
}
|
||||
|
||||
// Setup the input and output buffers which will be used as an input to CUDA.
|
||||
unsigned char **inputBuffer = (unsigned char **)malloc(sizeof(unsigned char *) * numInputTensors);
|
||||
if (inputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating memory for input buffer array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(inputBuffer, 0x00, sizeof(unsigned char *) * numInputTensors);
|
||||
resourceList.inputBuffer = inputBuffer;
|
||||
for (uint32_t ii = 0; ii < numInputTensors; ii++) {
|
||||
inputBuffer[ii] = (unsigned char *)malloc(inputTensorDesc[ii].size);
|
||||
if (inputBuffer[ii] == NULL) {
|
||||
DPRINTF("Error in allocating input memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(inputBuffer[ii], 0x01, inputTensorDesc[ii].size);
|
||||
}
|
||||
|
||||
unsigned char **outputBuffer = (unsigned char **)malloc(sizeof(unsigned char *) * numOutputTensors);
|
||||
if (outputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating memory for output buffer array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(outputBuffer, 0x00, sizeof(unsigned char *) * numOutputTensors);
|
||||
resourceList.outputBuffer = outputBuffer;
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
outputBuffer[ii] = (unsigned char *)malloc(outputTensorDesc[ii].size);
|
||||
if (outputBuffer[ii] == NULL) {
|
||||
DPRINTF("Error in allocating output memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(outputBuffer[ii], 0x00, outputTensorDesc[ii].size);
|
||||
}
|
||||
|
||||
unsigned char **statisticsOutputBuffer =
|
||||
(unsigned char **)malloc(sizeof(unsigned char *) * numOutputTaskStatistics);
|
||||
if (statisticsOutputBuffer == NULL) {
|
||||
DPRINTF("Error in allocating memory for output buffer array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(statisticsOutputBuffer, 0x00, sizeof(unsigned char *) * numOutputTaskStatistics);
|
||||
resourceList.statisticsOutputBuffer = statisticsOutputBuffer;
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
statisticsOutputBuffer[ii] = (unsigned char *)malloc(outputTaskStatisticsDesc[ii].size);
|
||||
if (outputBuffer[ii] == NULL) {
|
||||
DPRINTF("Error in allocating output memory\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(statisticsOutputBuffer[ii], 0x00, outputTaskStatisticsDesc[ii].size);
|
||||
}
|
||||
|
||||
// Allocate memory on GPU.
|
||||
void **inputBufferGPU = (void **)malloc(sizeof(void *) * numInputTensors);
|
||||
if (inputBufferGPU == NULL) {
|
||||
DPRINTF("Error in allocating memory for input buffer GPU array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(inputBufferGPU, 0x00, sizeof(void *) * numInputTensors);
|
||||
resourceList.inputBufferGPU = inputBufferGPU;
|
||||
|
||||
for (uint32_t ii = 0; ii < numInputTensors; ii++) {
|
||||
result = cudaMalloc(&(inputBufferGPU[ii]), inputTensorDesc[ii].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating input memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void **outputBufferGPU = (void **)malloc(sizeof(void *) * numOutputTensors);
|
||||
if (outputBufferGPU == NULL) {
|
||||
DPRINTF("Error in allocating memory for output buffer GPU array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(outputBufferGPU, 0x00, sizeof(void *) * numOutputTensors);
|
||||
resourceList.outputBufferGPU = outputBufferGPU;
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
result = cudaMalloc(&(outputBufferGPU[ii]), outputTensorDesc[ii].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating output memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void **outputTaskStatisticsGPU = (void **)malloc(sizeof(void *) * numOutputTaskStatistics);
|
||||
if (outputTaskStatisticsGPU == NULL) {
|
||||
DPRINTF("Error in allocating memory for output task statistics GPU array\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(outputTaskStatisticsGPU, 0x00, sizeof(void *) * numOutputTaskStatistics);
|
||||
resourceList.outputTaskStatisticsGPU = outputTaskStatisticsGPU;
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
result = cudaMalloc(&(outputTaskStatisticsGPU[ii]), outputTaskStatisticsDesc[ii].size);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in allocating task statistics memory on GPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t **inputBufferRegisteredPtr = (uint64_t **)malloc(sizeof(uint64_t *) * numInputTensors);
|
||||
uint64_t **outputBufferRegisteredPtr = (uint64_t **)malloc(sizeof(uint64_t *) * numOutputTensors);
|
||||
uint64_t **outputTaskStatisticsRegisteredPtr = (uint64_t **)malloc(sizeof(uint64_t *) * numOutputTaskStatistics);
|
||||
|
||||
if ((inputBufferRegisteredPtr == NULL) || (outputBufferRegisteredPtr == NULL)
|
||||
|| (outputTaskStatisticsRegisteredPtr == NULL)) {
|
||||
if (inputBufferRegisteredPtr != NULL) {
|
||||
free(inputBufferRegisteredPtr);
|
||||
inputBufferRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
if (outputBufferRegisteredPtr != NULL) {
|
||||
free(outputBufferRegisteredPtr);
|
||||
outputBufferRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
if (outputTaskStatisticsRegisteredPtr != NULL) {
|
||||
free(outputTaskStatisticsRegisteredPtr);
|
||||
outputTaskStatisticsRegisteredPtr = NULL;
|
||||
}
|
||||
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.inputBufferRegisteredPtr = inputBufferRegisteredPtr;
|
||||
resourceList.outputBufferRegisteredPtr = outputBufferRegisteredPtr;
|
||||
resourceList.outputTaskStatisticsRegisteredPtr = outputTaskStatisticsRegisteredPtr;
|
||||
|
||||
// Register the CUDA-allocated buffers.
|
||||
for (uint32_t ii = 0; ii < numInputTensors; ii++) {
|
||||
err = cudlaMemRegister(
|
||||
devHandle, (uint64_t *)(inputBufferGPU[ii]), inputTensorDesc[ii].size, &(inputBufferRegisteredPtr[ii]), 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering input memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
err = cudlaMemRegister(devHandle,
|
||||
(uint64_t *)(outputBufferGPU[ii]),
|
||||
outputTensorDesc[ii].size,
|
||||
&(outputBufferRegisteredPtr[ii]),
|
||||
0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
err = cudlaMemRegister(devHandle,
|
||||
(uint64_t *)(outputTaskStatisticsGPU[ii]),
|
||||
outputTaskStatisticsDesc[ii].size,
|
||||
&(outputTaskStatisticsRegisteredPtr[ii]),
|
||||
CUDLA_TASK_STATISTICS);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering statistics output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("ALL MEMORY REGISTERED SUCCESSFULLY\n");
|
||||
|
||||
// Copy data from CPU buffers to GPU buffers.
|
||||
for (uint32_t ii = 0; ii < numInputTensors; ii++) {
|
||||
result = cudaMemcpyAsync(
|
||||
inputBufferGPU[ii], inputBuffer[ii], inputTensorDesc[ii].size, cudaMemcpyHostToDevice, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memcpy for input\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
result = cudaMemsetAsync(outputBufferGPU[ii], 0, outputTensorDesc[ii].size, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memset for output\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
result = cudaMemsetAsync(outputTaskStatisticsGPU[ii], 0, outputTaskStatisticsDesc[ii].size, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in enqueueing memset for statistics output\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t *outputStatisticsBufferRegisteredPtr[numOutputTensors + numOutputTaskStatistics] = {0};
|
||||
uint32_t index = 0;
|
||||
for (; index < numOutputTensors; index++) {
|
||||
outputStatisticsBufferRegisteredPtr[index] = ((outputBufferRegisteredPtr[index]));
|
||||
}
|
||||
|
||||
for (uint32_t jj = 0; jj < numOutputTaskStatistics; jj++) {
|
||||
outputStatisticsBufferRegisteredPtr[index++] = ((outputTaskStatisticsRegisteredPtr[jj]));
|
||||
}
|
||||
|
||||
// Enqueue a cuDLA task.
|
||||
cudlaTask task;
|
||||
task.moduleHandle = moduleHandle;
|
||||
task.outputTensor = (uint64_t *const *)&outputStatisticsBufferRegisteredPtr;
|
||||
|
||||
if (statSupport == 1) {
|
||||
task.numOutputTensors = (numOutputTensors + numOutputTaskStatistics);
|
||||
DPRINTF("Layerwise profiling is requested \n");
|
||||
}
|
||||
else {
|
||||
task.numOutputTensors = numOutputTensors;
|
||||
DPRINTF("Layerwise profiling is not requested \n");
|
||||
}
|
||||
|
||||
task.numInputTensors = numInputTensors;
|
||||
task.inputTensor = inputBufferRegisteredPtr;
|
||||
task.waitEvents = NULL;
|
||||
task.signalEvents = NULL;
|
||||
|
||||
err = cudlaSubmitTask(devHandle, &task, 1, stream, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("no of output tensor %u \n", (task.numOutputTensors));
|
||||
DPRINTF("Error in submitting task\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("SUBMIT IS DONE !!!\n");
|
||||
|
||||
result = cudaStreamSynchronize(stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in synchronizing stream = %s\n", cudaGetErrorName(result));
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Wait for stream operations to finish and bring output buffer to CPU.
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
result = cudaMemcpyAsync(
|
||||
outputBuffer[ii], outputBufferGPU[ii], outputTensorDesc[ii].size, cudaMemcpyDeviceToHost, stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in bringing result back to CPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
result = cudaStreamSynchronize(stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in synchronizing stream\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (statSupport == 1) {
|
||||
// copy statistics data to cpu
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
result = cudaMemcpyAsync(statisticsOutputBuffer[ii],
|
||||
outputTaskStatisticsGPU[ii],
|
||||
outputTaskStatisticsDesc[ii].size,
|
||||
cudaMemcpyDeviceToHost,
|
||||
stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in bringing result back to CPU\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
result = cudaStreamSynchronize(stream);
|
||||
if (result != cudaSuccess) {
|
||||
DPRINTF("Error in synchronizing stream\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// To get the last index of the filename prefix in which statistics will be dumped
|
||||
uint32_t index = 0;
|
||||
if (argc == 5) {
|
||||
while (argv[4][index] != '\0') {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
const cudlaExternalEtbl *etbl = NULL;
|
||||
if (cudlaGetExternalExportTable(&etbl, 0) != cudlaSuccess) {
|
||||
DPRINTF("Error in getting export table\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void **csv = (void **)malloc(sizeof(void *) * numOutputTaskStatistics);
|
||||
if (csv == NULL) {
|
||||
DPRINTF("Error in allocating memory for csv stream\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(csv, 0x00, sizeof(void *) * numOutputTaskStatistics);
|
||||
resourceList.csv = csv;
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
cudlaTranslateCsvAttribute csvAttribute;
|
||||
uint64_t csvStreamLength = 0;
|
||||
|
||||
err = etbl->etiTranslateStats(
|
||||
devHandle, statisticsOutputBuffer[ii], dlaFreqInMHz, ii, CUDLA_GET_CSV_LENGTH, &csvAttribute);
|
||||
csv[ii] = (void *)malloc(csvAttribute.csvStreamLength);
|
||||
csvStreamLength = csvAttribute.csvStreamLength;
|
||||
DPRINTF("size for statistics buffer %u is %lu \n", ii, csvStreamLength);
|
||||
|
||||
if (csv[ii] == NULL) {
|
||||
DPRINTF("Error in allocating memory for csv stream\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
memset(csv[ii], 0x00, csvAttribute.csvStreamLength);
|
||||
|
||||
csvAttribute.csvStreamStats = csv[ii];
|
||||
err = etbl->etiTranslateStats(
|
||||
devHandle, statisticsOutputBuffer[ii], dlaFreqInMHz, ii, CUDLA_GET_CSV_STATS, &csvAttribute);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in translating stats\n");
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 5) {
|
||||
sprintf(filename, "%s%u%s", argv[4], (ii + 1), suffix);
|
||||
fp = fopen(filename, "w+");
|
||||
if (fp == NULL) {
|
||||
DPRINTF("Cannot open file %s\n", filename);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ret_val = fwrite(csv[ii], sizeof(char), csvStreamLength, fp);
|
||||
if (ret_val != csvStreamLength) {
|
||||
DPRINTF("number of elements written to file is %u \n", ret_val);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
DPRINTF("%s \n", (char *)csv[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unregister the CUDA-allocated buffers.
|
||||
for (uint32_t ii = 0; ii < numInputTensors; ii++) {
|
||||
err = cudlaMemUnregister(devHandle, (inputBufferRegisteredPtr[ii]));
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering input memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTensors; ii++) {
|
||||
err = cudlaMemUnregister(devHandle, (outputBufferRegisteredPtr[ii]));
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < numOutputTaskStatistics; ii++) {
|
||||
err = cudlaMemUnregister(devHandle, (outputTaskStatisticsRegisteredPtr[ii]));
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in registering output memory = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("ALL MEMORY UNREGISTERED SUCCESSFULLY\n");
|
||||
|
||||
result = cudaStreamDestroy(stream);
|
||||
if (result != cudaSuccess) {
|
||||
errPtr = cudaGetErrorName(result);
|
||||
DPRINTF("Error in destroying cuda stream = %s\n", errPtr);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
|
||||
resourceList.stream = NULL;
|
||||
|
||||
err = cudlaModuleUnload(moduleHandle, 0);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cudlaModuleUnload = %d\n", err);
|
||||
cleanUp(&resourceList);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
DPRINTF("Successfully unloaded module\n");
|
||||
}
|
||||
|
||||
resourceList.moduleHandle = NULL;
|
||||
|
||||
err = cudlaDestroyDevice(devHandle);
|
||||
if (err != cudlaSuccess) {
|
||||
DPRINTF("Error in cuDLA destroy device = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
DPRINTF("Device destroyed successfully\n");
|
||||
|
||||
resourceList.devHandle = NULL;
|
||||
|
||||
cleanUp(&resourceList);
|
||||
|
||||
DPRINTF("cuDLALayerwiseStatsHybrid DONE !!!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cuDLALayerwiseStatsStandalone LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(NVSCI)
|
||||
find_library(CUDLA_LIB cudla PATHS ${CUDAToolkit_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CUDLA_LIB)
|
||||
if(NVSCI_FOUND)
|
||||
# Source file
|
||||
# Add target for cuDLALayerwiseStatsStandalone
|
||||
add_executable(cuDLALayerwiseStatsStandalone main.cpp)
|
||||
|
||||
target_compile_options(cuDLALayerwiseStatsStandalone PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cuDLALayerwiseStatsStandalone PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cuDLALayerwiseStatsStandalone PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cuDLALayerwiseStatsStandalone PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
${NVSCI_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cuDLALayerwiseStatsStandalone
|
||||
${CUDLA_LIB}
|
||||
${NVSCI_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
message(STATUS "NvSCI not found - will not build sample 'cuDLALayerwiseStatsStandalone'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "CUDLA not found - will not build sample 'cuDLALayerwiseStatsStandalone'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cuDLALayerwiseStatsStandalone - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
@@ -0,0 +1,33 @@
|
||||
# cuDLALayerwiseStatsStandalone - cuDLA Layerwise Statistics Standalone Mode
|
||||
|
||||
## Description
|
||||
|
||||
This sample is used to provide layerwise statistics to the application in cuDLA standalone mode where DLA is programmed without using CUDA.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
cuDLA, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[NVSCI](../../../README.md#nvsci)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
1306
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/main.cpp
Normal file
1306
cpp/8_Platform_Specific/Tegra/cuDLALayerwiseStatsStandalone/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cuDLAStandaloneMode LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(NVSCI)
|
||||
find_library(CUDLA_LIB cudla PATHS ${CUDAToolkit_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CUDLA_LIB)
|
||||
if(NVSCI_FOUND)
|
||||
# Source file
|
||||
# Add target for cuDLAStandaloneMode
|
||||
add_executable(cuDLAStandaloneMode main.cpp)
|
||||
|
||||
target_compile_options(cuDLAStandaloneMode PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cuDLAStandaloneMode PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cuDLAStandaloneMode PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cuDLAStandaloneMode PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
${NVSCI_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cuDLAStandaloneMode
|
||||
${CUDLA_LIB}
|
||||
${NVSCI_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
message(STATUS "NvSCI not found - will not build sample 'cuDLAStandaloneMode'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "CUDLA not found - will not build sample 'cuDLAStandaloneMode'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cuDLAStandaloneMode - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
33
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/README.md
Normal file
33
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# cuDLAStandaloneMode - cuDLA Standalone Mode
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates cuDLA standalone mode wherein DLA can be programmed without using CUDA.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
cuDLA, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[NVSCI](../../../README.md#nvsci)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
1015
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/main.cpp
Normal file
1015
cpp/8_Platform_Specific/Tegra/cuDLAStandaloneMode/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
cpp/8_Platform_Specific/Tegra/cudaNvSciBufMultiplanar/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cudaNvSciBufMultiplanar/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cudaNvSciBufMultiplanar/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cudaNvSciBufMultiplanar/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cudaNvSciBufMultiplanar LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(NVSCI)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(NVSCI_FOUND)
|
||||
# Source file
|
||||
# Add target for cudaNvSciBufMultiplanar
|
||||
add_executable(cudaNvSciBufMultiplanar imageKernels.cu cudaNvSciBufMultiplanar.cpp main.cpp)
|
||||
|
||||
target_compile_options(cudaNvSciBufMultiplanar PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cudaNvSciBufMultiplanar PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cudaNvSciBufMultiplanar PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cudaNvSciBufMultiplanar PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
${NVSCI_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cudaNvSciBufMultiplanar
|
||||
CUDA::cuda_driver
|
||||
${NVSCI_LIBRARIES}
|
||||
)
|
||||
# Copy yuv_planar_img1.yuv to the output directory
|
||||
add_custom_command(TARGET cudaNvSciBufMultiplanar POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yuv_planar_img1.yuv ${CMAKE_CURRENT_BINARY_DIR}/yuv_planar_img1.yuv
|
||||
)
|
||||
# Specify additional clean files
|
||||
set_target_properties(cudaNvSciBufMultiplanar PROPERTIES
|
||||
ADDITIONAL_CLEAN_FILES "image_out.yuv"
|
||||
)
|
||||
else()
|
||||
message(STATUS "NvSCI not found - will not build sample 'cudaNvSciBufMultiplanar'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cudaNvSciBufMultiplanar - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
@@ -0,0 +1,36 @@
|
||||
# cudaNvSciBufMultiplanar - CUDA NvSciBufMultiplanar Image Samples
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates CUDA-NvSciBuf Interop for Multiplanar images. A YUV 420 multiplanar image is flipped and allocated using NvSciBuf APIs and imported into CUDA with CUDA External Resource Interoperability. A CUDA surface is created from the corresponding mapped CUDA array and again bit flipping is performed on the surface. The result is copied back to a YUV image which is compared against the input.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
CUDA NvSci Interop, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus) [SM 10.0 ](https://developer.nvidia.com/cuda-gpus) [SM 10.1 ](https://developer.nvidia.com/cuda-gpus) [SM 12.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaDeviceGetAttribute, cudaNvSciBufMultiplanar, cudaDestroyExternalMemory, cuDriverGetVersion, cuDeviceGetUuid, cudaSetDevice, cudaGetMipmappedArrayLevel, cudaFreeMipmappedArray, cudaImportExternalMemory, cudaCreateChannelDesc, cudaExternalMemoryGetMappedMipmappedArray, cuCtxSynchronize, cudaMemcpy2DToArray, cudaMemcpy2DFromArray
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[NVSCI](../../../README.md#nvsci)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
@@ -0,0 +1,453 @@
|
||||
/* Copyright (c) 2024, 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.
|
||||
*/
|
||||
#include "cudaNvSciBufMultiplanar.h"
|
||||
|
||||
NvSciBufModule module;
|
||||
NvSciBufObj buffObj;
|
||||
CUuuid uuid;
|
||||
|
||||
void flipBits(uint8_t *pBuff, uint32_t size)
|
||||
{
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
pBuff[i] = (~pBuff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Compare input and generated image files
|
||||
void compareFiles(std::string &path1, std::string &path2)
|
||||
{
|
||||
bool result = true;
|
||||
FILE *fp1, *fp2;
|
||||
int ch1, ch2;
|
||||
|
||||
fp1 = fopen(path1.c_str(), "rb");
|
||||
fp2 = fopen(path2.c_str(), "rb");
|
||||
if (!fp1) {
|
||||
result = false;
|
||||
printf("File %s open failed in %s line %d\n", path1.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!fp2) {
|
||||
result = false;
|
||||
printf("File %s open failed in %s line %d\n", path2.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
do {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
|
||||
if (ch1 != ch2) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
} while (ch1 != EOF && ch2 != EOF);
|
||||
|
||||
if (result) {
|
||||
printf("Input file : %s and output file : %s match SUCCESS\n", path1.c_str(), path2.c_str());
|
||||
}
|
||||
else {
|
||||
printf("Input file : %s and output file : %s match FAILURE\n", path1.c_str(), path2.c_str());
|
||||
}
|
||||
|
||||
if (fp1) {
|
||||
fclose(fp1);
|
||||
}
|
||||
if (fp2) {
|
||||
fclose(fp2);
|
||||
}
|
||||
}
|
||||
|
||||
void Caller::init()
|
||||
{
|
||||
checkNvSciErrors(NvSciBufAttrListCreate(module, &attrList));
|
||||
attrListOut = NULL;
|
||||
}
|
||||
|
||||
void Caller::deinit()
|
||||
{
|
||||
NvSciBufAttrListFree(attrList);
|
||||
checkCudaErrors(cudaDestroyExternalMemory(extMem));
|
||||
}
|
||||
|
||||
// Set NvSciBufImage attribute values in the attribute list
|
||||
void Caller::setAttrListImageMultiPlanes(int imageWidth, int imageHeight)
|
||||
{
|
||||
NvSciBufType bufType = NvSciBufType_Image;
|
||||
NvSciBufAttrValImageLayoutType layout = NvSciBufImage_BlockLinearType;
|
||||
bool cpuAccessFlag = false;
|
||||
NvSciBufAttrValAccessPerm perm = NvSciBufAccessPerm_ReadWrite;
|
||||
NvSciRmGpuId gpuid;
|
||||
bool vpr = false;
|
||||
int32_t planeCount = PLANAR_NUM_PLANES;
|
||||
int drvVersion;
|
||||
// Dimensions of the imported image in the YUV 420 planar format
|
||||
int32_t planeWidths[] = {imageWidth, imageWidth / 2, imageWidth / 2};
|
||||
int32_t planeHeights[] = {imageHeight, imageHeight / 2, imageHeight / 2};
|
||||
NvSciBufAttrKeyValuePair keyPair;
|
||||
NvSciBufAttrKeyValuePair pairArray[ATTR_SIZE];
|
||||
|
||||
NvSciBufAttrValColorFmt planeColorFmts[] = {NvSciColor_Y8, NvSciColor_V8, NvSciColor_U8};
|
||||
NvSciBufAttrValImageScanType planeScanType[] = {NvSciBufScan_ProgressiveType};
|
||||
|
||||
memcpy(&gpuid.bytes, &uuid.bytes, sizeof(uuid.bytes));
|
||||
|
||||
NvSciBufAttrKeyValuePair imgBuffAttrsArr[] = {
|
||||
{NvSciBufGeneralAttrKey_Types, &bufType, sizeof(bufType)},
|
||||
{NvSciBufGeneralAttrKey_NeedCpuAccess, &cpuAccessFlag, sizeof(cpuAccessFlag)},
|
||||
{NvSciBufGeneralAttrKey_RequiredPerm, &perm, sizeof(perm)},
|
||||
{NvSciBufGeneralAttrKey_GpuId, &gpuid, sizeof(gpuid)},
|
||||
{NvSciBufImageAttrKey_Layout, &layout, sizeof(layout)},
|
||||
{NvSciBufImageAttrKey_VprFlag, &vpr, sizeof(vpr)},
|
||||
{NvSciBufImageAttrKey_PlaneCount, &planeCount, sizeof(planeCount)},
|
||||
{NvSciBufImageAttrKey_PlaneColorFormat, planeColorFmts, sizeof(planeColorFmts)},
|
||||
{NvSciBufImageAttrKey_PlaneWidth, planeWidths, sizeof(planeWidths)},
|
||||
{NvSciBufImageAttrKey_PlaneHeight, planeHeights, sizeof(planeHeights)},
|
||||
{NvSciBufImageAttrKey_PlaneScanType, planeScanType, sizeof(planeScanType)},
|
||||
};
|
||||
|
||||
std::vector<NvSciBufAttrKeyValuePair> imgBuffAttrsVec(
|
||||
imgBuffAttrsArr, imgBuffAttrsArr + (sizeof(imgBuffAttrsArr) / sizeof(imgBuffAttrsArr[0])));
|
||||
|
||||
memset(pairArray, 0, sizeof(NvSciBufAttrKeyValuePair) * imgBuffAttrsVec.size());
|
||||
std::copy(imgBuffAttrsVec.begin(), imgBuffAttrsVec.end(), pairArray);
|
||||
checkNvSciErrors(NvSciBufAttrListSetAttrs(attrList, pairArray, imgBuffAttrsVec.size()));
|
||||
}
|
||||
|
||||
cudaNvSciBufMultiplanar::cudaNvSciBufMultiplanar(size_t width, size_t height, std::vector<int> &deviceIds)
|
||||
: imageWidth(width)
|
||||
, imageHeight(height)
|
||||
{
|
||||
mCudaDeviceId = deviceIds[0];
|
||||
attrListReconciled = NULL;
|
||||
attrListConflict = NULL;
|
||||
checkNvSciErrors(NvSciBufModuleOpen(&module));
|
||||
initCuda(mCudaDeviceId);
|
||||
}
|
||||
|
||||
void cudaNvSciBufMultiplanar::initCuda(int devId)
|
||||
{
|
||||
int major = 0, minor = 0, drvVersion;
|
||||
NvSciRmGpuId gpuid;
|
||||
|
||||
checkCudaErrors(cudaSetDevice(mCudaDeviceId));
|
||||
checkCudaErrors(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, mCudaDeviceId));
|
||||
checkCudaErrors(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, mCudaDeviceId));
|
||||
printf("[cudaNvSciBufMultiplanar] GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
mCudaDeviceId,
|
||||
_ConvertSMVer2ArchName(major, minor),
|
||||
major,
|
||||
minor);
|
||||
|
||||
checkCudaDrvErrors(cuDriverGetVersion(&drvVersion));
|
||||
|
||||
if (drvVersion <= 11030) {
|
||||
checkCudaDrvErrors(cuDeviceGetUuid(&uuid, devId));
|
||||
}
|
||||
else {
|
||||
checkCudaDrvErrors(cuDeviceGetUuid_v2(&uuid, devId));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Caller1 flips a YUV image which is allocated to nvscibuf APIs and copied into CUDA Array.
|
||||
It is mapped to CUDA surface and bit flip is done. Caller2 in the same thread copies
|
||||
CUDA Array to a YUV image file. The original image is compared with the double bit
|
||||
flipped image.
|
||||
*/
|
||||
void cudaNvSciBufMultiplanar::runCudaNvSciBufPlanar(std::string &imageFilename, std::string &imageFilenameOut)
|
||||
{
|
||||
cudaArray_t levelArray1[PLANAR_NUM_PLANES];
|
||||
cudaArray_t levelArray2[PLANAR_NUM_PLANES];
|
||||
Caller caller1;
|
||||
Caller caller2;
|
||||
|
||||
int numPlanes = PLANAR_NUM_PLANES;
|
||||
caller1.init();
|
||||
caller2.init();
|
||||
|
||||
// Set NvSciBufImage attribute values in the attribute list
|
||||
caller1.setAttrListImageMultiPlanes(imageWidth, imageHeight);
|
||||
caller2.setAttrListImageMultiPlanes(imageWidth, imageHeight);
|
||||
|
||||
// Reconcile attribute lists and allocate NvSciBuf object
|
||||
reconcileAttrList(&caller1.attrList, &caller2.attrList);
|
||||
caller1.copyExtMemToMultiPlanarArrays();
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelArray1[i], caller1.multiPlanarArray[i], 0));
|
||||
}
|
||||
caller1.copyYUVToCudaArrayAndFlipBits(imageFilename, levelArray1);
|
||||
|
||||
caller2.copyExtMemToMultiPlanarArrays();
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelArray2[i], caller2.multiPlanarArray[i], 0));
|
||||
}
|
||||
// Maps cudaArray to surface memory and launches a kernel to flip bits
|
||||
launchFlipSurfaceBitsKernel(levelArray2, caller2.multiPlanarWidth, caller2.multiPlanarHeight, numPlanes);
|
||||
|
||||
// Synchronization can be done using nvSciSync when non CUDA callers and cross-process signaler-waiter
|
||||
// applications are involved. Please refer to the cudaNvSci sample library for more details.
|
||||
checkCudaDrvErrors(cuCtxSynchronize());
|
||||
printf("Bit flip of the surface memory done\n");
|
||||
|
||||
caller2.copyCudaArrayToYUV(imageFilenameOut, levelArray2);
|
||||
compareFiles(imageFilename, imageFilenameOut);
|
||||
|
||||
// Release memory
|
||||
printf("Releasing memory\n");
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
checkCudaErrors(cudaFreeMipmappedArray(caller1.multiPlanarArray[i]));
|
||||
checkCudaErrors(cudaFreeMipmappedArray(caller2.multiPlanarArray[i]));
|
||||
}
|
||||
tearDown(&caller1, &caller2);
|
||||
}
|
||||
|
||||
// Map NvSciBufObj to cudaMipmappedArray
|
||||
void Caller::copyExtMemToMultiPlanarArrays()
|
||||
{
|
||||
checkNvSciErrors(NvSciBufObjGetAttrList(buffObj, &attrListOut));
|
||||
memset(pairArrayOut, 0, sizeof(NvSciBufAttrKeyValuePair) * PLANE_ATTR_SIZE);
|
||||
cudaExternalMemoryHandleDesc memHandleDesc;
|
||||
cudaExternalMemoryMipmappedArrayDesc mipmapDesc = {0};
|
||||
cudaChannelFormatDesc desc = {0};
|
||||
cudaExtent extent = {0};
|
||||
|
||||
pairArrayOut[PLANE_SIZE].key = NvSciBufImageAttrKey_Size; // Datatype: @c uint64_t
|
||||
pairArrayOut[PLANE_ALIGNED_SIZE].key = NvSciBufImageAttrKey_PlaneAlignedSize; // Datatype: @c uint64_t[]
|
||||
pairArrayOut[PLANE_OFFSET].key = NvSciBufImageAttrKey_PlaneOffset; // Datatype: @c uint64_t[]
|
||||
pairArrayOut[PLANE_HEIGHT].key = NvSciBufImageAttrKey_PlaneHeight; // Datatype: @c uint32_t[]
|
||||
pairArrayOut[PLANE_WIDTH].key = NvSciBufImageAttrKey_PlaneWidth; // Datatype: @c int32_t[]
|
||||
pairArrayOut[PLANE_CHANNEL_COUNT].key = NvSciBufImageAttrKey_PlaneChannelCount; // Datatype: @c uint8_t
|
||||
pairArrayOut[PLANE_BITS_PER_PIXEL].key = NvSciBufImageAttrKey_PlaneBitsPerPixel; // Datatype: @c uint32_t[]
|
||||
pairArrayOut[PLANE_COUNT].key = NvSciBufImageAttrKey_PlaneCount; // Datatype: @c uint32_t
|
||||
checkNvSciErrors(NvSciBufAttrListGetAttrs(attrListOut, pairArrayOut, (PLANE_ATTR_SIZE)));
|
||||
|
||||
uint64_t size = *(uint64_t *)pairArrayOut[PLANE_SIZE].value;
|
||||
uint64_t *planeAlignedSize = (uint64_t *)pairArrayOut[PLANE_ALIGNED_SIZE].value;
|
||||
int32_t *planeWidth = (int32_t *)pairArrayOut[PLANE_WIDTH].value;
|
||||
int32_t *planeHeight = (int32_t *)pairArrayOut[PLANE_HEIGHT].value;
|
||||
uint64_t *planeOffset = (uint64_t *)pairArrayOut[PLANE_OFFSET].value;
|
||||
uint8_t planeChannelCount = *(uint8_t *)pairArrayOut[PLANE_CHANNEL_COUNT].value;
|
||||
uint32_t *planeBitsPerPixel = (uint32_t *)pairArrayOut[PLANE_BITS_PER_PIXEL].value;
|
||||
uint32_t planeCount = *(uint32_t *)pairArrayOut[PLANE_COUNT].value;
|
||||
|
||||
numPlanes = planeCount;
|
||||
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
multiPlanarWidth[i] = planeWidth[i];
|
||||
multiPlanarHeight[i] = planeHeight[i];
|
||||
}
|
||||
|
||||
memset(&memHandleDesc, 0, sizeof(memHandleDesc));
|
||||
memHandleDesc.type = cudaExternalMemoryHandleTypeNvSciBuf;
|
||||
memHandleDesc.handle.nvSciBufObject = buffObj;
|
||||
memHandleDesc.size = size;
|
||||
checkCudaErrors(cudaImportExternalMemory(&extMem, &memHandleDesc));
|
||||
|
||||
desc = cudaCreateChannelDesc(planeBitsPerPixel[0], 0, 0, 0, cudaChannelFormatKindUnsigned);
|
||||
memset(&mipmapDesc, 0, sizeof(mipmapDesc));
|
||||
mipmapDesc.numLevels = 1;
|
||||
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
memset(&extent, 0, sizeof(extent));
|
||||
extent.width = planeWidth[i];
|
||||
extent.height = planeHeight[i];
|
||||
extent.depth = 0;
|
||||
mipmapDesc.offset = planeOffset[i];
|
||||
mipmapDesc.formatDesc = desc;
|
||||
mipmapDesc.extent = extent;
|
||||
mipmapDesc.flags = cudaArraySurfaceLoadStore;
|
||||
;
|
||||
checkCudaErrors(cudaExternalMemoryGetMappedMipmappedArray(&multiPlanarArray[i], extMem, &mipmapDesc));
|
||||
}
|
||||
}
|
||||
|
||||
void cudaNvSciBufMultiplanar::reconcileAttrList(NvSciBufAttrList *attrList1, NvSciBufAttrList *attrList2)
|
||||
{
|
||||
attrList[0] = *attrList1;
|
||||
attrList[1] = *attrList2;
|
||||
bool isReconciled = false;
|
||||
|
||||
checkNvSciErrors(NvSciBufAttrListReconcile(attrList, 2, &attrListReconciled, &attrListConflict));
|
||||
checkNvSciErrors(NvSciBufAttrListIsReconciled(attrListReconciled, &isReconciled));
|
||||
checkNvSciErrors(NvSciBufObjAlloc(attrListReconciled, &buffObj));
|
||||
printf("NvSciBufAttrList reconciled\n");
|
||||
}
|
||||
|
||||
// YUV 420 image is flipped and copied to cuda Array which is mapped to nvsciBuf
|
||||
void Caller::copyYUVToCudaArrayAndFlipBits(std::string &path, cudaArray_t *cudaArr)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
uint8_t *pYBuff, *pUBuff, *pVBuff, *pChroma;
|
||||
uint8_t *pBuff = NULL;
|
||||
uint32_t uvOffset[numPlanes] = {0}, copyWidthInBytes[numPlanes] = {0}, copyHeight[numPlanes] = {0};
|
||||
uint32_t width = multiPlanarWidth[0];
|
||||
uint32_t height = multiPlanarHeight[0];
|
||||
|
||||
fp = fopen(path.c_str(), "rb");
|
||||
if (!fp) {
|
||||
printf("CudaProducer: Error opening file: %s in %s line %d\n", path.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pBuff = (uint8_t *)malloc((width * height * PLANAR_CHROMA_WIDTH_ORDER * PLANAR_CHROMA_HEIGHT_ORDER)
|
||||
* sizeof(unsigned char));
|
||||
if (!pBuff) {
|
||||
printf("CudaProducer: Failed to allocate image buffer in %s line %d\n", __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Y V U order in the buffer. Fully planar formats use
|
||||
// three planes to store the Y, Cb and Cr components separately.
|
||||
pYBuff = pBuff;
|
||||
pVBuff = pYBuff + width * height;
|
||||
pUBuff = pVBuff + (width / PLANAR_CHROMA_WIDTH_ORDER) * (height / PLANAR_CHROMA_HEIGHT_ORDER);
|
||||
for (uint32_t i = 0; i < height; i++) {
|
||||
if (fread(pYBuff, width, 1, fp) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %s in %s line %d\n", path.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
flipBits(pYBuff, width);
|
||||
pYBuff += width;
|
||||
}
|
||||
|
||||
pChroma = pVBuff;
|
||||
for (uint32_t i = 0; i < height / PLANAR_CHROMA_HEIGHT_ORDER; i++) {
|
||||
if (fread(pChroma, width / PLANAR_CHROMA_WIDTH_ORDER, 1, fp) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %s in %s line %d\n", path.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
flipBits(pChroma, width);
|
||||
pChroma += width / PLANAR_CHROMA_WIDTH_ORDER;
|
||||
}
|
||||
|
||||
pChroma = pUBuff;
|
||||
for (uint32_t i = 0; i < height / PLANAR_CHROMA_HEIGHT_ORDER; i++) {
|
||||
if (fread(pChroma, width / PLANAR_CHROMA_WIDTH_ORDER, 1, fp) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %s in %s line %d\n", path.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
flipBits(pChroma, width);
|
||||
pChroma += width / PLANAR_CHROMA_WIDTH_ORDER;
|
||||
}
|
||||
uvOffset[0] = 0;
|
||||
copyHeight[0] = height;
|
||||
copyHeight[1] = height / PLANAR_CHROMA_HEIGHT_ORDER;
|
||||
copyHeight[2] = height / PLANAR_CHROMA_HEIGHT_ORDER;
|
||||
copyWidthInBytes[0] = width;
|
||||
// Width of the second and third planes is half of the first plane.
|
||||
copyWidthInBytes[1] = width / PLANAR_CHROMA_WIDTH_ORDER;
|
||||
copyWidthInBytes[2] = width / PLANAR_CHROMA_WIDTH_ORDER;
|
||||
uvOffset[1] = width * height;
|
||||
uvOffset[2] = uvOffset[1] + (width / PLANAR_CHROMA_WIDTH_ORDER) * (height / PLANAR_CHROMA_HEIGHT_ORDER);
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
checkCudaDrvErrors(cuCtxSynchronize());
|
||||
checkCudaErrors(cudaMemcpy2DToArray(cudaArr[i],
|
||||
0,
|
||||
0,
|
||||
(void *)(pBuff + uvOffset[i]),
|
||||
copyWidthInBytes[i],
|
||||
copyWidthInBytes[i],
|
||||
copyHeight[i],
|
||||
cudaMemcpyHostToDevice));
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
if (pBuff) {
|
||||
free(pBuff);
|
||||
pBuff = NULL;
|
||||
}
|
||||
printf("Image %s copied to CUDA Array and bit flip done\n", path.c_str());
|
||||
}
|
||||
|
||||
// Copy Cuda Array in YUV 420 format to a file
|
||||
void Caller::copyCudaArrayToYUV(std::string &path, cudaArray_t *cudaArr)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int bufferSize;
|
||||
uint32_t width = multiPlanarWidth[0];
|
||||
uint32_t height = multiPlanarHeight[0];
|
||||
uint32_t copyWidthInBytes = 0, copyHeight = 0;
|
||||
uint8_t *pCudaCopyMem = NULL;
|
||||
|
||||
fp = fopen(path.c_str(), "wb+");
|
||||
if (!fp) {
|
||||
printf("WriteFrame: file open failed %s in %s line %d\n", path.c_str(), __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
if (i == 0) {
|
||||
bufferSize = width * height;
|
||||
copyWidthInBytes = width;
|
||||
copyHeight = height;
|
||||
|
||||
pCudaCopyMem = (uint8_t *)malloc(bufferSize);
|
||||
if (pCudaCopyMem == NULL) {
|
||||
printf("pCudaCopyMem malloc failed in %s line %d\n", __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bufferSize = ((height / PLANAR_CHROMA_HEIGHT_ORDER) * (width / PLANAR_CHROMA_WIDTH_ORDER));
|
||||
copyWidthInBytes = width / PLANAR_CHROMA_WIDTH_ORDER;
|
||||
copyHeight = height / PLANAR_CHROMA_HEIGHT_ORDER;
|
||||
}
|
||||
memset(pCudaCopyMem, 0, bufferSize);
|
||||
|
||||
checkCudaErrors(cudaMemcpy2DFromArray((void *)pCudaCopyMem,
|
||||
copyWidthInBytes,
|
||||
cudaArr[i],
|
||||
0,
|
||||
0,
|
||||
copyWidthInBytes,
|
||||
copyHeight,
|
||||
cudaMemcpyDeviceToHost));
|
||||
|
||||
checkCudaDrvErrors(cuCtxSynchronize());
|
||||
|
||||
if (fwrite(pCudaCopyMem, bufferSize, 1, fp) != 1) {
|
||||
printf("Cuda consumer: output file write failed in %s line %d\n", __FILE__, __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
printf("Output file : %s saved\n", path.c_str());
|
||||
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cudaNvSciBufMultiplanar::tearDown(Caller *caller1, Caller *caller2)
|
||||
{
|
||||
caller1->deinit();
|
||||
caller2->deinit();
|
||||
NvSciBufObjFree(buffObj);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/* Copyright (c) 2024, 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.
|
||||
*/
|
||||
#ifndef CUDA_NVSCIBUF_MULTIPLANAR_H
|
||||
#define CUDA_NVSCIBUF_MULTIPLANAR_H
|
||||
|
||||
#include <cuda.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <nvscibuf.h>
|
||||
#include <vector>
|
||||
|
||||
#define PLANAR_NUM_PLANES 3
|
||||
#define PLANAR_CHROMA_WIDTH_ORDER 2
|
||||
#define PLANAR_CHROMA_HEIGHT_ORDER 2
|
||||
|
||||
#define ATTR_SIZE 20
|
||||
#define DEFAULT_GPU 0
|
||||
|
||||
#define checkNvSciErrors(call) \
|
||||
do { \
|
||||
NvSciError _status = call; \
|
||||
if (NvSciError_Success != _status) { \
|
||||
printf("NVSCI call in file '%s' in line %i returned" \
|
||||
" %d, expected %d\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
_status, \
|
||||
NvSciError_Success); \
|
||||
fflush(stdout); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define checkCudaDrvErrors(call) \
|
||||
do { \
|
||||
CUresult err = call; \
|
||||
if (CUDA_SUCCESS != err) { \
|
||||
const char *errorStr = NULL; \
|
||||
cuGetErrorString(err, &errorStr); \
|
||||
printf("checkCudaDrvErrors() Driver API error" \
|
||||
" = %04d \"%s\" from file <%s>, " \
|
||||
"line %i.\n", \
|
||||
err, \
|
||||
errorStr, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern void launchFlipSurfaceBitsKernel(cudaArray_t *levelArray,
|
||||
int32_t *multiPlanarWidth,
|
||||
int32_t *multiPlanarHeight,
|
||||
int numPlanes);
|
||||
|
||||
class Caller
|
||||
{
|
||||
private:
|
||||
NvSciBufAttrList attrListOut;
|
||||
NvSciBufAttrKeyValuePair pairArrayOut[ATTR_SIZE];
|
||||
cudaExternalMemory_t extMem;
|
||||
int32_t numPlanes;
|
||||
|
||||
public:
|
||||
NvSciBufAttrList attrList;
|
||||
cudaMipmappedArray_t multiPlanarArray[PLANAR_NUM_PLANES];
|
||||
int32_t multiPlanarWidth[PLANAR_NUM_PLANES];
|
||||
int32_t multiPlanarHeight[PLANAR_NUM_PLANES];
|
||||
|
||||
void init();
|
||||
void deinit();
|
||||
void copyExtMemToMultiPlanarArrays();
|
||||
void copyYUVToCudaArrayAndFlipBits(std::string &image_filename, cudaArray_t *yuvPlanes);
|
||||
void copyCudaArrayToYUV(std::string &image_filename, cudaArray_t *yuvPlanes);
|
||||
void setAttrListImageMultiPlanes(int imageWidth, int imageHeight);
|
||||
};
|
||||
|
||||
|
||||
class cudaNvSciBufMultiplanar
|
||||
{
|
||||
private:
|
||||
size_t imageWidth;
|
||||
size_t imageHeight;
|
||||
int mCudaDeviceId;
|
||||
int deviceCnt;
|
||||
NvSciBufAttrList attrList[2];
|
||||
NvSciBufAttrList attrListReconciled;
|
||||
NvSciBufAttrList attrListConflict;
|
||||
|
||||
public:
|
||||
cudaNvSciBufMultiplanar(size_t imageWidth, size_t imageHeight, std::vector<int> &deviceIds);
|
||||
void initCuda(int devId);
|
||||
void reconcileAttrList(NvSciBufAttrList *attrList1, NvSciBufAttrList *attrList2);
|
||||
void runCudaNvSciBufPlanar(std::string &image_filename, std::string &image_filename_out);
|
||||
void tearDown(Caller *caller1, Caller *caller2);
|
||||
};
|
||||
|
||||
enum NvSciBufImageAttributes {
|
||||
PLANE_SIZE,
|
||||
PLANE_ALIGNED_SIZE,
|
||||
PLANE_OFFSET,
|
||||
PLANE_HEIGHT,
|
||||
PLANE_WIDTH,
|
||||
PLANE_CHANNEL_COUNT,
|
||||
PLANE_BITS_PER_PIXEL,
|
||||
PLANE_COUNT,
|
||||
PLANE_ATTR_SIZE
|
||||
};
|
||||
|
||||
#endif // CUDA_NVSCIBUF_MULTIPLANAR_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright (c) 2024, 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.
|
||||
*/
|
||||
#include <cuda.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
static __global__ void flipSurfaceBits(cudaSurfaceObject_t surfObj, int width, int height)
|
||||
{
|
||||
char data;
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if (x < width && y < height) {
|
||||
// Read from input surface
|
||||
surf2Dread(&data, surfObj, x, y);
|
||||
// Write to output surface
|
||||
data = ~data;
|
||||
surf2Dwrite(data, surfObj, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy cudaArray to surface memory and launch the CUDA kernel
|
||||
void launchFlipSurfaceBitsKernel(cudaArray_t *levelArray,
|
||||
int32_t *multiPlanarWidth,
|
||||
int32_t *multiPlanarHeight,
|
||||
int numPlanes)
|
||||
{
|
||||
|
||||
cudaSurfaceObject_t surfObject[numPlanes] = {0};
|
||||
cudaResourceDesc resDesc;
|
||||
|
||||
for (int i = 0; i < numPlanes; i++) {
|
||||
memset(&resDesc, 0, sizeof(resDesc));
|
||||
resDesc.resType = cudaResourceTypeArray;
|
||||
resDesc.res.array.array = levelArray[i];
|
||||
checkCudaErrors(cudaCreateSurfaceObject(&surfObject[i], &resDesc));
|
||||
dim3 threadsperBlock(16, 16);
|
||||
dim3 numBlocks((multiPlanarWidth[i] + threadsperBlock.x - 1) / threadsperBlock.x,
|
||||
(multiPlanarHeight[i] + threadsperBlock.y - 1) / threadsperBlock.y);
|
||||
flipSurfaceBits<<<numBlocks, threadsperBlock>>>(surfObject[i], multiPlanarWidth[i], multiPlanarHeight[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2024, 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.
|
||||
*/
|
||||
#include <cuda.h>
|
||||
#include <helper_image.h>
|
||||
#include <vector>
|
||||
|
||||
#include "cudaNvSciBufMultiplanar.h"
|
||||
|
||||
#define MAX_FILE_SIZE 100
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int numOfGPUs = 0;
|
||||
std::vector<int> deviceIds;
|
||||
(cudaGetDeviceCount(&numOfGPUs));
|
||||
|
||||
printf("%d GPUs found\n", numOfGPUs);
|
||||
if (!numOfGPUs) {
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
else {
|
||||
for (int devID = 0; devID < numOfGPUs; devID++) {
|
||||
int major = 0, minor = 0;
|
||||
(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID));
|
||||
(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID));
|
||||
if (major >= 6) {
|
||||
deviceIds.push_back(devID);
|
||||
}
|
||||
}
|
||||
if (deviceIds.size() == 0) {
|
||||
printf("cudaNvSciBufMultiplanar requires one or more GPUs of Pascal(SM 6.0) or higher "
|
||||
"archs\nWaiving..\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
}
|
||||
|
||||
std::string image_filename = sdkFindFilePath("yuv_planar_img1.yuv", argv[0]);
|
||||
std::string image_filename_out = "image_out.yuv";
|
||||
uint32_t imageWidth = 720;
|
||||
uint32_t imageHeight = 480;
|
||||
|
||||
printf("input image %s , width = %d, height = %d\n", image_filename.c_str(), imageWidth, imageHeight);
|
||||
|
||||
cudaNvSciBufMultiplanar cudaNvSciBufMultiplanarApp(imageWidth, imageHeight, deviceIds);
|
||||
cudaNvSciBufMultiplanarApp.runCudaNvSciBufPlanar(image_filename, image_filename_out);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Binary file not shown.
18
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(cudaNvSciNvMedia LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(NVSCI)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Find the NVSCI/NVMEDIA libraries
|
||||
# use CMAKE_LIBRARY_PATH so that users can also specify the NVSCI lib path in cmake command
|
||||
set(CMAKE_LIBRARY_PATH "/usr/lib" ${CMAKE_LIBRARY_PATH})
|
||||
foreach(LIBRARY_PATH ${CMAKE_LIBRARY_PATH})
|
||||
file(GLOB_RECURSE NVMEDIA_LIB
|
||||
${LIBRARY_PATH}/libnvmedia.so
|
||||
${LIBRARY_PATH}/*/libnvmedia.so
|
||||
)
|
||||
if(NVMEDIA_LIB)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Find the NVSCI/NVMEDIA header files
|
||||
# use CMAKE_INCLUDE_PATH so that users can also specify the NVSCI/NVMEDIA include path in cmake command
|
||||
set(CMAKE_INCLUDE_PATH
|
||||
"/usr/include"
|
||||
"/usr/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu/include"
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
)
|
||||
find_path(NVMEDIA_INCLUDE_DIR nvmedia_core.h PATHS ${CMAKE_INCLUDE_PATH})
|
||||
|
||||
if(NVSCI_FOUND)
|
||||
if(NVMEDIA_LIB AND NVMEDIA_INCLUDE_DIR)
|
||||
message(STATUS "FOUND NVMEDIA libs: ${NVMEDIA_LIB}")
|
||||
message(STATUS "Using NVMEDIA headers path: ${NVMEDIA_INCLUDE_DIR}")
|
||||
# Source file
|
||||
# Add target for cudaNvSciNvMedia
|
||||
add_executable(cudaNvSciNvMedia imageKernels.cu cudaNvSciNvMedia.cpp main.cpp)
|
||||
|
||||
target_compile_options(cudaNvSciNvMedia PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(cudaNvSciNvMedia PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(cudaNvSciNvMedia PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(cudaNvSciNvMedia PUBLIC
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
${NVSCI_INCLUDE_DIRS}
|
||||
${NVMEDIA_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(cudaNvSciNvMedia
|
||||
CUDA::cuda_driver
|
||||
${NVSCI_LIBRARIES}
|
||||
${NVMEDIA_LIB}
|
||||
)
|
||||
# Copy teapot.rgba to the output directory
|
||||
add_custom_command(TARGET cudaNvSciNvMedia POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/teapot.rgba ${CMAKE_CURRENT_BINARY_DIR}/teapot.rgba
|
||||
)
|
||||
|
||||
# Specify additional clean files
|
||||
set_target_properties(cudaNvSciNvMedia PROPERTIES
|
||||
ADDITIONAL_CLEAN_FILES "teapot_out.rgba"
|
||||
)
|
||||
else()
|
||||
message(STATUS "NvMedia not found - will not build sample 'cudaNvSciNvMedia'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "NvSCI not found - will not build sample 'cudaNvSciNvMedia'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample cudaNvSciNvMedia - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
39
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/README.md
Normal file
39
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# cudaNvSciNvMedia - NvMedia CUDA Interop
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates CUDA-NvMedia interop via NvSciBuf/NvSciSync APIs. Note that this sample only supports cross build from x86_64 to aarch64, aarch64 native build is not supported. For detailed workflow of the sample please check cudaNvSciNvMedia_Readme.pdf in the sample directory.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
CUDA NvSci Interop, Data Parallel Algorithms, Image Processing
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, QNX
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Driver API](http://docs.nvidia.com/cuda/cuda-driver-api/index.html)
|
||||
cuDeviceGetUuid
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaImportExternalSemaphore, cudaGetMipmappedArrayLevel, cudaSetDevice, cudaDestroySurfaceObject, cudaCreateSurfaceObject, cudaImportNvSciImage, cudaCreateChannelDesc, cudaMallocHost, cudaSignalExternalSemaphoresAsync, cudaFreeHost, cudaMemcpyAsync, cudaStreamCreateWithFlags, cudaExternalMemoryGetMappedMipmappedArray, cudaMallocArray, cudaFreeArray, cudaStreamDestroy, cudaDeviceGetNvSciSyncAttributes, cudaDestroyExternalMemory, cudaImportExternalMemory, cudaDestroyExternalSemaphore, cudaFreeMipmappedArray, cudaImportNvSciSync, cudaFree, cudaStreamSynchronize, cudaMalloc, cudaWaitExternalSemaphoresAsync
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[NVSCI](../../../README.md#nvsci), [NvMedia](../../../README.md#nvmedia)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
Binary file not shown.
406
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/cuda_consumer.cu
Normal file
406
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/cuda_consumer.cu
Normal file
@@ -0,0 +1,406 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_image.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "cuda_consumer.h"
|
||||
#include "nvmedia_image_nvscibuf.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
|
||||
// Enable this to 1 if require cuda processed output to ppm file.
|
||||
#define WRITE_OUTPUT_IMAGE 0
|
||||
|
||||
#define checkNvSciErrors(call) \
|
||||
do { \
|
||||
NvSciError _status = call; \
|
||||
if (NvSciError_Success != _status) { \
|
||||
printf("NVSCI call in file '%s' in line %i returned" \
|
||||
" %d, expected %d\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
_status, \
|
||||
NvSciError_Success); \
|
||||
fflush(stdout); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
__global__ static void
|
||||
yuvToGrayscale(cudaSurfaceObject_t surfaceObject, unsigned int *dstImage, int32_t imageWidth, int32_t imageHeight)
|
||||
{
|
||||
size_t x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
size_t y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
||||
uchar4 *dstImageUchar4 = (uchar4 *)dstImage;
|
||||
for (; x < imageWidth && y < imageHeight; x += gridDim.x * blockDim.x, y += gridDim.y * blockDim.y) {
|
||||
int colInBytes = x * sizeof(unsigned char);
|
||||
unsigned char luma = surf2Dread<unsigned char>(surfaceObject, colInBytes, y);
|
||||
uchar4 grayscalePix = make_uchar4(luma, luma, luma, 0);
|
||||
|
||||
dstImageUchar4[y * imageWidth + x] = grayscalePix;
|
||||
}
|
||||
}
|
||||
|
||||
static void cudaImportNvSciSync(cudaExternalSemaphore_t &extSem, NvSciSyncObj &syncObj)
|
||||
{
|
||||
cudaExternalSemaphoreHandleDesc extSemDesc;
|
||||
memset(&extSemDesc, 0, sizeof(extSemDesc));
|
||||
extSemDesc.type = cudaExternalSemaphoreHandleTypeNvSciSync;
|
||||
extSemDesc.handle.nvSciSyncObj = (void *)syncObj;
|
||||
|
||||
checkCudaErrors(cudaImportExternalSemaphore(&extSem, &extSemDesc));
|
||||
}
|
||||
|
||||
static void waitExternalSemaphore(cudaExternalSemaphore_t &waitSem, NvSciSyncFence *fence, cudaStream_t stream)
|
||||
{
|
||||
cudaExternalSemaphoreWaitParams waitParams;
|
||||
memset(&waitParams, 0, sizeof(waitParams));
|
||||
// For cross-process signaler-waiter applications need to use NvSciIpc
|
||||
// and NvSciSync[Export|Import] utilities to share the NvSciSyncFence
|
||||
// across process. This step is optional in single-process.
|
||||
waitParams.params.nvSciSync.fence = (void *)fence;
|
||||
waitParams.flags = 0;
|
||||
|
||||
checkCudaErrors(cudaWaitExternalSemaphoresAsync(&waitSem, &waitParams, 1, stream));
|
||||
}
|
||||
|
||||
static void signalExternalSemaphore(cudaExternalSemaphore_t &signalSem, NvSciSyncFence *fence, cudaStream_t stream)
|
||||
{
|
||||
cudaExternalSemaphoreSignalParams signalParams;
|
||||
memset(&signalParams, 0, sizeof(signalParams));
|
||||
// For cross-process signaler-waiter applications need to use NvSciIpc
|
||||
// and NvSciSync[Export|Import] utilities to share the NvSciSyncFence
|
||||
// across process. This step is optional in single-process.
|
||||
signalParams.params.nvSciSync.fence = (void *)fence;
|
||||
signalParams.flags = 0;
|
||||
|
||||
checkCudaErrors(cudaSignalExternalSemaphoresAsync(&signalSem, &signalParams, 1, stream));
|
||||
}
|
||||
|
||||
static void yuvToGrayscaleCudaKernel(cudaExternalResInterop &cudaExtResObj, int32_t imageWidth, int32_t imageHeight)
|
||||
{
|
||||
#if WRITE_OUTPUT_IMAGE
|
||||
unsigned int *h_dstImage;
|
||||
checkCudaErrors(cudaMallocHost(&h_dstImage, sizeof(unsigned int) * imageHeight * imageWidth));
|
||||
#endif
|
||||
dim3 block(16, 16, 1);
|
||||
dim3 grid((imageWidth / block.x) + 1, (imageHeight / block.y) + 1, 1);
|
||||
|
||||
yuvToGrayscale<<<grid, block, 0, cudaExtResObj.stream>>>(
|
||||
cudaExtResObj.cudaSurfaceNvmediaBuf[0], cudaExtResObj.d_outputImage, imageWidth, imageHeight);
|
||||
|
||||
#if WRITE_OUTPUT_IMAGE
|
||||
checkCudaErrors(cudaMemcpyAsync(h_dstImage,
|
||||
cudaExtResObj.d_outputImage,
|
||||
sizeof(unsigned int) * imageHeight * imageWidth,
|
||||
cudaMemcpyDeviceToHost,
|
||||
cudaExtResObj.stream));
|
||||
checkCudaErrors(cudaStreamSynchronize(cudaExtResObj.stream));
|
||||
char outputFilename[1024];
|
||||
std::string image_filename = "Grayscale";
|
||||
strcpy(outputFilename, image_filename.c_str());
|
||||
strcpy(outputFilename + image_filename.length(), "_nvsci_out.ppm");
|
||||
sdkSavePPM4ub(outputFilename, (unsigned char *)h_dstImage, imageWidth, imageHeight);
|
||||
printf("Wrote '%s'\n", outputFilename);
|
||||
checkCudaErrors(cudaFreeHost(h_dstImage));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cudaImportNvSciImage(cudaExternalResInterop &cudaExtResObj, NvSciBufObj &inputBufObj)
|
||||
{
|
||||
NvSciBufModule module = NULL;
|
||||
NvSciBufAttrList attrlist = NULL;
|
||||
NvSciBufAttrKeyValuePair pairArrayOut[10];
|
||||
|
||||
checkNvSciErrors(NvSciBufModuleOpen(&module));
|
||||
checkNvSciErrors(NvSciBufAttrListCreate(module, &attrlist));
|
||||
checkNvSciErrors(NvSciBufObjGetAttrList(inputBufObj, &attrlist));
|
||||
|
||||
memset(pairArrayOut, 0, sizeof(NvSciBufAttrKeyValuePair) * 10);
|
||||
|
||||
int numAttrs = 0;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_Size;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneChannelCount;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneCount;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneWidth;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneHeight;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_Layout;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneBitsPerPixel;
|
||||
pairArrayOut[numAttrs++].key = NvSciBufImageAttrKey_PlaneOffset;
|
||||
|
||||
checkNvSciErrors(NvSciBufAttrListGetAttrs(attrlist, pairArrayOut, numAttrs));
|
||||
|
||||
uint64_t size = *(uint64_t *)pairArrayOut[0].value;
|
||||
uint8_t channelCount = *(uint8_t *)pairArrayOut[1].value;
|
||||
cudaExtResObj.planeCount = *(int32_t *)pairArrayOut[2].value;
|
||||
cudaExtResObj.imageWidth = (int32_t *)malloc(sizeof(int32_t) * cudaExtResObj.planeCount);
|
||||
cudaExtResObj.imageHeight = (int32_t *)malloc(sizeof(int32_t) * cudaExtResObj.planeCount);
|
||||
cudaExtResObj.planeOffset = (uint64_t *)malloc(sizeof(uint64_t) * cudaExtResObj.planeCount);
|
||||
|
||||
memcpy(cudaExtResObj.imageWidth, (int32_t *)pairArrayOut[3].value, cudaExtResObj.planeCount * sizeof(int32_t));
|
||||
memcpy(cudaExtResObj.imageHeight, (int32_t *)pairArrayOut[4].value, cudaExtResObj.planeCount * sizeof(int32_t));
|
||||
memcpy(cudaExtResObj.planeOffset, (uint64_t *)pairArrayOut[7].value, cudaExtResObj.planeCount * sizeof(uint64_t));
|
||||
|
||||
NvSciBufAttrValImageLayoutType layout = *(NvSciBufAttrValImageLayoutType *)pairArrayOut[5].value;
|
||||
uint32_t bitsPerPixel = *(uint32_t *)pairArrayOut[6].value;
|
||||
|
||||
if (layout != NvSciBufImage_BlockLinearType) {
|
||||
printf("Image layout is not block linear.. waiving execution\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
cudaExternalMemoryHandleDesc memHandleDesc;
|
||||
memset(&memHandleDesc, 0, sizeof(memHandleDesc));
|
||||
memHandleDesc.type = cudaExternalMemoryHandleTypeNvSciBuf;
|
||||
memHandleDesc.handle.nvSciBufObject = inputBufObj;
|
||||
memHandleDesc.size = size;
|
||||
checkCudaErrors(cudaImportExternalMemory(&cudaExtResObj.extMemImageBuf, &memHandleDesc));
|
||||
|
||||
cudaExtResObj.d_mipmapArray =
|
||||
(cudaMipmappedArray_t *)malloc(sizeof(cudaMipmappedArray_t) * cudaExtResObj.planeCount);
|
||||
|
||||
for (int i = 0; i < cudaExtResObj.planeCount; i++) {
|
||||
cudaExtent extent = {};
|
||||
memset(&extent, 0, sizeof(extent));
|
||||
extent.width = cudaExtResObj.imageWidth[i];
|
||||
extent.height = cudaExtResObj.imageHeight[i];
|
||||
extent.depth = 0;
|
||||
cudaChannelFormatDesc desc;
|
||||
switch (channelCount) {
|
||||
case 1:
|
||||
default:
|
||||
desc = cudaCreateChannelDesc(bitsPerPixel, 0, 0, 0, cudaChannelFormatKindUnsigned);
|
||||
break;
|
||||
case 2:
|
||||
desc = cudaCreateChannelDesc(bitsPerPixel, bitsPerPixel, 0, 0, cudaChannelFormatKindUnsigned);
|
||||
break;
|
||||
case 3:
|
||||
desc = cudaCreateChannelDesc(bitsPerPixel, bitsPerPixel, bitsPerPixel, 0, cudaChannelFormatKindUnsigned);
|
||||
break;
|
||||
case 4:
|
||||
desc = cudaCreateChannelDesc(
|
||||
bitsPerPixel, bitsPerPixel, bitsPerPixel, bitsPerPixel, cudaChannelFormatKindUnsigned);
|
||||
break;
|
||||
}
|
||||
|
||||
cudaExternalMemoryMipmappedArrayDesc mipmapDesc = {0};
|
||||
mipmapDesc.offset = cudaExtResObj.planeOffset[i];
|
||||
mipmapDesc.formatDesc = desc;
|
||||
mipmapDesc.extent = extent;
|
||||
mipmapDesc.flags = 0;
|
||||
mipmapDesc.numLevels = 1;
|
||||
checkCudaErrors(cudaExternalMemoryGetMappedMipmappedArray(
|
||||
&cudaExtResObj.d_mipmapArray[i], cudaExtResObj.extMemImageBuf, &mipmapDesc));
|
||||
}
|
||||
}
|
||||
|
||||
static cudaSurfaceObject_t createCudaSurface(cudaArray_t &d_mipLevelArray)
|
||||
{
|
||||
cudaResourceDesc resourceDesc;
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.resType = cudaResourceTypeArray;
|
||||
resourceDesc.res.array.array = d_mipLevelArray;
|
||||
|
||||
cudaSurfaceObject_t surfaceObject;
|
||||
checkCudaErrors(cudaCreateSurfaceObject(&surfaceObject, &resourceDesc));
|
||||
return surfaceObject;
|
||||
}
|
||||
|
||||
static cudaStream_t createCudaStream(int deviceId)
|
||||
{
|
||||
checkCudaErrors(cudaSetDevice(deviceId));
|
||||
cudaStream_t stream;
|
||||
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
|
||||
return stream;
|
||||
}
|
||||
|
||||
// CUDA setup buffers/synchronization objects for interop via NvSci API.
|
||||
void setupCuda(cudaExternalResInterop &cudaExtResObj,
|
||||
NvSciBufObj &inputBufObj,
|
||||
NvSciSyncObj &syncObj,
|
||||
NvSciSyncObj &cudaSignalerSyncObj,
|
||||
int deviceId)
|
||||
{
|
||||
checkCudaErrors(cudaSetDevice(deviceId));
|
||||
cudaImportNvSciSync(cudaExtResObj.waitSem, syncObj);
|
||||
cudaImportNvSciSync(cudaExtResObj.signalSem, cudaSignalerSyncObj);
|
||||
|
||||
cudaImportNvSciImage(cudaExtResObj, inputBufObj);
|
||||
cudaExtResObj.d_mipLevelArray = (cudaArray_t *)malloc(sizeof(cudaArray_t) * cudaExtResObj.planeCount);
|
||||
cudaExtResObj.cudaSurfaceNvmediaBuf =
|
||||
(cudaSurfaceObject_t *)malloc(sizeof(cudaSurfaceObject_t) * cudaExtResObj.planeCount);
|
||||
|
||||
for (int i = 0; i < cudaExtResObj.planeCount; ++i) {
|
||||
uint32_t mipLevelId = 0;
|
||||
checkCudaErrors(
|
||||
cudaGetMipmappedArrayLevel(&cudaExtResObj.d_mipLevelArray[i], cudaExtResObj.d_mipmapArray[i], mipLevelId));
|
||||
cudaExtResObj.cudaSurfaceNvmediaBuf[i] = createCudaSurface(cudaExtResObj.d_mipLevelArray[i]);
|
||||
}
|
||||
|
||||
cudaExtResObj.stream = createCudaStream(deviceId);
|
||||
checkCudaErrors(cudaMalloc(&cudaExtResObj.d_outputImage,
|
||||
sizeof(unsigned int) * cudaExtResObj.imageWidth[0] * cudaExtResObj.imageHeight[0]));
|
||||
}
|
||||
|
||||
// CUDA clean up buffers used **with** NvSci API.
|
||||
void cleanupCuda(cudaExternalResInterop &cudaExtResObj)
|
||||
{
|
||||
for (int i = 0; i < cudaExtResObj.planeCount; i++) {
|
||||
checkCudaErrors(cudaDestroySurfaceObject(cudaExtResObj.cudaSurfaceNvmediaBuf[i]));
|
||||
checkCudaErrors(cudaFreeMipmappedArray(cudaExtResObj.d_mipmapArray[i]));
|
||||
}
|
||||
free(cudaExtResObj.d_mipmapArray);
|
||||
free(cudaExtResObj.d_mipLevelArray);
|
||||
free(cudaExtResObj.cudaSurfaceNvmediaBuf);
|
||||
free(cudaExtResObj.imageWidth);
|
||||
free(cudaExtResObj.imageHeight);
|
||||
checkCudaErrors(cudaDestroyExternalSemaphore(cudaExtResObj.waitSem));
|
||||
checkCudaErrors(cudaDestroyExternalSemaphore(cudaExtResObj.signalSem));
|
||||
checkCudaErrors(cudaDestroyExternalMemory(cudaExtResObj.extMemImageBuf));
|
||||
checkCudaErrors(cudaStreamDestroy(cudaExtResObj.stream));
|
||||
checkCudaErrors(cudaFree(cudaExtResObj.d_outputImage));
|
||||
}
|
||||
|
||||
void runCudaOperation(cudaExternalResInterop &cudaExtResObj,
|
||||
NvSciSyncFence *cudaWaitFence,
|
||||
NvSciSyncFence *cudaSignalFence,
|
||||
int deviceId,
|
||||
int iterations)
|
||||
{
|
||||
checkCudaErrors(cudaSetDevice(deviceId));
|
||||
static int64_t launch = 0;
|
||||
|
||||
waitExternalSemaphore(cudaExtResObj.waitSem, cudaWaitFence, cudaExtResObj.stream);
|
||||
|
||||
// run cuda kernel over surface object of the LUMA surface part to extract
|
||||
// grayscale.
|
||||
yuvToGrayscaleCudaKernel(cudaExtResObj, cudaExtResObj.imageWidth[0], cudaExtResObj.imageHeight[0]);
|
||||
|
||||
// signal fence till the second last iterations for NvMedia2DBlit to wait for
|
||||
// cuda signal and for final iteration as there is no corresponding NvMedia
|
||||
// operation pending therefore we end with cudaStreamSynchronize()
|
||||
if (launch < iterations - 1) {
|
||||
signalExternalSemaphore(cudaExtResObj.signalSem, cudaSignalFence, cudaExtResObj.stream);
|
||||
}
|
||||
else {
|
||||
checkCudaErrors(cudaStreamSynchronize(cudaExtResObj.stream));
|
||||
}
|
||||
launch++;
|
||||
}
|
||||
|
||||
// CUDA imports and operates on NvSci buffer/synchronization objects
|
||||
void setupCuda(Blit2DTest *ctx, cudaResources &cudaResObj, int deviceId)
|
||||
{
|
||||
checkCudaErrors(cudaSetDevice(deviceId));
|
||||
cudaResObj.d_yuvArray = (cudaArray_t *)malloc(sizeof(cudaArray_t) * ctx->numSurfaces);
|
||||
cudaResObj.cudaSurfaceNvmediaBuf = (cudaSurfaceObject_t *)malloc(sizeof(cudaSurfaceObject_t) * ctx->numSurfaces);
|
||||
cudaChannelFormatDesc channelDesc;
|
||||
switch (ctx->bytesPerPixel) {
|
||||
case 1:
|
||||
default:
|
||||
channelDesc = cudaCreateChannelDesc(8, 0, 0, 0, cudaChannelFormatKindUnsigned);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < ctx->numSurfaces; k++) {
|
||||
checkCudaErrors(cudaMallocArray(&cudaResObj.d_yuvArray[k],
|
||||
&channelDesc,
|
||||
ctx->widthSurface * ctx->xScalePtr[k] * ctx->bytesPerPixel,
|
||||
ctx->heightSurface * ctx->yScalePtr[k]));
|
||||
cudaResObj.cudaSurfaceNvmediaBuf[k] = createCudaSurface(cudaResObj.d_yuvArray[k]);
|
||||
}
|
||||
checkCudaErrors(
|
||||
cudaMalloc(&cudaResObj.d_outputImage, sizeof(unsigned int) * ctx->widthSurface * ctx->heightSurface));
|
||||
|
||||
cudaResObj.stream = createCudaStream(deviceId);
|
||||
}
|
||||
|
||||
// CUDA clean up buffers used **without** NvSci API.
|
||||
void cleanupCuda(Blit2DTest *ctx, cudaResources &cudaResObj)
|
||||
{
|
||||
for (int k = 0; k < ctx->numSurfaces; k++) {
|
||||
checkCudaErrors(cudaDestroySurfaceObject(cudaResObj.cudaSurfaceNvmediaBuf[k]));
|
||||
checkCudaErrors(cudaFreeArray(cudaResObj.d_yuvArray[k]));
|
||||
}
|
||||
|
||||
free(cudaResObj.cudaSurfaceNvmediaBuf);
|
||||
|
||||
checkCudaErrors(cudaStreamDestroy(cudaResObj.stream));
|
||||
checkCudaErrors(cudaFree(cudaResObj.d_outputImage));
|
||||
}
|
||||
|
||||
static void
|
||||
yuvToGrayscaleCudaKernelNonNvSci(cudaResources &cudaResObj, int deviceId, int32_t imageWidth, int32_t imageHeight)
|
||||
{
|
||||
#if WRITE_OUTPUT_IMAGE
|
||||
unsigned int *h_dstImage;
|
||||
checkCudaErrors(cudaMallocHost(&h_dstImage, sizeof(unsigned int) * imageHeight * imageWidth));
|
||||
#endif
|
||||
dim3 block(16, 16, 1);
|
||||
dim3 grid((imageWidth / block.x) + 1, (imageHeight / block.y) + 1, 1);
|
||||
|
||||
yuvToGrayscale<<<grid, block, 0, cudaResObj.stream>>>(
|
||||
cudaResObj.cudaSurfaceNvmediaBuf[0], cudaResObj.d_outputImage, imageWidth, imageHeight);
|
||||
|
||||
#if WRITE_OUTPUT_IMAGE
|
||||
checkCudaErrors(cudaMemcpyAsync(h_dstImage,
|
||||
cudaResObj.d_outputImage,
|
||||
sizeof(unsigned int) * imageHeight * imageWidth,
|
||||
cudaMemcpyDeviceToHost,
|
||||
cudaResObj.stream));
|
||||
checkCudaErrors(cudaStreamSynchronize(cudaResObj.stream));
|
||||
char outputFilename[1024];
|
||||
std::string image_filename = "Grayscale";
|
||||
strcpy(outputFilename, image_filename.c_str());
|
||||
strcpy(outputFilename + image_filename.length(), "_non-nvsci_out.ppm");
|
||||
sdkSavePPM4ub(outputFilename, (unsigned char *)h_dstImage, imageWidth, imageHeight);
|
||||
printf("Wrote '%s'\n", outputFilename);
|
||||
checkCudaErrors(cudaFreeHost(h_dstImage));
|
||||
#else
|
||||
checkCudaErrors(cudaStreamSynchronize(cudaResObj.stream));
|
||||
#endif
|
||||
}
|
||||
|
||||
// CUDA operates **without** NvSci APIs buffer/synchronization objects.
|
||||
void runCudaOperation(Blit2DTest *ctx, cudaResources &cudaResObj, int deviceId)
|
||||
{
|
||||
for (int k = 0; k < ctx->numSurfaces; k++) {
|
||||
checkCudaErrors(cudaMemcpy2DToArray(cudaResObj.d_yuvArray[k],
|
||||
0,
|
||||
0,
|
||||
ctx->dstBuff[k],
|
||||
ctx->widthSurface * ctx->xScalePtr[k] * ctx->bytesPerPixel,
|
||||
ctx->widthSurface * ctx->xScalePtr[k] * ctx->bytesPerPixel,
|
||||
ctx->heightSurface * ctx->yScalePtr[k],
|
||||
cudaMemcpyHostToDevice));
|
||||
}
|
||||
// run cuda kernel over surface object of the LUMA surface part to extract
|
||||
// grayscale.
|
||||
yuvToGrayscaleCudaKernelNonNvSci(cudaResObj, deviceId, ctx->widthSurface, ctx->heightSurface);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __CUDA_BUFIMPORT_KERNEL_H__
|
||||
#define __CUDA_BUFIMPORT_KERNEL_H__
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "helper_cuda.h"
|
||||
#include "nvmedia_image_nvscibuf.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
#include "nvscisync.h"
|
||||
|
||||
struct cudaExternalResInterop
|
||||
{
|
||||
cudaMipmappedArray_t *d_mipmapArray;
|
||||
cudaArray_t *d_mipLevelArray;
|
||||
cudaSurfaceObject_t *cudaSurfaceNvmediaBuf;
|
||||
cudaStream_t stream;
|
||||
cudaExternalMemory_t extMemImageBuf;
|
||||
cudaExternalSemaphore_t waitSem;
|
||||
cudaExternalSemaphore_t signalSem;
|
||||
|
||||
int32_t planeCount;
|
||||
uint64_t *planeOffset;
|
||||
int32_t *imageWidth;
|
||||
int32_t *imageHeight;
|
||||
unsigned int *d_outputImage;
|
||||
};
|
||||
|
||||
struct cudaResources
|
||||
{
|
||||
cudaArray_t *d_yuvArray;
|
||||
cudaStream_t stream;
|
||||
cudaSurfaceObject_t *cudaSurfaceNvmediaBuf;
|
||||
unsigned int *d_outputImage;
|
||||
};
|
||||
|
||||
void runCudaOperation(cudaExternalResInterop &cudaExtResObj,
|
||||
NvSciSyncFence *fence,
|
||||
NvSciSyncFence *cudaSignalfence,
|
||||
int deviceId,
|
||||
int iterations);
|
||||
void runCudaOperation(Blit2DTest *ctx, cudaResources &cudaResObj, int deviceId);
|
||||
|
||||
void setupCuda(cudaExternalResInterop &cudaExtResObj,
|
||||
NvSciBufObj &inputBufObj,
|
||||
NvSciSyncObj &syncObj,
|
||||
NvSciSyncObj &cudaSignalerSyncObj,
|
||||
int deviceId);
|
||||
void setupCuda(Blit2DTest *ctx, cudaResources &cudaResObj, int deviceId);
|
||||
void cleanupCuda(cudaExternalResInterop &cudaObjs);
|
||||
void cleanupCuda(Blit2DTest *ctx, cudaResources &cudaResObj);
|
||||
|
||||
#endif
|
||||
211
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/main.cpp
Normal file
211
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/main.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/* standard headers */
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
|
||||
/* Nvidia headers */
|
||||
#include <nvscisync.h>
|
||||
|
||||
#include "cuda_consumer.h"
|
||||
#include "nvmedia_2d.h"
|
||||
#include "nvmedia_2d_nvscisync.h"
|
||||
#include "nvmedia_image.h"
|
||||
#include "nvmedia_image_nvscibuf.h"
|
||||
#include "nvmedia_producer.h"
|
||||
#include "nvmedia_surface.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
#include "nvmedia_utils/image_utils.h"
|
||||
#include "nvsci_setup.h"
|
||||
|
||||
#define checkNvSciErrors(call) \
|
||||
do { \
|
||||
NvSciError _status = call; \
|
||||
if (NvSciError_Success != _status) { \
|
||||
printf("NVSCI call in file '%s' in line %i returned" \
|
||||
" %d, expected %d\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
_status, \
|
||||
NvSciError_Success); \
|
||||
fflush(stdout); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void cleanup(Blit2DTest *ctx, NvMediaStatus status)
|
||||
{
|
||||
if (ctx->i2d != NULL) {
|
||||
NvMedia2DDestroy(ctx->i2d);
|
||||
}
|
||||
|
||||
if (ctx->device != NULL) {
|
||||
NvMediaDeviceDestroy(ctx->device);
|
||||
}
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TestArgs args;
|
||||
Blit2DTest ctx;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_ERROR;
|
||||
NvSciSyncFence nvMediaSignalerFence = NvSciSyncFenceInitializer;
|
||||
NvSciSyncFence cudaSignalerFence = NvSciSyncFenceInitializer;
|
||||
|
||||
int cudaDeviceId;
|
||||
uint64_t startTime, endTime;
|
||||
uint64_t operationStartTime, operationEndTime;
|
||||
double processingTime;
|
||||
|
||||
/* Read configuration from command line and config file */
|
||||
memset(&args, 0, sizeof(TestArgs));
|
||||
memset(&ctx, 0, sizeof(Blit2DTest));
|
||||
|
||||
/* ParseArgs parses the command line and the 2D configuration file and
|
||||
* populates all initParams and run time configuration in to appropriate
|
||||
* structures within args
|
||||
*/
|
||||
if (ParseArgs(argc, argv, &args)) {
|
||||
PrintUsage();
|
||||
return -1;
|
||||
}
|
||||
/* Check version */
|
||||
NvMediaVersion version;
|
||||
status = NvMedia2DGetVersion(&version);
|
||||
if (status == NVMEDIA_STATUS_OK) {
|
||||
printf("Library version: %u.%u\n", version.major, version.minor);
|
||||
printf("Header version: %u.%u\n", NVMEDIA_2D_VERSION_MAJOR, NVMEDIA_2D_VERSION_MINOR);
|
||||
if ((version.major != NVMEDIA_2D_VERSION_MAJOR) || (version.minor != NVMEDIA_2D_VERSION_MINOR)) {
|
||||
printf("Library and Header mismatch!\n");
|
||||
cleanup(&ctx, status);
|
||||
}
|
||||
}
|
||||
|
||||
// Create NvMedia device
|
||||
ctx.device = NvMediaDeviceCreate();
|
||||
if (!ctx.device) {
|
||||
printf("%s: Failed to create NvMedia device\n", __func__);
|
||||
cleanup(&ctx, status);
|
||||
}
|
||||
|
||||
// Create 2D blitter
|
||||
ctx.i2d = NvMedia2DCreate(ctx.device);
|
||||
if (!ctx.i2d) {
|
||||
printf("%s: Failed to create NvMedia 2D i2d\n", __func__);
|
||||
cleanup(&ctx, status);
|
||||
}
|
||||
|
||||
cudaDeviceId = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
// NvMedia-CUDA operations without NvSCI APIs starts
|
||||
cudaResources cudaResObj;
|
||||
GetTimeMicroSec(&startTime);
|
||||
setupNvMedia(&args, &ctx);
|
||||
setupCuda(&ctx, cudaResObj, cudaDeviceId);
|
||||
|
||||
GetTimeMicroSec(&operationStartTime);
|
||||
for (int i = 0; i < args.iterations; i++) {
|
||||
runNvMediaBlit2D(&args, &ctx);
|
||||
runCudaOperation(&ctx, cudaResObj, cudaDeviceId);
|
||||
}
|
||||
GetTimeMicroSec(&operationEndTime);
|
||||
|
||||
cleanupNvMedia(&ctx);
|
||||
cleanupCuda(&ctx, cudaResObj);
|
||||
GetTimeMicroSec(&endTime);
|
||||
// NvMedia-CUDA operations without NvSCI APIs ends
|
||||
|
||||
processingTime = (double)(operationEndTime - operationStartTime) / 1000.0;
|
||||
printf("Overall Processing time of NvMedia-CUDA Operations without NvSCI APIs "
|
||||
"%.4f ms with %zu iterations\n",
|
||||
processingTime,
|
||||
args.iterations);
|
||||
processingTime = (double)(endTime - startTime) / 1000.0;
|
||||
printf("Overall Processing time of NvMedia-CUDA Operations + allocation/cleanup "
|
||||
"without NvSCI APIs %.4f ms with %zu iterations\n",
|
||||
processingTime,
|
||||
args.iterations);
|
||||
|
||||
NvSciBufObj dstNvSciBufobj, srcNvSciBufobj;
|
||||
NvSciSyncObj nvMediaSignalerSyncObj, cudaSignalerSyncObj;
|
||||
cudaExternalResInterop cudaExtResObj;
|
||||
// NvMedia-CUDA operations via interop with NvSCI APIs starts
|
||||
GetTimeMicroSec(&startTime);
|
||||
setupNvMediaSignalerNvSciSync(&ctx, nvMediaSignalerSyncObj, cudaDeviceId);
|
||||
setupCudaSignalerNvSciSync(&ctx, cudaSignalerSyncObj, cudaDeviceId);
|
||||
setupNvMedia(
|
||||
&args, &ctx, srcNvSciBufobj, dstNvSciBufobj, nvMediaSignalerSyncObj, cudaSignalerSyncObj, cudaDeviceId);
|
||||
setupCuda(cudaExtResObj, dstNvSciBufobj, nvMediaSignalerSyncObj, cudaSignalerSyncObj, cudaDeviceId);
|
||||
|
||||
GetTimeMicroSec(&operationStartTime);
|
||||
for (int i = 0; i < args.iterations; i++) {
|
||||
runNvMediaBlit2D(&args, &ctx, nvMediaSignalerSyncObj, &cudaSignalerFence, &nvMediaSignalerFence);
|
||||
runCudaOperation(cudaExtResObj, &nvMediaSignalerFence, &cudaSignalerFence, cudaDeviceId, args.iterations);
|
||||
}
|
||||
GetTimeMicroSec(&operationEndTime);
|
||||
|
||||
cleanupNvMedia(&ctx, nvMediaSignalerSyncObj, cudaSignalerSyncObj);
|
||||
cleanupCuda(cudaExtResObj);
|
||||
cleanupNvSciSync(nvMediaSignalerSyncObj);
|
||||
cleanupNvSciSync(cudaSignalerSyncObj);
|
||||
cleanupNvSciBuf(srcNvSciBufobj);
|
||||
cleanupNvSciBuf(dstNvSciBufobj);
|
||||
GetTimeMicroSec(&endTime);
|
||||
// NvMedia-CUDA operations via interop with NvSCI APIs ends
|
||||
|
||||
processingTime = (double)(operationEndTime - operationStartTime) / 1000.0;
|
||||
printf("Overall Processing time of NvMedia-CUDA Operations with NvSCI APIs %.4f "
|
||||
"ms with %zu iterations\n",
|
||||
processingTime,
|
||||
args.iterations);
|
||||
processingTime = (double)(endTime - startTime) / 1000.0;
|
||||
printf("Overall Processing time of NvMedia-CUDA Operations + allocation/cleanup "
|
||||
"with NvSCI APIs %.4f ms with %zu iterations\n",
|
||||
processingTime,
|
||||
args.iterations);
|
||||
|
||||
if (ctx.i2d != NULL) {
|
||||
NvMedia2DDestroy(ctx.i2d);
|
||||
}
|
||||
|
||||
if (ctx.device != NULL) {
|
||||
NvMediaDeviceDestroy(ctx.device);
|
||||
}
|
||||
|
||||
if (status == NVMEDIA_STATUS_OK) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
/* Nvidia headers */
|
||||
#include "nvmedia_2d.h"
|
||||
#include "nvmedia_2d_nvscisync.h"
|
||||
#include "nvmedia_image.h"
|
||||
#include "nvmedia_image_nvscibuf.h"
|
||||
#include "nvmedia_producer.h"
|
||||
#include "nvmedia_surface.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
#include "nvmedia_utils/image_utils.h"
|
||||
#include "nvsci_setup.h"
|
||||
|
||||
NvMediaImage *NvMediaImageCreateUsingNvScibuf(NvMediaDevice *device,
|
||||
NvMediaSurfaceType type,
|
||||
const NvMediaSurfAllocAttr *attrs,
|
||||
uint32_t numAttrs,
|
||||
uint32_t flags,
|
||||
NvSciBufObj &bufobj,
|
||||
int cudaDeviceId)
|
||||
{
|
||||
NvSciBufModule module = NULL;
|
||||
NvSciError err = NvSciError_Success;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_OK;
|
||||
NvSciBufAttrList attrlist = NULL;
|
||||
NvSciBufAttrList conflictlist = NULL;
|
||||
NvSciBufAttrValAccessPerm access_perm = NvSciBufAccessPerm_ReadWrite;
|
||||
NvSciBufAttrKeyValuePair attr_kvp = {NvSciBufGeneralAttrKey_RequiredPerm, &access_perm, sizeof(access_perm)};
|
||||
NvSciBufAttrKeyValuePair pairArrayOut[10];
|
||||
|
||||
NvMediaImage *image = NULL;
|
||||
|
||||
err = NvSciBufModuleOpen(&module);
|
||||
if (err != NvSciError_Success) {
|
||||
printf("%s: NvSciBuffModuleOpen failed. Error: %d \n", __func__, err);
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
||||
err = NvSciBufAttrListCreate(module, &attrlist);
|
||||
if (err != NvSciError_Success) {
|
||||
printf("%s: SciBufAttrListCreate failed. Error: %d \n", __func__, err);
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
||||
err = NvSciBufAttrListSetAttrs(attrlist, &attr_kvp, 1);
|
||||
if (err != NvSciError_Success) {
|
||||
printf("%s: AccessPermSetAttr failed. Error: %d \n", __func__, err);
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
||||
status = NvMediaImageFillNvSciBufAttrs(device, type, attrs, numAttrs, 0, attrlist);
|
||||
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: ImageFillSciBufAttrs failed. Error: %d \n", __func__, err);
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
||||
setupNvSciBuf(bufobj, attrlist, cudaDeviceId);
|
||||
|
||||
status = NvMediaImageCreateFromNvSciBuf(device, bufobj, &image);
|
||||
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: ImageCreatefromSciBuf failed. Error: %d \n", __func__, err);
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
||||
NvSciBufAttrListFree(attrlist);
|
||||
|
||||
if (module != NULL) {
|
||||
NvSciBufModuleClose(module);
|
||||
}
|
||||
|
||||
return image;
|
||||
|
||||
fail_cleanup:
|
||||
if (attrlist != NULL) {
|
||||
NvSciBufAttrListFree(attrlist);
|
||||
}
|
||||
if (bufobj != NULL) {
|
||||
NvSciBufObjFree(bufobj);
|
||||
bufobj = NULL;
|
||||
}
|
||||
|
||||
if (module != NULL) {
|
||||
NvSciBufModuleClose(module);
|
||||
}
|
||||
NvMediaImageDestroy(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create NvMediaImage surface based on the input attributes.
|
||||
* Returns NVMEDIA_STATUS_OK on success
|
||||
*/
|
||||
static NvMediaStatus createSurface(Blit2DTest *ctx,
|
||||
NvMediaSurfFormatAttr *surfFormatAttrs,
|
||||
NvMediaSurfAllocAttr *surfAllocAttrs,
|
||||
uint32_t numSurfAllocAttrs,
|
||||
NvMediaImage **image,
|
||||
NvSciBufObj &bufObj,
|
||||
int cudaDeviceId)
|
||||
{
|
||||
NvMediaSurfaceType surfType;
|
||||
|
||||
/* create source image */
|
||||
surfType = NvMediaSurfaceFormatGetType(surfFormatAttrs, NVM_SURF_FMT_ATTR_MAX);
|
||||
*image = NvMediaImageCreateUsingNvScibuf(ctx->device, /* device */
|
||||
surfType, /* surface type */
|
||||
surfAllocAttrs,
|
||||
numSurfAllocAttrs,
|
||||
0,
|
||||
bufObj,
|
||||
cudaDeviceId);
|
||||
|
||||
if (*image == NULL) {
|
||||
printf("Unable to create image\n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
InitImage(*image, surfAllocAttrs[0].value, surfAllocAttrs[1].value);
|
||||
|
||||
/* printf("%s: NvMediaImageCreate:: Image size: %ux%u Image type: %d\n",
|
||||
__func__, surfAllocAttrs[0].value, surfAllocAttrs[1].value,
|
||||
surfType);*/
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
/* Create NvMediaImage surface based on the input attributes.
|
||||
* Returns NVMEDIA_STATUS_OK on success
|
||||
*/
|
||||
static NvMediaStatus createSurfaceNonNvSCI(Blit2DTest *ctx,
|
||||
NvMediaSurfFormatAttr *surfFormatAttrs,
|
||||
NvMediaSurfAllocAttr *surfAllocAttrs,
|
||||
uint32_t numSurfAllocAttrs,
|
||||
NvMediaImage **image)
|
||||
{
|
||||
NvMediaSurfaceType surfType;
|
||||
|
||||
/* create source image */
|
||||
surfType = NvMediaSurfaceFormatGetType(surfFormatAttrs, NVM_SURF_FMT_ATTR_MAX);
|
||||
|
||||
*image = NvMediaImageCreateNew(ctx->device, surfType, surfAllocAttrs, numSurfAllocAttrs, 0);
|
||||
|
||||
if (*image == NULL) {
|
||||
printf("Unable to create image\n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
InitImage(*image, surfAllocAttrs[0].value, surfAllocAttrs[1].value);
|
||||
|
||||
/* printf("%s: NvMediaImageCreate:: Image size: %ux%u Image type: %d\n",
|
||||
__func__, surfAllocAttrs[0].value, surfAllocAttrs[1].value,
|
||||
surfType);*/
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
static void destroySurface(NvMediaImage *image) { NvMediaImageDestroy(image); }
|
||||
|
||||
static NvMediaStatus blit2DImage(Blit2DTest *ctx,
|
||||
TestArgs *args,
|
||||
NvSciSyncObj &nvMediaSignalerSyncObj,
|
||||
NvSciSyncFence *preSyncFence,
|
||||
NvSciSyncFence *fence)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
|
||||
status = ReadImage(args->inputFileName, /* fileName */
|
||||
0, /* frameNum */
|
||||
args->srcSurfAllocAttrs[0].value, /* source image width */
|
||||
args->srcSurfAllocAttrs[1].value, /* source image height */
|
||||
ctx->srcImage, /* srcImage */
|
||||
NVMEDIA_TRUE, /* uvOrderFlag */
|
||||
1, /* bytesPerPixel */
|
||||
MSB_ALIGNED); /* pixelAlignment */
|
||||
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: ReadImage failed for input buffer: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((args->srcRect.x1 <= args->srcRect.x0) || (args->srcRect.y1 <= args->srcRect.y0)) {
|
||||
ctx->srcRect = NULL;
|
||||
}
|
||||
else {
|
||||
ctx->srcRect = &(args->srcRect);
|
||||
}
|
||||
|
||||
if ((args->dstRect.x1 <= args->dstRect.x0) || (args->dstRect.y1 <= args->dstRect.y0)) {
|
||||
ctx->dstRect = NULL;
|
||||
}
|
||||
else {
|
||||
ctx->dstRect = &(args->dstRect);
|
||||
}
|
||||
|
||||
static int64_t launch = 0;
|
||||
// Start inserting pre-fence from second launch inorder to for NvMedia2Blit to
|
||||
// wait
|
||||
// for cuda signal on fence.
|
||||
if (launch) {
|
||||
status = NvMedia2DInsertPreNvSciSyncFence(ctx->i2d, preSyncFence);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DSetNvSciSyncObjforEOF failed: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
NvSciSyncFenceClear(preSyncFence);
|
||||
}
|
||||
launch++;
|
||||
|
||||
status = NvMedia2DSetNvSciSyncObjforEOF(ctx->i2d, nvMediaSignalerSyncObj);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DSetNvSciSyncObjforEOF failed: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* 2DBlit processing on input image */
|
||||
status = NvMedia2DBlitEx(ctx->i2d, /* i2d */
|
||||
ctx->dstImage, /* dstSurface */
|
||||
ctx->dstRect, /* dstRect */
|
||||
ctx->srcImage, /* srcSurface */
|
||||
ctx->srcRect, /* srcRect */
|
||||
&args->blitParams, /* params */
|
||||
NULL); /* paramsOut */
|
||||
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DBlitEx failed: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = NvMedia2DGetEOFNvSciSyncFence(ctx->i2d, nvMediaSignalerSyncObj, fence);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DGetEOFNvSciSyncFence failed: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
static NvMediaStatus blit2DImageNonNvSCI(Blit2DTest *ctx, TestArgs *args)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
|
||||
status = ReadImage(args->inputFileName, /* fileName */
|
||||
0, /* frameNum */
|
||||
args->srcSurfAllocAttrs[0].value, /* source image width */
|
||||
args->srcSurfAllocAttrs[1].value, /* source image height */
|
||||
ctx->srcImage, /* srcImage */
|
||||
NVMEDIA_TRUE, /* uvOrderFlag */
|
||||
1, /* bytesPerPixel */
|
||||
MSB_ALIGNED); /* pixelAlignment */
|
||||
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: ReadImage failed for input buffer: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((args->srcRect.x1 <= args->srcRect.x0) || (args->srcRect.y1 <= args->srcRect.y0)) {
|
||||
ctx->srcRect = NULL;
|
||||
}
|
||||
else {
|
||||
ctx->srcRect = &(args->srcRect);
|
||||
}
|
||||
|
||||
if ((args->dstRect.x1 <= args->dstRect.x0) || (args->dstRect.y1 <= args->dstRect.y0)) {
|
||||
ctx->dstRect = NULL;
|
||||
}
|
||||
else {
|
||||
ctx->dstRect = &(args->dstRect);
|
||||
}
|
||||
|
||||
/* 2DBlit processing on input image */
|
||||
status = NvMedia2DBlitEx(ctx->i2d, /* i2d */
|
||||
ctx->dstImage, /* dstSurface */
|
||||
ctx->dstRect, /* dstRect */
|
||||
ctx->srcImage, /* srcSurface */
|
||||
ctx->srcRect, /* srcRect */
|
||||
&args->blitParams, /* params */
|
||||
NULL); /* paramsOut */
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DBlitEx failed: %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write output image into buffer */
|
||||
ctx->bytesPerPixel = 1;
|
||||
WriteImageToAllocatedBuffer(ctx, ctx->dstImage, NVMEDIA_TRUE, NVMEDIA_FALSE, ctx->bytesPerPixel);
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
static void cleanup(Blit2DTest *ctx, NvMediaStatus status = NVMEDIA_STATUS_OK)
|
||||
{
|
||||
if (ctx->srcImage != NULL) {
|
||||
NvMedia2DImageUnRegister(ctx->i2d, ctx->srcImage);
|
||||
destroySurface(ctx->srcImage);
|
||||
}
|
||||
if (ctx->dstImage != NULL) {
|
||||
NvMedia2DImageUnRegister(ctx->i2d, ctx->dstImage);
|
||||
destroySurface(ctx->dstImage);
|
||||
}
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupNvMedia(Blit2DTest *ctx, NvSciSyncObj &syncObj, NvSciSyncObj &preSyncObj)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
cleanup(ctx);
|
||||
status = NvMedia2DUnregisterNvSciSyncObj(ctx->i2d, syncObj);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageSciBufInit failed\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
status = NvMedia2DUnregisterNvSciSyncObj(ctx->i2d, preSyncObj);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageSciBufInit failed\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
NvMediaImageNvSciBufDeinit();
|
||||
}
|
||||
|
||||
void cleanupNvMedia(Blit2DTest *ctx)
|
||||
{
|
||||
cleanup(ctx);
|
||||
free(ctx->dstBuffPitches);
|
||||
free(ctx->dstBuffer);
|
||||
free(ctx->dstBuff);
|
||||
}
|
||||
|
||||
void setupNvMedia(TestArgs *args,
|
||||
Blit2DTest *ctx,
|
||||
NvSciBufObj &srcNvSciBufobj,
|
||||
NvSciBufObj &dstNvSciBufobj,
|
||||
NvSciSyncObj &syncObj,
|
||||
NvSciSyncObj &preSyncObj,
|
||||
int cudaDeviceId)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
status = NvMediaImageNvSciBufInit();
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageSciBufInit failed\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Create source surface
|
||||
status = createSurface(ctx,
|
||||
args->srcSurfFormatAttrs,
|
||||
args->srcSurfAllocAttrs,
|
||||
args->numSurfAllocAttrs,
|
||||
&ctx->srcImage,
|
||||
srcNvSciBufobj,
|
||||
cudaDeviceId);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to create buffer pools\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Create destination surface
|
||||
status = createSurface(ctx,
|
||||
args->dstSurfFormatAttrs,
|
||||
args->dstSurfAllocAttrs,
|
||||
args->numSurfAllocAttrs,
|
||||
&ctx->dstImage,
|
||||
dstNvSciBufobj,
|
||||
cudaDeviceId);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to create buffer pools\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Register source Surface
|
||||
status = NvMedia2DImageRegister(ctx->i2d, ctx->srcImage, NVMEDIA_ACCESS_MODE_READ);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to register source surface\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
// Register destination Surface
|
||||
status = NvMedia2DImageRegister(ctx->i2d, ctx->dstImage, NVMEDIA_ACCESS_MODE_READ_WRITE);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to register destination surface\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
status = NvMedia2DRegisterNvSciSyncObj(ctx->i2d, NVMEDIA_EOFSYNCOBJ, syncObj);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to NvMedia2DRegisterNvSciSyncObj\n", __func__);
|
||||
}
|
||||
|
||||
status = NvMedia2DRegisterNvSciSyncObj(ctx->i2d, NVMEDIA_PRESYNCOBJ, preSyncObj);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to NvMedia2DRegisterNvSciSyncObj\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
// Create NvMedia src & dst image without NvSciBuf
|
||||
void setupNvMedia(TestArgs *args, Blit2DTest *ctx)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
|
||||
// Create source surface
|
||||
status = createSurfaceNonNvSCI(
|
||||
ctx, args->srcSurfFormatAttrs, args->srcSurfAllocAttrs, args->numSurfAllocAttrs, &ctx->srcImage);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to create buffer pools\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Create destination surface
|
||||
status = createSurfaceNonNvSCI(
|
||||
ctx, args->dstSurfFormatAttrs, args->dstSurfAllocAttrs, args->numSurfAllocAttrs, &ctx->dstImage);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to create buffer pools\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Register source Surface
|
||||
status = NvMedia2DImageRegister(ctx->i2d, ctx->srcImage, NVMEDIA_ACCESS_MODE_READ);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to register source surface\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Register destination Surface
|
||||
status = NvMedia2DImageRegister(ctx->i2d, ctx->dstImage, NVMEDIA_ACCESS_MODE_READ_WRITE);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Unable to register destination surface\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
|
||||
// Allocate buffer for writing image & set image parameters in Blit2DTest.
|
||||
ctx->bytesPerPixel = 1;
|
||||
AllocateBufferToWriteImage(ctx,
|
||||
ctx->dstImage,
|
||||
NVMEDIA_TRUE, /* uvOrderFlag */
|
||||
NVMEDIA_FALSE); /* appendFlag */
|
||||
}
|
||||
|
||||
void runNvMediaBlit2D(TestArgs *args, Blit2DTest *ctx)
|
||||
{
|
||||
// Blit2D function
|
||||
NvMediaStatus status = blit2DImageNonNvSCI(ctx, args);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Blit2D failed\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
}
|
||||
|
||||
void runNvMediaBlit2D(TestArgs *args,
|
||||
Blit2DTest *ctx,
|
||||
NvSciSyncObj &nvMediaSignalerSyncObj,
|
||||
NvSciSyncFence *preSyncFence,
|
||||
NvSciSyncFence *fence)
|
||||
{
|
||||
// Blit2D function
|
||||
NvMediaStatus status = blit2DImage(ctx, args, nvMediaSignalerSyncObj, preSyncFence, fence);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Blit2D failed\n", __func__);
|
||||
cleanup(ctx, status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __NVMEDIA_PRODUCER_H__
|
||||
#define __NVMEDIA_PRODUCER_H__
|
||||
#include "nvmedia_2d.h"
|
||||
#include "nvmedia_image.h"
|
||||
#include "nvmedia_image_nvscibuf.h"
|
||||
#include "nvmedia_surface.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
#include "nvmedia_utils/image_utils.h"
|
||||
#include "nvscisync.h"
|
||||
|
||||
void runNvMediaBlit2D(TestArgs *args,
|
||||
Blit2DTest *ctx,
|
||||
NvSciSyncObj &syncObj,
|
||||
NvSciSyncFence *preSyncFence,
|
||||
NvSciSyncFence *fence);
|
||||
void runNvMediaBlit2D(TestArgs *args, Blit2DTest *ctx);
|
||||
void setupNvMedia(TestArgs *args,
|
||||
Blit2DTest *ctx,
|
||||
NvSciBufObj &srcNvSciBufobj,
|
||||
NvSciBufObj &dstNvSciBufobj,
|
||||
NvSciSyncObj &syncObj,
|
||||
NvSciSyncObj &preSyncObj,
|
||||
int cudaDeviceId);
|
||||
void setupNvMedia(TestArgs *args, Blit2DTest *ctx);
|
||||
void cleanupNvMedia(Blit2DTest *ctx, NvSciSyncObj &syncObj, NvSciSyncObj &preSyncObj);
|
||||
void cleanupNvMedia(Blit2DTest *ctx);
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
|
||||
/* Standard headers */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Nvidia headers */
|
||||
#include "cmdline.h"
|
||||
#include "config_parser.h"
|
||||
#include "helper_cuda.h"
|
||||
#include "log_utils.h"
|
||||
#include "misc_utils.h"
|
||||
|
||||
/* see cmdline.h for details */
|
||||
void PrintUsage()
|
||||
{
|
||||
printf("cudaNvSciNvMedia\n");
|
||||
printf("Usage: cudaNvSciNvMedia [options]\n");
|
||||
printf("Options:\n");
|
||||
printf("-h Prints usage\n");
|
||||
printf("-device=n (n >= 0 for cuda device ID)\n");
|
||||
printf("-cf=[config] 2d config file. Path length limited to %u chars\n", FILE_NAME_SIZE);
|
||||
printf("-iterations=n (n > 0 - num of iterations of NvMedia-CUDA operations to be launched)\n");
|
||||
}
|
||||
|
||||
SectionMap sectionsMap[] = {
|
||||
{SECTION_NONE, "", 0, 0} /* Has to be the last item - specifies the end of array */
|
||||
};
|
||||
|
||||
/* see cmdline.h for details */
|
||||
int ParseArgs(int argc, char *argv[], TestArgs *args)
|
||||
{
|
||||
NvMediaBool bLastArg = NVMEDIA_FALSE;
|
||||
NvMediaBool bDataAvailable = NVMEDIA_FALSE;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_OK;
|
||||
const char *filename = NULL;
|
||||
int i;
|
||||
|
||||
args->srcSurfAllocAttrs[0].type = args->dstSurfAllocAttrs[0].type = NVM_SURF_ATTR_WIDTH;
|
||||
args->srcSurfAllocAttrs[1].type = args->dstSurfAllocAttrs[1].type = NVM_SURF_ATTR_HEIGHT;
|
||||
args->srcSurfAllocAttrs[2].type = args->dstSurfAllocAttrs[2].type = NVM_SURF_ATTR_EMB_LINES_TOP;
|
||||
args->srcSurfAllocAttrs[3].type = args->dstSurfAllocAttrs[3].type = NVM_SURF_ATTR_EMB_LINES_BOTTOM;
|
||||
args->srcSurfAllocAttrs[4].type = args->dstSurfAllocAttrs[4].type = NVM_SURF_ATTR_CPU_ACCESS;
|
||||
args->srcSurfAllocAttrs[5].type = args->dstSurfAllocAttrs[5].type = NVM_SURF_ATTR_ALLOC_TYPE;
|
||||
args->srcSurfAllocAttrs[6].type = args->dstSurfAllocAttrs[6].type = NVM_SURF_ATTR_SCAN_TYPE;
|
||||
args->srcSurfAllocAttrs[7].type = args->dstSurfAllocAttrs[7].type = NVM_SURF_ATTR_COLOR_STD_TYPE;
|
||||
args->numSurfAllocAttrs = 8;
|
||||
|
||||
args->srcSurfFormatAttrs[0].type = args->dstSurfFormatAttrs[0].type = NVM_SURF_ATTR_SURF_TYPE;
|
||||
args->srcSurfFormatAttrs[1].type = args->dstSurfFormatAttrs[1].type = NVM_SURF_ATTR_LAYOUT;
|
||||
args->srcSurfFormatAttrs[2].type = args->dstSurfFormatAttrs[2].type = NVM_SURF_ATTR_DATA_TYPE;
|
||||
args->srcSurfFormatAttrs[3].type = args->dstSurfFormatAttrs[3].type = NVM_SURF_ATTR_MEMORY;
|
||||
args->srcSurfFormatAttrs[4].type = args->dstSurfFormatAttrs[4].type = NVM_SURF_ATTR_SUB_SAMPLING_TYPE;
|
||||
args->srcSurfFormatAttrs[5].type = args->dstSurfFormatAttrs[5].type = NVM_SURF_ATTR_BITS_PER_COMPONENT;
|
||||
args->srcSurfFormatAttrs[6].type = args->dstSurfFormatAttrs[6].type = NVM_SURF_ATTR_COMPONENT_ORDER;
|
||||
|
||||
/* ConfigParamsMap
|
||||
* See nvmedia_2d.h and sample config file(s) for details.
|
||||
*/
|
||||
ConfigParamsMap paramsMap[] = {
|
||||
/*ParamName, &args->variableName, paramType, D, LimitType, Mn,
|
||||
Mx, CharSize, p2C, section */
|
||||
{"transformMode", &args->blitParams.dstTransform, TYPE_UINT, 0, LIMITS_BOTH, 0, 7, 0, 0, SECTION_NONE},
|
||||
{"filterMode", &args->blitParams.filter, TYPE_UINT, 1, LIMITS_BOTH, 1, 4, 0, 0, SECTION_NONE},
|
||||
{"colorStd", &args->blitParams.colorStandard, TYPE_UINT, 0, LIMITS_MIN, 0, 3, 0, 0, SECTION_NONE},
|
||||
{"validOperations", &args->blitParams.validFields, TYPE_UINT, 0, LIMITS_BOTH, 0, 15, 0, 0, SECTION_NONE},
|
||||
{"inputfile", &args->inputFileName, TYPE_CHAR_ARR, 0, LIMITS_NONE, 0, 0, FILE_NAME_SIZE, 0, SECTION_NONE},
|
||||
|
||||
/*src surface alloc attributes*/
|
||||
{"srcWidth", &args->srcSurfAllocAttrs[0].value, TYPE_UINT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"srcHeight", &args->srcSurfAllocAttrs[1].value, TYPE_UINT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"srcCPUAccess", &args->srcSurfAllocAttrs[4].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"srcAllocType", &args->srcSurfAllocAttrs[5].value, TYPE_UINT, 0, LIMITS_BOTH, 0, 1, 0, 0, SECTION_NONE},
|
||||
{"srcScanType", &args->srcSurfAllocAttrs[6].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 1, 0, 0, SECTION_NONE},
|
||||
{"srcColorStd", &args->srcSurfAllocAttrs[7].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 12, 0, 0, SECTION_NONE},
|
||||
/*src surface format attributes*/
|
||||
{"srcSurfType", &args->srcSurfFormatAttrs[0].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"srcLayout", &args->srcSurfFormatAttrs[1].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 2, 0, 0, SECTION_NONE},
|
||||
{"srcDataType", &args->srcSurfFormatAttrs[2].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 4, 0, 0, SECTION_NONE},
|
||||
{"srcMemory", &args->srcSurfFormatAttrs[3].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"srcSubSamplingType", &args->srcSurfFormatAttrs[4].value, TYPE_UINT, 1, LIMITS_BOTH, 0, 4, 0, 0, SECTION_NONE},
|
||||
{"srcBitsPerComponent",
|
||||
&args->srcSurfFormatAttrs[5].value,
|
||||
TYPE_UINT,
|
||||
1,
|
||||
LIMITS_BOTH,
|
||||
1,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
SECTION_NONE},
|
||||
{"srcComponentOrder", &args->srcSurfFormatAttrs[6].value, TYPE_UINT, 2, LIMITS_BOTH, 1, 45, 0, 0, SECTION_NONE},
|
||||
/*srcRect*/
|
||||
{"srcRectx0", &args->srcRect.x0, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"srcRecty0", &args->srcRect.y0, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"srcRectx1", &args->srcRect.x1, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"srcRecty1", &args->srcRect.y1, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
/*dst surface alloc attributes*/
|
||||
{"dstWidth", &args->dstSurfAllocAttrs[0].value, TYPE_UINT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"dstHeight", &args->dstSurfAllocAttrs[1].value, TYPE_UINT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"dstCPUAccess", &args->dstSurfAllocAttrs[4].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"dstAllocType", &args->dstSurfAllocAttrs[5].value, TYPE_UINT, 0, LIMITS_BOTH, 0, 1, 0, 0, SECTION_NONE},
|
||||
{"dstScanType", &args->dstSurfAllocAttrs[6].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 1, 0, 0, SECTION_NONE},
|
||||
{"dstColorStd", &args->dstSurfAllocAttrs[7].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 12, 0, 0, SECTION_NONE},
|
||||
/*dst surface format attributes*/
|
||||
{"dstSurfType", &args->dstSurfFormatAttrs[0].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"dstLayout", &args->dstSurfFormatAttrs[1].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 2, 0, 0, SECTION_NONE},
|
||||
{"dstDataType", &args->dstSurfFormatAttrs[2].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 4, 0, 0, SECTION_NONE},
|
||||
{"dstMemory", &args->dstSurfFormatAttrs[3].value, TYPE_UINT, 1, LIMITS_BOTH, 1, 3, 0, 0, SECTION_NONE},
|
||||
{"dstSubSamplingType", &args->dstSurfFormatAttrs[4].value, TYPE_UINT, 1, LIMITS_BOTH, 0, 4, 0, 0, SECTION_NONE},
|
||||
{"dstBitsPerComponent",
|
||||
&args->dstSurfFormatAttrs[5].value,
|
||||
TYPE_UINT,
|
||||
1,
|
||||
LIMITS_BOTH,
|
||||
1,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
SECTION_NONE},
|
||||
{"dstComponentOrder", &args->dstSurfFormatAttrs[6].value, TYPE_UINT, 2, LIMITS_BOTH, 1, 45, 0, 0, SECTION_NONE},
|
||||
/*dstRect*/
|
||||
{"dstRectx0", &args->dstRect.x0, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"dstRecty0", &args->dstRect.y0, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"dstRectx1", &args->dstRect.x1, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
{"dstRecty1", &args->dstRect.y1, TYPE_USHORT, 0, LIMITS_MIN, 0, 0, 0, 0, SECTION_NONE},
|
||||
/*End of the array */
|
||||
{NULL, NULL, TYPE_UINT, 0, LIMITS_NONE, 0, 0, 0, 0, SECTION_NONE}};
|
||||
|
||||
args->iterations = 100; // Set default iterations value.
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
|
||||
return -1;
|
||||
}
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "cf")) {
|
||||
|
||||
char *inputFileName = NULL;
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "cf", (char **)&inputFileName);
|
||||
if (!inputFileName) {
|
||||
printf("ERR: Invalid config file name\n");
|
||||
return -1;
|
||||
}
|
||||
filename = sdkFindFilePath(inputFileName, ".");
|
||||
}
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "iterations")) {
|
||||
args->iterations = getCmdLineArgumentInt(argc, (const char **)argv, "iterations");
|
||||
}
|
||||
|
||||
if (filename == NULL) {
|
||||
// Set default file to use if no config file given.
|
||||
filename = sdkFindFilePath("sample.cfg", ".");
|
||||
}
|
||||
|
||||
if (filename != NULL) {
|
||||
printf("Using config file %s\n", filename);
|
||||
|
||||
/* Init Parser Map*/
|
||||
status = ConfigParser_InitParamsMap(paramsMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("ERR: ConfigParser_InitParamsMap failed! status:%x\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = ConfigParser_ParseFile(paramsMap, 1, sectionsMap, (char *)filename);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("ERR: Failed to parse config file. status:%x\n", status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("ParseArgs: Validating params from config file\n");
|
||||
status = ConfigParser_ValidateParams(paramsMap, sectionsMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("ERR: Some of the params in config file are invalid.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NVMEDIA_2D_CMD_LINE_H_
|
||||
#define _NVMEDIA_2D_CMD_LINE_H_
|
||||
|
||||
/* Include header containing NvMedia2D declarations */
|
||||
#include "nvmedia_2d.h"
|
||||
|
||||
/* Maximum length of the path including file name */
|
||||
#define FILE_NAME_SIZE 1024
|
||||
|
||||
/* TestArgs contains all arguments required to run the 2D test */
|
||||
typedef struct _TestArgs
|
||||
{
|
||||
char inputFileName[FILE_NAME_SIZE];
|
||||
|
||||
NvMediaSurfAllocAttr srcSurfAllocAttrs[NVM_SURF_ALLOC_ATTR_MAX];
|
||||
NvMediaSurfAllocAttr dstSurfAllocAttrs[NVM_SURF_ALLOC_ATTR_MAX];
|
||||
uint32_t numSurfAllocAttrs;
|
||||
|
||||
NvMediaSurfFormatAttr srcSurfFormatAttrs[NVM_SURF_FMT_ATTR_MAX];
|
||||
NvMediaSurfFormatAttr dstSurfFormatAttrs[NVM_SURF_FMT_ATTR_MAX];
|
||||
|
||||
NvMediaRect srcRect;
|
||||
NvMediaRect dstRect;
|
||||
NvMedia2DBlitParameters blitParams;
|
||||
size_t iterations;
|
||||
} TestArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NvMediaDevice *device;
|
||||
/* I2D for 2D blit processing */
|
||||
NvMedia2D *i2d;
|
||||
NvMediaImage *srcImage;
|
||||
NvMediaImage *dstImage;
|
||||
NvMediaRect *srcRect;
|
||||
NvMediaRect *dstRect;
|
||||
uint8_t **dstBuff;
|
||||
uint32_t *dstBuffPitches;
|
||||
uint8_t *dstBuffer;
|
||||
uint32_t numSurfaces;
|
||||
uint32_t bytesPerPixel;
|
||||
uint32_t heightSurface;
|
||||
uint32_t widthSurface;
|
||||
float *xScalePtr;
|
||||
float *yScalePtr;
|
||||
|
||||
} Blit2DTest;
|
||||
|
||||
/* Prints application usage options */
|
||||
void PrintUsage(void);
|
||||
|
||||
/* Parses command line arguments.
|
||||
* Also parses any configuration files supplied in the command line arguments.
|
||||
* Arguments:
|
||||
* argc
|
||||
* (in) Number of tokens in the command line
|
||||
* argv
|
||||
* (in) Command line tokens
|
||||
* args
|
||||
* (out) Pointer to test arguments structure
|
||||
*/
|
||||
int ParseArgs(int argc, char **argv, TestArgs *args);
|
||||
|
||||
#endif /* _NVMEDIA_2D_CMD_LINE_H_ */
|
||||
@@ -0,0 +1,616 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include "config_parser.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "log_utils.h"
|
||||
#if defined(__QNX__)
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
static NvMediaStatus GetParamIndex(ConfigParamsMap *paramsMap, char *paramName, unsigned int *index)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (paramsMap[i].paramName != NULL) {
|
||||
if (strcasecmp(paramsMap[i].paramName, paramName) == 0) {
|
||||
*index = i;
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
NvMediaStatus ConfigParser_GetSectionIndexByName(SectionMap *sectionsMap, char *sectionName, unsigned int *index)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
while (sectionsMap[i].secType != SECTION_NONE) {
|
||||
if (strcmp(sectionsMap[i].name, sectionName) == 0) {
|
||||
*index = i;
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
NvMediaStatus ConfigParser_GetSectionIndexByType(SectionMap *sectionsMap, SectionType sectionType, unsigned int *index)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
while (sectionsMap[i].secType != SECTION_NONE) {
|
||||
if (sectionsMap[i].secType == sectionType) {
|
||||
*index = i;
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*index = i;
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
static NvMediaStatus GetFileContent(char *filename, char **fileContentOut)
|
||||
{
|
||||
FILE *file;
|
||||
char *fileCotent;
|
||||
long fileSize;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
printf("Parser_GetFileContent: Cannot open configuration file %s\n", filename);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
if (fseek(file, 0, SEEK_END) != 0) {
|
||||
printf("Parser_GetFileContent: Cannot fseek in configuration file %s\n", filename);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
fileSize = ftell(file);
|
||||
if (fileSize < 0 || fileSize > 150000) {
|
||||
printf("Parser_GetFileContent: Unreasonable Filesize %ld encountered for file %s\n", fileSize, filename);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (fseek(file, 0, SEEK_SET) != 0) {
|
||||
printf("Parser_GetFileContent: Cannot fseek in configuration file %s\n", filename);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
fileCotent = (char *)malloc(fileSize + 1);
|
||||
if (fileCotent == NULL) {
|
||||
printf("Parser_GetFileContent: Failed allocating buffer for file Content\n");
|
||||
return NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fileSize = (long)fread(fileCotent, 1, fileSize, file);
|
||||
fileCotent[fileSize] = '\0';
|
||||
*fileContentOut = fileCotent;
|
||||
|
||||
fclose(file);
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
NvMediaStatus
|
||||
ConfigParser_ParseFile(ConfigParamsMap *paramsMap, unsigned int numParams, SectionMap *sectionsMap, char *fileName)
|
||||
{
|
||||
char *items[MAX_ITEMS_TO_PARSE] = {NULL};
|
||||
int intValue, itemsCount = 0, i = 0, sectionIndex = 0;
|
||||
double doubleValue;
|
||||
float floatValue;
|
||||
unsigned int currItemIndex, uintValue, sectionId = 0, currSectionId = 0, charValue, paramDefaultLength;
|
||||
unsigned short ushortValue;
|
||||
short shortValue;
|
||||
unsigned long long ullValue;
|
||||
NvMediaBool isInString = NVMEDIA_FALSE, isInItem = NVMEDIA_FALSE;
|
||||
char *buffer, *bufferEnd, *param, *pParamLength;
|
||||
char sectionName[100];
|
||||
char currDigit;
|
||||
char *configContentBuf = NULL;
|
||||
unsigned int numSetsInSection = 0;
|
||||
|
||||
if (GetFileContent(fileName, &configContentBuf) != NVMEDIA_STATUS_OK) {
|
||||
printf("ConfigParser_ParseFile: Failed reading file %s", fileName);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
buffer = configContentBuf;
|
||||
bufferEnd = &configContentBuf[strlen(configContentBuf)];
|
||||
|
||||
// Stage one: Create items mapping in the content using "items" pointers array. For each parameter we have 3 items:
|
||||
// param name, '=' char and the param value.
|
||||
while (buffer < bufferEnd) {
|
||||
if (itemsCount >= MAX_ITEMS_TO_PARSE) {
|
||||
LOG_WARN("ConfigParser_ParseFile: Number of items in configuration file exceeded the maximum allowed (%d). "
|
||||
"Only %d items will be parsed.\n",
|
||||
MAX_ITEMS_TO_PARSE,
|
||||
MAX_ITEMS_TO_PARSE);
|
||||
itemsCount = MAX_ITEMS_TO_PARSE;
|
||||
break;
|
||||
}
|
||||
switch (*buffer) {
|
||||
// Carriage return
|
||||
case 13:
|
||||
++buffer;
|
||||
break;
|
||||
case '#':
|
||||
*buffer = '\0'; // Replace '#' with '\0' in case of comment immediately following integer or string
|
||||
while (*buffer != '\n' && buffer < bufferEnd) { // Skip till EOL or EOF
|
||||
++buffer;
|
||||
}
|
||||
isInString = NVMEDIA_FALSE;
|
||||
isInItem = NVMEDIA_FALSE;
|
||||
break;
|
||||
case '\n':
|
||||
isInItem = NVMEDIA_FALSE;
|
||||
isInString = NVMEDIA_FALSE;
|
||||
*buffer++ = '\0';
|
||||
break;
|
||||
case ' ':
|
||||
case '\t': // Skip whitespace, leave state unchanged
|
||||
if (isInString)
|
||||
buffer++;
|
||||
else { // Terminate non-strings once whitespace is found
|
||||
*buffer++ = '\0';
|
||||
isInItem = NVMEDIA_FALSE;
|
||||
}
|
||||
break;
|
||||
case '"': // Begin/End of String
|
||||
*buffer++ = '\0';
|
||||
if (!isInString) {
|
||||
items[itemsCount++] = buffer;
|
||||
isInItem = ~isInItem;
|
||||
}
|
||||
else {
|
||||
isInItem = NVMEDIA_FALSE;
|
||||
}
|
||||
isInString = ~isInString; // Toggle
|
||||
break;
|
||||
case '[':
|
||||
*(buffer++) = '\0';
|
||||
items[itemsCount++] = buffer;
|
||||
while (*buffer != ' ' && *buffer != '\n'
|
||||
&& buffer < bufferEnd) { // Skip till whitespace (after which is located the parsed section number)
|
||||
// or EOL or EOF
|
||||
sectionName[i++] = *(buffer++);
|
||||
}
|
||||
sectionName[i] = '\0';
|
||||
i = 0;
|
||||
while (*buffer == ' ') {
|
||||
*(buffer++) = '\0';
|
||||
}
|
||||
items[itemsCount++] = buffer;
|
||||
while (*buffer != ']' && *buffer != '\n' && buffer < bufferEnd) { // Read the section number
|
||||
currDigit = *buffer;
|
||||
sectionIndex = sectionIndex * 10 + (currDigit - '0');
|
||||
buffer++;
|
||||
}
|
||||
*(buffer++) = '\0';
|
||||
sectionIndex--;
|
||||
if (ConfigParser_GetSectionIndexByName(sectionsMap, sectionName, §ionId) != NVMEDIA_STATUS_OK) {
|
||||
printf("ConfigParser_ParseFile: SectionName couldn't be found in section map: '%s'.\n", sectionName);
|
||||
}
|
||||
numSetsInSection++;
|
||||
sectionsMap[sectionId].lastSectionIndex = sectionIndex;
|
||||
sectionIndex = 0;
|
||||
isInString = NVMEDIA_FALSE;
|
||||
isInItem = NVMEDIA_FALSE;
|
||||
break;
|
||||
default:
|
||||
if (!isInItem) {
|
||||
items[itemsCount++] = buffer;
|
||||
isInItem = ~isInItem;
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
itemsCount--;
|
||||
|
||||
if (numSetsInSection > numParams) {
|
||||
printf("%s: Not enough buffers allocated for parsing. Number of sets allocated: %d. Number of sets in config "
|
||||
"file: %d \n",
|
||||
__func__,
|
||||
numParams,
|
||||
numSetsInSection);
|
||||
if (configContentBuf) {
|
||||
free(configContentBuf);
|
||||
}
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Stage 2: Go through the list of items and save their values in parameters map
|
||||
for (i = 0; i < itemsCount; i += 3) {
|
||||
if (ConfigParser_GetSectionIndexByName(sectionsMap, items[i], &currItemIndex) == NVMEDIA_STATUS_OK) {
|
||||
currSectionId = atoi(items[i + 1]);
|
||||
currSectionId--;
|
||||
LOG_DBG("ConfigParser_ParseFile: Parsing section %s index %d\n", items[i], currSectionId);
|
||||
i -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetParamIndex(paramsMap, items[i], &currItemIndex) != NVMEDIA_STATUS_OK) {
|
||||
LOG_WARN("ConfigParser_ParseFile: Parameter Name '%s' is not recognized. Dismissing this parameter.\n",
|
||||
items[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp("=", items[i + 1])) {
|
||||
printf("ConfigParser_ParseFile: '=' expected as the second token in each line. Error caught while parsing "
|
||||
"parameter '%s'.\n",
|
||||
items[i]);
|
||||
i -= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ConfigParser_GetSectionIndexByType(sectionsMap, paramsMap[currItemIndex].sectionType, §ionId)
|
||||
!= NVMEDIA_STATUS_OK) {
|
||||
printf(
|
||||
"ConfigParser_ParseFile: Section index couldn't be found in section map by type. Param Name: '%s'.\n",
|
||||
paramsMap[currItemIndex].paramName);
|
||||
}
|
||||
|
||||
if (sectionsMap[sectionId].lastSectionIndex == 0) {
|
||||
// Param is not part of a collection or collection includes only one item
|
||||
currSectionId = 0;
|
||||
}
|
||||
|
||||
param = (char *)paramsMap[currItemIndex].mappedLocation + currSectionId * sectionsMap[sectionId].sizeOfStruct;
|
||||
pParamLength =
|
||||
(char *)paramsMap[currItemIndex].stringLengthAddr + currSectionId * sectionsMap[sectionId].sizeOfStruct;
|
||||
paramDefaultLength = paramsMap[currItemIndex].stringLength;
|
||||
|
||||
// Interpret the Value
|
||||
LOG_DBG("ConfigParser_ParseFile: Interpreting parameter %s\n", items[i]);
|
||||
switch (paramsMap[currItemIndex].type) {
|
||||
case TYPE_INT:
|
||||
if (sscanf(items[i + 2], "%d", &intValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected numerical value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(int *)(void *)param = intValue;
|
||||
break;
|
||||
case TYPE_UINT:
|
||||
if (sscanf(items[i + 2], "%u", &uintValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected numerical value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(unsigned int *)(void *)param = uintValue;
|
||||
break;
|
||||
case TYPE_UINT_HEX:
|
||||
if (sscanf(items[i + 2], "%x", &uintValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected unsigned char value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(unsigned int *)(void *)param = uintValue;
|
||||
break;
|
||||
case TYPE_CHAR_ARR:
|
||||
if (items[i + 2] == NULL)
|
||||
memset(param, 0, (pParamLength != NULL && *pParamLength != 0) ? *pParamLength : paramDefaultLength);
|
||||
else {
|
||||
strncpy(param, items[i + 2], paramsMap[currItemIndex].stringLength);
|
||||
param[strlen(items[i + 2])] = '\0';
|
||||
}
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
if (sscanf(items[i + 2], "%lf", &doubleValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected double value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(double *)(void *)param = doubleValue;
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
if (sscanf(items[i + 2], "%f", &floatValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected double value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(float *)(void *)param = floatValue;
|
||||
break;
|
||||
case TYPE_UCHAR:
|
||||
if (sscanf(items[i + 2], "%u", &charValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected unsigned char value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(unsigned char *)(void *)param = charValue;
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
if (sscanf(items[i + 2], "%hu", &ushortValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected unsigned short value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(unsigned short *)(void *)param = ushortValue;
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
if (sscanf(items[i + 2], "%hd", &shortValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected short value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(short *)(void *)param = shortValue;
|
||||
break;
|
||||
case TYPE_UCHAR_ARR:
|
||||
if (items[i + 2] == NULL)
|
||||
memset(param, 0, (pParamLength != NULL && *pParamLength != 0) ? *pParamLength : paramDefaultLength);
|
||||
else {
|
||||
strncpy(param, items[i + 2], paramsMap[currItemIndex].stringLength);
|
||||
param[strlen(items[i + 2])] = '\0';
|
||||
}
|
||||
break;
|
||||
case TYPE_ULLONG:
|
||||
if (sscanf(items[i + 2], "%llu", &ullValue) != 1) {
|
||||
printf("ConfigParser_ParseFile: Expected numerical value for Parameter %s, found value '%s'\n",
|
||||
items[i],
|
||||
items[i + 2]);
|
||||
}
|
||||
*(unsigned long long *)(void *)param = ullValue;
|
||||
break;
|
||||
default:
|
||||
printf("ConfigParser_ParseFile: Encountered unknown value type in the map\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (configContentBuf)
|
||||
free(configContentBuf);
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
NvMediaStatus ConfigParser_InitParamsMap(ConfigParamsMap *paramsMap)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (paramsMap[i].paramName != NULL) {
|
||||
if (paramsMap[i].mappedLocation == NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (paramsMap[i].type) {
|
||||
case TYPE_UINT:
|
||||
case TYPE_UINT_HEX:
|
||||
*(unsigned int *)(paramsMap[i].mappedLocation) = (unsigned int)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_INT:
|
||||
*(int *)(paramsMap[i].mappedLocation) = (int)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
*(double *)(paramsMap[i].mappedLocation) = (double)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
*(float *)(paramsMap[i].mappedLocation) = (float)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_UCHAR:
|
||||
*(unsigned char *)(paramsMap[i].mappedLocation) = (NvMediaBool)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
*(unsigned short *)(paramsMap[i].mappedLocation) = (unsigned short)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
*(short *)(paramsMap[i].mappedLocation) = (short)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_ULLONG:
|
||||
*(unsigned long long *)(paramsMap[i].mappedLocation) = (unsigned long long)paramsMap[i].defaultValue;
|
||||
break;
|
||||
case TYPE_CHAR_ARR:
|
||||
case TYPE_UCHAR_ARR:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
NvMediaStatus ConfigParser_ValidateParams(ConfigParamsMap *paramsMap, SectionMap *sectionsMap)
|
||||
{
|
||||
NvMediaStatus status = NVMEDIA_STATUS_OK;
|
||||
unsigned int sectionId = 0, i = 0, j;
|
||||
char *param;
|
||||
|
||||
while (paramsMap[i].paramName != NULL) {
|
||||
if (ConfigParser_GetSectionIndexByType(sectionsMap, paramsMap[i].sectionType, §ionId)
|
||||
!= NVMEDIA_STATUS_OK) {
|
||||
printf("ConfigParser_ValidateParams: Section index couldn't be found in section map. Param Name: '%s'.\n",
|
||||
paramsMap[i].paramName);
|
||||
}
|
||||
|
||||
for (j = 0; j <= sectionsMap[sectionId].lastSectionIndex; j++) {
|
||||
if (paramsMap[i].paramLimits == 1 || paramsMap[i].paramLimits == 2) {
|
||||
param = (char *)paramsMap[i].mappedLocation + j * sectionsMap[sectionId].sizeOfStruct;
|
||||
if (param == NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
switch (paramsMap[i].type) {
|
||||
case TYPE_UINT:
|
||||
case TYPE_UINT_HEX:
|
||||
if (*(unsigned int *)(void *)param < (unsigned int)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2
|
||||
&& *(unsigned int *)(void *)param > (unsigned int)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
if (*(double *)(void *)param < (double)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2
|
||||
&& *(double *)(void *)param > (double)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
if (*(float *)(void *)param < (float)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2 && *(float *)(void *)param > (float)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_INT:
|
||||
if (*(int *)(void *)param < (int)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2 && *(int *)(void *)param > (int)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
if (*(unsigned short *)(void *)param < (unsigned short)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2
|
||||
&& *(unsigned short *)(void *)param > (unsigned short)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
if (*(short *)(void *)param < (short)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2 && *(short *)(void *)param > (short)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
case TYPE_ULLONG:
|
||||
if (*(unsigned long long *)(void *)param < (unsigned long long)paramsMap[i].minLimit
|
||||
|| (paramsMap[i].paramLimits == 2
|
||||
&& *(unsigned long long *)(void *)param > (unsigned long long)paramsMap[i].maxLimit)) {
|
||||
printf("ConfigParser_ValidateParams: Error in input parameter %s\n", paramsMap[i].paramName);
|
||||
printf("Check configuration file for parameter limits\n");
|
||||
status = NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NvMediaStatus ConfigParser_DisplayParams(ConfigParamsMap *pParamsMap, SectionMap *pSectionsMap)
|
||||
{
|
||||
unsigned int i = 0, j, sectionId = 0;
|
||||
char *param;
|
||||
|
||||
while (pParamsMap[i].paramName != NULL) {
|
||||
if (ConfigParser_GetSectionIndexByType(pSectionsMap, pParamsMap[i].sectionType, §ionId)
|
||||
!= NVMEDIA_STATUS_OK) {
|
||||
printf("ConfigParser_DisplayParams: Section index couldn't be found in section map by type. Param Name: "
|
||||
"'%s'.\n",
|
||||
pParamsMap[i].paramName);
|
||||
}
|
||||
|
||||
for (j = 0; j <= pSectionsMap[sectionId].lastSectionIndex; j++) {
|
||||
param = (char *)pParamsMap[i].mappedLocation + j * pSectionsMap[sectionId].sizeOfStruct;
|
||||
if (param == NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (pParamsMap[i].type) {
|
||||
case TYPE_UINT:
|
||||
printf("(%d) %s = %u\n", j, pParamsMap[i].paramName, *(unsigned int *)(void *)param);
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
printf("(%d) %s = %.2lf\n", j, pParamsMap[i].paramName, *(double *)(void *)param);
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
printf("(%d) %s = %.2f\n", j, pParamsMap[i].paramName, *(float *)(void *)param);
|
||||
break;
|
||||
case TYPE_UCHAR:
|
||||
printf("(%d) %s = %d\n", j, pParamsMap[i].paramName, *(unsigned char *)(void *)param);
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
printf("(%d) %s = %hu\n", j, pParamsMap[i].paramName, *(unsigned short *)(void *)param);
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
printf("(%d) %s = %hd\n", j, pParamsMap[i].paramName, *(short *)(void *)param);
|
||||
break;
|
||||
case TYPE_ULLONG:
|
||||
printf("(%d) %s = %llu\n", j, pParamsMap[i].paramName, *(unsigned long long *)(void *)param);
|
||||
break;
|
||||
case TYPE_CHAR_ARR:
|
||||
printf("(%d) %s = "
|
||||
"%s"
|
||||
"\n",
|
||||
j,
|
||||
pParamsMap[i].paramName,
|
||||
param);
|
||||
break;
|
||||
case TYPE_UCHAR_ARR:
|
||||
printf("(%d) %s = "
|
||||
"%s"
|
||||
"\n",
|
||||
j,
|
||||
pParamsMap[i].paramName,
|
||||
(unsigned char *)(void *)param);
|
||||
break;
|
||||
case TYPE_INT:
|
||||
printf("(%d) %s = %d\n", j, pParamsMap[i].paramName, *(int *)(void *)param);
|
||||
break;
|
||||
case TYPE_UINT_HEX:
|
||||
printf("(%d) %s = %x\n", j, pParamsMap[i].paramName, *(unsigned int *)(void *)param);
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef _NVMEDIA_TEST_CONFIG_PARSER_H_
|
||||
#define _NVMEDIA_TEST_CONFIG_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nvmedia_core.h"
|
||||
#include "nvmedia_surface.h"
|
||||
|
||||
#define MAX_ITEMS_TO_PARSE 10000
|
||||
|
||||
typedef enum _ParamType {
|
||||
TYPE_UINT = 0,
|
||||
TYPE_UINT_HEX,
|
||||
TYPE_INT,
|
||||
TYPE_DOUBLE,
|
||||
TYPE_FLOAT,
|
||||
TYPE_UCHAR,
|
||||
TYPE_ULLONG,
|
||||
TYPE_USHORT,
|
||||
TYPE_CHAR_ARR,
|
||||
TYPE_UCHAR_ARR,
|
||||
TYPE_SHORT
|
||||
} ParamType;
|
||||
|
||||
typedef enum { LIMITS_NONE = 0, LIMITS_MIN = 1, LIMITS_BOTH = 2 } LimitsType;
|
||||
|
||||
typedef enum {
|
||||
SECTION_NONE,
|
||||
SECTION_CAPTURE,
|
||||
SECTION_QP,
|
||||
SECTION_RC,
|
||||
SECTION_ENCODE_PIC,
|
||||
SECTION_ENCODE_PIC_H264,
|
||||
SECTION_ENCODE_PIC_H265,
|
||||
SECTION_MVC,
|
||||
SECTION_PAYLOAD,
|
||||
SECTION_2DPROCESSOR
|
||||
} SectionType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SectionType secType;
|
||||
const char *name;
|
||||
unsigned int lastSectionIndex;
|
||||
size_t sizeOfStruct;
|
||||
} SectionMap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *paramName;
|
||||
void *mappedLocation;
|
||||
ParamType type;
|
||||
double defaultValue;
|
||||
LimitsType paramLimits;
|
||||
double minLimit;
|
||||
double maxLimit;
|
||||
unsigned int stringLength; // string param size
|
||||
unsigned int *stringLengthAddr; // address of string param size
|
||||
SectionType sectionType;
|
||||
} ConfigParamsMap;
|
||||
|
||||
NvMediaStatus ConfigParser_InitParamsMap(ConfigParamsMap *paramsMap);
|
||||
NvMediaStatus
|
||||
ConfigParser_ParseFile(ConfigParamsMap *paramsMap, unsigned int numParams, SectionMap *sectionsMap, char *file);
|
||||
NvMediaStatus ConfigParser_ValidateParams(ConfigParamsMap *paramsMap, SectionMap *sectionsMap);
|
||||
NvMediaStatus ConfigParser_DisplayParams(ConfigParamsMap *paramsMap, SectionMap *sectionsMap);
|
||||
NvMediaStatus ConfigParser_GetSectionIndexByName(SectionMap *sectionsMap, char *sectionName, unsigned int *index);
|
||||
NvMediaStatus
|
||||
ConfigParser_GetSectionIndexByType(SectionMap *sectionsMap, SectionType sectionType, unsigned int *index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NVMEDIA_TEST_CONFIG_PARSER_H_ */
|
||||
@@ -0,0 +1,785 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "image_utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "misc_utils.h"
|
||||
#include "nvmedia_surface.h"
|
||||
|
||||
#define MAXM_NUM_SURFACES 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float heightFactor[6];
|
||||
float widthFactor[6];
|
||||
unsigned int numSurfaces;
|
||||
} ImgUtilSurfParams;
|
||||
|
||||
ImgUtilSurfParams ImgSurfParamsTable_RGBA = {
|
||||
.heightFactor = {1, 0, 0, 0, 0, 0},
|
||||
.widthFactor = {1, 0, 0, 0, 0, 0},
|
||||
.numSurfaces = 1,
|
||||
};
|
||||
|
||||
ImgUtilSurfParams ImgSurfParamsTable_RAW = {
|
||||
.heightFactor = {1, 0, 0, 0, 0, 0},
|
||||
.widthFactor = {1, 0, 0, 0, 0, 0},
|
||||
.numSurfaces = 1,
|
||||
};
|
||||
|
||||
ImgUtilSurfParams ImgSurfParamsTable_YUV[][4] = {
|
||||
{
|
||||
/* PLANAR */
|
||||
{
|
||||
/* 420 */
|
||||
.heightFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 422 */
|
||||
.heightFactor = {1, 1, 1, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 444 */
|
||||
.heightFactor = {1, 1, 1, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 1, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 422R */
|
||||
.heightFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 1, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* SEMI_PLANAR */
|
||||
{
|
||||
/* 420 */
|
||||
.heightFactor = {1, 0.5, 0, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0, 0, 0, 0},
|
||||
.numSurfaces = 2,
|
||||
},
|
||||
{
|
||||
/* 422 */
|
||||
.heightFactor = {1, 1, 0, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0, 0, 0, 0},
|
||||
.numSurfaces = 2,
|
||||
},
|
||||
{
|
||||
/* 444 */
|
||||
.heightFactor = {1, 1, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 2,
|
||||
},
|
||||
{
|
||||
/* 422R */
|
||||
.heightFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* PACKED */
|
||||
{
|
||||
/* 420 */
|
||||
.heightFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 422 */
|
||||
.heightFactor = {1, 1, 1, 0, 0, 0},
|
||||
.widthFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 444 */
|
||||
.heightFactor = {1, 1, 1, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 1, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
{
|
||||
/* 422R */
|
||||
.heightFactor = {1, 0.5, 0.5, 0, 0, 0},
|
||||
.widthFactor = {1, 1, 1, 0, 0, 0},
|
||||
.numSurfaces = 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
ImgUtilSurfParams ImgSurfParamsTable_Packed = {
|
||||
.heightFactor = {1, 0, 0, 0, 0, 0},
|
||||
.widthFactor = {1, 0, 0, 0, 0, 0},
|
||||
.numSurfaces = 1,
|
||||
};
|
||||
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_RGBA[][6] = {
|
||||
{4, 0, 0, 0, 0, 0}, /* 8 */
|
||||
};
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_RGBA16[][6] = {
|
||||
{8, 0, 0, 0, 0, 0}, /* 16 */
|
||||
};
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_RG16[6] = {4, 0, 0, 0, 0, 0};
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_Alpha[][6] = {
|
||||
{1, 0, 0, 0, 0, 0}, /* 8 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 10 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 12 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 14 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 16 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 32 */
|
||||
};
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_RAW[][6] = {
|
||||
{1, 0, 0, 0, 0, 0}, /* 8 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 10 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 12 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 14 */
|
||||
{2, 0, 0, 0, 0, 0}, /* 16 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 32 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 16_8_8 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 10_8_8 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 2_10_10_10 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 20 */
|
||||
};
|
||||
|
||||
unsigned int ImgBytesPerPixelTable_YUV[][9][6] = {{
|
||||
/* PLANAR */
|
||||
{1, 1, 1, 0, 0, 0}, /* 8 */
|
||||
{2, 2, 2, 0, 0, 0}, /* 10 */
|
||||
{2, 2, 2, 0, 0, 0}, /* 12 */
|
||||
{2, 2, 2, 0, 0, 0}, /* 14 */
|
||||
{2, 2, 2, 0, 0, 0}, /* 16 */
|
||||
{4, 4, 4, 0, 0, 0}, /* 32 */
|
||||
{2, 1, 1, 0, 0, 0}, /* 16_8_8 */
|
||||
{2, 1, 1, 0, 0, 0}, /* 10_8_8 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 2_10_10_10 */
|
||||
},
|
||||
{
|
||||
/* SEMI_PLANAR */
|
||||
{1, 2, 0, 0, 0, 0}, /* 8 */
|
||||
{2, 4, 0, 0, 0, 0}, /* 10 */
|
||||
{2, 4, 0, 0, 0, 0}, /* 12 */
|
||||
{2, 4, 0, 0, 0, 0}, /* 14 */
|
||||
{2, 4, 0, 0, 0, 0}, /* 16 */
|
||||
{4, 8, 0, 0, 0, 0}, /* 32 */
|
||||
{2, 2, 0, 0, 0, 0}, /* 16_8_8 */
|
||||
{2, 2, 0, 0, 0, 0}, /* 10_8_8 */
|
||||
{4, 0, 0, 0, 0, 0}, /* 2_10_10_10 */
|
||||
}};
|
||||
|
||||
static NvMediaStatus GetBytesPerCompForPackedYUV(unsigned int surfBPCidx, unsigned int *bytespercomp)
|
||||
{
|
||||
switch (surfBPCidx) {
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_8:
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_LAYOUT_2_10_10_10:
|
||||
*bytespercomp = 1;
|
||||
break;
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_10:
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_12:
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_14:
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_16:
|
||||
*bytespercomp = 2;
|
||||
break;
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_20:
|
||||
*bytespercomp = 3;
|
||||
break;
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_32:
|
||||
*bytespercomp = 4;
|
||||
break;
|
||||
default:
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
static NvMediaStatus GetSurfParams(unsigned int surfaceType,
|
||||
float **xScale,
|
||||
float **yScale,
|
||||
unsigned int **bytePerPixel,
|
||||
uint32_t *numSurfacesVal)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
unsigned int surfType, surfMemoryType, surfSubSamplingType, surfBPC, surfCompOrder;
|
||||
float *xScalePtr = NULL, *yScalePtr = NULL;
|
||||
unsigned int *bytePerPixelPtr = NULL;
|
||||
NVM_SURF_FMT_DEFINE_ATTR(srcAttr);
|
||||
uint32_t numSurfaces = 1;
|
||||
static unsigned int yuvpackedtbl[6] = {1, 0, 0, 0, 0, 0};
|
||||
unsigned int numcomps = 1;
|
||||
|
||||
status = NvMediaSurfaceFormatGetAttrs(surfaceType, srcAttr, NVM_SURF_FMT_ATTR_MAX);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s:NvMediaSurfaceFormatGetAttrs failed\n", __func__);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
surfType = srcAttr[NVM_SURF_ATTR_SURF_TYPE].value;
|
||||
surfMemoryType = srcAttr[NVM_SURF_ATTR_MEMORY].value;
|
||||
surfSubSamplingType = srcAttr[NVM_SURF_ATTR_SUB_SAMPLING_TYPE].value;
|
||||
surfBPC = srcAttr[NVM_SURF_ATTR_BITS_PER_COMPONENT].value;
|
||||
surfCompOrder = srcAttr[NVM_SURF_ATTR_COMPONENT_ORDER].value;
|
||||
|
||||
switch (surfType) {
|
||||
case NVM_SURF_ATTR_SURF_TYPE_YUV:
|
||||
if (surfSubSamplingType == NVM_SURF_ATTR_SUB_SAMPLING_TYPE_NONE
|
||||
&& surfMemoryType == NVM_SURF_ATTR_MEMORY_PACKED) {
|
||||
|
||||
xScalePtr = &ImgSurfParamsTable_Packed.widthFactor[0];
|
||||
yScalePtr = &ImgSurfParamsTable_Packed.heightFactor[0];
|
||||
numSurfaces = ImgSurfParamsTable_Packed.numSurfaces;
|
||||
|
||||
if (NVMEDIA_STATUS_OK != GetBytesPerCompForPackedYUV(surfBPC, &yuvpackedtbl[0])) {
|
||||
printf("Invalid Bits per component and Packed YUV combination\n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
switch (surfCompOrder) {
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_VUYX:
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_XYUV:
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_XUYV:
|
||||
numcomps = 4;
|
||||
break;
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_UYVY:
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_VYUY:
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_YVYU:
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_YUYV:
|
||||
numcomps = 2;
|
||||
break;
|
||||
case NVM_SURF_ATTR_COMPONENT_ORDER_LUMA:
|
||||
numcomps = 1;
|
||||
break;
|
||||
default:
|
||||
printf("Invalid component Order and Packed YUV combination\n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
yuvpackedtbl[0] = yuvpackedtbl[0] * numcomps;
|
||||
bytePerPixelPtr = &yuvpackedtbl[0];
|
||||
}
|
||||
else {
|
||||
xScalePtr =
|
||||
&ImgSurfParamsTable_YUV[0][surfSubSamplingType - NVM_SURF_ATTR_SUB_SAMPLING_TYPE_420].widthFactor[0];
|
||||
yScalePtr =
|
||||
&ImgSurfParamsTable_YUV[0][surfSubSamplingType - NVM_SURF_ATTR_SUB_SAMPLING_TYPE_420].heightFactor[0];
|
||||
numSurfaces =
|
||||
ImgSurfParamsTable_YUV[0][surfSubSamplingType - NVM_SURF_ATTR_SUB_SAMPLING_TYPE_420].numSurfaces;
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_YUV[0][surfBPC - NVM_SURF_ATTR_BITS_PER_COMPONENT_8][0];
|
||||
}
|
||||
|
||||
break;
|
||||
case NVM_SURF_ATTR_SURF_TYPE_RGBA:
|
||||
if (surfCompOrder == NVM_SURF_ATTR_COMPONENT_ORDER_ALPHA) {
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_Alpha[surfBPC - NVM_SURF_ATTR_BITS_PER_COMPONENT_8][0];
|
||||
}
|
||||
else if (surfCompOrder == NVM_SURF_ATTR_COMPONENT_ORDER_RG) {
|
||||
if (surfBPC == NVM_SURF_ATTR_BITS_PER_COMPONENT_16) {
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_RG16[0];
|
||||
}
|
||||
else {
|
||||
printf("Invalid RGorder & Bitspercomp combination.Only RG16 is supported\n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else { /* RGBA, ARGB, BGRA */
|
||||
if (surfBPC == NVM_SURF_ATTR_BITS_PER_COMPONENT_16) {
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_RGBA16[0][0];
|
||||
}
|
||||
else if (surfBPC == NVM_SURF_ATTR_BITS_PER_COMPONENT_8) {
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_RGBA[0][0];
|
||||
}
|
||||
else {
|
||||
printf("RGBA orders with 8 and 16bits only is supported \n");
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
xScalePtr = &ImgSurfParamsTable_RGBA.widthFactor[0];
|
||||
yScalePtr = &ImgSurfParamsTable_RGBA.heightFactor[0];
|
||||
numSurfaces = ImgSurfParamsTable_RGBA.numSurfaces;
|
||||
break;
|
||||
case NVM_SURF_ATTR_SURF_TYPE_RAW:
|
||||
bytePerPixelPtr = &ImgBytesPerPixelTable_RAW[surfBPC - NVM_SURF_ATTR_BITS_PER_COMPONENT_8][0];
|
||||
xScalePtr = &ImgSurfParamsTable_RAW.widthFactor[0];
|
||||
yScalePtr = &ImgSurfParamsTable_RAW.heightFactor[0];
|
||||
numSurfaces = ImgSurfParamsTable_RAW.numSurfaces;
|
||||
break;
|
||||
default:
|
||||
printf("%s: Unsupported Pixel Format %d", __func__, surfType);
|
||||
return NVMEDIA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (xScale) {
|
||||
*xScale = xScalePtr;
|
||||
}
|
||||
if (yScale) {
|
||||
*yScale = yScalePtr;
|
||||
}
|
||||
if (bytePerPixel) {
|
||||
*bytePerPixel = bytePerPixelPtr;
|
||||
}
|
||||
if (numSurfacesVal) {
|
||||
*numSurfacesVal = numSurfaces;
|
||||
}
|
||||
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
|
||||
NvMediaStatus
|
||||
AllocateBufferToWriteImage(Blit2DTest *ctx, NvMediaImage *image, NvMediaBool uvOrderFlag, NvMediaBool appendFlag)
|
||||
{
|
||||
uint32_t imageSize = 0;
|
||||
unsigned int size[3] = {0};
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t i, k, newk = 0;
|
||||
unsigned int *bytePerPixelPtr = NULL;
|
||||
ctx->numSurfaces = 1;
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_ERROR;
|
||||
uint32_t lineWidth, numRows, startOffset;
|
||||
|
||||
if (!image) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock() failed\n", __func__);
|
||||
return status;
|
||||
}
|
||||
NvMediaImageUnlock(image);
|
||||
|
||||
ctx->dstBuff = (uint8_t **)malloc(sizeof(uint8_t *) * MAXM_NUM_SURFACES);
|
||||
if (!ctx->dstBuff) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->dstBuffPitches = (uint32_t *)calloc(1, sizeof(uint32_t) * MAXM_NUM_SURFACES);
|
||||
if (!ctx->dstBuffPitches) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->heightSurface = surfaceMap.height;
|
||||
ctx->widthSurface = surfaceMap.width;
|
||||
|
||||
status = GetSurfParams(image->type, &ctx->xScalePtr, &ctx->yScalePtr, &bytePerPixelPtr, &ctx->numSurfaces);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: GetSurfParams() failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
imageSize = 0;
|
||||
for (i = 0; i < ctx->numSurfaces; i++) {
|
||||
size[i] = (ctx->widthSurface * ctx->xScalePtr[i] * ctx->heightSurface * ctx->yScalePtr[i] * bytePerPixelPtr[i]);
|
||||
imageSize += size[i];
|
||||
ctx->dstBuffPitches[i] = (uint32_t)((float)ctx->widthSurface * ctx->xScalePtr[i]) * bytePerPixelPtr[i];
|
||||
}
|
||||
|
||||
// Embedded data size needs to be included for RAW surftype
|
||||
size[0] += image->embeddedDataTopSize;
|
||||
size[0] += image->embeddedDataBottomSize;
|
||||
imageSize += image->embeddedDataTopSize;
|
||||
imageSize += image->embeddedDataBottomSize;
|
||||
|
||||
buffer = (uint8_t *)calloc(1, imageSize);
|
||||
if (!buffer) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->dstBuffer = buffer;
|
||||
memset(buffer, 0xFF, imageSize);
|
||||
for (i = 0; i < ctx->numSurfaces; i++) {
|
||||
ctx->dstBuff[i] = buffer;
|
||||
buffer = buffer + (uint32_t)(ctx->heightSurface * ctx->yScalePtr[i] * ctx->dstBuffPitches[i]);
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
NvMediaStatus WriteImageToAllocatedBuffer(Blit2DTest *ctx,
|
||||
NvMediaImage *image,
|
||||
NvMediaBool uvOrderFlag,
|
||||
NvMediaBool appendFlag,
|
||||
uint32_t bytesPerPixel)
|
||||
{
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
|
||||
NvMediaStatus status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock() failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
status = NvMediaImageGetBits(image, NULL, (void **)ctx->dstBuff, ctx->dstBuffPitches);
|
||||
NvMediaImageUnlock(image);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaVideoSurfaceGetBits() failed \n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static NvMediaStatus ReadImageNew(char *fileName,
|
||||
uint32_t frameNum,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
NvMediaImage *image,
|
||||
NvMediaBool uvOrderFlag,
|
||||
uint32_t bytesPerPixel,
|
||||
uint32_t pixelAlignment)
|
||||
{
|
||||
uint8_t **pBuff = NULL;
|
||||
uint32_t *pBuffPitches = NULL;
|
||||
uint32_t imageSize = 0, surfaceSize = 0;
|
||||
uint8_t *buffer = NULL;
|
||||
uint8_t *pBuffer = NULL;
|
||||
uint32_t i, j, k, newk = 0;
|
||||
float *xScalePtr = NULL, *yScalePtr = NULL;
|
||||
unsigned int *bytePerPixelPtr = NULL;
|
||||
uint32_t numSurfaces = 1;
|
||||
unsigned int uHeightSurface, uWidthSurface;
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_ERROR;
|
||||
FILE *file = NULL;
|
||||
unsigned int count, index;
|
||||
NVM_SURF_FMT_DEFINE_ATTR(srcAttr);
|
||||
unsigned int surfType, surfBPC;
|
||||
|
||||
if (!image || !fileName) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock() failed\n", __func__);
|
||||
return status;
|
||||
}
|
||||
NvMediaImageUnlock(image);
|
||||
|
||||
uHeightSurface = surfaceMap.height;
|
||||
uWidthSurface = surfaceMap.width;
|
||||
|
||||
if (width > uWidthSurface || height > uHeightSurface) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
pBuff = (uint8_t **)malloc(sizeof(uint8_t *) * MAXM_NUM_SURFACES);
|
||||
if (!pBuff) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pBuffPitches = (uint32_t *)calloc(1, sizeof(uint32_t) * MAXM_NUM_SURFACES);
|
||||
if (!pBuffPitches) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = GetSurfParams(image->type, &xScalePtr, &yScalePtr, &bytePerPixelPtr, &numSurfaces);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: GetSurfParams() failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = NvMediaSurfaceFormatGetAttrs(image->type, srcAttr, NVM_SURF_FMT_ATTR_MAX);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s:NvMediaSurfaceFormatGetAttrs failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
surfType = srcAttr[NVM_SURF_ATTR_SURF_TYPE].value;
|
||||
surfBPC = srcAttr[NVM_SURF_ATTR_BITS_PER_COMPONENT].value;
|
||||
|
||||
surfaceSize = 0;
|
||||
imageSize = 0;
|
||||
for (i = 0; i < numSurfaces; i++) {
|
||||
surfaceSize += (uWidthSurface * xScalePtr[i] * uHeightSurface * yScalePtr[i] * bytePerPixelPtr[i]);
|
||||
imageSize += (width * xScalePtr[i] * height * yScalePtr[i] * bytePerPixelPtr[i]);
|
||||
pBuffPitches[i] = (uint32_t)((float)uWidthSurface * xScalePtr[i]) * bytePerPixelPtr[i];
|
||||
}
|
||||
|
||||
buffer = (uint8_t *)calloc(1, surfaceSize);
|
||||
if (!buffer) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pBuffer = buffer;
|
||||
memset(buffer, 0x10, surfaceSize);
|
||||
for (i = 0; i < numSurfaces; i++) {
|
||||
pBuff[i] = buffer;
|
||||
if (i) {
|
||||
memset(pBuff[i], 0x80, (uHeightSurface * yScalePtr[i] * pBuffPitches[i]));
|
||||
}
|
||||
buffer = buffer + (uint32_t)(uHeightSurface * yScalePtr[i] * pBuffPitches[i]);
|
||||
}
|
||||
|
||||
file = fopen(fileName, "rb");
|
||||
if (!file) {
|
||||
printf("%s: Error opening file: %s\n", __func__, fileName);
|
||||
status = NVMEDIA_STATUS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (frameNum > 0) {
|
||||
if (fseeko(file, frameNum * (off_t)imageSize, SEEK_SET)) {
|
||||
printf("ReadImage: Error seeking file: %s\n", fileName);
|
||||
status = NVMEDIA_STATUS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if ((surfType == NVM_SURF_ATTR_SURF_TYPE_RGBA) && strstr(fileName, ".png")) {
|
||||
printf("ReadImage: Does not support png format\n");
|
||||
status = NVMEDIA_STATUS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
for (k = 0; k < numSurfaces; k++) {
|
||||
for (j = 0; j < height * yScalePtr[k]; j++) {
|
||||
newk = (!uvOrderFlag && k) ? (numSurfaces - k) : k;
|
||||
index = j * pBuffPitches[newk];
|
||||
count = width * xScalePtr[newk] * bytePerPixelPtr[newk];
|
||||
if (fread(pBuff[newk] + index, count, 1, file) != 1) {
|
||||
status = NVMEDIA_STATUS_ERROR;
|
||||
printf("ReadImage: Error reading file: %s\n", fileName);
|
||||
goto done;
|
||||
}
|
||||
if ((surfType == NVM_SURF_ATTR_SURF_TYPE_YUV) && (pixelAlignment == LSB_ALIGNED)) {
|
||||
uint16_t *psrc = (uint16_t *)(pBuff[newk] + index);
|
||||
switch (surfBPC) {
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_10:
|
||||
for (i = 0; i < count / 2; i++) {
|
||||
*(psrc + i) = (*(psrc + i)) << (16 - 10);
|
||||
}
|
||||
break;
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_12:
|
||||
for (i = 0; i < count / 2; i++) {
|
||||
*(psrc + i) = (*(psrc + i)) << (16 - 12);
|
||||
}
|
||||
break;
|
||||
case NVM_SURF_ATTR_BITS_PER_COMPONENT_14:
|
||||
for (i = 0; i < count / 2; i++) {
|
||||
*(psrc + i) = (*(psrc + i)) << (16 - 14);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock() failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
status = NvMediaImagePutBits(image, NULL, (void **)pBuff, pBuffPitches);
|
||||
NvMediaImageUnlock(image);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: Failed to put bits\n", __func__);
|
||||
}
|
||||
|
||||
done:
|
||||
if (pBuff) {
|
||||
free(pBuff);
|
||||
}
|
||||
|
||||
if (pBuffPitches) {
|
||||
free(pBuffPitches);
|
||||
}
|
||||
|
||||
if (pBuffer) {
|
||||
free(pBuffer);
|
||||
}
|
||||
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NvMediaStatus ReadImage(char *fileName,
|
||||
uint32_t frameNum,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
NvMediaImage *image,
|
||||
NvMediaBool uvOrderFlag,
|
||||
uint32_t bytesPerPixel,
|
||||
uint32_t pixelAlignment)
|
||||
{
|
||||
NvMediaStatus status;
|
||||
NVM_SURF_FMT_DEFINE_ATTR(srcAttr);
|
||||
|
||||
status = NvMediaSurfaceFormatGetAttrs(image->type, srcAttr, NVM_SURF_FMT_ATTR_MAX);
|
||||
if (status == NVMEDIA_STATUS_OK) {
|
||||
return ReadImageNew(fileName, frameNum, width, height, image, uvOrderFlag, bytesPerPixel, pixelAlignment);
|
||||
}
|
||||
else {
|
||||
printf("%s:NvMediaSurfaceFormatGetAttrs failed\n", __func__);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
NvMediaStatus InitImage(NvMediaImage *image, uint32_t width, uint32_t height)
|
||||
{
|
||||
uint8_t **pBuff = NULL;
|
||||
uint32_t *pBuffPitches = NULL;
|
||||
uint32_t imageSize = 0, surfaceSize = 0;
|
||||
uint8_t *buffer = NULL;
|
||||
uint8_t *pBuffer = NULL;
|
||||
float *xScalePtr = NULL, *yScalePtr = NULL;
|
||||
unsigned int *bytePerPixelPtr = NULL;
|
||||
uint32_t numSurfaces = 1;
|
||||
uint32_t i;
|
||||
unsigned int uHeightSurface, uWidthSurface;
|
||||
NvMediaImageSurfaceMap surfaceMap;
|
||||
NvMediaStatus status = NVMEDIA_STATUS_ERROR;
|
||||
NVM_SURF_FMT_DEFINE_ATTR(srcAttr);
|
||||
|
||||
if (!image) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock failed\n", __func__);
|
||||
return status;
|
||||
}
|
||||
NvMediaImageUnlock(image);
|
||||
|
||||
|
||||
uHeightSurface = surfaceMap.height;
|
||||
uWidthSurface = surfaceMap.width;
|
||||
|
||||
if (width > uWidthSurface || height > uHeightSurface) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
pBuff = (uint8_t **)calloc(1, sizeof(uint8_t *) * MAXM_NUM_SURFACES);
|
||||
if (!pBuff) {
|
||||
printf("%s: out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pBuffPitches = (uint32_t *)calloc(1, sizeof(uint32_t) * MAXM_NUM_SURFACES);
|
||||
if (!pBuffPitches) {
|
||||
printf("%s: out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = GetSurfParams(image->type, &xScalePtr, &yScalePtr, &bytePerPixelPtr, &numSurfaces);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: GetSurfParams failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = NvMediaSurfaceFormatGetAttrs(image->type, srcAttr, NVM_SURF_FMT_ATTR_MAX);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaSurfaceFormatGetAttrs failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
surfaceSize = 0;
|
||||
imageSize = 0;
|
||||
for (i = 0; i < numSurfaces; i++) {
|
||||
surfaceSize += (uWidthSurface * xScalePtr[i] * uHeightSurface * yScalePtr[i] * bytePerPixelPtr[i]);
|
||||
imageSize += (width * xScalePtr[i] * height * yScalePtr[i] * bytePerPixelPtr[i]);
|
||||
pBuffPitches[i] = (uint32_t)((float)uWidthSurface * xScalePtr[i]) * bytePerPixelPtr[i];
|
||||
}
|
||||
|
||||
buffer = (uint8_t *)calloc(1, surfaceSize);
|
||||
if (!buffer) {
|
||||
printf("%s: out of memory\n", __func__);
|
||||
status = NVMEDIA_STATUS_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pBuffer = buffer;
|
||||
memset(buffer, 0x00, surfaceSize);
|
||||
for (i = 0; i < numSurfaces; i++) {
|
||||
pBuff[i] = buffer;
|
||||
buffer = buffer + (uint32_t)(uHeightSurface * yScalePtr[i] * pBuffPitches[i]);
|
||||
}
|
||||
|
||||
status = NvMediaImageLock(image, NVMEDIA_IMAGE_ACCESS_WRITE, &surfaceMap);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImageLock failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
status = NvMediaImagePutBits(image, NULL, (void **)pBuff, pBuffPitches);
|
||||
NvMediaImageUnlock(image);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMediaImagePutBits failed\n", __func__);
|
||||
}
|
||||
|
||||
done:
|
||||
if (pBuff) {
|
||||
free(pBuff);
|
||||
}
|
||||
|
||||
if (pBuffPitches) {
|
||||
free(pBuffPitches);
|
||||
}
|
||||
|
||||
if (pBuffer) {
|
||||
free(pBuffer);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef _NVMEDIA_TEST_IMAGE_UTILS_H_
|
||||
#define _NVMEDIA_TEST_IMAGE_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "cmdline.h"
|
||||
#include "misc_utils.h"
|
||||
#include "nvmedia_core.h"
|
||||
#include "nvmedia_image.h"
|
||||
#include "nvmedia_surface.h"
|
||||
|
||||
#if (NV_IS_SAFETY == 1)
|
||||
#include "nvmedia_image_internal.h"
|
||||
#endif
|
||||
|
||||
#define PACK_RGBA(R, G, B, A) (((uint32_t)(A) << 24) | ((uint32_t)(B) << 16) | ((uint32_t)(G) << 8) | (uint32_t)(R))
|
||||
#define DEFAULT_ALPHA 0x80
|
||||
|
||||
|
||||
// ReadImage
|
||||
//
|
||||
// ReadImage() Read image from file
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// filename
|
||||
// (in) Input file name
|
||||
//
|
||||
// frameNum
|
||||
// (in) Frame number to read. Use for stream input files.
|
||||
//
|
||||
// width
|
||||
// (in) Surface width
|
||||
//
|
||||
// height
|
||||
// (in) Surface height
|
||||
//
|
||||
// image
|
||||
// (out) Pointer to pre-allocated output surface
|
||||
//
|
||||
// uvOrderFlag
|
||||
// (in) Flag for UV order. If true - UV; If false - VU;
|
||||
//
|
||||
// bytesPerPixel
|
||||
// (in) Bytes per pixel. Nedded for RAW image types handling.
|
||||
// RAW8 - 1 byte per pixel
|
||||
// RAW10, RAW12, RAW14 - 2 bytes per pixel
|
||||
//
|
||||
// pixelAlignment
|
||||
// (in) Alignment of bits in pixel.
|
||||
// 0 - LSB Aligned
|
||||
// 1 - MSB Aligned
|
||||
|
||||
NvMediaStatus ReadImage(char *fileName,
|
||||
uint32_t frameNum,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
NvMediaImage *image,
|
||||
NvMediaBool uvOrderFlag,
|
||||
uint32_t bytesPerPixel,
|
||||
uint32_t pixelAlignment);
|
||||
|
||||
// InitImage
|
||||
//
|
||||
// InitImage() Init image data to zeros
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// image
|
||||
// (in) image to initialize
|
||||
//
|
||||
// width
|
||||
// (in) Surface width
|
||||
//
|
||||
// height
|
||||
// (in) Surface height
|
||||
|
||||
NvMediaStatus InitImage(NvMediaImage *image, uint32_t width, uint32_t height);
|
||||
|
||||
NvMediaStatus
|
||||
AllocateBufferToWriteImage(Blit2DTest *ctx, NvMediaImage *image, NvMediaBool uvOrderFlag, NvMediaBool appendFlag);
|
||||
|
||||
// WriteImageToBuffer
|
||||
//
|
||||
// WriteImageToBuffer() Save RGB or YUV image
|
||||
//
|
||||
NvMediaStatus WriteImageToAllocatedBuffer(Blit2DTest *ctx,
|
||||
NvMediaImage *image,
|
||||
NvMediaBool uvOrderFlag,
|
||||
NvMediaBool appendFlag,
|
||||
uint32_t bytesPerPixel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NVMEDIA_TEST_IMAGE_UTILS_H_ */
|
||||
@@ -0,0 +1,154 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef NVMEDIA_ANDROID
|
||||
#define LOG_TAG "nvmedia_common"
|
||||
#define LOG_NDEBUG 1
|
||||
#include <utils/Log.h>
|
||||
#endif
|
||||
#ifdef NVMEDIA_QNX
|
||||
#include <sys/slog.h>
|
||||
#endif
|
||||
|
||||
#include "log_utils.h"
|
||||
|
||||
#ifdef NVMEDIA_QNX
|
||||
#define NV_SLOGCODE 0xAAAA
|
||||
#endif
|
||||
#define MAX_STATS_LEN 500
|
||||
|
||||
#define LOG_BUFFER_BYTES 1024
|
||||
|
||||
static enum LogLevel msg_level = LEVEL_ERR;
|
||||
static enum LogStyle msg_style = LOG_STYLE_NORMAL;
|
||||
static FILE *msg_file = NULL;
|
||||
|
||||
void SetLogLevel(enum LogLevel level)
|
||||
{
|
||||
if (level > LEVEL_DBG)
|
||||
return;
|
||||
|
||||
msg_level = level;
|
||||
}
|
||||
|
||||
void SetLogStyle(enum LogStyle style)
|
||||
{
|
||||
if (style > LOG_STYLE_FUNCTION_LINE)
|
||||
return;
|
||||
|
||||
msg_style = style;
|
||||
}
|
||||
|
||||
void SetLogFile(FILE *logFileHandle)
|
||||
{
|
||||
if (!logFileHandle)
|
||||
return;
|
||||
|
||||
msg_file = logFileHandle;
|
||||
}
|
||||
|
||||
void LogLevelMessage(enum LogLevel level, const char *functionName, int lineNumber, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char str[LOG_BUFFER_BYTES] = {
|
||||
'\0',
|
||||
};
|
||||
FILE *logFile = msg_file ? msg_file : stdout;
|
||||
|
||||
if (level > msg_level)
|
||||
return;
|
||||
|
||||
#ifndef NVMEDIA_ANDROID
|
||||
/** In the case of Android ADB log, if LOG_TAG is defined,
|
||||
* before 'Log.h' is included in source file,
|
||||
* LOG_TAG is automatically concatenated at the beginning of log message,
|
||||
* so, we don't copy 'nvmedia: ' into 'str'.
|
||||
*/
|
||||
strcpy(str, "nvmedia: ");
|
||||
|
||||
/** As LOG_TAG is concatednated, log level is also automatically concatenated,
|
||||
* by calling different ADB log function such as ALOGE(for eror log message),
|
||||
* ALOGW(for warning log message).
|
||||
*/
|
||||
switch (level) {
|
||||
case LEVEL_ERR:
|
||||
strcat(str, "ERROR: ");
|
||||
break;
|
||||
case LEVEL_WARN:
|
||||
strcat(str, "WARNING: ");
|
||||
break;
|
||||
case LEVEL_INFO:
|
||||
case LEVEL_DBG:
|
||||
// Empty
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(str + strlen(str), sizeof(str) - strlen(str), format, ap);
|
||||
|
||||
if (msg_style == LOG_STYLE_NORMAL) {
|
||||
// Add trailing new line char
|
||||
if (strlen(str) && str[strlen(str) - 1] != '\n')
|
||||
strcat(str, "\n");
|
||||
}
|
||||
else if (msg_style == LOG_STYLE_FUNCTION_LINE) {
|
||||
// Remove trailing new line char
|
||||
if (strlen(str) && str[strlen(str) - 1] == '\n')
|
||||
str[strlen(str) - 1] = 0;
|
||||
|
||||
// Add function and line info
|
||||
snprintf(str + +strlen(str), sizeof(str) - strlen(str), " at %s():%d\n", functionName, lineNumber);
|
||||
}
|
||||
|
||||
#ifdef NVMEDIA_ANDROID
|
||||
switch (msg_level) {
|
||||
case LEVEL_ERR:
|
||||
ALOGE("%s", str);
|
||||
break;
|
||||
case LEVEL_WARN:
|
||||
ALOGW("%s", str);
|
||||
break;
|
||||
case LEVEL_INFO:
|
||||
ALOGI("%s", str);
|
||||
break;
|
||||
case LEVEL_DBG:
|
||||
ALOGD("%s", str);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
fprintf(logFile, "%s", str);
|
||||
#endif
|
||||
#ifdef NVMEDIA_QNX
|
||||
/* send to system logger */
|
||||
slogf(_SLOG_SETCODE(NV_SLOGCODE, 0), _SLOG_ERROR, str);
|
||||
#endif
|
||||
va_end(ap);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef _NVMEDIA_TEST_LOG_UTILS_H_
|
||||
#define _NVMEDIA_TEST_LOG_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
enum LogLevel {
|
||||
LEVEL_ERR = 0,
|
||||
LEVEL_WARN = 1,
|
||||
LEVEL_INFO = 2,
|
||||
LEVEL_DBG = 3,
|
||||
};
|
||||
|
||||
enum LogStyle { LOG_STYLE_NORMAL = 0, LOG_STYLE_FUNCTION_LINE };
|
||||
|
||||
#define LINE_INFO __FUNCTION__, __LINE__
|
||||
#define LOG_DBG(...) LogLevelMessage(LEVEL_DBG, LINE_INFO, __VA_ARGS__)
|
||||
#define LOG_INFO(...) LogLevelMessage(LEVEL_INFO, LINE_INFO, __VA_ARGS__)
|
||||
#define LOG_WARN(...) LogLevelMessage(LEVEL_WARN, LINE_INFO, __VA_ARGS__)
|
||||
|
||||
// SetLogLevel
|
||||
//
|
||||
// SetLogLevel() Set logging level
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// level
|
||||
// (in) Logging level
|
||||
|
||||
void SetLogLevel(enum LogLevel level);
|
||||
|
||||
// SetLogStyle
|
||||
//
|
||||
// SetLogStyle() Set logging print slyle
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// level
|
||||
// (in) Logging style
|
||||
|
||||
void SetLogStyle(enum LogStyle style);
|
||||
|
||||
// SetLogFile
|
||||
//
|
||||
// SetLogFile() Set logging file handle
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// level
|
||||
// (in) Logging file handle
|
||||
|
||||
void SetLogFile(FILE *logFileHandle);
|
||||
|
||||
// LogLevelMessage
|
||||
//
|
||||
// LogLevelMessage() Print message if logging level is higher than message level
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// LogLevel
|
||||
// (in) Message level
|
||||
//
|
||||
// format
|
||||
// (in) Message format
|
||||
//
|
||||
// ...
|
||||
// (in) Parameters list
|
||||
|
||||
void LogLevelMessage(enum LogLevel level, const char *functionName, int lineNumber, const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NVMEDIA_TEST_LOG_UTILS_H_ */
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__QNX__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include "misc_utils.h"
|
||||
|
||||
uint32_t u32(const uint8_t *ptr) { return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); }
|
||||
|
||||
NvMediaStatus GetTimeMicroSec(uint64_t *uTime)
|
||||
{
|
||||
struct timespec t;
|
||||
#if !(defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 && _POSIX_TIMERS > 0)
|
||||
struct timeval tv;
|
||||
#endif
|
||||
|
||||
if (!uTime)
|
||||
return NVMEDIA_STATUS_BAD_PARAMETER;
|
||||
|
||||
#if !(defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 && _POSIX_TIMERS > 0)
|
||||
gettimeofday(&tv, NULL);
|
||||
t.tv_sec = tv.tv_sec;
|
||||
t.tv_nsec = tv.tv_usec * 1000L;
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
#endif
|
||||
|
||||
*uTime = (uint64_t)t.tv_sec * 1000000LL + (uint64_t)t.tv_nsec / 1000LL;
|
||||
return NVMEDIA_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef _NVMEDIA_TEST_MISC_UTILS_H_
|
||||
#define _NVMEDIA_TEST_MISC_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "nvmedia_common.h"
|
||||
#include "nvmedia_core.h"
|
||||
|
||||
#ifndef __INTEGRITY
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
typedef enum { LSB_ALIGNED, MSB_ALIGNED } PixelAlignment;
|
||||
|
||||
|
||||
// u32
|
||||
//
|
||||
// u32() Reads 4 bytes from buffer and returns the read value
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// ptr
|
||||
// (in) Input buffer
|
||||
|
||||
uint32_t u32(const uint8_t *ptr);
|
||||
|
||||
// GetTimeMicroSec
|
||||
//
|
||||
// GetTimeMicroSec() Returns current time in microseconds
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// uTime
|
||||
// (out) Pointer to current time in microseconds
|
||||
|
||||
NvMediaStatus GetTimeMicroSec(uint64_t *uTime);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NVMEDIA_TEST_MISC_UTILS_H_ */
|
||||
154
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/nvsci_setup.cpp
Normal file
154
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/nvsci_setup.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include "nvsci_setup.h"
|
||||
|
||||
#include <cuda.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "helper_cuda.h"
|
||||
#include "nvmedia_2d_nvscisync.h"
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
|
||||
#define checkNvSciErrors(call) \
|
||||
do { \
|
||||
NvSciError _status = call; \
|
||||
if (NvSciError_Success != _status) { \
|
||||
printf("NVSCI call in file '%s' in line %i returned" \
|
||||
" %d, expected %d\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
_status, \
|
||||
NvSciError_Success); \
|
||||
fflush(stdout); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void setupNvMediaSignalerNvSciSync(Blit2DTest *ctx, NvSciSyncObj &syncObj, int cudaDeviceId)
|
||||
{
|
||||
NvSciSyncModule sciSyncModule;
|
||||
checkNvSciErrors(NvSciSyncModuleOpen(&sciSyncModule));
|
||||
NvSciSyncAttrList signalerAttrList, waiterAttrList;
|
||||
NvSciSyncAttrList syncUnreconciledList[2];
|
||||
NvSciSyncAttrList syncReconciledList, syncConflictList;
|
||||
|
||||
checkNvSciErrors(NvSciSyncAttrListCreate(sciSyncModule, &signalerAttrList));
|
||||
checkNvSciErrors(NvSciSyncAttrListCreate(sciSyncModule, &waiterAttrList));
|
||||
|
||||
NvMediaStatus status = NvMedia2DFillNvSciSyncAttrList(ctx->i2d, signalerAttrList, NVMEDIA_SIGNALER);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DFillNvSciSyncAttrList failed\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaSetDevice(cudaDeviceId));
|
||||
checkCudaErrors(cudaDeviceGetNvSciSyncAttributes(waiterAttrList, cudaDeviceId, cudaNvSciSyncAttrWait));
|
||||
|
||||
syncUnreconciledList[0] = signalerAttrList;
|
||||
syncUnreconciledList[1] = waiterAttrList;
|
||||
checkNvSciErrors(NvSciSyncAttrListReconcile(syncUnreconciledList, 2, &syncReconciledList, &syncConflictList));
|
||||
checkNvSciErrors(NvSciSyncObjAlloc(syncReconciledList, &syncObj));
|
||||
|
||||
NvSciSyncAttrListFree(signalerAttrList);
|
||||
NvSciSyncAttrListFree(waiterAttrList);
|
||||
if (syncConflictList != nullptr) {
|
||||
NvSciSyncAttrListFree(syncConflictList);
|
||||
}
|
||||
}
|
||||
|
||||
void setupCudaSignalerNvSciSync(Blit2DTest *ctx, NvSciSyncObj &syncObj, int cudaDeviceId)
|
||||
{
|
||||
NvSciSyncModule sciSyncModule;
|
||||
checkNvSciErrors(NvSciSyncModuleOpen(&sciSyncModule));
|
||||
NvSciSyncAttrList signalerAttrList, waiterAttrList;
|
||||
NvSciSyncAttrList syncUnreconciledList[2];
|
||||
NvSciSyncAttrList syncReconciledList, syncConflictList;
|
||||
|
||||
checkNvSciErrors(NvSciSyncAttrListCreate(sciSyncModule, &signalerAttrList));
|
||||
checkNvSciErrors(NvSciSyncAttrListCreate(sciSyncModule, &waiterAttrList));
|
||||
|
||||
NvMediaStatus status = NvMedia2DFillNvSciSyncAttrList(ctx->i2d, waiterAttrList, NVMEDIA_WAITER);
|
||||
if (status != NVMEDIA_STATUS_OK) {
|
||||
printf("%s: NvMedia2DFillNvSciSyncAttrList failed\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaSetDevice(cudaDeviceId));
|
||||
checkCudaErrors(cudaDeviceGetNvSciSyncAttributes(signalerAttrList, cudaDeviceId, cudaNvSciSyncAttrSignal));
|
||||
|
||||
syncUnreconciledList[0] = signalerAttrList;
|
||||
syncUnreconciledList[1] = waiterAttrList;
|
||||
checkNvSciErrors(NvSciSyncAttrListReconcile(syncUnreconciledList, 2, &syncReconciledList, &syncConflictList));
|
||||
checkNvSciErrors(NvSciSyncObjAlloc(syncReconciledList, &syncObj));
|
||||
|
||||
NvSciSyncAttrListFree(signalerAttrList);
|
||||
NvSciSyncAttrListFree(waiterAttrList);
|
||||
if (syncConflictList != nullptr) {
|
||||
NvSciSyncAttrListFree(syncConflictList);
|
||||
}
|
||||
}
|
||||
|
||||
void setupNvSciBuf(NvSciBufObj &bufobj, NvSciBufAttrList &nvmediaAttrlist, int cudaDeviceId)
|
||||
{
|
||||
CUuuid devUUID;
|
||||
NvSciBufAttrList conflictlist;
|
||||
NvSciBufAttrList bufUnreconciledAttrlist[1];
|
||||
|
||||
CUresult res = cuDeviceGetUuid(&devUUID, cudaDeviceId);
|
||||
if (res != CUDA_SUCCESS) {
|
||||
fprintf(stderr, "Driver API error = %04d \n", res);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
NvSciBufAttrKeyValuePair attr_gpuid[] = {NvSciBufGeneralAttrKey_GpuId, &devUUID, sizeof(devUUID)};
|
||||
|
||||
// set CUDA GPU ID to attribute list
|
||||
checkNvSciErrors(
|
||||
NvSciBufAttrListSetAttrs(nvmediaAttrlist, attr_gpuid, sizeof(attr_gpuid) / sizeof(NvSciBufAttrKeyValuePair)));
|
||||
|
||||
bufUnreconciledAttrlist[0] = nvmediaAttrlist;
|
||||
|
||||
checkNvSciErrors(NvSciBufAttrListReconcileAndObjAlloc(bufUnreconciledAttrlist, 1, &bufobj, &conflictlist));
|
||||
if (conflictlist != NULL) {
|
||||
NvSciBufAttrListFree(conflictlist);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupNvSciBuf(NvSciBufObj &Bufobj)
|
||||
{
|
||||
if (Bufobj != NULL) {
|
||||
NvSciBufObjFree(Bufobj);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupNvSciSync(NvSciSyncObj &syncObj)
|
||||
{
|
||||
if (NvSciSyncObjFree != NULL) {
|
||||
NvSciSyncObjFree(syncObj);
|
||||
}
|
||||
}
|
||||
40
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/nvsci_setup.h
Normal file
40
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/nvsci_setup.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __NVSCI_SETUP_H__
|
||||
#define __NVSCI_SETUP_H__
|
||||
#include <nvscibuf.h>
|
||||
#include <nvscisync.h>
|
||||
|
||||
#include "nvmedia_utils/cmdline.h"
|
||||
|
||||
void setupNvMediaSignalerNvSciSync(Blit2DTest *ctx, NvSciSyncObj &syncObj, int cudaDeviceId);
|
||||
void setupCudaSignalerNvSciSync(Blit2DTest *ctx, NvSciSyncObj &syncObj, int cudaDeviceId);
|
||||
void setupNvSciBuf(NvSciBufObj &bufobj, NvSciBufAttrList &nvmediaAttrlist, int cudaDeviceId);
|
||||
void cleanupNvSciBuf(NvSciBufObj &Bufobj);
|
||||
void cleanupNvSciSync(NvSciSyncObj &syncObj);
|
||||
#endif
|
||||
198
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/sample.cfg
Normal file
198
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/sample.cfg
Normal file
@@ -0,0 +1,198 @@
|
||||
###################################################################################################
|
||||
#
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All Rights Reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto. Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
||||
#
|
||||
# 2D configuration file for nvimg_2d application.
|
||||
#
|
||||
# Plese see nvmedia_2d.h for detailed information about parameters and datatypes
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
|
||||
###################################################################################################
|
||||
# Top level application parameters
|
||||
#
|
||||
# inputFile name limited to 1024 chars
|
||||
inputfile = "teapot.rgba"
|
||||
|
||||
|
||||
# The following bit-masks can be ORed:
|
||||
# 1 => If the user wants to enable Filtering mode
|
||||
# 2 => Reserved for future use
|
||||
# 4 => If the user wants to enable Transformation mode
|
||||
# 8 => If the user wants to enable color space conversion standard
|
||||
validOperations = 0
|
||||
|
||||
# Transformation Mode for Blit2D
|
||||
# 0 => IDENTITY
|
||||
# 1 => ROTATE_90
|
||||
# 2 => ROTATE_180
|
||||
# 3 => ROTATE_270
|
||||
# 4 => FLIP_HORIZONTAL
|
||||
# 5 => INV_TRANSPOSE
|
||||
# 6 => FLIP_VERTICAL
|
||||
# 7 => TRANSPOSE
|
||||
transformMode = 0
|
||||
|
||||
# Filtering mode for Blit2D
|
||||
# 1 => FILTER_OFF
|
||||
# 2 => FILTER_LOW
|
||||
# 3 => FILTER_MEDIUM
|
||||
# 4 => FILTER_HIGH
|
||||
filterMode = 1
|
||||
|
||||
# color space conversion standard
|
||||
# 0 => ITU BT.601
|
||||
# 1 => ITU BT.709
|
||||
# 2 => SMTE 240M
|
||||
# 3 => BT.601 Extended Range
|
||||
colorStd = 0
|
||||
|
||||
####################### source image properties##########################
|
||||
srcWidth = 1024
|
||||
srcHeight = 1024
|
||||
# 1 => Uncached (mapped) access type flag
|
||||
# 2 => Cached (mapped) access type flag
|
||||
# 3 => Unmapped access type flag
|
||||
srcCPUAccess = 3
|
||||
# Allocation type
|
||||
# 0 => none
|
||||
# 1 => isochronous
|
||||
srcAllocType = 1
|
||||
# Surface scan type
|
||||
# Only progressive scan is supported
|
||||
# 1 => Progressive
|
||||
srcScanType = 1
|
||||
# Color Standard type
|
||||
# 1 => sRGB
|
||||
# 2 => YCbCr Rec.601 (Studio Range)
|
||||
# 3 => YCbCr Rec.601 (Extended Range)
|
||||
# 4 => YCbCr Rec.709 (Studio Range)
|
||||
# 5 => YCbCr Rec.709 (Extended Range)
|
||||
# 11 => Sensor RGBA
|
||||
srcColorStd = 1
|
||||
|
||||
# 1 => YUV
|
||||
# 2 => RGBA
|
||||
# 3 => RAW
|
||||
srcSurfType = 2
|
||||
# 1 => Block Linear
|
||||
# 2 => Pitch Linear
|
||||
srcLayout = 2
|
||||
# 1 => uint
|
||||
# 2 => int
|
||||
srcDataType = 1
|
||||
# 1 => planar
|
||||
# 2 => Semi Planar
|
||||
# 3 => Packed
|
||||
srcMemory = 3
|
||||
# Sub-Sampling type of the input surface
|
||||
# 1 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_420
|
||||
# 2 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_422
|
||||
# 3 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_444
|
||||
# 4 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_422R
|
||||
# 0 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_NONE
|
||||
srcSubSamplingType = 0
|
||||
# Bits per component of the input surface
|
||||
# 1 => NVM_SURF_ATTR_BITS_PER_COMPONENT_8
|
||||
# 2 => NVM_SURF_ATTR_BITS_PER_COMPONENT_10
|
||||
# 3 => NVM_SURF_ATTR_BITS_PER_COMPONENT_12
|
||||
# 5 => NVM_SURF_ATTR_BITS_PER_COMPONENT_16
|
||||
srcBitsPerComponent = 1
|
||||
# 1 => NVM_SURF_ATTR_COMPONENT_ORDER_LUMA
|
||||
# 2 => NVM_SURF_ATTR_COMPONENT_ORDER_YUV
|
||||
# 3 => NVM_SURF_ATTR_COMPONENT_ORDER_YVU
|
||||
# 4 => NVM_SURF_ATTR_COMPONENT_ORDER_YUYV
|
||||
# 5 => NVM_SURF_ATTR_COMPONENT_ORDER_YVYU
|
||||
# 6 => NVM_SURF_ATTR_COMPONENT_ORDER_VYUY
|
||||
# 10 => NVM_SURF_ATTR_COMPONENT_ORDER_VUYX
|
||||
# 18 => NVM_SURF_ATTR_COMPONENT_ORDER_RGBA
|
||||
# 20 => NVM_SURF_ATTR_COMPONENT_ORDER_BGRA
|
||||
srcComponentOrder = 18
|
||||
|
||||
# srcRect Structure containing co-ordinates of the rectangle in the source image.
|
||||
# Left X co-ordinate.
|
||||
srcRectx0 = 0
|
||||
# Top Y co-ordinate.
|
||||
srcRecty0 = 0
|
||||
# Right X co-ordinate.
|
||||
srcRectx1 = 1024
|
||||
# Bottom Y co-ordinate.
|
||||
srcRecty1 = 1024
|
||||
|
||||
####################### output image properties##########################
|
||||
dstWidth = 1024
|
||||
dstHeight = 1024
|
||||
# 1 => Uncached (mapped) access type flag
|
||||
# 2 => Cached (mapped) access type flag
|
||||
# 3 => Unmapped access type flag
|
||||
dstCPUAccess = 3
|
||||
# Allocation type
|
||||
# 0 => none
|
||||
# 1 => isochronous
|
||||
dstAllocType = 1
|
||||
# Surface scan type
|
||||
# Only progressive scan is supported
|
||||
# 1 => Progressive
|
||||
dstScanType = 1
|
||||
# Color Standard type
|
||||
# 1 => sRGB
|
||||
# 2 => YCbCr Rec.601 (Studio Range)
|
||||
# 3 => YCbCr Rec.601 (Extended Range)
|
||||
# 4 => YCbCr Rec.709 (Studio Range)
|
||||
# 5 => YCbCr Rec.709 (Extended Range)
|
||||
# 11 => Sensor RGBA
|
||||
dstColorStd = 2
|
||||
|
||||
# 1 => YUV
|
||||
# 2 => RGBA
|
||||
# 3 => RAW
|
||||
dstSurfType = 1
|
||||
# 1 => Block Linear
|
||||
# 2 => Pitch Linear
|
||||
dstLayout = 1
|
||||
# 1 => uint
|
||||
# 2 => int
|
||||
dstDataType = 1
|
||||
# 1 => planar
|
||||
# 2 => Semi Planar
|
||||
# 3 => Packed
|
||||
dstMemory = 1
|
||||
# Sub-Sampling type of the output surface
|
||||
# 1 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_420
|
||||
# 2 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_422
|
||||
# 3 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_444
|
||||
# 4 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_422R
|
||||
# 0 => NVM_SURF_ATTR_SUB_SAMPLING_TYPE_NONE
|
||||
dstSubSamplingType = 1
|
||||
# Bits per component of the output surface
|
||||
# 1 => NVM_SURF_ATTR_BITS_PER_COMPONENT_8
|
||||
# 2 => NVM_SURF_ATTR_BITS_PER_COMPONENT_10
|
||||
# 3 => NVM_SURF_ATTR_BITS_PER_COMPONENT_12
|
||||
# 5 => NVM_SURF_ATTR_BITS_PER_COMPONENT_16
|
||||
dstBitsPerComponent = 1
|
||||
# 1 => NVM_SURF_ATTR_COMPONENT_ORDER_LUMA
|
||||
# 2 => NVM_SURF_ATTR_COMPONENT_ORDER_YUV
|
||||
# 3 => NVM_SURF_ATTR_COMPONENT_ORDER_YVU
|
||||
# 4 => NVM_SURF_ATTR_COMPONENT_ORDER_YUYV
|
||||
# 5 => NVM_SURF_ATTR_COMPONENT_ORDER_YVYU
|
||||
# 6 => NVM_SURF_ATTR_COMPONENT_ORDER_VYUY
|
||||
# 10 => NVM_SURF_ATTR_COMPONENT_ORDER_VUYX
|
||||
# 18 => NVM_SURF_ATTR_COMPONENT_ORDER_RGBA
|
||||
# 20 => NVM_SURF_ATTR_COMPONENT_ORDER_BGRA
|
||||
dstComponentOrder = 2
|
||||
# dstRect Structure containing co-ordinates of the rectangle in the destination image.
|
||||
# Left X co-ordinate.
|
||||
dstRectx0 = 0
|
||||
# Top Y co-ordinate.
|
||||
dstRecty0 = 0
|
||||
# Right X co-ordinate.
|
||||
dstRectx1 = 1024
|
||||
# Bottom Y co-ordinate.
|
||||
dstRecty1 = 1024
|
||||
BIN
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/teapot.rgba
Normal file
BIN
cpp/8_Platform_Specific/Tegra/cudaNvSciNvMedia/teapot.rgba
Normal file
Binary file not shown.
18
cpp/8_Platform_Specific/Tegra/fluidsGLES/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/fluidsGLES/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/fluidsGLES/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/fluidsGLES/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
76
cpp/8_Platform_Specific/Tegra/fluidsGLES/CMakeLists.txt
Normal file
76
cpp/8_Platform_Specific/Tegra/fluidsGLES/CMakeLists.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(fluidsGLES LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(EGL)
|
||||
find_package(X11)
|
||||
find_package(OpenGL)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Source file
|
||||
if(${OpenGL_FOUND})
|
||||
if(${EGL_FOUND})
|
||||
if(${X11_FOUND})
|
||||
# Add target for fluidsGLES
|
||||
add_executable(fluidsGLES fluidsGLES.cpp fluidsGLES_kernels.cu)
|
||||
|
||||
target_compile_options(fluidsGLES PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(fluidsGLES PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(fluidsGLES PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(fluidsGLES PUBLIC
|
||||
${EGL_INCLUDE_DIR}
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(fluidsGLES
|
||||
CUDA::cuda_driver
|
||||
CUDA::cufft
|
||||
${EGL_LIBRARY}
|
||||
${X11_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
)
|
||||
|
||||
# Copy the .glsl files to the output directory
|
||||
add_custom_command(TARGET fluidsGLES POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mesh.frag.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mesh.vert.glsl
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
else()
|
||||
message(STATUS "X11 libraries not found - will not build sample 'fluidsGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "EGL not found - will not build sample 'fluidsGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenGL not found - will not build sample 'fluidsGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample fluidsGLES - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
36
cpp/8_Platform_Specific/Tegra/fluidsGLES/README.md
Normal file
36
cpp/8_Platform_Specific/Tegra/fluidsGLES/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# fluidsGLES - Fluids (OpenGLES Version)
|
||||
|
||||
## Description
|
||||
|
||||
An example of fluid simulation using CUDA and CUFFT, with OpenGLES rendering.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
Graphics Interop, CUFFT Library, Physically-Based Simulation
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
armv7l
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaGraphicsUnmapResources, cudaMemcpy, cudaMallocArray, cudaFreeArray, cudaFree, cudaMallocPitch, cudaGraphicsResourceGetMappedPointer, cudaGraphicsMapResources, cudaDestroyTextureObject, cudaCreateTextureObject, cudaGraphicsUnregisterResource, cudaMalloc, cudaGraphicsGLRegisterBuffer, cudaGetDeviceProperties
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[X11](../../../README.md#x11), [OpenGL ES](../../../README.md#opengl-es), [CUFFT](../../../README.md#cufft)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
BIN
cpp/8_Platform_Specific/Tegra/fluidsGLES/data/ref_fluidsGLES.ppm
Normal file
BIN
cpp/8_Platform_Specific/Tegra/fluidsGLES/data/ref_fluidsGLES.ppm
Normal file
Binary file not shown.
47
cpp/8_Platform_Specific/Tegra/fluidsGLES/defines.h
Normal file
47
cpp/8_Platform_Specific/Tegra/fluidsGLES/defines.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define DIM 512 // Square size of solver domain
|
||||
#define DS (DIM * DIM) // Total domain size
|
||||
#define CPADW (DIM / 2 + 1) // Padded width for real->complex in-place FFT
|
||||
#define RPADW (2 * (DIM / 2 + 1)) // Padded width for real->complex in-place FFT
|
||||
#define PDS (DIM * CPADW) // Padded total domain size
|
||||
|
||||
#define DT 0.09f // Delta T for interative solver
|
||||
#define VIS 0.0025f // Viscosity constant
|
||||
#define FORCE (5.8f * DIM) // Force scale factor
|
||||
#define FR 4 // Force update radius
|
||||
|
||||
#define TILEX 64 // Tile width
|
||||
#define TILEY 64 // Tile height
|
||||
#define TIDSX 64 // Tids in X
|
||||
#define TIDSY 4 // Tids in Y
|
||||
|
||||
#endif
|
||||
695
cpp/8_Platform_Specific/Tegra/fluidsGLES/fluidsGLES.cpp
Normal file
695
cpp/8_Platform_Specific/Tegra/fluidsGLES/fluidsGLES.cpp
Normal file
@@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Copyright 1993-2015 NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* Please refer to the NVIDIA end user license agreement (EULA) associated
|
||||
* with this source code for terms and conditions that govern your use of
|
||||
* this software. Any use, reproduction, disclosure, or distribution of
|
||||
* this software and related documentation outside the terms of the EULA
|
||||
* is strictly prohibited.
|
||||
*
|
||||
*/
|
||||
|
||||
// Includes
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void error_exit(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// GLES related includes and Xlib and EGL stuff
|
||||
#include "graphics_interface.h"
|
||||
|
||||
// CUDA standard includes
|
||||
#include <cuda_gl_interop.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
// CUDA FFT Libraries
|
||||
#include <cufft.h>
|
||||
|
||||
// CUDA helper functions
|
||||
#include <helper_cuda.h>
|
||||
#include <rendercheck_gles.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "fluidsGLES_kernels.h"
|
||||
#include "helper_functions.h"
|
||||
|
||||
typedef float matrix4[4][4];
|
||||
typedef float vector3[3];
|
||||
|
||||
#define MAX_EPSILON_ERROR 1.0f
|
||||
|
||||
const char *sSDKname = "fluidsGLES";
|
||||
// CUDA example code that implements the frequency space version of
|
||||
// Jos Stam's paper 'Stable Fluids' in 2D. This application uses the
|
||||
// CUDA FFT library (CUFFT) to perform velocity diffusion and to
|
||||
// force non-divergence in the velocity field at each time step. It uses
|
||||
// CUDA-OpenGLES interoperability to update the particle field directly
|
||||
// instead of doing a copy to system memory before drawing. Texture is
|
||||
// used for automatic bilinear interpolation at the velocity advection step.
|
||||
|
||||
void cleanup(void);
|
||||
void reshape(int x, int y);
|
||||
|
||||
// CUFFT plan handle
|
||||
cufftHandle planr2c;
|
||||
cufftHandle planc2r;
|
||||
static cData *vxfield = NULL;
|
||||
static cData *vyfield = NULL;
|
||||
|
||||
cData *hvfield = NULL;
|
||||
cData *dvfield = NULL;
|
||||
static int wWidth = MAX(512, DIM);
|
||||
static int wHeight = MAX(512, DIM);
|
||||
|
||||
static int clicked = 0;
|
||||
static int fpsCount = 0;
|
||||
static int fpsLimit = 1;
|
||||
StopWatchInterface *timer = NULL;
|
||||
|
||||
int gui_mode; // For X window
|
||||
// Rotate & translate variable temp., will remove and use shaders.
|
||||
float rotate_x = 0.0, rotate_y = 0.0;
|
||||
float translate_z = -3.0;
|
||||
|
||||
|
||||
// Particle data
|
||||
GLuint vbo = 0, vao = 0; // OpenGLES vertex buffer object
|
||||
GLuint m_texture = 0;
|
||||
struct cudaGraphicsResource *cuda_vbo_resource; // handles OpenGLES-CUDA exchange
|
||||
static cData *particles = NULL; // particle positions in host memory
|
||||
static int lastx = 0, lasty = 0;
|
||||
|
||||
// Texture pitch
|
||||
size_t tPitch = 0; // Now this is compatible with gcc in 64-bit
|
||||
|
||||
char *ref_file = NULL;
|
||||
bool g_bQAAddTestForce = true;
|
||||
int g_iFrameToCompare = 100;
|
||||
int g_TotalErrors = 0;
|
||||
|
||||
bool g_bExitESC = false;
|
||||
|
||||
const unsigned int window_width = 512;
|
||||
const unsigned int window_height = 512;
|
||||
|
||||
// CheckFBO/BackBuffer class objects
|
||||
CheckRender *g_CheckRender = NULL;
|
||||
|
||||
void autoTest(char **);
|
||||
void displayFrame();
|
||||
void keyboard(unsigned char key, int x, int y, int argc, char **argv);
|
||||
|
||||
extern "C" void addForces(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r);
|
||||
extern "C" void advectVelocity(cData *v, float *vx, float *vy, int dx, int pdx, int dy, float dt);
|
||||
extern "C" void diffuseProject(cData *vx, cData *vy, int dx, int dy, float dt, float visc);
|
||||
extern "C" void updateVelocity(cData *v, float *vx, float *vy, int dx, int pdx, int dy);
|
||||
extern "C" void advectParticles(GLuint vbo, cData *v, int dx, int dy, float dt);
|
||||
|
||||
void simulateFluids(void)
|
||||
{
|
||||
// simulate fluid
|
||||
advectVelocity(dvfield, (float *)vxfield, (float *)vyfield, DIM, RPADW, DIM, DT);
|
||||
diffuseProject(vxfield, vyfield, CPADW, DIM, DT, VIS);
|
||||
updateVelocity(dvfield, (float *)vxfield, (float *)vyfield, DIM, RPADW, DIM);
|
||||
advectParticles(vbo, dvfield, DIM, DIM, DT);
|
||||
}
|
||||
|
||||
GLuint mesh_shader = 0;
|
||||
|
||||
void mat_identity(matrix4 m)
|
||||
{
|
||||
m[0][1] = m[0][2] = m[0][3] = m[1][0] = m[1][2] = m[1][3] = m[2][0] = m[2][1] = m[2][3] = m[3][0] = m[3][1] =
|
||||
m[3][2] = 0.0f;
|
||||
|
||||
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void mat_multiply(matrix4 m0, matrix4 m1)
|
||||
{
|
||||
float m[4];
|
||||
for (int r = 0; r < 4; r++) {
|
||||
m[0] = m[1] = m[2] = m[3] = 0.0f;
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m[c] += m0[i][r] * m1[c][i];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < 4; c++) {
|
||||
m0[c][r] = m[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mat4f_Ortho(float left, float right, float bottom, float top, float near, float far, matrix4 m)
|
||||
{
|
||||
float r_l = right - left;
|
||||
float t_b = top - bottom;
|
||||
float f_n = far - near;
|
||||
float tx = -(right + left) / (right - left);
|
||||
float ty = -(top + bottom) / (top - bottom);
|
||||
float tz = -(far + near) / (far - near);
|
||||
|
||||
matrix4 m2;
|
||||
|
||||
m2[0][0] = 2.0f / r_l;
|
||||
m2[0][1] = 0.0f;
|
||||
m2[0][2] = 0.0f;
|
||||
m2[0][3] = 0.0f;
|
||||
|
||||
m2[1][0] = 0.0f;
|
||||
m2[1][1] = 2.0f / t_b;
|
||||
m2[1][2] = 0.0f;
|
||||
m2[1][3] = 0.0f;
|
||||
|
||||
m2[2][0] = 0.0f;
|
||||
m2[2][1] = 0.0f;
|
||||
m2[2][2] = -2.0f / f_n;
|
||||
m2[2][3] = 0.0f;
|
||||
|
||||
m2[3][0] = tx;
|
||||
m2[3][1] = ty;
|
||||
m2[3][2] = tz;
|
||||
m2[3][3] = 1.0f;
|
||||
|
||||
mat_multiply(m, m2);
|
||||
}
|
||||
|
||||
void readAndCompileShaderFromGLSLFile(GLuint new_shaderprogram, const char *filename, GLenum shaderType)
|
||||
{
|
||||
FILE *file = fopen(filename, "rb"); // open shader text file
|
||||
if (!file)
|
||||
error_exit("Filename %s does not exist\n", filename);
|
||||
|
||||
/* get the size of the file and read it */
|
||||
fseek(file, 0, SEEK_END);
|
||||
GLint size = ftell(file);
|
||||
char *data = (char *)malloc(sizeof(char) * (size + 1));
|
||||
memset(data, 0, sizeof(char) * (size + 1));
|
||||
fseek(file, 0, SEEK_SET);
|
||||
size_t res = fread(data, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
GLuint shader = glCreateShader(shaderType);
|
||||
glShaderSource(shader, 1, (const GLchar **)&data, &size);
|
||||
glCompileShader(shader);
|
||||
|
||||
GET_GLERROR(0);
|
||||
GLint compile_success = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_success);
|
||||
GET_GLERROR(0);
|
||||
|
||||
if (compile_success == GL_FALSE) {
|
||||
printf("Compilation of %s failed!\n Reason:\n", filename);
|
||||
|
||||
GLint maxLength = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
|
||||
char errorLog[maxLength];
|
||||
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
|
||||
|
||||
printf("%s", errorLog);
|
||||
|
||||
glDeleteShader(shader);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glAttachShader(new_shaderprogram, shader);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
GLuint ShaderCreate(const char *vshader_filename, const char *fshader_filename)
|
||||
{
|
||||
printf("Loading GLSL shaders %s %s\n", vshader_filename, fshader_filename);
|
||||
|
||||
GLuint new_shaderprogram = glCreateProgram();
|
||||
|
||||
GET_GLERROR(0);
|
||||
if (vshader_filename)
|
||||
readAndCompileShaderFromGLSLFile(new_shaderprogram, vshader_filename, GL_VERTEX_SHADER);
|
||||
|
||||
GET_GLERROR(0);
|
||||
if (fshader_filename)
|
||||
readAndCompileShaderFromGLSLFile(new_shaderprogram, fshader_filename, GL_FRAGMENT_SHADER);
|
||||
|
||||
GET_GLERROR(0);
|
||||
|
||||
glLinkProgram(new_shaderprogram);
|
||||
|
||||
GET_GLERROR(0);
|
||||
GLint link_success;
|
||||
glGetProgramiv(new_shaderprogram, GL_LINK_STATUS, &link_success);
|
||||
|
||||
if (link_success == GL_FALSE) {
|
||||
printf("Linking of %s with %s failed!\n Reason:\n", vshader_filename, fshader_filename);
|
||||
|
||||
GLint maxLength = 0;
|
||||
glGetShaderiv(new_shaderprogram, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
|
||||
char errorLog[maxLength];
|
||||
glGetShaderInfoLog(new_shaderprogram, maxLength, &maxLength, &errorLog[0]);
|
||||
|
||||
printf("%s", errorLog);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return new_shaderprogram;
|
||||
}
|
||||
|
||||
void motion(int x, int y)
|
||||
{
|
||||
// Convert motion coordinates to domain
|
||||
float fx = (lastx / (float)wWidth);
|
||||
float fy = (lasty / (float)wHeight);
|
||||
int nx = (int)(fx * DIM);
|
||||
int ny = (int)(fy * DIM);
|
||||
|
||||
if (clicked && nx < DIM - FR && nx > FR - 1 && ny < DIM - FR && ny > FR - 1) {
|
||||
int ddx = x - lastx;
|
||||
int ddy = y - lasty;
|
||||
fx = ddx / (float)wWidth;
|
||||
fy = ddy / (float)wHeight;
|
||||
int spy = ny - FR;
|
||||
int spx = nx - FR;
|
||||
addForces(dvfield, DIM, DIM, spx, spy, FORCE * DT * fx, FORCE * DT * fy, FR);
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// InitGraphicsState() - initialize OpenGLES
|
||||
//===========================================================================
|
||||
static void InitGraphicsState(int argc, char **argv)
|
||||
{
|
||||
char *GL_version = (char *)glGetString(GL_VERSION);
|
||||
char *GL_vendor = (char *)glGetString(GL_VENDOR);
|
||||
char *GL_renderer = (char *)glGetString(GL_RENDERER);
|
||||
|
||||
printf("Version: %s\n", GL_version);
|
||||
printf("Vendor: %s\n", GL_vendor);
|
||||
printf("Renderer: %s\n", GL_renderer);
|
||||
|
||||
// Allocate and initialize host data
|
||||
GLint bsize;
|
||||
|
||||
// initialize buffer object
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(cData) * DS, particles, GL_DYNAMIC_DRAW);
|
||||
|
||||
glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bsize);
|
||||
|
||||
if (bsize != (sizeof(cData) * DS)) {
|
||||
printf("Failed to initialize GL extensions.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_vbo_resource, vbo, cudaGraphicsMapFlagsNone));
|
||||
|
||||
// GLSL stuff
|
||||
char *vertex_shader_path = sdkFindFilePath("mesh.vert.glsl", argv[0]);
|
||||
char *fragment_shader_path = sdkFindFilePath("mesh.frag.glsl", argv[0]);
|
||||
|
||||
if (vertex_shader_path == NULL || fragment_shader_path == NULL) {
|
||||
printf("Error finding shader file\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mesh_shader = ShaderCreate(vertex_shader_path, fragment_shader_path);
|
||||
GET_GLERROR(0);
|
||||
|
||||
free(vertex_shader_path);
|
||||
free(fragment_shader_path);
|
||||
|
||||
glUseProgram(mesh_shader);
|
||||
}
|
||||
|
||||
void displayFrame(void)
|
||||
{
|
||||
if (!ref_file) {
|
||||
sdkStartTimer(&timer);
|
||||
simulateFluids();
|
||||
}
|
||||
|
||||
GLint view_arr[4];
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glUseProgram(mesh_shader);
|
||||
|
||||
// Set modelview and projection matricies
|
||||
GLint h_ModelViewMatrix = glGetUniformLocation(mesh_shader, "modelview");
|
||||
GLint h_ProjectionMatrix = glGetUniformLocation(mesh_shader, "projection");
|
||||
matrix4 modelview;
|
||||
matrix4 projection;
|
||||
mat_identity(modelview);
|
||||
mat_identity(projection);
|
||||
|
||||
// (float left, float right, float bottom, float top, float near, float far, matrix4 m)
|
||||
mat4f_Ortho(0.0, 1.0, 1.0, 0.0, 0.0, 1.0, projection);
|
||||
|
||||
glUniformMatrix4fv(h_ModelViewMatrix, 1, GL_FALSE, (GLfloat *)modelview);
|
||||
glUniformMatrix4fv(h_ProjectionMatrix, 1, GL_FALSE, (GLfloat *)projection);
|
||||
|
||||
// Set position coords
|
||||
GLint h_position = glGetAttribLocation(mesh_shader, "a_position");
|
||||
glEnableVertexAttribArray(h_position);
|
||||
glVertexAttribPointer(h_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, DS * sizeof(cData));
|
||||
glDisableVertexAttribArray(h_position);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
if (ref_file) {
|
||||
return;
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
// Finish timing before swap buffers to avoid refresh sync
|
||||
sdkStopTimer(&timer);
|
||||
graphics_swap_buffers();
|
||||
|
||||
fpsCount++;
|
||||
|
||||
if (fpsCount == fpsLimit) {
|
||||
char fps[256];
|
||||
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
|
||||
sprintf(fps, "Cuda/GL Stable Fluids (%d x %d): %3.1f fps", DIM, DIM, ifps);
|
||||
graphics_set_windowtitle(fps);
|
||||
fpsCount = 0;
|
||||
fpsLimit = (int)MAX(ifps, 1.f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
}
|
||||
|
||||
void autoTest(char **argv)
|
||||
{
|
||||
CFrameBufferObject *fbo = new CFrameBufferObject(wWidth, wHeight, 4, false, GL_TEXTURE_2D);
|
||||
g_CheckRender = new CheckFBO(wWidth, wHeight, 4, fbo);
|
||||
|
||||
g_CheckRender->setPixelFormat(GL_RGBA);
|
||||
g_CheckRender->setExecPath(argv[0]);
|
||||
g_CheckRender->EnableQAReadback(true);
|
||||
|
||||
fbo->bindRenderPath();
|
||||
|
||||
for (int count = 0; count < g_iFrameToCompare; count++) {
|
||||
simulateFluids();
|
||||
|
||||
// add in a little force so the automated testing is interesing.
|
||||
if (ref_file) {
|
||||
int x = wWidth / (count + 1);
|
||||
int y = wHeight / (count + 1);
|
||||
float fx = (x / (float)wWidth);
|
||||
float fy = (y / (float)wHeight);
|
||||
int nx = (int)(fx * DIM);
|
||||
int ny = (int)(fy * DIM);
|
||||
|
||||
int ddx = 35;
|
||||
int ddy = 35;
|
||||
fx = ddx / (float)wWidth;
|
||||
fy = ddy / (float)wHeight;
|
||||
int spy = ny - FR;
|
||||
int spx = nx - FR;
|
||||
|
||||
addForces(dvfield, DIM, DIM, spx, spy, FORCE * DT * fx, FORCE * DT * fy, FR);
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
getLastCudaError("addForces kernel failed");
|
||||
}
|
||||
}
|
||||
|
||||
displayFrame();
|
||||
|
||||
fbo->unbindRenderPath();
|
||||
|
||||
// compare to offical reference image, printing PASS or FAIL.
|
||||
printf("> (Frame %d) Readback BackBuffer\n", 100);
|
||||
g_CheckRender->readback(wWidth, wHeight);
|
||||
g_CheckRender->savePPM("fluidsGLES.ppm", true, NULL);
|
||||
|
||||
if (!g_CheckRender->PPMvsPPM("fluidsGLES.ppm", ref_file, MAX_EPSILON_ERROR, 0.25f)) {
|
||||
g_TotalErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
// Run fluids Simulation
|
||||
bool runFluidsSimulation(int argc, char **argv, char *ref_file)
|
||||
{
|
||||
// Create the CUTIL timer
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
|
||||
if (ref_file != NULL) {
|
||||
// command line mode only - auto test
|
||||
graphics_setup_window(0, 0, wWidth, wHeight, sSDKname);
|
||||
InitGraphicsState(argc, argv); // set up GLES stuff
|
||||
autoTest(argv);
|
||||
cleanup();
|
||||
}
|
||||
else {
|
||||
// create X11 window and set up associated OpenGL ES context
|
||||
graphics_setup_window(0, 0, wWidth, wHeight, sSDKname);
|
||||
|
||||
InitGraphicsState(argc, argv); // set up GLES stuff
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
graphics_swap_buffers();
|
||||
XEvent event;
|
||||
KeySym key;
|
||||
char text[255];
|
||||
|
||||
while (1) {
|
||||
while (XPending(display) > 0) {
|
||||
XNextEvent(display, &event);
|
||||
|
||||
if (event.type == Expose && event.xexpose.count == 0) {
|
||||
printf("Redraw requested!\n");
|
||||
}
|
||||
|
||||
if (event.type == KeyPress && XLookupString(&event.xkey, text, 255, &key, 0) == 1) {
|
||||
if (text[0] == 27 || text[0] == 'q' || text[0] == 'Q') {
|
||||
keyboard(text[0], 0, 0, argc, argv);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (text[0] == 114) {
|
||||
keyboard(text[0], 0, 0, argc, argv);
|
||||
}
|
||||
|
||||
printf("You pressed the %c key!\n", text[0]);
|
||||
}
|
||||
|
||||
if (event.type == ButtonPress) {
|
||||
lastx = event.xbutton.x;
|
||||
lasty = event.xbutton.y;
|
||||
clicked = !clicked;
|
||||
}
|
||||
|
||||
if (event.type == ButtonRelease) {
|
||||
lastx = event.xbutton.x;
|
||||
lasty = event.xbutton.y;
|
||||
clicked = !clicked;
|
||||
}
|
||||
|
||||
if (event.type == MotionNotify) {
|
||||
motion(event.xmotion.x, event.xmotion.y);
|
||||
}
|
||||
else {
|
||||
XFlush(display);
|
||||
}
|
||||
}
|
||||
displayFrame();
|
||||
usleep(1000); // need not take full CPU and GPU
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// very simple von neumann middle-square prng. can't use rand() in -qatest
|
||||
// mode because its implementation varies across platforms which makes testing
|
||||
// for consistency in the important parts of this program difficult.
|
||||
float myrand(void)
|
||||
{
|
||||
static int seed = 72191;
|
||||
char sq[22];
|
||||
|
||||
if (ref_file) {
|
||||
seed *= seed;
|
||||
sprintf(sq, "%010d", seed);
|
||||
// pull the middle 5 digits out of sq
|
||||
sq[8] = 0;
|
||||
seed = atoi(&sq[3]);
|
||||
|
||||
return seed / 99999.f;
|
||||
}
|
||||
else {
|
||||
return rand() / (float)RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void initParticles(cData *p, int dx, int dy)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < dy; i++) {
|
||||
for (j = 0; j < dx; j++) {
|
||||
p[i * dx + j].x = (j + 0.5f + (myrand() - 0.5f)) / dx;
|
||||
p[i * dx + j].y = (i + 0.5f + (myrand() - 0.5f)) / dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard(unsigned char key, int x, int y, int argc, char **argv)
|
||||
{
|
||||
switch (key) {
|
||||
case 'q':
|
||||
case 'Q':
|
||||
case 27:
|
||||
g_bExitESC = true;
|
||||
cleanup();
|
||||
graphics_close_window(); // close window and destroy OpenGL ES context
|
||||
return;
|
||||
break;
|
||||
case 'r':
|
||||
printf("\nResetting\n");
|
||||
memset(hvfield, 0, sizeof(cData) * DS);
|
||||
cudaMemcpy(dvfield, hvfield, sizeof(cData) * DS, cudaMemcpyHostToDevice);
|
||||
|
||||
initParticles(particles, DIM, DIM);
|
||||
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(cuda_vbo_resource));
|
||||
|
||||
getLastCudaError("cudaGraphicsUnregisterBuffer failed");
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
InitGraphicsState(argc, argv); // set up GLES stuff
|
||||
graphics_swap_buffers();
|
||||
|
||||
getLastCudaError("cudaGraphicsGLRegisterBuffer failed");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(cuda_vbo_resource));
|
||||
|
||||
deleteTexture();
|
||||
|
||||
// Free all host and device resources
|
||||
free(hvfield);
|
||||
free(particles);
|
||||
checkCudaErrors(cudaFree(dvfield));
|
||||
checkCudaErrors(cudaFree(vxfield));
|
||||
checkCudaErrors(cudaFree(vyfield));
|
||||
checkCudaErrors(cufftDestroy(planr2c));
|
||||
checkCudaErrors(cufftDestroy(planc2r));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int devID;
|
||||
cudaDeviceProp deviceProps;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
printf("%s Starting...\n\n", sSDKname);
|
||||
|
||||
printf("NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is "
|
||||
"enabled.\n\n");
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm__)
|
||||
// find iGPU on the system which is compute capable which will perform GLES-CUDA interop
|
||||
devID = findIntegratedGPU();
|
||||
#else
|
||||
// use command-line specified CUDA device, otherwise use device with highest Gflops/s
|
||||
devID = findCudaDevice(argc, (const char **)argv);
|
||||
#endif
|
||||
|
||||
// get number of SMs on this GPU
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProps, devID));
|
||||
printf("CUDA device [%s] has %d Multi-Processors\n", deviceProps.name, deviceProps.multiProcessorCount);
|
||||
|
||||
// automated build testing harness
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file", &ref_file);
|
||||
}
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkResetTimer(&timer);
|
||||
|
||||
hvfield = (cData *)malloc(sizeof(cData) * DS);
|
||||
memset(hvfield, 0, sizeof(cData) * DS);
|
||||
|
||||
// Allocate and initialize device data
|
||||
checkCudaErrors(cudaMallocPitch((void **)&dvfield, &tPitch, sizeof(cData) * DIM, DIM));
|
||||
|
||||
checkCudaErrors(cudaMemcpy(dvfield, hvfield, sizeof(cData) * DS, cudaMemcpyHostToDevice));
|
||||
// Temporary complex velocity field data
|
||||
checkCudaErrors(cudaMalloc((void **)&vxfield, sizeof(cData) * PDS));
|
||||
checkCudaErrors(cudaMalloc((void **)&vyfield, sizeof(cData) * PDS));
|
||||
|
||||
setupTexture(DIM, DIM);
|
||||
|
||||
// Create particle array
|
||||
particles = (cData *)malloc(sizeof(cData) * DS);
|
||||
memset(particles, 0, sizeof(cData) * DS);
|
||||
|
||||
initParticles(particles, DIM, DIM);
|
||||
|
||||
// Create CUFFT transform plan configuration
|
||||
checkCudaErrors(cufftPlan2d(&planr2c, DIM, DIM, CUFFT_R2C));
|
||||
checkCudaErrors(cufftPlan2d(&planc2r, DIM, DIM, CUFFT_C2R));
|
||||
|
||||
runFluidsSimulation(argc, argv, ref_file);
|
||||
|
||||
if (ref_file) {
|
||||
printf("[fluidsGLES] - Test Results: %d Failures\n", g_TotalErrors);
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
|
||||
if (!ref_file) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
356
cpp/8_Platform_Specific/Tegra/fluidsGLES/fluidsGLES_kernels.cu
Normal file
356
cpp/8_Platform_Specific/Tegra/fluidsGLES/fluidsGLES_kernels.cu
Normal file
@@ -0,0 +1,356 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <cufft.h> // CUDA FFT Libraries
|
||||
#include <helper_cuda.h> // Helper functions for CUDA Error handling
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// OpenGL Graphics includes
|
||||
#include <GLES3/gl31.h>
|
||||
|
||||
// FluidsGLES CUDA kernel definitions
|
||||
#include "fluidsGLES_kernels.cuh"
|
||||
|
||||
// Texture object for reading velocity field
|
||||
cudaTextureObject_t texObj;
|
||||
static cudaArray *array = NULL;
|
||||
|
||||
// Particle data
|
||||
extern GLuint vbo; // OpenGL vertex buffer object
|
||||
extern struct cudaGraphicsResource *cuda_vbo_resource; // handles OpenGL-CUDA exchange
|
||||
|
||||
// Texture pitch
|
||||
extern size_t tPitch;
|
||||
extern cufftHandle planr2c;
|
||||
extern cufftHandle planc2r;
|
||||
cData *vxfield = NULL;
|
||||
cData *vyfield = NULL;
|
||||
|
||||
void setupTexture(int x, int y)
|
||||
{
|
||||
cudaChannelFormatDesc desc = cudaCreateChannelDesc<float2>();
|
||||
|
||||
cudaMallocArray(&array, &desc, y, x);
|
||||
getLastCudaError("cudaMalloc failed");
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = array;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&texObj, &texRes, &texDescr, NULL));
|
||||
}
|
||||
|
||||
void updateTexture(cData *data, size_t wib, size_t h, size_t pitch)
|
||||
{
|
||||
checkCudaErrors(cudaMemcpy2DToArray(array, 0, 0, data, pitch, wib, h, cudaMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
void deleteTexture(void)
|
||||
{
|
||||
checkCudaErrors(cudaDestroyTextureObject(texObj));
|
||||
checkCudaErrors(cudaFreeArray(array));
|
||||
}
|
||||
|
||||
// Note that these kernels are designed to work with arbitrary
|
||||
// domain sizes, not just domains that are multiples of the tile
|
||||
// size. Therefore, we have extra code that checks to make sure
|
||||
// a given thread location falls within the domain boundaries in
|
||||
// both X and Y. Also, the domain is covered by looping over
|
||||
// multiple elements in the Y direction, while there is a one-to-one
|
||||
// mapping between threads in X and the tile size in X.
|
||||
// Nolan Goodnight 9/22/06
|
||||
|
||||
// This method adds constant force vectors to the velocity field
|
||||
// stored in 'v' according to v(x,t+1) = v(x,t) + dt * f.
|
||||
__global__ void addForces_k(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r, size_t pitch)
|
||||
{
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
cData *fj = (cData *)((char *)v + (ty + spy) * pitch) + tx + spx;
|
||||
|
||||
cData vterm = *fj;
|
||||
tx -= r;
|
||||
ty -= r;
|
||||
float s = 1.f / (1.f + tx * tx * tx * tx + ty * ty * ty * ty);
|
||||
vterm.x += s * fx;
|
||||
vterm.y += s * fy;
|
||||
*fj = vterm;
|
||||
}
|
||||
|
||||
// This method performs the velocity advection step, where we
|
||||
// trace velocity vectors back in time to update each grid cell.
|
||||
// That is, v(x,t+1) = v(p(x,-dt),t). Here we perform bilinear
|
||||
// interpolation in the velocity space.
|
||||
__global__ void advectVelocity_k(cData *v,
|
||||
float *vx,
|
||||
float *vy,
|
||||
int dx,
|
||||
int pdx,
|
||||
int dy,
|
||||
float dt,
|
||||
int lb,
|
||||
cudaTextureObject_t texObject)
|
||||
{
|
||||
int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
|
||||
int p;
|
||||
|
||||
cData vterm, ploc;
|
||||
float vxterm, vyterm;
|
||||
|
||||
// gtidx is the domain location in x for this thread
|
||||
if (gtidx < dx) {
|
||||
for (p = 0; p < lb; p++) {
|
||||
// fi is the domain location in y for this thread
|
||||
int fi = gtidy + p;
|
||||
|
||||
if (fi < dy) {
|
||||
int fj = fi * pdx + gtidx;
|
||||
vterm = tex2D<cData>(texObject, (float)gtidx, (float)fi);
|
||||
ploc.x = (gtidx + 0.5f) - (dt * vterm.x * dx);
|
||||
ploc.y = (fi + 0.5f) - (dt * vterm.y * dy);
|
||||
vterm = tex2D<cData>(texObject, ploc.x, ploc.y);
|
||||
vxterm = vterm.x;
|
||||
vyterm = vterm.y;
|
||||
vx[fj] = vxterm;
|
||||
vy[fj] = vyterm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method performs velocity diffusion and forces mass conservation
|
||||
// in the frequency domain. The inputs 'vx' and 'vy' are complex-valued
|
||||
// arrays holding the Fourier coefficients of the velocity field in
|
||||
// X and Y. Diffusion in this space takes a simple form described as:
|
||||
// v(k,t) = v(k,t) / (1 + visc * dt * k^2), where visc is the viscosity,
|
||||
// and k is the wavenumber. The projection step forces the Fourier
|
||||
// velocity vectors to be orthogonal to the vectors for each
|
||||
// wavenumber: v(k,t) = v(k,t) - ((k dot v(k,t) * k) / k^2.
|
||||
__global__ void diffuseProject_k(cData *vx, cData *vy, int dx, int dy, float dt, float visc, int lb)
|
||||
{
|
||||
int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
|
||||
int p;
|
||||
|
||||
cData xterm, yterm;
|
||||
|
||||
// gtidx is the domain location in x for this thread
|
||||
if (gtidx < dx) {
|
||||
for (p = 0; p < lb; p++) {
|
||||
// fi is the domain location in y for this thread
|
||||
int fi = gtidy + p;
|
||||
|
||||
if (fi < dy) {
|
||||
int fj = fi * dx + gtidx;
|
||||
xterm = vx[fj];
|
||||
yterm = vy[fj];
|
||||
|
||||
// Compute the index of the wavenumber based on the
|
||||
// data order produced by a standard NN FFT.
|
||||
int iix = gtidx;
|
||||
int iiy = (fi > dy / 2) ? (fi - (dy)) : fi;
|
||||
|
||||
// Velocity diffusion
|
||||
float kk = (float)(iix * iix + iiy * iiy); // k^2
|
||||
float diff = 1.f / (1.f + visc * dt * kk);
|
||||
xterm.x *= diff;
|
||||
xterm.y *= diff;
|
||||
yterm.x *= diff;
|
||||
yterm.y *= diff;
|
||||
|
||||
// Velocity projection
|
||||
if (kk > 0.f) {
|
||||
float rkk = 1.f / kk;
|
||||
// Real portion of velocity projection
|
||||
float rkp = (iix * xterm.x + iiy * yterm.x);
|
||||
// Imaginary portion of velocity projection
|
||||
float ikp = (iix * xterm.y + iiy * yterm.y);
|
||||
xterm.x -= rkk * rkp * iix;
|
||||
xterm.y -= rkk * ikp * iix;
|
||||
yterm.x -= rkk * rkp * iiy;
|
||||
yterm.y -= rkk * ikp * iiy;
|
||||
}
|
||||
|
||||
vx[fj] = xterm;
|
||||
vy[fj] = yterm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method updates the velocity field 'v' using the two complex
|
||||
// arrays from the previous step: 'vx' and 'vy'. Here we scale the
|
||||
// real components by 1/(dx*dy) to account for an unnormalized FFT.
|
||||
__global__ void updateVelocity_k(cData *v, float *vx, float *vy, int dx, int pdx, int dy, int lb, size_t pitch)
|
||||
{
|
||||
int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
|
||||
int p;
|
||||
|
||||
float vxterm, vyterm;
|
||||
cData nvterm;
|
||||
|
||||
// gtidx is the domain location in x for this thread
|
||||
if (gtidx < dx) {
|
||||
for (p = 0; p < lb; p++) {
|
||||
// fi is the domain location in y for this thread
|
||||
int fi = gtidy + p;
|
||||
|
||||
if (fi < dy) {
|
||||
int fjr = fi * pdx + gtidx;
|
||||
vxterm = vx[fjr];
|
||||
vyterm = vy[fjr];
|
||||
|
||||
// Normalize the result of the inverse FFT
|
||||
float scale = 1.f / (dx * dy);
|
||||
nvterm.x = vxterm * scale;
|
||||
nvterm.y = vyterm * scale;
|
||||
|
||||
cData *fj = (cData *)((char *)v + fi * pitch) + gtidx;
|
||||
*fj = nvterm;
|
||||
}
|
||||
} // If this thread is inside the domain in Y
|
||||
} // If this thread is inside the domain in X
|
||||
}
|
||||
|
||||
// This method updates the particles by moving particle positions
|
||||
// according to the velocity field and time step. That is, for each
|
||||
// particle: p(t+1) = p(t) + dt * v(p(t)).
|
||||
__global__ void advectParticles_k(cData *part, cData *v, int dx, int dy, float dt, int lb, size_t pitch)
|
||||
{
|
||||
int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
|
||||
int p;
|
||||
|
||||
// gtidx is the domain location in x for this thread
|
||||
cData pterm, vterm;
|
||||
|
||||
if (gtidx < dx) {
|
||||
for (p = 0; p < lb; p++) {
|
||||
// fi is the domain location in y for this thread
|
||||
int fi = gtidy + p;
|
||||
|
||||
if (fi < dy) {
|
||||
int fj = fi * dx + gtidx;
|
||||
pterm = part[fj];
|
||||
|
||||
int xvi = ((int)(pterm.x * dx));
|
||||
int yvi = ((int)(pterm.y * dy));
|
||||
vterm = *((cData *)((char *)v + yvi * pitch) + xvi);
|
||||
|
||||
pterm.x += dt * vterm.x;
|
||||
pterm.x = pterm.x - (int)pterm.x;
|
||||
pterm.x += 1.f;
|
||||
pterm.x = pterm.x - (int)pterm.x;
|
||||
pterm.y += dt * vterm.y;
|
||||
pterm.y = pterm.y - (int)pterm.y;
|
||||
pterm.y += 1.f;
|
||||
pterm.y = pterm.y - (int)pterm.y;
|
||||
|
||||
part[fj] = pterm;
|
||||
}
|
||||
} // If this thread is inside the domain in Y
|
||||
} // If this thread is inside the domain in X
|
||||
}
|
||||
|
||||
// These are the external function calls necessary for launching fluid simuation
|
||||
extern "C" void addForces(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r)
|
||||
{
|
||||
dim3 tids(2 * r + 1, 2 * r + 1);
|
||||
|
||||
addForces_k<<<1, tids>>>(v, dx, dy, spx, spy, fx, fy, r, tPitch);
|
||||
getLastCudaError("addForces_k failed.");
|
||||
}
|
||||
|
||||
extern "C" void advectVelocity(cData *v, float *vx, float *vy, int dx, int pdx, int dy, float dt)
|
||||
{
|
||||
dim3 grid((dx / TILEX) + (!(dx % TILEX) ? 0 : 1), (dy / TILEY) + (!(dy % TILEY) ? 0 : 1));
|
||||
|
||||
dim3 tids(TIDSX, TIDSY);
|
||||
|
||||
updateTexture(v, DIM * sizeof(cData), DIM, tPitch);
|
||||
advectVelocity_k<<<grid, tids>>>(v, vx, vy, dx, pdx, dy, dt, TILEY / TIDSY, texObj);
|
||||
getLastCudaError("advectVelocity_k failed.");
|
||||
}
|
||||
|
||||
extern "C" void diffuseProject(cData *vx, cData *vy, int dx, int dy, float dt, float visc)
|
||||
{
|
||||
// Forward FFT
|
||||
checkCudaErrors(cufftExecR2C(planr2c, (cufftReal *)vx, (cufftComplex *)vx));
|
||||
checkCudaErrors(cufftExecR2C(planr2c, (cufftReal *)vy, (cufftComplex *)vy));
|
||||
|
||||
uint3 grid = make_uint3((dx / TILEX) + (!(dx % TILEX) ? 0 : 1), (dy / TILEY) + (!(dy % TILEY) ? 0 : 1), 1);
|
||||
uint3 tids = make_uint3(TIDSX, TIDSY, 1);
|
||||
|
||||
diffuseProject_k<<<grid, tids>>>(vx, vy, dx, dy, dt, visc, TILEY / TIDSY);
|
||||
getLastCudaError("diffuseProject_k failed.");
|
||||
|
||||
// Inverse FFT
|
||||
checkCudaErrors(cufftExecC2R(planc2r, (cufftComplex *)vx, (cufftReal *)vx));
|
||||
checkCudaErrors(cufftExecC2R(planc2r, (cufftComplex *)vy, (cufftReal *)vy));
|
||||
}
|
||||
|
||||
extern "C" void updateVelocity(cData *v, float *vx, float *vy, int dx, int pdx, int dy)
|
||||
{
|
||||
dim3 grid((dx / TILEX) + (!(dx % TILEX) ? 0 : 1), (dy / TILEY) + (!(dy % TILEY) ? 0 : 1));
|
||||
dim3 tids(TIDSX, TIDSY);
|
||||
|
||||
updateVelocity_k<<<grid, tids>>>(v, vx, vy, dx, pdx, dy, TILEY / TIDSY, tPitch);
|
||||
getLastCudaError("updateVelocity_k failed.");
|
||||
}
|
||||
|
||||
extern "C" void advectParticles(GLuint vbo, cData *v, int dx, int dy, float dt)
|
||||
{
|
||||
dim3 grid((dx / TILEX) + (!(dx % TILEX) ? 0 : 1), (dy / TILEY) + (!(dy % TILEY) ? 0 : 1));
|
||||
dim3 tids(TIDSX, TIDSY);
|
||||
|
||||
cData *p;
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_vbo_resource, 0));
|
||||
getLastCudaError("cudaGraphicsMapResources failed");
|
||||
|
||||
size_t num_bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&p, &num_bytes, cuda_vbo_resource));
|
||||
getLastCudaError("cudaGraphicsResourceGetMappedPointer failed");
|
||||
|
||||
advectParticles_k<<<grid, tids>>>(p, v, dx, dy, dt, TILEY / TIDSY, tPitch);
|
||||
getLastCudaError("advectParticles_k failed.");
|
||||
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_vbo_resource, 0));
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __STABLEFLUIDS_KERNELS_CUH_
|
||||
#define __STABLEFLUIDS_KERNELS_CUH_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
// Vector data type used to velocity and force fields
|
||||
typedef float2 cData;
|
||||
|
||||
void setupTexture(int x, int y);
|
||||
void updateTexture(cData *data, size_t w, size_t h, size_t pitch);
|
||||
void deleteTexture(void);
|
||||
|
||||
// This method adds constant force vectors to the velocity field
|
||||
// stored in 'v' according to v(x,t+1) = v(x,t) + dt * f.
|
||||
__global__ void addForces_k(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r, size_t pitch);
|
||||
|
||||
// This method performs the velocity advection step, where we
|
||||
// trace velocity vectors back in time to update each grid cell.
|
||||
// That is, v(x,t+1) = v(p(x,-dt),t). Here we perform bilinear
|
||||
// interpolation in the velocity space.
|
||||
__global__ void
|
||||
advectVelocity_k(cData *v, float *vx, float *vy, int dx, int pdx, int dy, float dt, int lb, cudaTextureObject_t tex);
|
||||
|
||||
// This method performs velocity diffusion and forces mass conservation
|
||||
// in the frequency domain. The inputs 'vx' and 'vy' are complex-valued
|
||||
// arrays holding the Fourier coefficients of the velocity field in
|
||||
// X and Y. Diffusion in this space takes a simple form described as:
|
||||
// v(k,t) = v(k,t) / (1 + visc * dt * k^2), where visc is the viscosity,
|
||||
// and k is the wavenumber. The projection step forces the Fourier
|
||||
// velocity vectors to be orthogonal to the wave wave vectors for each
|
||||
// wavenumber: v(k,t) = v(k,t) - ((k dot v(k,t) * k) / k^2.
|
||||
__global__ void diffuseProject_k(cData *vx, cData *vy, int dx, int dy, float dt, float visc, int lb);
|
||||
|
||||
// This method updates the velocity field 'v' using the two complex
|
||||
// arrays from the previous step: 'vx' and 'vy'. Here we scale the
|
||||
// real components by 1/(dx*dy) to account for an unnormalized FFT.
|
||||
__global__ void updateVelocity_k(cData *v, float *vx, float *vy, int dx, int pdx, int dy, int lb, size_t pitch);
|
||||
|
||||
// This method updates the particles by moving particle positions
|
||||
// according to the velocity field and time step. That is, for each
|
||||
// particle: p(t+1) = p(t) + dt * v(p(t)).
|
||||
__global__ void advectParticles_k(cData *part, cData *v, int dx, int dy, float dt, int lb, size_t pitch);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1993-2015 NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* Please refer to the NVIDIA end user license agreement (EULA) associated
|
||||
* with this source code for terms and conditions that govern your use of
|
||||
* this software. Any use, reproduction, disclosure, or distribution of
|
||||
* this software and related documentation outside the terms of the EULA
|
||||
* is strictly prohibited.
|
||||
*
|
||||
*/
|
||||
#ifndef __STABLEFLUIDS_KERNELS_CUH_
|
||||
#define __STABLEFLUIDS_KERNELS_CUH_
|
||||
|
||||
// Vector data type used to velocity and force fields
|
||||
typedef float2 cData;
|
||||
|
||||
void setupTexture(int x, int y);
|
||||
void updateTexture(cData *data, size_t w, size_t h, size_t pitch);
|
||||
void deleteTexture(void);
|
||||
|
||||
// This method adds constant force vectors to the velocity field
|
||||
// stored in 'v' according to v(x,t+1) = v(x,t) + dt * f.
|
||||
__global__ void addForces_k(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r, size_t pitch);
|
||||
|
||||
// This method performs the velocity advection step, where we
|
||||
// trace velocity vectors back in time to update each grid cell.
|
||||
// That is, v(x,t+1) = v(p(x,-dt),t). Here we perform bilinear
|
||||
// interpolation in the velocity space.
|
||||
__global__ void
|
||||
advectVelocity_k(cData *v, float *vx, float *vy, int dx, int pdx, int dy, float dt, int lb, cudaTextureObject_t tex);
|
||||
|
||||
// This method performs velocity diffusion and forces mass conservation
|
||||
// in the frequency domain. The inputs 'vx' and 'vy' are complex-valued
|
||||
// arrays holding the Fourier coefficients of the velocity field in
|
||||
// X and Y. Diffusion in this space takes a simple form described as:
|
||||
// v(k,t) = v(k,t) / (1 + visc * dt * k^2), where visc is the viscosity,
|
||||
// and k is the wavenumber. The projection step forces the Fourier
|
||||
// velocity vectors to be orthogonal to the wave wave vectors for each
|
||||
// wavenumber: v(k,t) = v(k,t) - ((k dot v(k,t) * k) / k^2.
|
||||
__global__ void diffuseProject_k(cData *vx, cData *vy, int dx, int dy, float dt, float visc, int lb);
|
||||
|
||||
// This method updates the velocity field 'v' using the two complex
|
||||
// arrays from the previous step: 'vx' and 'vy'. Here we scale the
|
||||
// real components by 1/(dx*dy) to account for an unnormalized FFT.
|
||||
__global__ void updateVelocity_k(cData *v, float *vx, float *vy, int dx, int pdx, int dy, int lb, size_t pitch);
|
||||
|
||||
// This method updates the particles by moving particle positions
|
||||
// according to the velocity field and time step. That is, for each
|
||||
// particle: p(t+1) = p(t) + dt * v(p(t)).
|
||||
__global__ void advectParticles_k(cData *part, cData *v, int dx, int dy, float dt, int lb, size_t pitch);
|
||||
|
||||
#endif
|
||||
213
cpp/8_Platform_Specific/Tegra/fluidsGLES/graphics_interface.h
Normal file
213
cpp/8_Platform_Specific/Tegra/fluidsGLES/graphics_interface.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
Display *display;
|
||||
int screen;
|
||||
Window win = 0;
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES3/gl31.h>
|
||||
|
||||
#define GET_GLERROR(ret) \
|
||||
\
|
||||
{ \
|
||||
GLenum err = glGetError(); \
|
||||
if (err != GL_NO_ERROR) { \
|
||||
fprintf(stderr, "[%s line %d] OpenGL Error: 0x%x\n", __FILE__, __LINE__, err); \
|
||||
fflush(stderr); \
|
||||
\
|
||||
switch (err) { \
|
||||
case GL_INVALID_ENUM: \
|
||||
printf("GL_INVALID_ENUM\n"); \
|
||||
break; \
|
||||
case GL_INVALID_VALUE: \
|
||||
printf("GL_INVALID_VALUE\n"); \
|
||||
break; \
|
||||
case GL_INVALID_OPERATION: \
|
||||
printf("GL_INVALID_OPERATION\n"); \
|
||||
break; \
|
||||
case GL_OUT_OF_MEMORY: \
|
||||
printf("GL_OUT_OF_MEMORY\n"); \
|
||||
break; \
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION: \
|
||||
printf("GL_INVALID_FRAMEBUFFER_OPERATION\n"); \
|
||||
break; \
|
||||
default: \
|
||||
printf("UKNOWN OPENGL ERROR CODE 0x%x\n", err); \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
EGLContext eglContext = EGL_NO_CONTEXT;
|
||||
|
||||
int graphics_setup_window(int xpos, int ypos, int width, int height, const char *windowname)
|
||||
{
|
||||
// OpenGL ES 3.1
|
||||
EGLint configAttrs[] = {EGL_RED_SIZE,
|
||||
1,
|
||||
EGL_GREEN_SIZE,
|
||||
1,
|
||||
EGL_BLUE_SIZE,
|
||||
1,
|
||||
EGL_DEPTH_SIZE,
|
||||
16,
|
||||
EGL_SAMPLE_BUFFERS,
|
||||
0,
|
||||
EGL_SAMPLES,
|
||||
0,
|
||||
// EGL_CONFORMANT, EGL_OPENGL_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES2_BIT, // 3_BIT_KHR,
|
||||
EGL_NONE};
|
||||
EGLint contextAttrs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||
|
||||
EGLConfig *configList = NULL;
|
||||
EGLint configCount;
|
||||
|
||||
display = XOpenDisplay(NULL);
|
||||
if (!display)
|
||||
error_exit("Error opening X display.\n");
|
||||
|
||||
screen = DefaultScreen(display);
|
||||
|
||||
eglDisplay = eglGetDisplay(0);
|
||||
|
||||
if (eglDisplay == EGL_NO_DISPLAY)
|
||||
error_exit("EGL failed to obtain display\n");
|
||||
|
||||
if (!eglInitialize(eglDisplay, 0, 0))
|
||||
error_exit("EGL failed to initialize\n");
|
||||
|
||||
if (!eglChooseConfig(eglDisplay, configAttrs, NULL, 0, &configCount) || !configCount)
|
||||
error_exit("EGL failed to return any matching configurations\n");
|
||||
|
||||
configList = (EGLConfig *)malloc(configCount * sizeof(EGLConfig));
|
||||
|
||||
if (!eglChooseConfig(eglDisplay, configAttrs, configList, configCount, &configCount) || !configCount)
|
||||
error_exit("EGL failed to populate configuration list\n");
|
||||
|
||||
Window xRootWindow = DefaultRootWindow(display);
|
||||
XSetWindowAttributes xCreateWindowAttributes;
|
||||
xCreateWindowAttributes.event_mask = ExposureMask;
|
||||
win = XCreateWindow(display,
|
||||
xRootWindow,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
CWEventMask,
|
||||
&xCreateWindowAttributes);
|
||||
XMapWindow(display, win);
|
||||
Atom netWmStateAtom = XInternAtom(display, "_NET_WM_STATE", false);
|
||||
XEvent xEvent;
|
||||
memset(&xEvent, 0, sizeof(xEvent));
|
||||
xEvent.type = ClientMessage;
|
||||
xEvent.xclient.window = win;
|
||||
xEvent.xclient.message_type = netWmStateAtom;
|
||||
xEvent.xclient.format = 32;
|
||||
xEvent.xclient.data.l[0] = 1;
|
||||
xEvent.xclient.data.l[1] = false;
|
||||
XSendEvent(display, xRootWindow, false, SubstructureNotifyMask, &xEvent);
|
||||
|
||||
XStoreName(display, win, windowname);
|
||||
|
||||
XSelectInput(display,
|
||||
win,
|
||||
ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | KeyReleaseMask
|
||||
| VisibilityChangeMask | PointerMotionMask);
|
||||
|
||||
EGLint windowAttrs[] = {EGL_NONE};
|
||||
|
||||
eglSurface = eglCreateWindowSurface(eglDisplay, configList[0], (EGLNativeWindowType)win, windowAttrs);
|
||||
|
||||
if (!eglSurface)
|
||||
error_exit("EGL couldn't create window\n");
|
||||
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
eglContext = eglCreateContext(eglDisplay, configList[0], NULL, contextAttrs);
|
||||
if (!eglContext)
|
||||
error_exit("EGL couldn't create context\n");
|
||||
|
||||
if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext))
|
||||
error_exit("EGL couldn't make context/surface current\n");
|
||||
|
||||
EGLint Context_RendererType;
|
||||
eglQueryContext(eglDisplay, eglContext, EGL_CONTEXT_CLIENT_TYPE, &Context_RendererType);
|
||||
|
||||
switch (Context_RendererType) {
|
||||
case EGL_OPENGL_API:
|
||||
printf("Using OpenGL API is not supported\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case EGL_OPENGL_ES_API:
|
||||
printf("Using OpenGL ES API");
|
||||
break;
|
||||
case EGL_OPENVG_API:
|
||||
error_exit("Context Query Returned OpenVG. This is Unsupported\n");
|
||||
default:
|
||||
error_exit("Unknown Context Type. %04X\n", Context_RendererType);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void graphics_set_windowtitle(const char *windowname) { XStoreName(display, win, windowname); }
|
||||
|
||||
void graphics_swap_buffers() { eglSwapBuffers(eglDisplay, eglSurface); }
|
||||
|
||||
void graphics_close_window()
|
||||
{
|
||||
if (eglDisplay != EGL_NO_DISPLAY) {
|
||||
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (eglContext != EGL_NO_CONTEXT)
|
||||
eglDestroyContext(eglDisplay, eglContext);
|
||||
|
||||
if (eglSurface != EGL_NO_SURFACE)
|
||||
eglDestroySurface(eglDisplay, eglSurface);
|
||||
|
||||
eglTerminate(eglDisplay);
|
||||
}
|
||||
|
||||
if (win)
|
||||
XDestroyWindow(display, win);
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
34
cpp/8_Platform_Specific/Tegra/fluidsGLES/mesh.frag.glsl
Normal file
34
cpp/8_Platform_Specific/Tegra/fluidsGLES/mesh.frag.glsl
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
if (length(gl_PointCoord - vec2(0.5)) > 0.5)
|
||||
discard;
|
||||
|
||||
gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);
|
||||
}
|
||||
37
cpp/8_Platform_Specific/Tegra/fluidsGLES/mesh.vert.glsl
Normal file
37
cpp/8_Platform_Specific/Tegra/fluidsGLES/mesh.vert.glsl
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
attribute vec4 a_position;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 modelview;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_PointSize = 1.0;
|
||||
gl_Position = projection * modelview * a_position;
|
||||
}
|
||||
18
cpp/8_Platform_Specific/Tegra/nbody_opengles/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/nbody_opengles/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/nbody_opengles/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/nbody_opengles/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
67
cpp/8_Platform_Specific/Tegra/nbody_opengles/CMakeLists.txt
Normal file
67
cpp/8_Platform_Specific/Tegra/nbody_opengles/CMakeLists.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(nbody_opengles LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(EGL)
|
||||
find_package(X11)
|
||||
find_package(OpenGL)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Source file
|
||||
if(${OpenGL_FOUND})
|
||||
if(${EGL_FOUND})
|
||||
if(${X11_FOUND})
|
||||
# Add target for nbody_opengles
|
||||
add_executable(nbody_opengles bodysystemcuda.cu render_particles.cpp nbody_opengles.cpp)
|
||||
|
||||
target_compile_options(nbody_opengles PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(nbody_opengles PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(nbody_opengles PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(nbody_opengles PUBLIC
|
||||
${EGL_INCLUDE_DIR}
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(nbody_opengles
|
||||
${EGL_LIBRARY}
|
||||
${X11_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
message(STATUS "X11 libraries not found - will not build sample 'nbody_opengles'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "EGL not found - will not build sample 'nbody_opengles'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenGL not found - will not build sample 'nbody_opengles'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample nbody_opengles - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
36
cpp/8_Platform_Specific/Tegra/nbody_opengles/README.md
Normal file
36
cpp/8_Platform_Specific/Tegra/nbody_opengles/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# nbody_opengles - CUDA N-Body Simulation with GLES
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates efficient all-pairs simulation of a gravitational n-body simulation in CUDA. Unlike the OpenGL nbody sample, there is no user interaction.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
Graphics Interop, Data Parallel Algorithms, Physically-Based Simulation
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
armv7l
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaGraphicsUnmapResources, cudaSetDeviceFlags, cudaGraphicsResourceSetMapFlags, cudaGraphicsResourceGetMappedPointer, cudaGraphicsMapResources, cudaSetDevice, cudaEventSynchronize, cudaGetDeviceProperties, cudaDeviceSynchronize, cudaEventRecord, cudaGetDevice, cudaMemcpyToSymbol, cudaStreamQuery, cudaEventDestroy, cudaEventElapsedTime, cudaGetDeviceCount, cudaEventCreate
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[X11](../../../README.md#x11), [OpenGL ES](../../../README.md#opengl-es)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
291
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystem.h
Normal file
291
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystem.h
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __BODYSYSTEM_H__
|
||||
#define __BODYSYSTEM_H__
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
enum NBodyConfig { NBODY_CONFIG_RANDOM, NBODY_CONFIG_SHELL, NBODY_CONFIG_EXPAND, NBODY_NUM_CONFIGS };
|
||||
|
||||
enum BodyArray {
|
||||
BODYSYSTEM_POSITION,
|
||||
BODYSYSTEM_VELOCITY,
|
||||
};
|
||||
|
||||
template <typename T> struct vec3
|
||||
{
|
||||
typedef float Type;
|
||||
}; // dummy
|
||||
template <> struct vec3<float>
|
||||
{
|
||||
typedef float3 Type;
|
||||
};
|
||||
template <> struct vec3<double>
|
||||
{
|
||||
typedef double3 Type;
|
||||
};
|
||||
|
||||
template <typename T> struct vec4
|
||||
{
|
||||
typedef float Type;
|
||||
}; // dummy
|
||||
template <> struct vec4<float>
|
||||
{
|
||||
typedef float4 Type;
|
||||
};
|
||||
template <> struct vec4<double>
|
||||
{
|
||||
typedef double4 Type;
|
||||
};
|
||||
|
||||
class string;
|
||||
|
||||
// BodySystem abstract base class
|
||||
template <typename T> class BodySystem
|
||||
{
|
||||
public: // methods
|
||||
BodySystem(int numBodies) {}
|
||||
virtual ~BodySystem() {}
|
||||
|
||||
virtual void loadTipsyFile(const std::string &filename) = 0;
|
||||
|
||||
virtual void update(T deltaTime) = 0;
|
||||
|
||||
virtual void setSoftening(T softening) = 0;
|
||||
virtual void setDamping(T damping) = 0;
|
||||
|
||||
virtual T *getArray(BodyArray array) = 0;
|
||||
virtual void setArray(BodyArray array, const T *data) = 0;
|
||||
|
||||
virtual unsigned int getCurrentReadBuffer() const = 0;
|
||||
|
||||
virtual unsigned int getNumBodies() const = 0;
|
||||
|
||||
virtual void synchronizeThreads() const {};
|
||||
|
||||
protected: // methods
|
||||
BodySystem() {} // default constructor
|
||||
|
||||
virtual void _initialize(int numBodies) = 0;
|
||||
virtual void _finalize() = 0;
|
||||
};
|
||||
|
||||
inline float3 scalevec(float3 &vector, float scalar)
|
||||
{
|
||||
float3 rt = vector;
|
||||
rt.x *= scalar;
|
||||
rt.y *= scalar;
|
||||
rt.z *= scalar;
|
||||
return rt;
|
||||
}
|
||||
|
||||
inline float normalize(float3 &vector)
|
||||
{
|
||||
float dist = sqrtf(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
|
||||
|
||||
if (dist > 1e-6) {
|
||||
vector.x /= dist;
|
||||
vector.y /= dist;
|
||||
vector.z /= dist;
|
||||
}
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
inline float dot(float3 v0, float3 v1) { return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z; }
|
||||
|
||||
inline float3 cross(float3 v0, float3 v1)
|
||||
{
|
||||
float3 rt;
|
||||
rt.x = v0.y * v1.z - v0.z * v1.y;
|
||||
rt.y = v0.z * v1.x - v0.x * v1.z;
|
||||
rt.z = v0.x * v1.y - v0.y * v1.x;
|
||||
return rt;
|
||||
}
|
||||
|
||||
// utility function
|
||||
template <typename T>
|
||||
void randomizeBodies(NBodyConfig config,
|
||||
T *pos,
|
||||
T *vel,
|
||||
float *color,
|
||||
float clusterScale,
|
||||
float velocityScale,
|
||||
int numBodies,
|
||||
bool vec4vel)
|
||||
{
|
||||
switch (config) {
|
||||
default:
|
||||
case NBODY_CONFIG_RANDOM: {
|
||||
float scale = clusterScale * std::max<float>(1.0f, numBodies / (1024.0f));
|
||||
float vscale = velocityScale * scale;
|
||||
|
||||
int p = 0, v = 0;
|
||||
int i = 0;
|
||||
|
||||
while (i < numBodies) {
|
||||
float3 point;
|
||||
// const int scale = 16;
|
||||
point.x = rand() / (float)RAND_MAX * 2 - 1;
|
||||
point.y = rand() / (float)RAND_MAX * 2 - 1;
|
||||
point.z = rand() / (float)RAND_MAX * 2 - 1;
|
||||
float lenSqr = dot(point, point);
|
||||
|
||||
if (lenSqr > 1)
|
||||
continue;
|
||||
|
||||
float3 velocity;
|
||||
velocity.x = rand() / (float)RAND_MAX * 2 - 1;
|
||||
velocity.y = rand() / (float)RAND_MAX * 2 - 1;
|
||||
velocity.z = rand() / (float)RAND_MAX * 2 - 1;
|
||||
lenSqr = dot(velocity, velocity);
|
||||
|
||||
if (lenSqr > 1)
|
||||
continue;
|
||||
|
||||
pos[p++] = point.x * scale; // pos.x
|
||||
pos[p++] = point.y * scale; // pos.y
|
||||
pos[p++] = point.z * scale; // pos.z
|
||||
pos[p++] = 1.0f; // mass
|
||||
|
||||
vel[v++] = velocity.x * vscale; // pos.x
|
||||
vel[v++] = velocity.y * vscale; // pos.x
|
||||
vel[v++] = velocity.z * vscale; // pos.x
|
||||
|
||||
if (vec4vel)
|
||||
vel[v++] = 1.0f; // inverse mass
|
||||
|
||||
i++;
|
||||
}
|
||||
} break;
|
||||
|
||||
case NBODY_CONFIG_SHELL: {
|
||||
float scale = clusterScale;
|
||||
float vscale = scale * velocityScale;
|
||||
float inner = 2.5f * scale;
|
||||
float outer = 4.0f * scale;
|
||||
|
||||
int p = 0, v = 0;
|
||||
int i = 0;
|
||||
|
||||
while (i < numBodies) // for(int i=0; i < numBodies; i++)
|
||||
{
|
||||
float x, y, z;
|
||||
x = rand() / (float)RAND_MAX * 2 - 1;
|
||||
y = rand() / (float)RAND_MAX * 2 - 1;
|
||||
z = rand() / (float)RAND_MAX * 2 - 1;
|
||||
|
||||
float3 point = {x, y, z};
|
||||
float len = normalize(point);
|
||||
|
||||
if (len > 1)
|
||||
continue;
|
||||
|
||||
pos[p++] = point.x * (inner + (outer - inner) * rand() / (float)RAND_MAX);
|
||||
pos[p++] = point.y * (inner + (outer - inner) * rand() / (float)RAND_MAX);
|
||||
pos[p++] = point.z * (inner + (outer - inner) * rand() / (float)RAND_MAX);
|
||||
pos[p++] = 1.0f;
|
||||
|
||||
x = 0.0f; // * (rand() / (float) RAND_MAX * 2 - 1);
|
||||
y = 0.0f; // * (rand() / (float) RAND_MAX * 2 - 1);
|
||||
z = 1.0f; // * (rand() / (float) RAND_MAX * 2 - 1);
|
||||
float3 axis = {x, y, z};
|
||||
normalize(axis);
|
||||
|
||||
if (1 - dot(point, axis) < 1e-6) {
|
||||
axis.x = point.y;
|
||||
axis.y = point.x;
|
||||
normalize(axis);
|
||||
}
|
||||
|
||||
// if (point.y < 0) axis = scalevec(axis, -1);
|
||||
float3 vv = {(float)pos[4 * i], (float)pos[4 * i + 1], (float)pos[4 * i + 2]};
|
||||
vv = cross(vv, axis);
|
||||
vel[v++] = vv.x * vscale;
|
||||
vel[v++] = vv.y * vscale;
|
||||
vel[v++] = vv.z * vscale;
|
||||
|
||||
if (vec4vel)
|
||||
vel[v++] = 1.0f;
|
||||
|
||||
i++;
|
||||
}
|
||||
} break;
|
||||
|
||||
case NBODY_CONFIG_EXPAND: {
|
||||
float scale = clusterScale * numBodies / (1024.f);
|
||||
|
||||
if (scale < 1.0f)
|
||||
scale = clusterScale;
|
||||
|
||||
float vscale = scale * velocityScale;
|
||||
|
||||
int p = 0, v = 0;
|
||||
|
||||
for (int i = 0; i < numBodies;) {
|
||||
float3 point;
|
||||
|
||||
point.x = rand() / (float)RAND_MAX * 2 - 1;
|
||||
point.y = rand() / (float)RAND_MAX * 2 - 1;
|
||||
point.z = rand() / (float)RAND_MAX * 2 - 1;
|
||||
|
||||
float lenSqr = dot(point, point);
|
||||
|
||||
if (lenSqr > 1)
|
||||
continue;
|
||||
|
||||
pos[p++] = point.x * scale; // pos.x
|
||||
pos[p++] = point.y * scale; // pos.y
|
||||
pos[p++] = point.z * scale; // pos.z
|
||||
pos[p++] = 1.0f; // mass
|
||||
vel[v++] = point.x * vscale; // pos.x
|
||||
vel[v++] = point.y * vscale; // pos.x
|
||||
vel[v++] = point.z * vscale; // pos.x
|
||||
|
||||
if (vec4vel)
|
||||
vel[v++] = 1.0f; // inverse mass
|
||||
|
||||
i++;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
if (color) {
|
||||
int v = 0;
|
||||
|
||||
for (int i = 0; i < numBodies; i++) {
|
||||
// const int scale = 16;
|
||||
color[v++] = rand() / (float)RAND_MAX;
|
||||
color[v++] = rand() / (float)RAND_MAX;
|
||||
color[v++] = rand() / (float)RAND_MAX;
|
||||
color[v++] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __BODYSYSTEM_H__
|
||||
77
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcpu.h
Normal file
77
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcpu.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __BODYSYSTEMCPU_H__
|
||||
#define __BODYSYSTEMCPU_H__
|
||||
|
||||
#include "bodysystem.h"
|
||||
|
||||
// CPU Body System
|
||||
template <typename T> class BodySystemCPU : public BodySystem<T>
|
||||
{
|
||||
public:
|
||||
BodySystemCPU(int numBodies);
|
||||
virtual ~BodySystemCPU();
|
||||
|
||||
virtual void loadTipsyFile(const std::string &filename);
|
||||
|
||||
virtual void update(T deltaTime);
|
||||
|
||||
virtual void setSoftening(T softening) { m_softeningSquared = softening * softening; }
|
||||
virtual void setDamping(T damping) { m_damping = damping; }
|
||||
|
||||
virtual T *getArray(BodyArray array);
|
||||
virtual void setArray(BodyArray array, const T *data);
|
||||
|
||||
virtual unsigned int getCurrentReadBuffer() const { return 0; }
|
||||
|
||||
virtual unsigned int getNumBodies() const { return m_numBodies; }
|
||||
|
||||
protected: // methods
|
||||
BodySystemCPU() {} // default constructor
|
||||
|
||||
virtual void _initialize(int numBodies);
|
||||
virtual void _finalize();
|
||||
|
||||
void _computeNBodyGravitation();
|
||||
void _integrateNBodySystem(T deltaTime);
|
||||
|
||||
protected: // data
|
||||
int m_numBodies;
|
||||
bool m_bInitialized;
|
||||
|
||||
T *m_pos;
|
||||
T *m_vel;
|
||||
T *m_force;
|
||||
|
||||
T m_softeningSquared;
|
||||
T m_damping;
|
||||
};
|
||||
|
||||
#include "bodysystemcpu_impl.h"
|
||||
|
||||
#endif // __BODYSYSTEMCPU_H__
|
||||
@@ -0,0 +1,270 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bodysystemcpu.h"
|
||||
#include "tipsy.h"
|
||||
|
||||
#ifdef OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
BodySystemCPU<T>::BodySystemCPU(int numBodies)
|
||||
: m_numBodies(numBodies)
|
||||
, m_bInitialized(false)
|
||||
, m_force(0)
|
||||
, m_softeningSquared(.00125f)
|
||||
, m_damping(0.995f)
|
||||
{
|
||||
m_pos = 0;
|
||||
m_vel = 0;
|
||||
|
||||
_initialize(numBodies);
|
||||
}
|
||||
|
||||
template <typename T> BodySystemCPU<T>::~BodySystemCPU()
|
||||
{
|
||||
_finalize();
|
||||
m_numBodies = 0;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::_initialize(int numBodies)
|
||||
{
|
||||
assert(!m_bInitialized);
|
||||
|
||||
m_numBodies = numBodies;
|
||||
|
||||
m_pos = new T[m_numBodies * 4];
|
||||
m_vel = new T[m_numBodies * 4];
|
||||
m_force = new T[m_numBodies * 3];
|
||||
|
||||
memset(m_pos, 0, m_numBodies * 4 * sizeof(T));
|
||||
memset(m_vel, 0, m_numBodies * 4 * sizeof(T));
|
||||
memset(m_force, 0, m_numBodies * 3 * sizeof(T));
|
||||
|
||||
m_bInitialized = true;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::_finalize()
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
delete[] m_pos;
|
||||
delete[] m_vel;
|
||||
delete[] m_force;
|
||||
|
||||
m_bInitialized = false;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::loadTipsyFile(const std::string &filename)
|
||||
{
|
||||
if (m_bInitialized)
|
||||
_finalize();
|
||||
|
||||
vector<typename vec4<T>::Type> positions;
|
||||
vector<typename vec4<T>::Type> velocities;
|
||||
vector<int> ids;
|
||||
|
||||
int nBodies = 0;
|
||||
int nFirst = 0, nSecond = 0, nThird = 0;
|
||||
|
||||
read_tipsy_file(positions, velocities, ids, filename, nBodies, nFirst, nSecond, nThird);
|
||||
|
||||
_initialize(nBodies);
|
||||
|
||||
memcpy(m_pos, &positions[0], sizeof(vec4<T>) * nBodies);
|
||||
memcpy(m_vel, &velocities[0], sizeof(vec4<T>) * nBodies);
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::update(T deltaTime)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
_integrateNBodySystem(deltaTime);
|
||||
|
||||
// std::swap(m_currentRead, m_currentWrite);
|
||||
}
|
||||
|
||||
template <typename T> T *BodySystemCPU<T>::getArray(BodyArray array)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
T *data = 0;
|
||||
|
||||
switch (array) {
|
||||
default:
|
||||
case BODYSYSTEM_POSITION:
|
||||
data = m_pos;
|
||||
break;
|
||||
|
||||
case BODYSYSTEM_VELOCITY:
|
||||
data = m_vel;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::setArray(BodyArray array, const T *data)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
T *target = 0;
|
||||
|
||||
switch (array) {
|
||||
default:
|
||||
case BODYSYSTEM_POSITION:
|
||||
target = m_pos;
|
||||
break;
|
||||
|
||||
case BODYSYSTEM_VELOCITY:
|
||||
target = m_vel;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(target, data, m_numBodies * 4 * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> T sqrt_T(T x) { return sqrt(x); }
|
||||
|
||||
template <> float sqrt_T<float>(float x) { return sqrtf(x); }
|
||||
|
||||
template <typename T> void bodyBodyInteraction(T accel[3], T posMass0[4], T posMass1[4], T softeningSquared)
|
||||
{
|
||||
T r[3];
|
||||
|
||||
// r_01 [3 FLOPS]
|
||||
r[0] = posMass1[0] - posMass0[0];
|
||||
r[1] = posMass1[1] - posMass0[1];
|
||||
r[2] = posMass1[2] - posMass0[2];
|
||||
|
||||
// d^2 + e^2 [6 FLOPS]
|
||||
T distSqr = r[0] * r[0] + r[1] * r[1] + r[2] * r[2];
|
||||
distSqr += softeningSquared;
|
||||
|
||||
// invDistCube =1/distSqr^(3/2) [4 FLOPS (2 mul, 1 sqrt, 1 inv)]
|
||||
T invDist = (T)1.0 / (T)sqrt((double)distSqr);
|
||||
T invDistCube = invDist * invDist * invDist;
|
||||
|
||||
// s = m_j * invDistCube [1 FLOP]
|
||||
T s = posMass1[3] * invDistCube;
|
||||
|
||||
// (m_1 * r_01) / (d^2 + e^2)^(3/2) [6 FLOPS]
|
||||
accel[0] += r[0] * s;
|
||||
accel[1] += r[1] * s;
|
||||
accel[2] += r[2] * s;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::_computeNBodyGravitation()
|
||||
{
|
||||
#ifdef OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < m_numBodies; i++) {
|
||||
int indexForce = 3 * i;
|
||||
|
||||
T acc[3] = {0, 0, 0};
|
||||
|
||||
// We unroll this loop 4X for a small performance boost.
|
||||
int j = 0;
|
||||
|
||||
while (j < m_numBodies) {
|
||||
bodyBodyInteraction<T>(acc, &m_pos[4 * i], &m_pos[4 * j], m_softeningSquared);
|
||||
j++;
|
||||
bodyBodyInteraction<T>(acc, &m_pos[4 * i], &m_pos[4 * j], m_softeningSquared);
|
||||
j++;
|
||||
bodyBodyInteraction<T>(acc, &m_pos[4 * i], &m_pos[4 * j], m_softeningSquared);
|
||||
j++;
|
||||
bodyBodyInteraction<T>(acc, &m_pos[4 * i], &m_pos[4 * j], m_softeningSquared);
|
||||
j++;
|
||||
}
|
||||
|
||||
m_force[indexForce] = acc[0];
|
||||
m_force[indexForce + 1] = acc[1];
|
||||
m_force[indexForce + 2] = acc[2];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCPU<T>::_integrateNBodySystem(T deltaTime)
|
||||
{
|
||||
_computeNBodyGravitation();
|
||||
|
||||
#ifdef OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < m_numBodies; ++i) {
|
||||
int index = 4 * i;
|
||||
int indexForce = 3 * i;
|
||||
|
||||
T pos[3], vel[3], force[3];
|
||||
pos[0] = m_pos[index + 0];
|
||||
pos[1] = m_pos[index + 1];
|
||||
pos[2] = m_pos[index + 2];
|
||||
T invMass = m_pos[index + 3];
|
||||
|
||||
vel[0] = m_vel[index + 0];
|
||||
vel[1] = m_vel[index + 1];
|
||||
vel[2] = m_vel[index + 2];
|
||||
|
||||
force[0] = m_force[indexForce + 0];
|
||||
force[1] = m_force[indexForce + 1];
|
||||
force[2] = m_force[indexForce + 2];
|
||||
|
||||
// acceleration = force / mass;
|
||||
// new velocity = old velocity + acceleration * deltaTime
|
||||
vel[0] += (force[0] * invMass) * deltaTime;
|
||||
vel[1] += (force[1] * invMass) * deltaTime;
|
||||
vel[2] += (force[2] * invMass) * deltaTime;
|
||||
|
||||
vel[0] *= m_damping;
|
||||
vel[1] *= m_damping;
|
||||
vel[2] *= m_damping;
|
||||
|
||||
// new position = old position + velocity * deltaTime
|
||||
pos[0] += vel[0] * deltaTime;
|
||||
pos[1] += vel[1] * deltaTime;
|
||||
pos[2] += vel[2] * deltaTime;
|
||||
|
||||
m_pos[index + 0] = pos[0];
|
||||
m_pos[index + 1] = pos[1];
|
||||
m_pos[index + 2] = pos[2];
|
||||
|
||||
m_vel[index + 0] = vel[0];
|
||||
m_vel[index + 1] = vel[1];
|
||||
m_vel[index + 2] = vel[2];
|
||||
}
|
||||
}
|
||||
273
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcuda.cu
Normal file
273
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcuda.cu
Normal file
@@ -0,0 +1,273 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <helper_cuda.h>
|
||||
#include <math.h>
|
||||
|
||||
// #include <GL/glew.h>
|
||||
// #include <GL/freeglut.h>
|
||||
|
||||
// CUDA standard includes
|
||||
#include <cuda_runtime.h>
|
||||
// #include <cuda_gl_interop.h>
|
||||
|
||||
#include "bodysystem.h"
|
||||
|
||||
__constant__ float softeningSquared;
|
||||
__constant__ double softeningSquared_fp64;
|
||||
|
||||
cudaError_t setSofteningSquared(float softeningSq)
|
||||
{
|
||||
return cudaMemcpyToSymbol(softeningSquared, &softeningSq, sizeof(float), 0, cudaMemcpyHostToDevice);
|
||||
}
|
||||
|
||||
cudaError_t setSofteningSquared(double softeningSq)
|
||||
{
|
||||
return cudaMemcpyToSymbol(softeningSquared_fp64, &softeningSq, sizeof(double), 0, cudaMemcpyHostToDevice);
|
||||
}
|
||||
|
||||
template <class T> struct SharedMemory
|
||||
{
|
||||
__device__ inline operator T *()
|
||||
{
|
||||
extern __shared__ int __smem[];
|
||||
return (T *)__smem;
|
||||
}
|
||||
|
||||
__device__ inline operator const T *() const
|
||||
{
|
||||
extern __shared__ int __smem[];
|
||||
return (T *)__smem;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> __device__ T rsqrt_T(T x) { return rsqrt(x); }
|
||||
|
||||
template <> __device__ float rsqrt_T<float>(float x) { return rsqrtf(x); }
|
||||
|
||||
template <> __device__ double rsqrt_T<double>(double x) { return rsqrt(x); }
|
||||
|
||||
// Macros to simplify shared memory addressing
|
||||
#define SX(i) sharedPos[i + blockDim.x * threadIdx.y]
|
||||
// This macro is only used when multithreadBodies is true (below)
|
||||
#define SX_SUM(i, j) sharedPos[i + blockDim.x * j]
|
||||
|
||||
template <typename T> __device__ T getSofteningSquared() { return softeningSquared; }
|
||||
template <> __device__ double getSofteningSquared<double>() { return softeningSquared_fp64; }
|
||||
|
||||
template <typename T> struct DeviceData
|
||||
{
|
||||
T *dPos[2]; // mapped host pointers
|
||||
T *dVel;
|
||||
cudaEvent_t event;
|
||||
unsigned int offset;
|
||||
unsigned int numBodies;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
__device__ typename vec3<T>::Type
|
||||
bodyBodyInteraction(typename vec3<T>::Type ai, typename vec4<T>::Type bi, typename vec4<T>::Type bj)
|
||||
{
|
||||
typename vec3<T>::Type r;
|
||||
|
||||
// r_ij [3 FLOPS]
|
||||
r.x = bj.x - bi.x;
|
||||
r.y = bj.y - bi.y;
|
||||
r.z = bj.z - bi.z;
|
||||
|
||||
// distSqr = dot(r_ij, r_ij) + EPS^2 [6 FLOPS]
|
||||
T distSqr = r.x * r.x + r.y * r.y + r.z * r.z;
|
||||
distSqr += getSofteningSquared<T>();
|
||||
|
||||
// invDistCube =1/distSqr^(3/2) [4 FLOPS (2 mul, 1 sqrt, 1 inv)]
|
||||
T invDist = rsqrt_T(distSqr);
|
||||
T invDistCube = invDist * invDist * invDist;
|
||||
|
||||
// s = m_j * invDistCube [1 FLOP]
|
||||
T s = bj.w * invDistCube;
|
||||
|
||||
// a_i = a_i + s * r_ij [6 FLOPS]
|
||||
ai.x += r.x * s;
|
||||
ai.y += r.y * s;
|
||||
ai.z += r.z * s;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__device__ typename vec3<T>::Type
|
||||
computeBodyAccel(typename vec4<T>::Type bodyPos, typename vec4<T>::Type *positions, int numTiles)
|
||||
{
|
||||
typename vec4<T>::Type *sharedPos = SharedMemory<typename vec4<T>::Type>();
|
||||
|
||||
typename vec3<T>::Type acc = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
for (int tile = 0; tile < numTiles; tile++) {
|
||||
sharedPos[threadIdx.x] = positions[tile * blockDim.x + threadIdx.x];
|
||||
|
||||
__syncthreads();
|
||||
|
||||
// This is the "tile_calculation" from the GPUG3 article.
|
||||
#pragma unroll 128
|
||||
|
||||
for (unsigned int counter = 0; counter < blockDim.x; counter++) {
|
||||
acc = bodyBodyInteraction<T>(acc, bodyPos, sharedPos[counter]);
|
||||
}
|
||||
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void integrateBodies(typename vec4<T>::Type *__restrict__ newPos,
|
||||
typename vec4<T>::Type *__restrict__ oldPos,
|
||||
typename vec4<T>::Type *vel,
|
||||
unsigned int deviceOffset,
|
||||
unsigned int deviceNumBodies,
|
||||
float deltaTime,
|
||||
float damping,
|
||||
int numTiles)
|
||||
{
|
||||
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
if (index >= deviceNumBodies) {
|
||||
return;
|
||||
}
|
||||
|
||||
typename vec4<T>::Type position = oldPos[deviceOffset + index];
|
||||
|
||||
typename vec3<T>::Type accel = computeBodyAccel<T>(position, oldPos, numTiles);
|
||||
|
||||
// acceleration = force / mass;
|
||||
// new velocity = old velocity + acceleration * deltaTime
|
||||
// note we factor out the body's mass from the equation, here and in
|
||||
// bodyBodyInteraction (because they cancel out). Thus here force ==
|
||||
// acceleration
|
||||
typename vec4<T>::Type velocity = vel[deviceOffset + index];
|
||||
|
||||
velocity.x += accel.x * deltaTime;
|
||||
velocity.y += accel.y * deltaTime;
|
||||
velocity.z += accel.z * deltaTime;
|
||||
|
||||
velocity.x *= damping;
|
||||
velocity.y *= damping;
|
||||
velocity.z *= damping;
|
||||
|
||||
// new position = old position + velocity * deltaTime
|
||||
position.x += velocity.x * deltaTime;
|
||||
position.y += velocity.y * deltaTime;
|
||||
position.z += velocity.z * deltaTime;
|
||||
|
||||
// store new position and velocity
|
||||
newPos[deviceOffset + index] = position;
|
||||
vel[deviceOffset + index] = velocity;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void integrateNbodySystem(DeviceData<T> *deviceData,
|
||||
cudaGraphicsResource **pgres,
|
||||
unsigned int currentRead,
|
||||
float deltaTime,
|
||||
float damping,
|
||||
unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
int blockSize,
|
||||
bool bUsePBO)
|
||||
{
|
||||
if (bUsePBO) {
|
||||
checkCudaErrors(cudaGraphicsResourceSetMapFlags(pgres[currentRead], cudaGraphicsMapFlagsReadOnly));
|
||||
checkCudaErrors(cudaGraphicsResourceSetMapFlags(pgres[1 - currentRead], cudaGraphicsMapFlagsWriteDiscard));
|
||||
checkCudaErrors(cudaGraphicsMapResources(2, pgres, 0));
|
||||
size_t bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
|
||||
(void **)&(deviceData[0].dPos[currentRead]), &bytes, pgres[currentRead]));
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
|
||||
(void **)&(deviceData[0].dPos[1 - currentRead]), &bytes, pgres[1 - currentRead]));
|
||||
}
|
||||
|
||||
for (unsigned int dev = 0; dev != numDevices; dev++) {
|
||||
if (numDevices > 1) {
|
||||
cudaSetDevice(dev);
|
||||
}
|
||||
|
||||
int numBlocks = (deviceData[dev].numBodies + blockSize - 1) / blockSize;
|
||||
int numTiles = (numBodies + blockSize - 1) / blockSize;
|
||||
int sharedMemSize = blockSize * 4 * sizeof(T); // 4 floats for pos
|
||||
|
||||
integrateBodies<T>
|
||||
<<<numBlocks, blockSize, sharedMemSize>>>((typename vec4<T>::Type *)deviceData[dev].dPos[1 - currentRead],
|
||||
(typename vec4<T>::Type *)deviceData[dev].dPos[currentRead],
|
||||
(typename vec4<T>::Type *)deviceData[dev].dVel,
|
||||
deviceData[dev].offset,
|
||||
deviceData[dev].numBodies,
|
||||
deltaTime,
|
||||
damping,
|
||||
numTiles);
|
||||
|
||||
if (numDevices > 1) {
|
||||
checkCudaErrors(cudaEventRecord(deviceData[dev].event));
|
||||
// MJH: Hack on older driver versions to force kernel launches to flush!
|
||||
cudaStreamQuery(0);
|
||||
}
|
||||
|
||||
// check if kernel invocation generated an error
|
||||
getLastCudaError("Kernel execution failed");
|
||||
}
|
||||
|
||||
if (numDevices > 1) {
|
||||
for (unsigned int dev = 0; dev < numDevices; dev++) {
|
||||
checkCudaErrors(cudaEventSynchronize(deviceData[dev].event));
|
||||
}
|
||||
}
|
||||
|
||||
if (bUsePBO) {
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(2, pgres, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit specializations needed to generate code
|
||||
template void integrateNbodySystem<float>(DeviceData<float> *deviceData,
|
||||
cudaGraphicsResource **pgres,
|
||||
unsigned int currentRead,
|
||||
float deltaTime,
|
||||
float damping,
|
||||
unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
int blockSize,
|
||||
bool bUsePBO);
|
||||
|
||||
template void integrateNbodySystem<double>(DeviceData<double> *deviceData,
|
||||
cudaGraphicsResource **pgres,
|
||||
unsigned int currentRead,
|
||||
float deltaTime,
|
||||
float damping,
|
||||
unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
int blockSize,
|
||||
bool bUsePBO);
|
||||
100
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcuda.h
Normal file
100
cpp/8_Platform_Specific/Tegra/nbody_opengles/bodysystemcuda.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __BODYSYSTEMCUDA_H__
|
||||
#define __BODYSYSTEMCUDA_H__
|
||||
|
||||
#include "bodysystem.h"
|
||||
|
||||
template <typename T> struct DeviceData
|
||||
{
|
||||
T *dPos[2]; // mapped host pointers
|
||||
T *dVel;
|
||||
cudaEvent_t event;
|
||||
unsigned int offset;
|
||||
unsigned int numBodies;
|
||||
};
|
||||
|
||||
// CUDA BodySystem: runs on the GPU
|
||||
template <typename T> class BodySystemCUDA : public BodySystem<T>
|
||||
{
|
||||
public:
|
||||
BodySystemCUDA(unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
unsigned int blockSize,
|
||||
bool usePBO,
|
||||
bool useSysMem = false);
|
||||
virtual ~BodySystemCUDA();
|
||||
|
||||
virtual void loadTipsyFile(const std::string &filename);
|
||||
|
||||
virtual void update(T deltaTime);
|
||||
|
||||
virtual void setSoftening(T softening);
|
||||
virtual void setDamping(T damping);
|
||||
|
||||
virtual T *getArray(BodyArray array);
|
||||
virtual void setArray(BodyArray array, const T *data);
|
||||
|
||||
virtual unsigned int getCurrentReadBuffer() const { return m_pbo[m_currentRead]; }
|
||||
|
||||
virtual unsigned int getNumBodies() const { return m_numBodies; }
|
||||
|
||||
protected: // methods
|
||||
BodySystemCUDA() {}
|
||||
|
||||
virtual void _initialize(int numBodies);
|
||||
virtual void _finalize();
|
||||
|
||||
protected: // data
|
||||
unsigned int m_numBodies;
|
||||
unsigned int m_numDevices;
|
||||
bool m_bInitialized;
|
||||
|
||||
// Host data
|
||||
T *m_hPos[2];
|
||||
T *m_hVel;
|
||||
|
||||
DeviceData<T> *m_deviceData;
|
||||
|
||||
bool m_bUsePBO;
|
||||
bool m_bUseSysMem;
|
||||
unsigned int m_SMVersion;
|
||||
|
||||
T m_damping;
|
||||
|
||||
unsigned int m_pbo[2];
|
||||
cudaGraphicsResource *m_pGRes[2];
|
||||
unsigned int m_currentRead;
|
||||
unsigned int m_currentWrite;
|
||||
|
||||
unsigned int m_blockSize;
|
||||
};
|
||||
|
||||
#include "bodysystemcuda_impl.h"
|
||||
|
||||
#endif // __BODYSYSTEMCUDA_H__
|
||||
@@ -0,0 +1,376 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <helper_cuda.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <vector>
|
||||
// #include <GL/glew.h>
|
||||
|
||||
#include <cuda_gl_interop.h>
|
||||
|
||||
template <typename T>
|
||||
void integrateNbodySystem(DeviceData<T> *deviceData,
|
||||
cudaGraphicsResource **pgres,
|
||||
unsigned int currentRead,
|
||||
float deltaTime,
|
||||
float damping,
|
||||
unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
int blockSize,
|
||||
bool bUsePBO);
|
||||
|
||||
cudaError_t setSofteningSquared(float softeningSq);
|
||||
cudaError_t setSofteningSquared(double softeningSq);
|
||||
|
||||
template <typename T>
|
||||
BodySystemCUDA<T>::BodySystemCUDA(unsigned int numBodies,
|
||||
unsigned int numDevices,
|
||||
unsigned int blockSize,
|
||||
bool usePBO,
|
||||
bool useSysMem)
|
||||
: m_numBodies(numBodies)
|
||||
, m_numDevices(numDevices)
|
||||
, m_bInitialized(false)
|
||||
, m_bUsePBO(usePBO)
|
||||
, m_bUseSysMem(useSysMem)
|
||||
, m_currentRead(0)
|
||||
, m_currentWrite(1)
|
||||
, m_blockSize(blockSize)
|
||||
{
|
||||
m_hPos[0] = m_hPos[1] = 0;
|
||||
m_hVel = 0;
|
||||
|
||||
m_deviceData = 0;
|
||||
|
||||
_initialize(numBodies);
|
||||
setSoftening(0.00125f);
|
||||
setDamping(0.995f);
|
||||
}
|
||||
|
||||
template <typename T> BodySystemCUDA<T>::~BodySystemCUDA()
|
||||
{
|
||||
_finalize();
|
||||
m_numBodies = 0;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::_initialize(int numBodies)
|
||||
{
|
||||
assert(!m_bInitialized);
|
||||
|
||||
m_numBodies = numBodies;
|
||||
|
||||
unsigned int memSize = sizeof(T) * 4 * numBodies;
|
||||
|
||||
m_deviceData = new DeviceData<T>[m_numDevices];
|
||||
|
||||
// divide up the workload amongst Devices
|
||||
float *weights = new float[m_numDevices];
|
||||
int *numSms = new int[m_numDevices];
|
||||
float total = 0;
|
||||
|
||||
for (unsigned int i = 0; i < m_numDevices; i++) {
|
||||
cudaDeviceProp props;
|
||||
checkCudaErrors(cudaGetDeviceProperties(&props, i));
|
||||
|
||||
// Choose the weight based on the Compute Capability
|
||||
// We estimate that a CC2.0 SM is about 4.0x faster than a CC 1.x SM for
|
||||
// this application (since a 15-SM GF100 is about 2X faster than a 30-SM
|
||||
// GT200).
|
||||
numSms[i] = props.multiProcessorCount;
|
||||
weights[i] = numSms[i] * (props.major >= 2 ? 4.f : 1.f);
|
||||
total += weights[i];
|
||||
}
|
||||
|
||||
unsigned int offset = 0;
|
||||
unsigned int remaining = m_numBodies;
|
||||
|
||||
for (unsigned int i = 0; i < m_numDevices; i++) {
|
||||
unsigned int count = (int)((weights[i] / total) * m_numBodies);
|
||||
unsigned int round = numSms[i] * 256;
|
||||
count = round * ((count + round - 1) / round);
|
||||
|
||||
if (count > remaining) {
|
||||
count = remaining;
|
||||
}
|
||||
|
||||
remaining -= count;
|
||||
m_deviceData[i].offset = offset;
|
||||
m_deviceData[i].numBodies = count;
|
||||
offset += count;
|
||||
|
||||
if ((i == m_numDevices - 1) && (offset < m_numBodies - 1)) {
|
||||
m_deviceData[i].numBodies += m_numBodies - offset;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] weights;
|
||||
delete[] numSms;
|
||||
|
||||
if (m_bUseSysMem) {
|
||||
checkCudaErrors(cudaHostAlloc((void **)&m_hPos[0], memSize, cudaHostAllocMapped | cudaHostAllocPortable));
|
||||
checkCudaErrors(cudaHostAlloc((void **)&m_hPos[1], memSize, cudaHostAllocMapped | cudaHostAllocPortable));
|
||||
checkCudaErrors(cudaHostAlloc((void **)&m_hVel, memSize, cudaHostAllocMapped | cudaHostAllocPortable));
|
||||
|
||||
memset(m_hPos[0], 0, memSize);
|
||||
memset(m_hPos[1], 0, memSize);
|
||||
memset(m_hVel, 0, memSize);
|
||||
|
||||
for (unsigned int i = 0; i < m_numDevices; i++) {
|
||||
if (m_numDevices > 1) {
|
||||
checkCudaErrors(cudaSetDevice(i));
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaEventCreate(&m_deviceData[i].event));
|
||||
checkCudaErrors(cudaHostGetDevicePointer((void **)&m_deviceData[i].dPos[0], (void *)m_hPos[0], 0));
|
||||
checkCudaErrors(cudaHostGetDevicePointer((void **)&m_deviceData[i].dPos[1], (void *)m_hPos[1], 0));
|
||||
checkCudaErrors(cudaHostGetDevicePointer((void **)&m_deviceData[i].dVel, (void *)m_hVel, 0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_hPos[0] = new T[m_numBodies * 4];
|
||||
m_hVel = new T[m_numBodies * 4];
|
||||
|
||||
memset(m_hPos[0], 0, memSize);
|
||||
memset(m_hVel, 0, memSize);
|
||||
|
||||
checkCudaErrors(cudaEventCreate(&m_deviceData[0].event));
|
||||
|
||||
if (m_bUsePBO) {
|
||||
// create the position pixel buffer objects for rendering
|
||||
// we will actually compute directly from this memory in CUDA too
|
||||
glGenBuffers(2, (GLuint *)m_pbo);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pbo[i]);
|
||||
glBufferData(GL_ARRAY_BUFFER, memSize, m_hPos[0], GL_DYNAMIC_DRAW);
|
||||
|
||||
int size = 0;
|
||||
glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, (GLint *)&size);
|
||||
|
||||
if ((unsigned)size != memSize) {
|
||||
fprintf(stderr, "WARNING: Pixel Buffer Object allocation failed!n");
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&m_pGRes[i], m_pbo[i], cudaGraphicsMapFlagsNone));
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkCudaErrors(cudaMalloc((void **)&m_deviceData[0].dPos[0], memSize));
|
||||
checkCudaErrors(cudaMalloc((void **)&m_deviceData[0].dPos[1], memSize));
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&m_deviceData[0].dVel, memSize));
|
||||
}
|
||||
|
||||
m_bInitialized = true;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::_finalize()
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
if (m_bUseSysMem) {
|
||||
checkCudaErrors(cudaFreeHost(m_hPos[0]));
|
||||
checkCudaErrors(cudaFreeHost(m_hPos[1]));
|
||||
checkCudaErrors(cudaFreeHost(m_hVel));
|
||||
|
||||
for (unsigned int i = 0; i < m_numDevices; i++) {
|
||||
cudaEventDestroy(m_deviceData[i].event);
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete[] m_hPos[0];
|
||||
delete[] m_hPos[1];
|
||||
delete[] m_hVel;
|
||||
|
||||
checkCudaErrors(cudaFree((void **)m_deviceData[0].dVel));
|
||||
|
||||
if (m_bUsePBO) {
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(m_pGRes[0]));
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(m_pGRes[1]));
|
||||
glDeleteBuffers(2, (const GLuint *)m_pbo);
|
||||
}
|
||||
else {
|
||||
checkCudaErrors(cudaFree((void **)m_deviceData[0].dPos[0]));
|
||||
checkCudaErrors(cudaFree((void **)m_deviceData[0].dPos[1]));
|
||||
}
|
||||
}
|
||||
|
||||
delete[] m_deviceData;
|
||||
|
||||
m_bInitialized = false;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::loadTipsyFile(const std::string &filename)
|
||||
{
|
||||
if (m_bInitialized)
|
||||
_finalize();
|
||||
|
||||
std::vector<typename vec4<T>::Type> positions;
|
||||
std::vector<typename vec4<T>::Type> velocities;
|
||||
std::vector<int> ids;
|
||||
|
||||
int nBodies = 0;
|
||||
int nFirst = 0, nSecond = 0, nThird = 0;
|
||||
|
||||
read_tipsy_file(positions, velocities, ids, filename, nBodies, nFirst, nSecond, nThird);
|
||||
|
||||
_initialize(nBodies);
|
||||
|
||||
setArray(BODYSYSTEM_POSITION, (T *)&positions[0]);
|
||||
setArray(BODYSYSTEM_VELOCITY, (T *)&velocities[0]);
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::setSoftening(T softening)
|
||||
{
|
||||
T softeningSq = softening * softening;
|
||||
|
||||
for (unsigned int i = 0; i < m_numDevices; i++) {
|
||||
if (m_numDevices > 1) {
|
||||
checkCudaErrors(cudaSetDevice(i));
|
||||
}
|
||||
|
||||
checkCudaErrors(setSofteningSquared(softeningSq));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::setDamping(T damping) { m_damping = damping; }
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::update(T deltaTime)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
integrateNbodySystem<T>(m_deviceData,
|
||||
m_pGRes,
|
||||
m_currentRead,
|
||||
(float)deltaTime,
|
||||
(float)m_damping,
|
||||
m_numBodies,
|
||||
m_numDevices,
|
||||
m_blockSize,
|
||||
m_bUsePBO);
|
||||
|
||||
std::swap(m_currentRead, m_currentWrite);
|
||||
}
|
||||
|
||||
template <typename T> T *BodySystemCUDA<T>::getArray(BodyArray array)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
T *hdata = 0;
|
||||
T *ddata = 0;
|
||||
|
||||
cudaGraphicsResource *pgres = NULL;
|
||||
|
||||
int currentReadHost = m_bUseSysMem ? m_currentRead : 0;
|
||||
|
||||
switch (array) {
|
||||
default:
|
||||
case BODYSYSTEM_POSITION:
|
||||
hdata = m_hPos[currentReadHost];
|
||||
ddata = m_deviceData[0].dPos[m_currentRead];
|
||||
|
||||
if (m_bUsePBO) {
|
||||
pgres = m_pGRes[m_currentRead];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BODYSYSTEM_VELOCITY:
|
||||
hdata = m_hVel;
|
||||
ddata = m_deviceData[0].dVel;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_bUseSysMem) {
|
||||
if (pgres) {
|
||||
checkCudaErrors(cudaGraphicsResourceSetMapFlags(pgres, cudaGraphicsMapFlagsReadOnly));
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &pgres, 0));
|
||||
size_t bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&ddata, &bytes, pgres));
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaMemcpy(hdata, ddata, m_numBodies * 4 * sizeof(T), cudaMemcpyDeviceToHost));
|
||||
|
||||
if (pgres) {
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &pgres, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return hdata;
|
||||
}
|
||||
|
||||
template <typename T> void BodySystemCUDA<T>::setArray(BodyArray array, const T *data)
|
||||
{
|
||||
assert(m_bInitialized);
|
||||
|
||||
m_currentRead = 0;
|
||||
m_currentWrite = 1;
|
||||
|
||||
switch (array) {
|
||||
default:
|
||||
case BODYSYSTEM_POSITION: {
|
||||
if (m_bUsePBO) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pbo[m_currentRead]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(T) * m_numBodies, data);
|
||||
|
||||
int size = 0;
|
||||
glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, (GLint *)&size);
|
||||
|
||||
if ((unsigned)size != 4 * (sizeof(T) * m_numBodies)) {
|
||||
fprintf(stderr, "WARNING: Pixel Buffer Object download failed!n");
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
else {
|
||||
if (m_bUseSysMem) {
|
||||
memcpy(m_hPos[m_currentRead], data, m_numBodies * 4 * sizeof(T));
|
||||
}
|
||||
else
|
||||
checkCudaErrors(cudaMemcpy(
|
||||
m_deviceData[0].dPos[m_currentRead], data, m_numBodies * 4 * sizeof(T), cudaMemcpyHostToDevice));
|
||||
}
|
||||
} break;
|
||||
|
||||
case BODYSYSTEM_VELOCITY:
|
||||
if (m_bUseSysMem) {
|
||||
memcpy(m_hVel, data, m_numBodies * 4 * sizeof(T));
|
||||
}
|
||||
else
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(m_deviceData[0].dVel, data, m_numBodies * 4 * sizeof(T), cudaMemcpyHostToDevice));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
BIN
cpp/8_Platform_Specific/Tegra/nbody_opengles/galaxy_20K.bin
Normal file
BIN
cpp/8_Platform_Specific/Tegra/nbody_opengles/galaxy_20K.bin
Normal file
Binary file not shown.
1166
cpp/8_Platform_Specific/Tegra/nbody_opengles/nbody_opengles.cpp
Normal file
1166
cpp/8_Platform_Specific/Tegra/nbody_opengles/nbody_opengles.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,377 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include "render_particles.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cuda_gl_interop.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <math.h>
|
||||
|
||||
void mat_identity(matrix4 m)
|
||||
{
|
||||
m[0][1] = m[0][2] = m[0][3] = m[1][0] = m[1][2] = m[1][3] = m[2][0] = m[2][1] = m[2][3] = m[3][0] = m[3][1] =
|
||||
m[3][2] = 0.0f;
|
||||
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void mat_multiply(matrix4 m0, matrix4 m1)
|
||||
{
|
||||
float m[4];
|
||||
|
||||
for (int r = 0; r < 4; r++) {
|
||||
m[0] = m[1] = m[2] = m[3] = 0.0f;
|
||||
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m[c] += m0[i][r] * m1[c][i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int c = 0; c < 4; c++) {
|
||||
m0[c][r] = m[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mat_translate(matrix4 m, vector3 v)
|
||||
{
|
||||
matrix4 m2;
|
||||
m2[0][0] = m2[1][1] = m2[2][2] = m2[3][3] = 1.0f;
|
||||
m2[0][1] = m2[0][2] = m2[0][3] = m2[1][0] = m2[1][2] = m2[1][3] = m2[2][0] = m2[2][1] = m2[2][3] = 0.0f;
|
||||
m2[3][0] = v[0];
|
||||
m2[3][1] = v[1];
|
||||
m2[3][2] = v[2];
|
||||
mat_multiply(m, m2);
|
||||
}
|
||||
|
||||
void mat_perspective(matrix4 m, GLfloat fovy, GLfloat aspect, GLfloat znear, GLfloat zfar)
|
||||
{
|
||||
matrix4 m2;
|
||||
m2[1][0] = m2[2][0] = m2[3][0] = m2[0][1] = m2[2][1] = m2[3][1] = m2[0][2] = m2[1][2] = m2[0][3] = m2[1][3] =
|
||||
m2[3][3] = 0.0f;
|
||||
m2[2][3] = -1.0f;
|
||||
|
||||
float f = 1 / tan((fovy * M_PI / 180) / 2);
|
||||
m2[0][0] = f / aspect;
|
||||
m2[1][1] = f;
|
||||
|
||||
m2[2][2] = ((znear + zfar) / (znear - zfar));
|
||||
m2[3][2] = ((2 * znear * zfar) / (znear - zfar));
|
||||
|
||||
mat_multiply(m, m2);
|
||||
}
|
||||
|
||||
ParticleRenderer::ParticleRenderer(unsigned int windowWidth, unsigned int windowHeight)
|
||||
: m_pos(0)
|
||||
, m_numParticles(0)
|
||||
, m_pointSize(1.0f)
|
||||
, m_spriteSize(2.0f)
|
||||
, m_vertexShader(0)
|
||||
, m_vertexShaderPoints(0)
|
||||
, m_fragmentShader(0)
|
||||
, m_programPoints(0)
|
||||
, m_programSprites(0)
|
||||
, m_texture(0)
|
||||
, m_pbo(0)
|
||||
, m_vboColor(0)
|
||||
, m_windowWidth(windowWidth)
|
||||
, m_windowHeight(windowHeight)
|
||||
, m_bFp64Positions(false)
|
||||
{
|
||||
m_camera[0] = 0;
|
||||
m_camera[1] = 0;
|
||||
m_camera[2] = 0;
|
||||
_initGL();
|
||||
}
|
||||
|
||||
ParticleRenderer::~ParticleRenderer() { m_pos = 0; }
|
||||
|
||||
void ParticleRenderer::resetPBO() { glDeleteBuffers(1, (GLuint *)&m_pbo); }
|
||||
|
||||
void ParticleRenderer::setPositions(float *pos, int numParticles)
|
||||
{
|
||||
m_pos = pos;
|
||||
m_numParticles = numParticles;
|
||||
|
||||
if (!m_pbo) {
|
||||
glGenBuffers(1, (GLuint *)&m_pbo);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(float), pos, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
checkGLErrors("Setting particle float position");
|
||||
}
|
||||
|
||||
void ParticleRenderer::setPositions(double *pos, int numParticles)
|
||||
{
|
||||
m_bFp64Positions = true;
|
||||
m_pos_fp64 = pos;
|
||||
m_numParticles = numParticles;
|
||||
|
||||
if (!m_pbo) {
|
||||
glGenBuffers(1, (GLuint *)&m_pbo);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(double), pos, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
checkGLErrors("Setting particle double position");
|
||||
}
|
||||
|
||||
void ParticleRenderer::setColors(float *color, int numParticles)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vboColor);
|
||||
glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(float), color, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void ParticleRenderer::setBaseColor(float color[4])
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_baseColor[i] = color[i];
|
||||
}
|
||||
|
||||
void ParticleRenderer::setPBO(unsigned int pbo, int numParticles, bool fp64)
|
||||
{
|
||||
m_pbo = pbo;
|
||||
m_numParticles = numParticles;
|
||||
|
||||
if (fp64)
|
||||
m_bFp64Positions = true;
|
||||
}
|
||||
|
||||
void ParticleRenderer::display()
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glUseProgram(m_programSprites);
|
||||
|
||||
// Set modelview and projection matrices
|
||||
GLint h_ModelViewMatrix = glGetUniformLocation(m_programSprites, "modelview");
|
||||
GLint h_ProjectionMatrix = glGetUniformLocation(m_programSprites, "projection");
|
||||
matrix4 modelview;
|
||||
matrix4 projection;
|
||||
mat_identity(modelview);
|
||||
mat_identity(projection);
|
||||
mat_translate(modelview, m_camera);
|
||||
mat_perspective(projection, 60, (float)m_windowWidth / (float)m_windowHeight, 0.1, 1000.0);
|
||||
glUniformMatrix4fv(h_ModelViewMatrix, 1, GL_FALSE, (GLfloat *)modelview);
|
||||
glUniformMatrix4fv(h_ProjectionMatrix, 1, GL_FALSE, (GLfloat *)projection);
|
||||
|
||||
// Set point size
|
||||
GLint h_PointSize = glGetUniformLocation(m_programSprites, "size");
|
||||
glUniform1f(h_PointSize, m_spriteSize);
|
||||
|
||||
// Set base and secondary colors
|
||||
GLint h_BaseColor = glGetUniformLocation(m_programSprites, "baseColor");
|
||||
GLint h_SecondaryColor = glGetUniformLocation(m_programSprites, "secondaryColor");
|
||||
glUniform4f(h_BaseColor, 1.0, 1.0, 1.0, 1.0);
|
||||
glUniform4f(h_SecondaryColor, m_baseColor[0], m_baseColor[1], m_baseColor[2], m_baseColor[3]);
|
||||
|
||||
// Set position coords
|
||||
GLint h_position = glGetAttribLocation(m_programSprites, "a_position");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pbo);
|
||||
glEnableVertexAttribArray(h_position);
|
||||
glVertexAttribPointer(h_position, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
GLuint texLoc = glGetUniformLocation(m_programSprites, "splatTexture");
|
||||
glUniform1i(texLoc, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, m_numParticles);
|
||||
|
||||
glDisableVertexAttribArray(h_position);
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
const char vertexShader[] = {"attribute vec4 a_position;"
|
||||
|
||||
"uniform mat4 projection;"
|
||||
"uniform mat4 modelview;"
|
||||
"uniform float size;"
|
||||
|
||||
"void main()"
|
||||
"{"
|
||||
"float pointSize = 500.0 * size;"
|
||||
"vec4 vert = a_position;"
|
||||
"vert.w = 1.0;"
|
||||
"vec3 pos_eye = vec3(modelview * vert);"
|
||||
"gl_PointSize = max(1.0, pointSize / (1.0 - pos_eye.z));"
|
||||
"gl_Position = projection * modelview * a_position;"
|
||||
"}"};
|
||||
|
||||
const char fragmentShader[] = {"uniform sampler2D splatTexture;"
|
||||
"uniform lowp vec4 baseColor;"
|
||||
"uniform lowp vec4 secondaryColor;"
|
||||
|
||||
"void main()"
|
||||
"{"
|
||||
"lowp vec4 textureColor = (0.6 + 0.4 * baseColor) * "
|
||||
"texture2D(splatTexture, gl_PointCoord);"
|
||||
"gl_FragColor = textureColor * secondaryColor;"
|
||||
"}"};
|
||||
|
||||
// Checks if the shader is compiled.
|
||||
static int CheckCompiled(GLuint shader)
|
||||
{
|
||||
GLint isCompiled = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
|
||||
|
||||
if (!isCompiled) {
|
||||
GLint infoLen = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
|
||||
|
||||
if (infoLen > 1) {
|
||||
char *infoLog = (char *)malloc(sizeof(char) * infoLen);
|
||||
|
||||
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
|
||||
printf("Error compiling program:\n%s\n", infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ParticleRenderer::_initGL()
|
||||
{
|
||||
m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
m_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
const char *v = vertexShader;
|
||||
const char *f = fragmentShader;
|
||||
glShaderSource(m_vertexShader, 1, &v, 0);
|
||||
glShaderSource(m_fragmentShader, 1, &f, 0);
|
||||
|
||||
checkGLErrors("Shader Source");
|
||||
|
||||
glCompileShader(m_vertexShader);
|
||||
glCompileShader(m_fragmentShader);
|
||||
|
||||
if (!CheckCompiled(m_vertexShader) || !CheckCompiled(m_fragmentShader)) {
|
||||
printf("A shader failed to compile.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
m_programSprites = glCreateProgram();
|
||||
|
||||
checkGLErrors("create program");
|
||||
|
||||
glAttachShader(m_programSprites, m_vertexShader);
|
||||
glAttachShader(m_programSprites, m_fragmentShader);
|
||||
|
||||
checkGLErrors("attaching shaders");
|
||||
|
||||
glLinkProgram(m_programSprites);
|
||||
|
||||
checkGLErrors("linking program");
|
||||
|
||||
EGLint linked;
|
||||
glGetProgramiv(m_programSprites, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
printf("A shader failed to link.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_createTexture(32);
|
||||
|
||||
glGenBuffers(1, (GLuint *)&m_vboColor);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vboColor);
|
||||
glBufferData(GL_ARRAY_BUFFER, m_numParticles * 4 * sizeof(float), 0, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Function : EvalHermite
|
||||
// Description :
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* EvalHermite(float pA, float pB, float vA, float vB, float u)
|
||||
* @brief Evaluates Hermite basis functions for the specified coefficients.
|
||||
*/
|
||||
inline float evalHermite(float pA, float pB, float vA, float vB, float u)
|
||||
{
|
||||
float u2 = (u * u), u3 = u2 * u;
|
||||
float B0 = 2 * u3 - 3 * u2 + 1;
|
||||
float B1 = -2 * u3 + 3 * u2;
|
||||
float B2 = u3 - 2 * u2 + u;
|
||||
float B3 = u3 - u;
|
||||
return (B0 * pA + B1 * pB + B2 * vA + B3 * vB);
|
||||
}
|
||||
|
||||
unsigned char *createGaussianMap(int N)
|
||||
{
|
||||
float *M = new float[2 * N * N];
|
||||
unsigned char *B = new unsigned char[4 * N * N];
|
||||
float X, Y, Y2, Dist;
|
||||
float Incr = 2.0f / N;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
Y = -1.0f;
|
||||
|
||||
// float mmax = 0;
|
||||
for (int y = 0; y < N; y++, Y += Incr) {
|
||||
Y2 = Y * Y;
|
||||
X = -1.0f;
|
||||
|
||||
for (int x = 0; x < N; x++, X += Incr, i += 2, j += 4) {
|
||||
Dist = (float)sqrtf(X * X + Y2);
|
||||
|
||||
if (Dist > 1)
|
||||
Dist = 1;
|
||||
|
||||
M[i + 1] = M[i] = evalHermite(1.0f, 0, 0, 0, Dist);
|
||||
B[j + 3] = B[j + 2] = B[j + 1] = B[j] = (unsigned char)(M[i] * 255);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] M;
|
||||
return (B);
|
||||
}
|
||||
|
||||
void ParticleRenderer::_createTexture(int resolution)
|
||||
{
|
||||
unsigned char *data = createGaussianMap(resolution);
|
||||
glGenTextures(1, (GLuint *)&m_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR); //_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, resolution, resolution, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
106
cpp/8_Platform_Specific/Tegra/nbody_opengles/render_particles.h
Normal file
106
cpp/8_Platform_Specific/Tegra/nbody_opengles/render_particles.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef __RENDER_PARTICLES__
|
||||
#define __RENDER_PARTICLES__
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES3/gl31.h>
|
||||
#include <cstdio>
|
||||
|
||||
typedef float matrix4[4][4];
|
||||
typedef float vector3[3];
|
||||
|
||||
// check for OpenGL errors
|
||||
inline void checkGLErrors(const char *s)
|
||||
{
|
||||
EGLenum error;
|
||||
|
||||
while ((error = glGetError()) != GL_NO_ERROR) {
|
||||
fprintf(stderr, "%s: error - %d\n", s, error);
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleRenderer
|
||||
{
|
||||
public:
|
||||
ParticleRenderer(unsigned int windowWidth = 720, unsigned int windowHeight = 480);
|
||||
~ParticleRenderer();
|
||||
|
||||
void setPositions(float *pos, int numParticles);
|
||||
void setPositions(double *pos, int numParticles);
|
||||
void setBaseColor(float color[4]);
|
||||
void setColors(float *color, int numParticles);
|
||||
void setPBO(unsigned int pbo, int numParticles, bool fp64);
|
||||
|
||||
enum DisplayMode { PARTICLE_POINTS, PARTICLE_SPRITES, PARTICLE_SPRITES_COLOR, PARTICLE_NUM_MODES };
|
||||
|
||||
void display();
|
||||
|
||||
void setPointSize(float size) { m_pointSize = size; }
|
||||
void setSpriteSize(float size) { m_spriteSize = size; }
|
||||
|
||||
void setCameraPos(vector3 camera_pos)
|
||||
{
|
||||
m_camera[0] = camera_pos[0];
|
||||
m_camera[1] = camera_pos[1];
|
||||
m_camera[2] = camera_pos[2];
|
||||
}
|
||||
|
||||
void resetPBO();
|
||||
|
||||
protected: // methods
|
||||
void _initGL();
|
||||
void _createTexture(int resolution);
|
||||
|
||||
protected: // data
|
||||
float *m_pos;
|
||||
double *m_pos_fp64;
|
||||
int m_numParticles;
|
||||
|
||||
float m_pointSize;
|
||||
float m_spriteSize;
|
||||
vector3 m_camera;
|
||||
|
||||
unsigned int m_vertexShader;
|
||||
unsigned int m_vertexShaderPoints;
|
||||
unsigned int m_fragmentShader;
|
||||
unsigned int m_programPoints;
|
||||
unsigned int m_programSprites;
|
||||
unsigned int m_texture;
|
||||
unsigned int m_pbo;
|
||||
unsigned int m_vboColor;
|
||||
unsigned int m_windowWidth;
|
||||
unsigned int m_windowHeight;
|
||||
|
||||
float m_baseColor[4];
|
||||
|
||||
bool m_bFp64Positions;
|
||||
};
|
||||
|
||||
#endif //__ RENDER_PARTICLES__
|
||||
166
cpp/8_Platform_Specific/Tegra/nbody_opengles/tipsy.h
Normal file
166
cpp/8_Platform_Specific/Tegra/nbody_opengles/tipsy.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#ifndef __TIPSY_H__
|
||||
#define __TIPSY_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MAXDIM 3
|
||||
|
||||
typedef float Real;
|
||||
|
||||
struct gas_particle
|
||||
{
|
||||
Real mass;
|
||||
Real pos[MAXDIM];
|
||||
Real vel[MAXDIM];
|
||||
Real rho;
|
||||
Real temp;
|
||||
Real hsmooth;
|
||||
Real metals;
|
||||
Real phi;
|
||||
};
|
||||
|
||||
// struct gas_particle *gas_particles;
|
||||
|
||||
struct dark_particle
|
||||
{
|
||||
Real mass;
|
||||
Real pos[MAXDIM];
|
||||
Real vel[MAXDIM];
|
||||
Real eps;
|
||||
int phi;
|
||||
};
|
||||
|
||||
// struct dark_particle *dark_particles;
|
||||
|
||||
struct star_particle
|
||||
{
|
||||
Real mass;
|
||||
Real pos[MAXDIM];
|
||||
Real vel[MAXDIM];
|
||||
Real metals;
|
||||
Real tform;
|
||||
Real eps;
|
||||
int phi;
|
||||
};
|
||||
|
||||
// struct star_particle *star_particles;
|
||||
|
||||
struct dump
|
||||
{
|
||||
double time;
|
||||
int nbodies;
|
||||
int ndim;
|
||||
int nsph;
|
||||
int ndark;
|
||||
int nstar;
|
||||
};
|
||||
|
||||
typedef struct dump header;
|
||||
|
||||
template <typename real4>
|
||||
void read_tipsy_file(vector<real4> &bodyPositions,
|
||||
vector<real4> &bodyVelocities,
|
||||
vector<int> &bodiesIDs,
|
||||
const std::string &fileName,
|
||||
int &NTotal,
|
||||
int &NFirst,
|
||||
int &NSecond,
|
||||
int &NThird)
|
||||
{
|
||||
/*
|
||||
Read in our custom version of the tipsy file format written by
|
||||
Jeroen Bedorf. Most important change is that we store particle id on the
|
||||
location where previously the potential was stored.
|
||||
*/
|
||||
|
||||
char fullFileName[256];
|
||||
sprintf(fullFileName, "%s", fileName.c_str());
|
||||
|
||||
cout << "Trying to read file: " << fullFileName << endl;
|
||||
|
||||
ifstream inputFile(fullFileName, ios::in | ios::binary);
|
||||
|
||||
if (!inputFile.is_open()) {
|
||||
cout << "Can't open input file \n";
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
dump h;
|
||||
inputFile.read((char *)&h, sizeof(h));
|
||||
|
||||
int idummy;
|
||||
real4 positions;
|
||||
real4 velocity;
|
||||
|
||||
|
||||
// Read tipsy header
|
||||
NTotal = h.nbodies;
|
||||
NFirst = h.ndark;
|
||||
NSecond = h.nstar;
|
||||
NThird = h.nsph;
|
||||
|
||||
// Start reading
|
||||
int particleCount = 0;
|
||||
|
||||
dark_particle d;
|
||||
star_particle s;
|
||||
|
||||
for (int i = 0; i < NTotal; i++) {
|
||||
if (i < NFirst) {
|
||||
inputFile.read((char *)&d, sizeof(d));
|
||||
velocity.w = d.eps;
|
||||
positions.w = d.mass;
|
||||
positions.x = d.pos[0];
|
||||
positions.y = d.pos[1];
|
||||
positions.z = d.pos[2];
|
||||
velocity.x = d.vel[0];
|
||||
velocity.y = d.vel[1];
|
||||
velocity.z = d.vel[2];
|
||||
idummy = d.phi;
|
||||
}
|
||||
else {
|
||||
inputFile.read((char *)&s, sizeof(s));
|
||||
velocity.w = s.eps;
|
||||
positions.w = s.mass;
|
||||
positions.x = s.pos[0];
|
||||
positions.y = s.pos[1];
|
||||
positions.z = s.pos[2];
|
||||
velocity.x = s.vel[0];
|
||||
velocity.y = s.vel[1];
|
||||
velocity.z = s.vel[2];
|
||||
idummy = s.phi;
|
||||
}
|
||||
|
||||
bodyPositions.push_back(positions);
|
||||
bodyVelocities.push_back(velocity);
|
||||
bodiesIDs.push_back(idummy);
|
||||
|
||||
particleCount++;
|
||||
} // end for
|
||||
|
||||
// round up to a multiple of 256 bodies since our kernel only supports that...
|
||||
int newTotal = NTotal;
|
||||
|
||||
if (NTotal % 256) {
|
||||
newTotal = ((NTotal / 256) + 1) * 256;
|
||||
}
|
||||
|
||||
for (int i = NTotal; i < newTotal; i++) {
|
||||
positions.w = positions.x = positions.y = positions.z = 0;
|
||||
velocity.x = velocity.y = velocity.z = 0;
|
||||
bodyPositions.push_back(positions);
|
||||
bodyVelocities.push_back(velocity);
|
||||
bodiesIDs.push_back(i);
|
||||
NFirst++;
|
||||
}
|
||||
|
||||
NTotal = newTotal;
|
||||
|
||||
inputFile.close();
|
||||
|
||||
cerr << "Read " << NTotal << " bodies" << endl;
|
||||
}
|
||||
|
||||
#endif //__TIPSY_H__
|
||||
18
cpp/8_Platform_Specific/Tegra/simpleGLES/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/8_Platform_Specific/Tegra/simpleGLES/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/8_Platform_Specific/Tegra/simpleGLES/.vscode/extensions.json
vendored
Normal file
7
cpp/8_Platform_Specific/Tegra/simpleGLES/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
76
cpp/8_Platform_Specific/Tegra/simpleGLES/CMakeLists.txt
Normal file
76
cpp/8_Platform_Specific/Tegra/simpleGLES/CMakeLists.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/Modules")
|
||||
|
||||
project(simpleGLES LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 87 110)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../../Common)
|
||||
|
||||
find_package(EGL)
|
||||
find_package(X11)
|
||||
find_package(OpenGL)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# Source file
|
||||
if(${OpenGL_FOUND})
|
||||
if(${EGL_FOUND})
|
||||
if(${X11_FOUND})
|
||||
# Add target for simpleGLES
|
||||
add_executable(simpleGLES simpleGLES.cu)
|
||||
|
||||
target_compile_options(simpleGLES PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(simpleGLES PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(simpleGLES PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(simpleGLES PUBLIC
|
||||
${EGL_INCLUDE_DIR}
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(simpleGLES
|
||||
${EGL_LIBRARY}
|
||||
${X11_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
)
|
||||
|
||||
# Copy the .glsl files to the output directory
|
||||
add_custom_command(TARGET simpleGLES POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mesh.frag.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mesh.vert.glsl
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
else()
|
||||
message(STATUS "X11 libraries not found - will not build sample 'simpleGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "EGL not found - will not build sample 'simpleGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenGL not found - will not build sample 'simpleGLES'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Will not build sample simpleGLES - requires Linux OS")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
36
cpp/8_Platform_Specific/Tegra/simpleGLES/README.md
Normal file
36
cpp/8_Platform_Specific/Tegra/simpleGLES/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# simpleGLES - Simple OpenGLES
|
||||
|
||||
## Description
|
||||
|
||||
Demonstrates data exchange between CUDA and OpenGL ES (aka Graphics interop). The program modifies vertex positions with CUDA and uses OpenGL ES to render the geometry.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
Graphics Interop, Vertex Buffers, 3D Graphics
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](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) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
armv7l
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaGraphicsUnmapResources, cudaMemcpy, cudaFree, cudaGraphicsResourceGetMappedPointer, cudaGraphicsMapResources, cudaDeviceSynchronize, cudaGraphicsUnregisterResource, cudaMalloc, cudaGraphicsGLRegisterBuffer
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[X11](../../../README.md#x11), [OpenGL ES](../../../README.md#opengl-es)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
BIN
cpp/8_Platform_Specific/Tegra/simpleGLES/data/ref_simpleGL.bin
Normal file
BIN
cpp/8_Platform_Specific/Tegra/simpleGLES/data/ref_simpleGL.bin
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user