我正在尝试为图像处理实现多通道计算着色器。 每次通过都有输入图像和输出图像。 下一个'输入图像是前一个'输出。
这是我第一次在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)有时也不会被写入。 我是否正确设置了一切,还是我缺少了什么? 看来这种带纹理的方法真的很慢,有没有其他可以提高性能的方法呢?
编辑1: 更改了记忆障碍标记。
答案 0 :(得分:5)
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
这是一个错误的障碍。屏障指定how you intend to access the data after the incoherent accesses。如果您尝试使用glGetTexImage
读取纹理,则必须使用GL_TEXTURE_UPDATE_BARRIER_BIT
。
答案 1 :(得分:3)
我不能100%确定这是否能解决您的问题;但是我没有看到你的标志显然有任何错误,无法初始化你的纹理设置。当我将您的代码与我的项目进行比较时,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()
函数调用下检查我的批次类时,这是调用ShaderManager的函数来设置制服使用纹理,然后调用ShaderManager的函数来设置如果纹理包含alpha通道,则再次设置纹理。在setTexture()
函数的ShaderManger类中,这是最终调用glActiveTexture()
和glBindTexture()
的位置。
因此,在简短摘要中,请尝试将glActiveTexture()
调用移至两个纹理的最后glTexParameter()
和最后glBindTexture()
次调用之间。我也认为它也应该在这两个电话之后glPixelStorei()
&amp; glTexImage2D()
因为您想要将纹理设置为活动状态,就像您要渲染它一样。
正如我之前提到的那样,我不能100%确定这是否是您问题的根本原因,但我相信值得尝试一下,看看它是否对您有所帮助。如果你试试这个,请告诉我会发生什么。我想知道这些API调用的顺序是否对它有任何影响。我会在我自己的解决方案中尝试它,但我不想打破我的课程或项目,因为它目前正常工作。
作为一个注释,纹理设置标志的唯一内容是在wrap / repeat部分中。您可以尝试使用GL_REPEAT
进行前两次glTexParameteri()
来电,而不是使用GL_CLAMP_TO_EDGE
让我知道您提出的问题,您不必担心mipmap最近两次glTexParameteri()
次调用的设置,因为您似乎没有使用您正在使用的设置中的mipmap。
答案 2 :(得分:3)
我终于可以解决这个问题了!
问题在于cv :: Mat的构造函数。 以下行仅为cv :: Mat创建标题:
cv::Mat result(image.rows,image.cols,image.type());
DOES 分配数据但 NOT 初始化该数据,这就是为什么我有这些奇怪的结果。这是记忆中的垃圾。
使用任何分配 AND 的函数初始化此数据可以解决问题:
cv::Mat::zeros
cv::Mat::ones
cv::Mat::create