2016-01-29 73 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