繁体   English   中英

OpenGL计算着色器 - 奇怪的结果

[英]OpenGL compute shader - strange results

我正在尝试为图像处理实现多通道计算着色器。 每次通过都有输入图像和输出图像。 下一个'输入图像是前一个输出'。

这是我第一次在OpenGL中使用计算着色器,因此我的设置可能存在一些问题。 我正在使用OpenCV的Mat作为读取/复制操作的容器。

代码的某些部分与问题无关,所以我没有包含。 其中一些部分包括加载图像或初始化上下文。

初始化:

//texture init
glGenTextures(1, &feedbackTexture_);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, feedbackTexture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);

glGenTextures(1, &resultTexture_);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, resultTexture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);

// shader init
computeShaderID = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(computeShaderID, 1, &computeShaderSourcePtr, &computeShaderLength);
glCompileShader(computeShaderID);
programID = glCreateProgram();
glAttachShader(programID, computeShaderID);
glLinkProgram(programID);
glDeleteShader(computeShaderID);

着色器代码:

//shader code (simple invert)
#version 430
layout (local_size_x = 1, local_size_y = 1) in;

layout (location = 0, binding = 0, /*format*/ rgba32f) uniform readonly image2D inImage;
layout (location = 1, binding = 1, /*format*/ rgba32f) uniform writeonly image2D resultImage;

uniform writeonly image2D image;

void main()
{
    // Acquire the coordinates to the texel we are to process.
    ivec2 texelCoords = ivec2(gl_GlobalInvocationID.xy);

    // Read the pixel from the first texture.
    vec4 pixel = imageLoad(inImage, texelCoords);

    pixel.rgb = 1. - pixel.rgb;

    imageStore(resultImage, texelCoords, pixel);
}

用法:

cv::Mat image = loadImage().clone();
cv::Mat result(image.rows,image.cols,image.type());
// These get the appropriate enums used by glTexImage2D
GLenum internalformat = GLUtils::getMatOpenGLImageFormat(image);
GLenum format = GLUtils::getMatOpenGLFormat(image);
GLenum type = GLUtils::getMatOpenGLType(image);

int dispatchX = 1;
int dispatchY = 1;

for ( int i = 0; i < shaderPasses_.size(); ++i)
{
    // Update textures
    glBindTexture(GL_TEXTURE_2D, feedbackTexture_);
    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, result.cols, result.rows, 0, format, type, result.data);
    glBindTexture(GL_TEXTURE_2D, resultTexture_);
    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, image.cols, image.rows, 0, format, type, 0);
    glBindTexture(GL_TEXTURE_2D, 0);

    glClear(GL_COLOR_BUFFER_BIT);
    std::shared_ptr<Shader> shaderPtr = shaderPasses_[i];
    // Enable shader
    shaderPtr->enable();
    {
        // Bind textures
        // location = 0, binding = 0
        glUniform1i(0,0);
        // binding = 0
        glBindImageTexture(0, feedbackTexture_, 0, GL_FALSE, 0, GL_READ_ONLY, internalformat);
        // location = 1, binding = 1
        glUniform1i(1,1);
        // binding = 1
        glBindImageTexture(1, resultTexture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);

        // Dispatch rendering
        glDispatchCompute((GLuint)image.cols/dispatchX,(GLuint)image.rows/dispatchY,1);
        // Barrier will synchronize
        glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
    }
    // disable shader
    shaderPtr->disable();

    // Here result is now the result of the last pass.
}

有时我得到奇怪的结果(毛刺纹理,部分渲染纹理),第一个像素(0,0)有时也不会被写入。 我是否正确设置了一切,还是我缺少了什么? 似乎这种带有纹理的方法真的很慢,有没有其他可以提高性能的方法呢?

Edit1: 更改了memorybarrier标志。

 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 

这是一个错误的障碍。 屏障指定了在非相干访问之后您打算如何访问数据 如果你想从纹理读glGetTexImage ,你必须使用GL_TEXTURE_UPDATE_BARRIER_BIT

