OpenGL计算着色器-奇怪的结果 [英] OpenGL compute shader - strange results
问题描述
我正在尝试实现用于图像处理的多遍计算着色器。
每遍都有输入图像和输出图像。
下一遍的输入图像是前一个的输出图像。
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屋!