OpenGL计算着色器-奇怪的结果 [英] OpenGL compute shader - strange results

查看:296
本文介绍了OpenGL计算着色器-奇怪的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现用于图像处理的多遍计算着色器。
每遍都有输入图像和输出图像。
下一遍的输入图像是前一个的输出图像。

I'm trying to implement a multipass compute shader for image processing. There is an input image and an output image in each pass. The next pass' input image is the previous ones' output.

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

This is the first time for me using compute shader in OpenGL so there may be some problems with my setup. I'm using OpenCV's Mat as the container to read/copy operations.

代码的某些部分与问题无关,因此我不包括在内。其中一些部分包括加载图像或初始化上下文。

There are some parts of the code which isn't related to the problem so I didn't include. Some of these parts include loading the image or initializing the context.

//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:

//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);
}



用法:



Usage:

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)。
我是否正确设置了所有东西,或者我缺少什么?
似乎这种带有纹理的方法确实很慢,是否有其他方法可以提高性能?

Sometimes I get strange results (glitchy textures, partially rendered textures), also the first pixel (at 0,0) is sometimes not written. Did I set up everything correctly or am I something missing? It seems that this method with the textures is really slow, is there any alternative which will increase performance?

Edit1: 更改了内存屏障标志。

推荐答案

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

I could solve this problem finally!

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

The problem lied in the cv::Mat's constructor. The following line only creates a header for the cv::Mat:

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

,但它确实 初始化该数据,这就是为什么我得到这些奇怪的结果的原因。

It DOES allocate data but it does NOT initialize that data, that's why I got these strange results. It was garbage in memory.

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

Using any function which allocates AND initializes this data solves the issue:

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

这篇关于OpenGL计算着色器-奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