2016-06-01 2 views
0

Моя цель - использовать CUDA через библиотеку-заглушку, которая инкапсулирует специфические функции, методы и данные CUDA. Материал CUDA будет находиться внутри DLL-файла, и он будет использоваться динамически через функции LoadLibrary и GetProcAddress Windows API. Я использую Visual Studio 2010 C++ компилятор для создания CUDA dll, но остальное делается другим компилятором. Это означает, что я не могу использовать кучную память (т. Е. Malloc, new или anything, которая живет за пределами стековой памяти. Даже глобальные переменные вызывают повреждение памяти) внутри CUDA dll, так что это буквально библиотека заглушек.Как использовать CUDA в dll?

Однако сначала я хочу закодировать тестовую программу: CUDAhost.exe и CUDAdevice.dll, которые оба скомпилированы Visual Studio 2010, два проекта в одном решении. Эта программа рисует текстуру OpenGL на экране, но сначала данные изображения копируются из readGLTexture в viewGLTexture с помощью CUDA. Обратите внимание, что во избежание использования памяти кучи я использую ссылки на указатели void void * & cReadCudaResource и void * & cViewCudaResource. Моя проблема в том, что я не могу заставить программу работать, окно черное. Я не могу найти ошибку. Я не уверен, что это вообще возможно, или я должен выбрать совершенно другое решение. Я надеюсь, что вы можете мне помочь. Любые предложения приветствуются. Ниже приведен исходный код:

CUDAhost.cpp:

#include "stdafx.h" 

const unsigned int window_width = 512; 
const unsigned int window_height = 512; 

GLuint viewGLTexture; 
GLuint readGLTexture; 
void* cViewCudaResource; 
void* cReadCudaResource; 
HINSTANCE dll; 
typedef void (*SETCUDA)(unsigned int& readGLTexture, void* &cReadCudaResource, unsigned int& viewGLTexture, void* &cViewCudaResource); 
SETCUDA setCuda; 
typedef void (*DRAWPICTURE)(void* &cReadCudaResource, void* &cViewCudaResource); 
DRAWPICTURE drawPicture; 

bool loadTexture(const wchar_t* name, GLuint& number) { 

    FILE* file; 
    BITMAPFILEHEADER bitmapFileHeader; 
    BITMAPINFOHEADER bitmapInfoHeader; 
    unsigned char *bitmap; 
    unsigned char temp; 
    wchar_t path[45]={0}; 
    int width; 
    int height; 

//prepare file path 
    wcsncat_s(path, L"Textures\\", 45); 
    wcsncat_s(path, name, 45); 
    wcsncat_s(path, L".bmp", 45); 

//open BMP file 
    file=_wfopen(path, L"rb"); 
    if (file==NULL) { 
    return false; 
    } 

//read bmp file header and sequre it is bmp file 
    fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, file); 
    if (bitmapFileHeader.bfType != 0x4D42) { 
    fclose(file); 
    return false; 
    } 

//read bmp info header and move to the beginning of image data 
    fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, file); 
    fseek(file, bitmapFileHeader.bfOffBits, SEEK_SET); 

//allocate memory space 
    bitmap=(unsigned char*)malloc(bitmapInfoHeader.biSizeImage); 
    if (!bitmap) { 
free(bitmap); 
bitmap=NULL; 
    fclose(file); 
    return false; 
    } 

//read image 
    fread(bitmap, 1, bitmapInfoHeader.biSizeImage, file); 
    if (file==NULL) { 
free(bitmap); 
bitmap=NULL; 
    fclose(file); 
    return false; 
    } 

//rearrange bgr to rgb 
    for (int i=0; i<bitmapInfoHeader.biSizeImage; i+=3) { 
    temp=bitmap[i]; 
    bitmap[i]=bitmap[i+2]; 
    bitmap[i+2]=temp; 
    } 

//query image width and height 
    width=bitmapInfoHeader.biWidth; 
    height=abs(bitmapInfoHeader.biHeight); 

//close bmp file 
    fclose(file); 
    glGetError(); 

//create OpenGL texture 
    glGenTextures(1, &number); 
    glBindTexture(GL_TEXTURE_2D, number); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

