/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NVIDIA CORPORATION nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // DESCRIPTION: Simple CUDA consumer rendering sample app // #include "cuda_consumer.h" #include #include "eglstrm_common.h" #if defined(EXTENSION_LIST) EXTENSION_LIST(EXTLST_EXTERN) #endif int checkbuf(FILE *fp1, FILE *fp2); CUresult cudaConsumerTest(test_cuda_consumer_s *data, char *fileName) { CUresult cuStatus = CUDA_SUCCESS; CUarray cudaArr = NULL; CUeglFrame cudaEgl; CUgraphicsResource cudaResource; unsigned int i; int check_result; FILE *pInFile1 = NULL, *pInFile2 = NULL, *file_p = NULL; EGLint streamState = 0; if (!data) { printf("%s: Bad parameter\n", __func__); goto done; } if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR, &streamState)) { printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n"); } if (streamState == EGL_STREAM_STATE_DISCONNECTED_KHR) { printf("CUDA Consumer: - EGL_STREAM_STATE_DISCONNECTED_KHR received\n"); } if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { cuStatus = cuEGLStreamConsumerAcquireFrame(&(data->cudaConn), &cudaResource, NULL, 16000); if (cuStatus == CUDA_SUCCESS) { CUdeviceptr pDevPtr = 0; int bufferSize; unsigned char *pCudaCopyMem = NULL; unsigned int copyWidthInBytes = 0, copyHeight = 0; file_p = fopen(fileName, "wb+"); if (!file_p) { printf("WriteFrame: file open failed %s\n", fileName); cuStatus = CUDA_ERROR_UNKNOWN; goto done; } cuStatus = cuGraphicsResourceGetMappedEglFrame(&cudaEgl, cudaResource, 0, 0); if (cuStatus != CUDA_SUCCESS) { printf("Cuda get resource failed with %d\n", cuStatus); goto done; } cuStatus = cuCtxSynchronize(); if (cuStatus != CUDA_SUCCESS) { printf("cuCtxSynchronize failed \n"); goto done; } if (!(cudaEgl.planeCount >= 1 && cudaEgl.planeCount <= 3)) { printf("Plane count is invalid\nExiting\n"); goto done; } for (i = 0; i < cudaEgl.planeCount; i++) { if (cudaEgl.frameType == CU_EGL_FRAME_TYPE_PITCH) { pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[i]; if (cudaEgl.planeCount == 1) { bufferSize = cudaEgl.pitch * cudaEgl.height; copyWidthInBytes = cudaEgl.pitch; copyHeight = data->height; } else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420 // semi-planar bufferSize = cudaEgl.pitch * cudaEgl.height / 2; copyWidthInBytes = cudaEgl.pitch; copyHeight = data->height / 2; } else { bufferSize = data->width * data->height; copyWidthInBytes = data->width; copyHeight = data->height; if (i > 0) { bufferSize >>= 2; copyWidthInBytes >>= 1; copyHeight >>= 1; } } } else { cudaArr = cudaEgl.frame.pArray[i]; if (cudaEgl.planeCount == 1) { bufferSize = data->width * data->height * 4; copyWidthInBytes = data->width * 4; copyHeight = data->height; } else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420 // semi-planar bufferSize = data->width * data->height / 2; copyWidthInBytes = data->width; copyHeight = data->height / 2; } else { bufferSize = data->width * data->height; copyWidthInBytes = data->width; copyHeight = data->height; if (i > 0) { bufferSize >>= 2; copyWidthInBytes >>= 1; copyHeight >>= 1; } } } if (i == 0) { pCudaCopyMem = (unsigned char *)malloc(bufferSize); if (pCudaCopyMem == NULL) { printf("pCudaCopyMem malloc failed\n"); goto done; } } memset(pCudaCopyMem, 0, bufferSize); if (data->pitchLinearOutput) { cuStatus = cuMemcpyDtoH(pCudaCopyMem, pDevPtr, bufferSize); if (cuStatus != CUDA_SUCCESS) { printf( "cuda_consumer: pitch linear Memcpy failed, bufferSize =%d\n", bufferSize); goto done; } cuStatus = cuCtxSynchronize(); if (cuStatus != CUDA_SUCCESS) { printf("cuda_consumer: cuCtxSynchronize failed after memcpy \n"); goto done; } } else { CUDA_MEMCPY3D cpdesc; memset(&cpdesc, 0, sizeof(cpdesc)); cpdesc.srcXInBytes = cpdesc.srcY = cpdesc.srcZ = cpdesc.srcLOD = 0; cpdesc.srcMemoryType = CU_MEMORYTYPE_ARRAY; cpdesc.srcArray = cudaArr; cpdesc.dstXInBytes = cpdesc.dstY = cpdesc.dstZ = cpdesc.dstLOD = 0; cpdesc.dstMemoryType = CU_MEMORYTYPE_HOST; cpdesc.dstHost = (void *)pCudaCopyMem; cpdesc.WidthInBytes = copyWidthInBytes; // data->width * 4; cpdesc.Height = copyHeight; // data->height; cpdesc.Depth = 1; cuStatus = cuMemcpy3D(&cpdesc); if (cuStatus != CUDA_SUCCESS) { printf( "Cuda consumer: cuMemCpy3D failed, copyWidthInBytes=%d, " "copyHight=%d\n", copyWidthInBytes, copyHeight); } cuStatus = cuCtxSynchronize(); if (cuStatus != CUDA_SUCCESS) { printf("cuCtxSynchronize failed after memcpy \n"); } } if (cuStatus == CUDA_SUCCESS) { if (fwrite(pCudaCopyMem, bufferSize, 1, file_p) != 1) { printf("Cuda consumer: output file write failed\n"); cuStatus = CUDA_ERROR_UNKNOWN; goto done; } } } pInFile1 = fopen(data->fileName1, "rb"); if (!pInFile1) { printf("Failed to open file :%s\n", data->fileName1); goto done; } pInFile2 = fopen(data->fileName2, "rb"); if (!pInFile2) { printf("Failed to open file :%s\n", data->fileName2); goto done; } rewind(file_p); check_result = checkbuf(file_p, pInFile1); if (check_result == -1) { rewind(file_p); check_result = checkbuf(file_p, pInFile2); if (check_result == -1) { printf("Frame received does not match any valid image: FAILED\n"); } else { printf("Frame check Passed\n"); } } else { printf("Frame check Passed\n"); } if (pCudaCopyMem) { free(pCudaCopyMem); pCudaCopyMem = NULL; } cuStatus = cuEGLStreamConsumerReleaseFrame(&data->cudaConn, cudaResource, NULL); if (cuStatus != CUDA_SUCCESS) { printf("cuEGLStreamConsumerReleaseFrame failed with cuStatus = %d\n", cuStatus); goto done; } } else { printf("cuda AcquireFrame FAILED with cuStatus=%d\n", cuStatus); goto done; } } done: if (file_p) { fclose(file_p); file_p = NULL; } if (pInFile1) { fclose(pInFile1); pInFile1 = NULL; } if (pInFile1) { fclose(pInFile2); pInFile2 = NULL; } return cuStatus; } int checkbuf(FILE *fp1, FILE *fp2) { int match = 0; int ch1, ch2; if (fp1 == NULL) { printf("Invalid file pointer for first file\n"); return -1; } else if (fp2 == NULL) { printf("Invalid file pointer for second file\n"); return -1; } else { ch1 = getc(fp1); ch2 = getc(fp2); while ((ch1 != EOF) && (ch2 != EOF) && (ch1 == ch2)) { ch1 = getc(fp1); ch2 = getc(fp2); } if (ch1 == ch2) { match = 1; } else if (ch1 != ch2) { match = -1; } } return match; } CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer, CUdevice device) { CUresult status = CUDA_SUCCESS; if (CUDA_SUCCESS != (status = cuInit(0))) { printf("Failed to initialize CUDA\n"); return status; } int major = 0, minor = 0; char deviceName[256]; checkCudaErrors(cuDeviceGetAttribute( &major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device)); checkCudaErrors(cuDeviceGetAttribute( &minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device)); checkCudaErrors(cuDeviceGetName(deviceName, 256, device)); printf( "CUDA Consumer on GPU Device %d: \"%s\" with compute capability " "%d.%d\n\n", device, deviceName, major, minor); if (CUDA_SUCCESS != (status = cuCtxCreate(&cudaConsumer->context, 0, device))) { printf("failed to create CUDA context\n"); return status; } checkCudaErrors(cuCtxPopCurrent(&cudaConsumer->context)); return status; } void cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args) { cudaConsumer->pitchLinearOutput = args->pitchLinearOutput; cudaConsumer->width = args->inputWidth; cudaConsumer->height = args->inputHeight; cudaConsumer->fileName1 = args->infile1; cudaConsumer->fileName2 = args->infile2; cudaConsumer->outFile1 = "cuda_out1.yuv"; cudaConsumer->outFile2 = "cuda_out2.yuv"; } CUresult cuda_consumer_deinit(test_cuda_consumer_s *cudaConsumer) { return cuEGLStreamConsumerDisconnect(&cudaConsumer->cudaConn); }