簡體   English   中英

如何在dll中使用CUDA?

[英]How to use CUDA in a dll?

我的目的是通過存根庫使用CUDA,該存根庫封裝了CUDA特定的功能,方法和數據。 CUDA內容將駐留在dll文件中,並將通過LoadLibrary和GetProcAddress Windows API函數動態使用。 我正在使用Visual Studio 2010 C ++編譯器創建CUDA dll,但其余工作由另一個編譯器完成。 這意味着,我不能在CUDA dll中使用堆內存(即,位於堆內存之外的malloc,new或其他任何東西,甚至全局變量也會導致內存損壞),因此它實際上是一個存根庫。

但是,首先,我想編寫一個測試程序:CUDAhost.exe和CUDAdevice.dll,它們都由Visual Studio 2010編譯,這兩個項目在一個解決方案中。 該程序在屏幕上繪制OpenGL紋理,但是首先,圖像數據由CUDA從readGLTexture復制到viewGLTexture。 請注意,為避免使用堆內存,我使用了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();
}

CUDAdevice的stdafx.h:

    #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庫。

如果有人閱讀此內容,可以在這里更好地更新解決方案...

上面的代碼不起作用。 整個想法是避免在DLL模塊中使用堆內存。 但是,CUDA需要紋理和表面是全局的:

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

但是,要避免使用堆內存,這些內存必須位於本地,因此這是不可能的。

此外,根據我的理解,在CUDA DLL模塊中使用堆內存應該沒有任何問題。 我已經制作了可以運行的EXE / DLL測試程序,該程序使用DL​​L模塊中的堆內存。 我以前的嘗試中沒有發現該錯誤,但這可能是由於GLEW庫造成的。 我的工作程序中沒有使用GLEW。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM