c++ 和cuda混合编程

 

装好CUDA 5.5 sdk后,默认会自动添加好系统环境变量。

 

 

因此不需要额外配置,不过为了保险起见,可以选择性地添加以下环境变量:

 

CUDA_BIN_PATH  %CUDA_PATH%\bin
CUDA_LIB_PATH  %CUDA_PATH%\lib\Win32
CUDA_SDK_BIN  %CUDA_SDK_PATH%\bin\Win32
CUDA_SDK_LIB  %CUDA_SDK_PATH%\common\lib\Win32
CUDA_SDK_PATH  C:\cuda\cudasdk\common

 

这时可以打开CUDA自带的sample运行一下,运行能通过才可以继续下面的内容————cpp和cuda联调。

 

 

方法一:先建立cuda工程,再添加cpp文件

 

1.打开vs2010,新建一个cuda项目,名称CudaCpp。

 

 

2.cuda默认建立的工程是如下,实现了两个一维向量的并行相加。kernel函数和执行函数还有main函数全都写在了一个cu文件里。

 

 

3.接下来在工程里添加一个空的cpp文件。将原来cu文件里main函数里的内容剪切到cpp文件main函数里。

为了让cpp能够调用cu文件里面的函数,在addWithCuda函数前加上extern "C"关键字  (注意C大写,为什么addKernel不用加呢?因为cpp里面直接调用的是addWithCuda)

 

 

4.在cpp里也要加上addWithCuda函数的完整前向声明。下图就是工程的完整结构

 

 

5.可以在cpp里的main函数return之间加入getchar()防止运行后一闪就退出,加上system("pause")或者直接ctrl+F5也行。

运行结果:

 

 

下面贴出CudaCpp项目代码。

kernel.cu

 

[plain] view plain copy

  1. #include "cuda_runtime.h"  
  2. #include "device_launch_parameters.h"  
  3.   
  4. #include <stdio.h>  
  5.   
  6. __global__ void addKernel(int *c, const int *a, const int *b)  
  7. {  
  8.     int i = threadIdx.x;  
  9.     c[i] = a[i] + b[i];  
  10. }  
  11. // Helper function for using CUDA to add vectors in parallel.  
  12. extern "C"  
  13. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)  
  14. {  
  15.     int *dev_a = 0;  
  16.     int *dev_b = 0;  
  17.     int *dev_c = 0;  
  18.     cudaError_t cudaStatus;  
  19.   
  20.     // Choose which GPU to run on, change this on a multi-GPU system.  
  21.     cudaStatus = cudaSetDevice(0);  
  22.     if (cudaStatus != cudaSuccess) {  
  23.         fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");  
  24.         goto Error;  
  25.     }  
  26.   
  27.     // Allocate GPU buffers for three vectors (two input, one output)    .  
  28.     cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));  
  29.     if (cudaStatus != cudaSuccess) {  
  30.         fprintf(stderr, "cudaMalloc failed!");  
  31.         goto Error;  
  32.     }  
  33.   
  34.     cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));  
  35.     if (cudaStatus != cudaSuccess) {  
  36.         fprintf(stderr, "cudaMalloc failed!");  
  37.         goto Error;  
  38.     }  
  39.   
  40.     cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));  
  41.     if (cudaStatus != cudaSuccess) {  
  42.         fprintf(stderr, "cudaMalloc failed!");  
  43.         goto Error;  
  44.     }  
  45.   
  46.     // Copy input vectors from host memory to GPU buffers.  
  47.     cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);  
  48.     if (cudaStatus != cudaSuccess) {  
  49.         fprintf(stderr, "cudaMemcpy failed!");  
  50.         goto Error;  
  51.     }  
  52.   
  53.     cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);  
  54.     if (cudaStatus != cudaSuccess) {  
  55.         fprintf(stderr, "cudaMemcpy failed!");  
  56.         goto Error;  
  57.     }  
  58.   
  59.     // Launch a kernel on the GPU with one thread for each element.  
  60.     addKernel<<<1, size>>>(dev_c, dev_a, dev_b);  
  61.   
  62.     // Check for any errors launching the kernel  
  63.     cudaStatus = cudaGetLastError();  
  64.     if (cudaStatus != cudaSuccess) {  
  65.         fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));  
  66.         goto Error;  
  67.     }  
  68.       
  69.     // cudaDeviceSynchronize waits for the kernel to finish, and returns  
  70.     // any errors encountered during the launch.  
  71.     cudaStatus = cudaDeviceSynchronize();  
  72.     if (cudaStatus != cudaSuccess) {  
  73.         fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);  
  74.         goto Error;  
  75.     }  
  76.   
  77.     // Copy output vector from GPU buffer to host memory.  
  78.     cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);  
  79.     if (cudaStatus != cudaSuccess) {  
  80.         fprintf(stderr, "cudaMemcpy failed!");  
  81.         goto Error;  
  82.     }  
  83.   
  84. Error:  
  85.     cudaFree(dev_c);  
  86.     cudaFree(dev_a);  
  87.     cudaFree(dev_b);  
  88.       
  89.     return cudaStatus;  
  90. }  

