使用 CUDA-OpenGL 互操作时,NPOT 纹理会导致渲染效果不佳

Posted

技术标签:

【中文标题】使用 CUDA-OpenGL 互操作时,NPOT 纹理会导致渲染效果不佳【英文标题】:When using CUDA-OpenGL interop,NPOT texture results in bad rendering 【发布时间】:2020-12-22 09:25:00 【问题描述】:

这里是代码,现在只是尝试渲染一个渐变。 我最终要完成的是使用 CUDA 渲染光线追踪场景,然后将其显示在屏幕上,并能够移动。 我遇到的主要问题是让我的计算图像正确显示,因为现在我只用渐变测试它,当我的屏幕不是两个平方的幂时我遇到了问题。

#define width 1024
#define height 256
struct cudaGraphicsResource* screen;
uchar4* rendered;
GLFWwindow* window;
GLuint image;
__global__ void computeFrame(uchar4* rendered)
    unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
    unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
    if (x > width || y > height) return;
    int index = y * height + x;
    rendered[index] = make_uchar4(y/(height*1.0f)*255, 0, 0, 255);

void createTexture()
    glGenTextures(1, &image);
    glBindTexture(GL_TEXTURE_2D, image);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);

int renderFrame() 
    cudaDeviceSynchronize();
    cudaGraphicsMapResources(1, &screen, 0);
    cudaArray* dstArray;
    cudaGraphicsSubResourceGetMappedArray(&dstArray, screen, 0, 0);
    dim3 block(16, 16);
    dim3 grid((width + block.x - 1) / block.x, (height + block.y - 1) / block.y);
    computeFrame << <grid, block >> > (rendered);
    cudaMemcpyToArray(dstArray,0,0, rendered, width * height * sizeof(uchar4), 
    cudaMemcpyDeviceToDevice);
    cudaDeviceSynchronize();
    cudaGraphicsUnmapResources(1, &screen, 0);
    return 0;


void displayFrame() 
    static int frno = 0;
    frno++;
    if (frno > 60) 
        frno = 0;
        printf("60frames passed\n");
    
    renderFrame();
    glBindTexture(GL_TEXTURE_2D, image);
    glEnable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-width,width, -height, height, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0,0, width, height);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-width, -height, 0.5);
    glTexCoord2f(1, 0.0); glVertex3f(width, -height, 0.5);
    glTexCoord2f(1, 1); glVertex3f(width, height, 0.5);
    glTexCoord2f(0.0, 1); glVertex3f(-width, height, 0.5);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glfwSwapBuffers(window);

int main(int argc, char** argv)
    glfwInit();
    glewInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    window = glfwCreateWindow(width,height, "Rotaru Leonard Claudiu", NULL, NULL);
    glfwMakeContextCurrent(window);
    cudaSetDevice(0);
    createTexture();
    cudaGraphicsGLRegisterImage(&screen, image, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsNone);
    cudaMalloc(&rendered, width * height * sizeof(uchar4));
    while (true) 
        displayFrame();
    
    glfwTerminate();

下面是运行宽高1024的结果: width 1024 height 1024 这是运行宽度 1024 和高度 512 的结果: width 1024 height 512

【问题讨论】:

您是否尝试过填充屏幕缓冲区,并使用 cudaMemcpy2D 和音高信息? 填充屏幕缓冲区是什么意思? 填充使其成为2的幂,实际内容由pitch指定 【参考方案1】:

以后请提供完整的代码。当您剥离包含标头时,它没有帮助。

根据我的测试,您至少有几个问题。

    在您的一个屏幕截图中,您可以看到编译器告诉您cudaMemcpyToArray 是deprecated。此外,无论如何在此设置中使用它都是不正确的。所以我们将其替换为cudaMemcpy2DToArray。而不是这个:

    cudaMemcpyToArray(dstArray,0,0, rendered, width * height * sizeof(uchar4), 
    cudaMemcpyDeviceToDevice);
    

    使用这个:

    cudaMemcpy2DToArray(dstArray,0,0, rendered, width * sizeof(uchar4), width * sizeof(uchar4), height, 
    cudaMemcpyDeviceToDevice);
    

    您在内核中的边界检查不正确:

    if (x > width || y > height) return;
    

    应该是:

    if (x >= width || y >= height) return;
    

    这是标准的计算机科学错误。

    您对index 的内核计算不正确:

    int index = y * height + x;
    

    应该是:

     int index = y * width + x;
    

    y 是您的高度变量,我们必须将其乘以每行的宽度才能得到正确的一维索引。

通过这些更改,您的代码对我来说似乎可以正常运行,如您所示,高度为 256。

【讨论】:

以上是关于使用 CUDA-OpenGL 互操作时,NPOT 纹理会导致渲染效果不佳的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个互操作会使 .NET 运行时崩溃?

如何在互操作期间阻止 MS Graph 组件弹出?

如何使用 Visual Studio 2022 注册 32 位 COM 互操作

本机 C++ 程序在使用 C++/CLI 和 C# 互操作 DLL 启动时崩溃

为 GCS 与 Terraform 启用“互操作”访问?

将反射与 COM 互操作一起使用