[英]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.