save_snippets.png

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}
// Helper function for using CUDA to add vectors in parallel.
extern "C"
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
    int *dev_a = 0;
    int *dev_b = 0;
    int *dev_c = 0;
    cudaError_t cudaStatus;

    // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
        goto Error;
    }

    // Allocate GPU buffers for three vectors (two input, one output)    .
    cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    // Copy input vectors from host memory to GPU buffers.
    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    // Launch a kernel on the GPU with one thread for each element.
    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);

    // Check for any errors launching the kernel
    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
        goto Error;
    }
    
    // cudaDeviceSynchronize waits for the kernel to finish, and returns
    // any errors encountered during the launch.
    cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
        goto Error;
    }

    // Copy output vector from GPU buffer to host memory.
    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

Error:
    cudaFree(dev_c);
    cudaFree(dev_a);
    cudaFree(dev_b);
    
    return cudaStatus;
}

main.cpp

 

 

[cpp] view plain copy

  1. #include <stdio.h>  
  2. #include "cuda_runtime.h"  
  3. #include "device_launch_parameters.h"  
  4.   
  5. extern "C"  
  6.     cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);  
  7. int main()  
  8. {  
  9.     const int arraySize = 5;  
  10.     const int a[arraySize] = { 1, 2, 3, 4, 5 };  
  11.     const int b[arraySize] = { 10, 20, 30, 40, 50 };  
  12.     int c[arraySize] = { 0 };  
  13.   
  14.     // Add vectors in parallel.  
  15.     cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);  
  16.     if (cudaStatus != cudaSuccess) {  
  17.         fprintf(stderr, "addWithCuda failed!");  
  18.         return 1;  
  19.     }  
  20.   
  21.     printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",  
  22.         c[0], c[1], c[2], c[3], c[4]);  
  23.     printf("cuda工程中调用cpp成功!\n");  
  24.   
  25.     // cudaDeviceReset must be called before exiting in order for profiling and  
  26.     // tracing tools such as Nsight and Visual Profiler to show complete traces.  
  27.     cudaStatus = cudaDeviceReset();  
  28.     if (cudaStatus != cudaSuccess) {  
  29.         fprintf(stderr, "cudaDeviceReset failed!");  
  30.         return 1;  
  31.     }  
  32.     getchar(); //here we want the console to hold for a while  
  33.     return 0;  
  34. }  

 
  1. #include <stdio.h>

  2. #include "cuda_runtime.h"

  3. #include "device_launch_parameters.h"

  4.  
  5. extern "C"

  6. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);

  7. int main()

  8. {

  9. const int arraySize = 5;

  10. const int a[arraySize] = { 1, 2, 3, 4, 5 };

  11. const int b[arraySize] = { 10, 20, 30, 40, 50 };

  12. int c[arraySize] = { 0 };

  13.  
  14. // Add vectors in parallel.

  15. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);

  16. if (cudaStatus != cudaSuccess) {

  17. fprintf(stderr, "addWithCuda failed!");

  18. return 1;

  19. }

  20.  
  21. printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",

  22. c[0], c[1], c[2], c[3], c[4]);

  23. printf("cuda工程中调用cpp成功!\n");

  24.  
  25. // cudaDeviceReset must be called before exiting in order for profiling and

  26. // tracing tools such as Nsight and Visual Profiler to show complete traces.

  27. cudaStatus = cudaDeviceReset();

  28. if (cudaStatus != cudaSuccess) {

  29. fprintf(stderr, "cudaDeviceReset failed!");

  30. return 1;

  31. }

  32. getchar(); //here we want the console to hold for a while

  33. return 0;

  34. }

 

 

方法二:先建立cpp工程,再添加cu文件

方法一由于是cuda工程是自动建立的,所以比较简单,不需要多少额外的配置。而在cpp工程里面添加cu就要复杂一些。为了简单起见,这里采用console程序讲解,至于MFC或者Direct3D程序同理。

 

 

1.建立一个空的win32控制台工程,名称CppCuda。

 

 

2.然后右键工程-->添加一个cu文件


 