//free temporary buffer 
    free(bitmap); 
    bitmap=NULL; 

//if success, return true 
    if (0==glGetError()) { 
    return true; 
    } else { 
    return false; 
    } 
} 

void initGLandCUDA(int argc, char* argv[]) { 

    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA); 
    glutInitWindowSize(window_width, window_height); 
    glutCreateWindow("CUDA GL Interop"); 

    glewInit(); 

    glEnable(GL_TEXTURE_2D); 
    bool success=loadTexture(L"Tex", readGLTexture); 

    glGenTextures(1, &viewGLTexture); 
    glBindTexture(GL_TEXTURE_2D, viewGLTexture); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
    glBindTexture(GL_TEXTURE_2D, 0); 

    dll=LoadLibraryW(L"CUDAdevice.dll"); 
    if (dll) { 
    setCuda=(SETCUDA)GetProcAddress(dll, "setCuda"); 
    setCuda(readGLTexture, cReadCudaResource, viewGLTexture, cViewCudaResource); 
    } 
}  

void renderFrame() { 
    if (dll) { 
    drawPicture=(DRAWPICTURE)GetProcAddress(dll, "drawPicture"); 
    drawPicture(cReadCudaResource, cViewCudaResource); 
    } 
    glBindTexture(GL_TEXTURE_2D, viewGLTexture); 
    { 
    glBegin(GL_QUADS); 
    { 
     glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); 
     glTexCoord2f(1.0f, 0.0f); glVertex2f(+1.0f, -1.0f); 
     glTexCoord2f(1.0f, 1.0f); glVertex2f(+1.0f, +1.0f); 
     glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, +1.0f); 
    } 
    glEnd(); 
    } 
    glBindTexture(GL_TEXTURE_2D, 0); 
    glFinish(); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    initGLandCUDA(argc, reinterpret_cast<char**>(argv)); 
    glutDisplayFunc(renderFrame); 
    glutMainLoop(); 
    return 0; 
} 

dllmain.cpp:

BOOL APIENTRY DllMain(HMODULE hModule, 
        DWORD ul_reason_for_call, 
        LPVOID lpReserved 
       ) 
{ 
    switch (ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
    case DLL_THREAD_ATTACH: 
    case DLL_THREAD_DETACH: 
    case DLL_PROCESS_DETACH: 
    break; 
    } 
    return TRUE; 
} 

//this function is used to setup CUDA 
void setCuda(unsigned int& readGLTexture, void* &cReadCudaResource, unsigned int& viewGLTexture, void* &cViewCudaResource) { 

    struct cudaGraphicsResource* viewCudaResource; 
    struct cudaGraphicsResource* readCudaResource; 
    cudaError cError; 

    cudaGLSetGLDevice(0); 
    cError=cudaGraphicsGLRegisterImage(&viewCudaResource, viewGLTexture, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsReadOnly); 
    cError=cudaGraphicsGLRegisterImage(&readCudaResource, readGLTexture, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsSurfaceLoadStore); 
    cReadCudaResource=reinterpret_cast<void*>(readCudaResource); 
    cViewCudaResource=reinterpret_cast<void*>(viewCudaResource); 
}  

//this function is used to draw texture image via CUDA 
void drawPicture(void* &cReadCudaResource, void* &cViewCudaResource) { 

    cudaError cError; 

    struct cudaGraphicsResource* viewCudaResource=reinterpret_cast<cudaGraphicsResource*>(cReadCudaResource); 
    struct cudaGraphicsResource* readCudaResource=reinterpret_cast<cudaGraphicsResource*>(cViewCudaResource); 
    cudaArray *readCudaArray; 
    cudaArray *viewCudaArray; 

    cError=cudaGraphicsMapResources(1, &readCudaResource); 
    cError=cudaGraphicsMapResources(1, &viewCudaResource); 
    cError=cudaGraphicsSubResourceGetMappedArray(&readCudaArray, readCudaResource, 0, 0); 
    cError=cudaGraphicsSubResourceGetMappedArray(&viewCudaArray, viewCudaResource, 0, 0); 
    callCUDAKernel(readCudaArray, viewCudaArray); 
    cudaGraphicsUnmapResources(1, &viewCudaResource); 
    cudaStreamSynchronize(0); 
} 

