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:
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user