3.将方法一中cu和cpp文件的代码分别拷贝到这个工程里来(做了少许修改,extern "C"关键字和某些头文件不要忘了加),工程结构如图:

 

 

这个时候编译是通不过的,需要作一些配置。

 

4.关键的一步,右键工程-->生成自定义 ,将对话框中CUDA5.5前面的勾打上。

 

 

这时点击 工程-->属性,会发现多了CUDA链接器这一项。

 

 

5.关键的一步,右键kernel.cu文件-->属性,在 常规-->项类型 里面选择CUDA C/C++(由于cu文件是由nvcc编译的,这里要修改编译链接属性)

 

 

6.工程-->属性-->链接器-->附加依赖项,加入cudart.lib

 

 

7.工具-->选项-->文本编辑器-->文件扩展名 添加cu \cuh两个文件扩展名

 

 

8.至此配置成功。运行一下:

 

 

9.为了更加确信cuda中的函数确实被调用,在main.cpp里面调用cuda函数的地方加入了一个断点。

 

 

单步执行一下。

 

 

可以看到程序跳到了cu文件里去执行了,说明cpp调用cuda函数成功。

 

 

贴上代码(其实跟方式一基本一样,没怎么改),工程CppCuda

kernel.cu

 

[plain] view plain copy

  1. #include "cuda_runtime.h"  
  2. #include "device_launch_parameters.h"  
  3.   
  4. #include <stdio.h>  
  5.   
  6. //cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);  
  7. __global__ void addKernel(int *c, const int *a, const int *b)  
  8. {  
  9.     int i = threadIdx.x;  
  10.     c[i] = a[i] + b[i];  
  11. }  
  12. // Helper function for using CUDA to add vectors in parallel.  
  13. extern "C"  
  14. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)  
  15. {  
  16.     int *dev_a = 0;  
  17.     int *dev_b = 0;  
  18.     int *dev_c = 0;  
  19.     cudaError_t cudaStatus;  
  20.   
  21.     // Choose which GPU to run on, change this on a multi-GPU system.  
  22.     cudaStatus = cudaSetDevice(0);  
  23.     if (cudaStatus != cudaSuccess) {  
  24.         fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");  
  25.         goto Error;  
  26.     }  
  27.   
  28.     // Allocate GPU buffers for three vectors (two input, one output)    .  
  29.     cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));  
  30.     if (cudaStatus != cudaSuccess) {  
  31.         fprintf(stderr, "cudaMalloc failed!");  
  32.         goto Error;  
  33.     }  
  34.   
  35.     cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));  
  36.     if (cudaStatus != cudaSuccess) {  
  37.         fprintf(stderr, "cudaMalloc failed!");  
  38.         goto Error;  
  39.     }  
  40.   
  41.     cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));  
  42.     if (cudaStatus != cudaSuccess) {  
  43.         fprintf(stderr, "cudaMalloc failed!");  
  44.         goto Error;  
  45.     }  
  46.   
  47.     // Copy input vectors from host memory to GPU buffers.  
  48.     cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);  
  49.     if (cudaStatus != cudaSuccess) {  
  50.         fprintf(stderr, "cudaMemcpy failed!");  
  51.         goto Error;  
  52.     }  
  53.   
  54.     cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);  
  55.     if (cudaStatus != cudaSuccess) {  
  56.         fprintf(stderr, "cudaMemcpy failed!");  
  57.         goto Error;  
  58.     }  
  59.   
  60.     // Launch a kernel on the GPU with one thread for each element.  
  61.     addKernel<<<1, size>>>(dev_c, dev_a, dev_b);  
  62.   
  63.     // Check for any errors launching the kernel  
  64.     cudaStatus = cudaGetLastError();  
  65.     if (cudaStatus != cudaSuccess) {  
  66.         fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));  
  67.         goto Error;  
  68.     }  
  69.       
  70.     // cudaDeviceSynchronize waits for the kernel to finish, and returns  
  71.     // any errors encountered during the launch.  
  72.     cudaStatus = cudaDeviceSynchronize();  
  73.     if (cudaStatus != cudaSuccess) {  
  74.         fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);  
  75.         goto Error;  
  76.     }  
  77.   
  78.     // Copy output vector from GPU buffer to host memory.  
  79.     cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);  
  80.     if (cudaStatus != cudaSuccess) {  
  81.         fprintf(stderr, "cudaMemcpy failed!");  
  82.         goto Error;  
  83.     }  
  84.   
  85. Error:  
  86.     cudaFree(dev_c);  
  87.     cudaFree(dev_a);  
  88.     cudaFree(dev_b);  
  89.       
  90.     return cudaStatus;  
  91. }  
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

//cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}
// Helper function for using CUDA to add vectors in parallel.
extern "C"
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
    int *dev_a = 0;
    int *dev_b = 0;
    int *dev_c = 0;
    cudaError_t cudaStatus;

    // Choose which GPU to run on, change this on a multi-GPU system.
    cudaStatus = cudaSetDevice(0);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
        goto Error;
    }

    // Allocate GPU buffers for three vectors (two input, one output)    .
    cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!");
        goto Error;
    }

    // Copy input vectors from host memory to GPU buffers.
    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

    // Launch a kernel on the GPU with one thread for each element.
    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);

    // Check for any errors launching the kernel
    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
        goto Error;
    }
    
    // cudaDeviceSynchronize waits for the kernel to finish, and returns
    // any errors encountered during the launch.
    cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
        goto Error;
    }

    // Copy output vector from GPU buffer to host memory.
    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMemcpy failed!");
        goto Error;
    }

Error:
    cudaFree(dev_c);
    cudaFree(dev_a);
    cudaFree(dev_b);
    
    return cudaStatus;
}

main.cpp

 

 

[cpp] view plain copy

  1. #include <iostream>  
  2. #include "cuda_runtime.h"  
  3. #include "device_launch_parameters.h"  
  4. using namespace std;  
  5.   
  6. extern "C"  
  7.     cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);  
  8. int main(int argc,char **argv)  
  9. {  
  10.     const int arraySize = 5;  
  11.     const int a[arraySize] = { 1, 2, 3, 4, 5 };  
  12.     const int b[arraySize] = { 10, 20, 30, 40, 50 };  
  13.     int c[arraySize] = { 0 };  
  14.   
  15.     // Add vectors in parallel.  
  16.     cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);  
  17.     if (cudaStatus != cudaSuccess) {  
  18.         fprintf(stderr, "addWithCuda failed!");  
  19.         return 1;  
  20.     }  
  21.   
  22.     cout<<"{1,2,3,4,5} + {10,20,30,40,50} = {"<<c[0]<<','<<c[1]<<','<<c[2]<<','<<c[3]<<'}'<<endl;  
  23.     printf("cpp工程中调用cu成功!\n");  
  24.   
  25.     // cudaDeviceReset must be called before exiting in order for profiling and  
  26.     // tracing tools such as Nsight and Visual Profiler to show complete traces.  
  27.     cudaStatus = cudaDeviceReset();  
  28.     if (cudaStatus != cudaSuccess) {  
  29.         fprintf(stderr, "cudaDeviceReset failed!");  
  30.         return 1;  
  31.     }  
  32.     system("pause"); //here we want the console to hold for a while  
  33.     return 0;  
  34. }  

 
  1. #include <iostream>

  2. #include "cuda_runtime.h"

  3. #include "device_launch_parameters.h"

  4. using namespace std;

  5.  
  6. extern "C"

  7. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);

  8. int main(int argc,char **argv)

  9. {

  10. const int arraySize = 5;

  11. const int a[arraySize] = { 1, 2, 3, 4, 5 };

  12. const int b[arraySize] = { 10, 20, 30, 40, 50 };

  13. int c[arraySize] = { 0 };

  14.  
  15. // Add vectors in parallel.

  16. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);

  17. if (cudaStatus != cudaSuccess) {

  18. fprintf(stderr, "addWithCuda failed!");

  19. return 1;

  20. }

  21.  
  22. cout<<"{1,2,3,4,5} + {10,20,30,40,50} = {"<<c[0]<<','<<c[1]<<','<<c[2]<<','<<c[3]<<'}'<<endl;

  23. printf("cpp工程中调用cu成功!\n");

  24.  
  25. // cudaDeviceReset must be called before exiting in order for profiling and

  26. // tracing tools such as Nsight and Visual Profiler to show complete traces.

  27. cudaStatus = cudaDeviceReset();

  28. if (cudaStatus != cudaSuccess) {

  29. fprintf(stderr, "cudaDeviceReset failed!");

  30. return 1;

  31. }

  32. system("pause"); //here we want the console to hold for a while

  33. return 0;

  34. }

注意有时候编译出问题,把  "device_launch_parameters.h"这个头文件去掉就好了(去掉之后就不能调里面的函数或变量了),至于为什么,还不是很清楚。
 

 

以后将cu文件加入到任何MFC,qt,D3D或者OpenGL等C++工程中步骤都是类似的。

copy来自     https://blog.csdn.net/zhangfuliang123/article/details/71440122

 

展开阅读全文

没有更多推荐了,返回首页