kernels.cu:

#include "stdafx.h" 

texture<uchar4, cudaTextureType2D, cudaReadModeElementType> readCudaTextureObject; 
surface<void, cudaSurfaceType2D> viewCudaSurfaceObject; 


__global__ void renderingKernel() { 

    unsigned int x = blockIdx.x * blockDim.x + threadIdx.x; 
    unsigned int y = blockIdx.y * blockDim.y + threadIdx.y; 

    uchar4 dd=tex2D(readCudaTextureObject, x, y); 

    surf2Dwrite(dd, viewCudaSurfaceObject, x*sizeof(dd), y, cudaBoundaryModeZero); 
} 


void callCUDAKernel(cudaArray *readCudaArray, cudaArray *viewCudaArray) { 

    cudaError cError; 

    cError=cudaBindTextureToArray(readCudaTextureObject, readCudaArray); 
    cError=cudaBindSurfaceToArray(viewCudaSurfaceObject, viewCudaArray); 
    dim3 block(256, 1, 1); 
    dim3 grid(2, 512, 1); 
    renderingKernel<<<grid, block>>>(); 
    cudaPeekAtLastError(); 
    cudaDeviceSynchronize(); 
} 

stdafx.h CUDAdevice в:

#pragma once 

#include "targetver.h" 

#define WIN32_LEAN_AND_MEAN    // Exclude rarely-used stuff from Windows headers 
// Windows Header Files: 
#include <windows.h> 



// TODO: reference additional headers your program requires here 
#include <cuda_runtime_api.h> 
#include <cuda_gl_interop.h> 

#include "kernels.h" 

#if defined (__cplusplus) 
extern "C" 
{ 
#endif 

__declspec(dllexport) void setCuda(unsigned int& readGLTexture, void* &cReadCudaResource, unsigned int& viewGLTexture, void* &cViewCudaResource); 
__declspec(dllexport) void drawPicture(void* &cReadCudaResource, void* &cViewCudaResource); 

#if defined (__cplusplus) 
} 
#endif 

kernels.h:

#ifndef __kernels_H 
#define __kernels_H 

void callCUDAKernel(cudaArray *readCudaArray, cudaArray *viewCudaArray); 

#endif 

PS. Я также установил пути к CUDA-библиотекам, заголовкам, источникам и двоичным файлам, добавил cudart.lib в дополнительные зависимости, установил цели CUDA 4.2 и compute_20, sm_21. Программа тестирования использует библиотеки GLEW и GLUT.

+0

Работает ли он без DLL? Используете ли вы отладчик? Где проверяется ошибка? – Drop

+0

Эта тестовая программа работает – mamannon

+0

Hello Drop, эта тестовая программа будет работать без DLL, но реальная, вероятно, нет, потому что большая часть кода не будет скомпилирована VS. И да, я использую отладчик Visual Studio, он работает как с EXE, так и с DLL. Ошибка проверки ошибок, кроме cudaError cError, чтобы сохранить код простым: я могу использовать отладчик VS, чтобы увидеть, что ошибок нет. Однако экран остается черным, поэтому что-то не так. Я хотел бы получить комментарии о моем использовании указателя cudaGraphicsResource *. – mamannon

ответ

1

Лучшее решение обновление здесь, если кто-то читает это ...

Приведенный выше код не может работать. Вся идея заключалась в том, чтобы избежать использования памяти кучи в модуле DLL. Но, CUDA нужны текстуры и поверхность, чтобы быть глобальными:

texture<uchar4, cudaTextureType2D, cudaReadModeElementType>readCudaTextureObject; 
surface<void, cudaSurfaceType2D> viewCudaSurfaceObject; 

Однако, чтобы избежать использования динамической памяти требуют, чтобы они были местными, так что это невозможно.

Кроме того, согласно моему пониманию, не должно быть никаких проблем с использованием кучной памяти внутри модуля CUDA DLL. Я уже создал рабочие тестовые программы EXE/DLL, которые используют кучную память внутри модуля DLL. Я не нашел ошибку в моих предыдущих попытках, но это может быть связано с библиотекой GLEW. Я не использую GLEW с моими рабочими программами.

Смежные вопросы