簡體   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