使用CUDA生成的顶点缓冲对象绘制图像,使用OpenGL

4
我正在使用CUDA生成这个ABGR输出图像。所讨论的图像存储在一个uchar4数组中。数组的每个元素表示图像中每个像素的颜色。显然,这个输出数组是一个2D图像,但它在CUDA中被分配为交错字节的线性内存。
我知道CUDA可以轻松地将此数组映射到OpenGL顶点缓冲对象。我的问题是,假设我有图像中每个像素的RGB值以及图像的宽度和高度,如何使用OpenGL将此图像绘制到屏幕上?
我知道肯定需要某种类型的着色器,但由于我的知识很少,我不知道着色器如何使用每个像素的颜色,但将其映射到正确的屏幕像素。
我知道我应该增加我的OpenGL知识,但这似乎是一个微不足道的任务。如果有一种简单的方法来绘制这张图片,我宁愿不花太多时间学习OpenGL。

只需绘制一个精灵(由2个三角形组成的四边形,上面映射着您的纹理)。 - Ivan Aksamentov - Drop
@Drop 我该怎么做? - Maghoumi
1
你看过任何CUDA/OpenGL互操作示例代码吗?如果你只有原始像素数据(似乎是你的情况),那么image interop example可能会引起你的兴趣。如果你想实际操纵几何图形,那么simple OpenGL sample可能会引起你的兴趣。 - Robert Crovella
1个回答

6
我终于找到了一个简单的方法来实现我想要的功能。不幸的是,我不知道Robert在NVIDIA网站上提到的示例的存在。
长话短说,最简单的绘制图像的方法是在OpenGL中定义一个像素缓冲区对象,将该缓冲区对象与CUDA注册,并将其作为uchar4输出数组传递给CUDA内核。以下是基于JOGL和JCUDA的快速伪代码,展示了所涉及的步骤。大部分代码都来自NVIDIA网站上的示例: 1) 创建OpenGL缓冲区
GL2 gl = drawable.getGL().getGL2();

int[] buffer = new int[1];

// Generate buffer
gl.glGenBuffers(1, IntBuffer.wrap(buffer));
glBuffer = buffer[0];

// Bind the generated buffer
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, glBuffer);
// Specify the size of the buffer (no data is pre-loaded in this buffer)
gl.glBufferData(GL2.GL_ARRAY_BUFFER, imageWidth * imageHeight * 4, (Buffer)null, GL2.GL_DYNAMIC_DRAW);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);

// The bufferResource is of type CUgraphicsResource and is defined as a class field
this.bufferResource = new CUgraphicsResource();

// Register buffer in CUDA
cuGraphicsGLRegisterBuffer(bufferResource, glBuffer, CUgraphicsMapResourceFlags.CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);

2) 初始化纹理并设置纹理参数

GL2 gl = drawable.getGL().getGL2();
int[] texture = new int[1];

gl.glGenTextures(1, IntBuffer.wrap(texture));
this.glTexture = texture[0];

gl.glBindTexture(GL2.GL_TEXTURE_2D, glTexture);

gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);


gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGBA8, imageWidth, imageHeight, 0, GL2.GL_BGRA, GL2.GL_UNSIGNED_BYTE, (Buffer)null);

gl.glBindTexture(GL2.GL_TEXTURE_2D, 0); 

3) 运行CUDA内核,并在OpenGL的显示循环中显示结果。

this.runCUDA();

GL2 gl = drawable.getGL().getGL2();

gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, glBuffer);

gl.glBindTexture(GL2.GL_TEXTURE_2D, glTexture);
gl.glTexSubImage2D(GL2.GL_TEXTURE_2D, 0, 0, 0,
                imageWidth, imageHeight,
                GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, 0); //The last argument must be ZERO! NOT NULL! :-)

gl.glBindBuffer(GL2.GL_PIXEL_PACK_BUFFER, 0);
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, 0);

gl.glBindTexture(GL2.GL_TEXTURE_2D, glTexture);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glDisable(GL2.GL_DEPTH_TEST);
gl.glDisable(GL2.GL_LIGHTING);
gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);

gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();

gl.glViewport(0, 0, imageWidth, imageHeight);


gl.glBegin(GL2.GL_QUADS);
    gl.glTexCoord2f(0.0f, 1.0f);
    gl.glVertex2f(-1.0f, -1.0f);


    gl.glTexCoord2f(1.0f, 1.0f);
    gl.glVertex2f(1.0f, -1.0f);


    gl.glTexCoord2f(1.0f, 0.0f);
    gl.glVertex2f(1.0f, 1.0f);


    gl.glTexCoord2f(0.0f, 0.0f);
    gl.glVertex2f(-1.0f, 1.0f);
gl.glEnd();

gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPopMatrix();

gl.glDisable(GL2.GL_TEXTURE_2D);

3.5) CUDA 调用:

public void runCuda(GLAutoDrawable drawable) {

    devOutput = new CUdeviceptr();
    // Map the OpenGL buffer to a resource and then obtain a CUDA pointer to that resource
    cuGraphicsMapResources(1, new CUgraphicsResource[]{bufferResource}, null);
    cuGraphicsResourceGetMappedPointer(devOutput, new long[1], bufferResource);

    // Setup the kernel parameters making sure that the devOutput pointer is passed to the kernel
    Pointer kernelParams = 
                            .
                            .
                            .
                            .

    int gridSize = (int) Math.ceil(imageWidth * imageHeight / (double)DESC_BLOCK_SIZE);

    cuLaunchKernel(function,
            gridSize, 1, 1,
            DESC_BLOCK_SIZE, 1, 1,
            0, null,
            kernelParams, null);
    cuCtxSynchronize();

    // Unmap the buffer so that it can be used in OpenGL
    cuGraphicsUnmapResources(1, new CUgraphicsResource[]{bufferResource}, null);
}

PS:感谢Robert提供示例的链接,也感谢那些没有任何有用反馈就给我的问题投了反对票的人!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接