我不是百分百确定这是否能解决你的问题; 但是我没有看到你的标志有任何明显错误的初始化你的纹理设置。 当我将您的代码与我的项目进行比较时,API调用的顺序引起了我的注意。 在您的来源中,您有此订单:

glGenTextures(...);    // Generate
glActiveTexture(...);  // Set Active
glBindTexture(...);    // Bind Texture
glTexParameteri(...);  // Wrap Setting
glTexParameteri(...);  // Wrap Setting
glTexParameteri(...);  // Mipmap Setting
glTexParameteri(...);  // Mipmap Setting
glBindTexture(...);    // Bind / Unbind

并且您为每个纹理重复此操作,除了传递纹理变量和增加id值。

我不知道它是否会产生影响,但是在我的引擎中并遵循我设置的逻辑路径; 尝试按此顺序执行,看看它是否有任何区别

glGenTextures(...);    // Generate
glBindTexture(...);    // Bind Texture
glTexParameteri(...);  // Wrap Setting
glTexParameteri(...);  // Wrap Setting
glTexParameteri(...);  // Mipmap Setting
glTexParameteri(...);  // Mipmap Setting

glActiveTexture(...);  // Set Active
glBindTexture(...);    // Bind / Unbind

我没有使用计算着色器,但在我的引擎中,我有几个类来管理不同的东西。 我有一个资产存储,它将所有资产保存到包含图像纹理的内存数据库中,我有一个ShaderManager类来管理目前只使用顶点和片段着色器的不同着色器。 它将读入并编译着色器文件,创建着色器程序,设置属性和制服,链接程序并运行着色器。 我正在使用批处理过程,我有一个批处理类和一个批处理管理器类来渲染不同类型的基元。 因此,当我通过我的解决方案并遵循逻辑路径或流程时,这就是我在代码中看到的内容。

正是AssetStorage类设置了纹理的属性,它在add()函数中按此顺序调用这些API调用,以便将纹理添加到内存中。

 glGenTextures(...);
 glBindTextures(...);
 glTexParameteri(...);
 glTexParameteri(...);
 glTexParameteri(...);
 glTexParameteri(...);

然后AssetStorage也在调用它们

glPixelStorei(...);
glTexImage2D(...)

将纹理添加到AssetStorage中的函数最终将返回TextureInfo对象的自定义结构。

当我在其render()函数调用下检查我的Batch类时,它调用ShaderManager的函数来设置使用纹理的制服,然后调用ShaderManager的函数来设置纹理,然后再次设置制服,如果纹理包含一个alpha通道。 setTexture()函数的ShaderManger类中,这是最终调用glActiveTexture()glBindTexture()地方。

因此,在简短的总结中,尝试将glActiveTexture()调用移动到最后一个glTexParameter()和两个纹理的最后一个glBindTexture()调用之间。 我认为它也应该在这两个调用之后以及glPixelStorei()glTexImage2D()因为你想要使纹理处于活动状态,就像你要渲染它一样。

正如我之前提到的那样,我不能100%确定这是否是你问题的根本原因,但我相信值得尝试一下,看看它是否对你有帮助。 如果你试试这个,请告诉我会发生什么。 我想知道这些API调用的顺序是否对它有任何影响。 我会在我自己的解决方案中尝试它,但我不想打破我的课程或项目,因为它目前正常工作。

作为一个注释,纹理设置的唯一标志是在包装/重复部分。 您可以尝试使用GL_REPEAT进行前两次glTexParameteri()调用,而不是使用GL_CLAMP_TO_EDGE ,让我知道你提出了什么,你不必担心最后两个glTexParameteri()调用的mipmap设置,因为它出现了您没有使用您正在使用的设置中的mipmap。

我终于可以解决这个问题!

问题在于cv :: Mat的构造函数。 以下行仅为cv :: Mat创建标题:

cv::Mat result(image.rows,image.cols,image.type());

分配的数据,但它初始化的数据,这就是为什么我有这些奇怪的结果。 它在记忆中是垃圾。

使用任何分配AND初始化此数据的函数可以解决问题:

cv::Mat::zeros
cv::Mat::ones
cv::Mat::create

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM