2016-01-29 72 views
1

我的本地计算机和EC2服务器都在Ubuntu 14.04上。假设我正在测试cuda opengl interop代码如下。如何在EC2上单元测试OpenGL

Test.cu

#include <iostream> 

#include <GL/glew.h> 
#include <GLFW/glfw3.h> 
#include <cuda_gl_interop.h> 

__global__ static void CUDAKernelTEST(float *data){ 
    const int x = blockIdx.x * blockDim.x + threadIdx.x; 
    const int y = blockIdx.y * blockDim.y + threadIdx.y; 
    const int mx = gridDim.x * blockDim.x; 

    data[y * mx + x] = 0.5; 
} 

GLFWwindow *glfw_window_; 

void Setup(){ 
    if (!glfwInit()) exit(EXIT_FAILURE); 

    glfwWindowHint(GLFW_VISIBLE, GL_FALSE); 

    glfw_window_ = glfwCreateWindow(10, 10, "", NULL, NULL); 

    if (!glfw_window_) glfwTerminate(); 

    glfwMakeContextCurrent(glfw_window_); 

    glewExperimental = GL_TRUE; 
    if (glewInit() != GLEW_OK) exit(EXIT_FAILURE); 
} 

void TearDown(){ 
    glfwDestroyWindow(glfw_window_); 
    glfwTerminate(); 
} 

int main(){ 
    Setup(); 

    GLuint id; 
    glGenBuffers(1, &id); 
    glBindBuffer(GL_ARRAY_BUFFER, id); 
    glBufferData(GL_ARRAY_BUFFER, 3 * 24 * sizeof(GLfloat), 0, GL_STATIC_DRAW); 
    cudaGraphicsResource *vbo_res; 
    cudaGraphicsGLRegisterBuffer(&vbo_res, id, cudaGraphicsMapFlagsWriteDiscard); 
    cudaGraphicsMapResources(1, &vbo_res, 0); 
    float *test; 
    size_t size; 
    cudaGraphicsResourceGetMappedPointer(
    reinterpret_cast<void **>(&test), &size, vbo_res); 
    dim3 blks(1, 1); 
    dim3 threads(72, 1); 
    CUDAKernelTEST<<<blks, threads>>>(test); 
    cudaDeviceSynchronize(); 
    cudaGraphicsUnmapResources(1, &vbo_res, 0); 

    // do some more with OpenGL 

    std::cout << "you passed the test" << std::endl; 

    TearDown(); 

    return 0; 
} 

目前的方法是创建一个隐藏的窗口和上下文。代码编译并在我的本地机器上正常运行。但是,在EC2上运行时,glfwInit()返回GL_FALSE。如果我将发送到错误回调的消息记录下来,它会显示“X11:DISPLAY环境变量丢失”,看起来它需要连接显示监视器才能工作。

我试着将GLFW中的Setup和TearDown部分替换为SDL或GLX,并且它返回类似的错误,看起来也需要连接一个显示监视器。

我也试着用Xvfb和Xdummy运行代码来伪造显示器,但是我从Xvfb“Xlib:扩展名”GLX“缺少显示”:99“和Xdummy”致命服务器错误:(EE)没有找到屏幕(EE)“

我不能成为第一个尝试在EC2上单元测试opengl相关代码的人,但是我在google搜索后找不到任何解决方案。

回答

2

DISPLAY变量有没有与连接的监视器有关这个环境变量告诉X11客户端程序与X11服务器对话在Linux中d Unix系统X11服务器是事实上的标准图形系统和窗口多路复用器。它也是GPU驱动程序的主机。

随着程序期望与X11服务器交谈,您必须为其提供具有必要功能的服务器。在你的情况下,这意味着支持GLX协议的Xorg服务器(以便可以使用OpenGL),并且由于您使用的是CUDA,它应该托管NVidia驱动程序。唯一能够做到这一点的X11服务器是加载了nvidia驱动程序的完整Xorg服务器。 Xvfb或Xdummy都不能。

所以,如果你真的想谈X11,那么你将不得不建立与NVIDIA驱动程序的Xorg服务器。不要紧,如果没有显示器连接,你可以哄司机进入无头操作就好(虽然可能需要一些说服力)。

但是因为最近有一个更好的办法: NVIDIA的最新驱动程序版本包括与CUDA的OpenGL互操作性完全支持建立在GPU上完全无头,关闭屏幕OpenGL方面的支持:http://devblogs.nvidia.com/parallelforall/egl-eye-opengl-visualization-without-x-server/

归根结底向下使用EGL创建OpenGL上下文,而不是使用配置为无头操作的显示设备使用X11/GLX,方法是选择PBuffer framebuffer属性。基本代码大纲看起来像这样(直接从NVidia代码示例中获得):

#include <EGL/egl.h> 

    static const EGLint configAttribs[] = { 
      EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, // make this off-screen 
      EGL_BLUE_SIZE, 8, 
      EGL_GREEN_SIZE, 8, 
      EGL_RED_SIZE, 8, 
      EGL_DEPTH_SIZE, 8, 
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 
      EGL_NONE 
    };  


    static const int pbufferWidth = 9; 
    static const int pbufferHeight = 9; 

    static const EGLint pbufferAttribs[] = { 
     EGL_WIDTH, pbufferWidth, 
     EGL_HEIGHT, pbufferHeight, 
     EGL_NONE, 
    }; 

int main(int argc, char *argv[]) 
{ 
    // 1. Initialize EGL 
    EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 

    EGLint major, minor; 

    eglInitialize(eglDpy, &major, &minor); 

    // 2. Select an appropriate configuration 
    EGLint numConfigs; 
    EGLConfig eglCfg; 

    eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs); 

    // 3. Create a surface 
    EGLSurface eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, 
               pbufferAttribs); 

    // 4. Bind the API 
    eglBindAPI(EGL_OPENGL_API); 

    // 5. Create a context and make it current 
    EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, 
             NULL); 

    eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx); 

    // from now on use your OpenGL context 

    // 6. Terminate EGL when finished 
    eglTerminate(eglDpy); 
    return 0; 
} 
+0

我在使用NVIDIA GPU的g2实例,我将研究如何设置Xorg服务器。我在服务器上运行完全相同的EGL代码,它显示libEGL警告:DRI2:xcb_connect失败,libEGL警告:DRI2:xcb_connect失败,libEGL警告:GLX:XOpenDisplay失败。你能够成功运行它吗? – user3667089

+1

@ user3667089:这些错误消息表明您没有正确安装驱动程序。 “DRI2”由Mesa驱动程序*使用,但从不*由NVidia驱动程序使用。使用NVidia GPU时,我强烈建议您卸载与Mesa相关的所有内容,并干净地重新安装NVidia驱动程序。 – datenwolf

+1

@ user3667089:另外我测试了这个代码,它完美的工作 - 如果驱动程序安装正确。 – datenwolf