(抱歉:我是从SO交叉发布的,那里没有答案。我认为将其放置在此站点上可能更合适。)

我正在尝试在OpenGL中构建计算着色器执行骨架化算法。我已经在仅CPU版本中测试了该算法,在那儿是正确的。但是,在将其移植到计算着色器代码时遇到了一些麻烦。

问题是,无论我运行了多少次计算着色器,输出都不会在第一次调用后发生变化。实际上,如果我在while循环结束时取出检查,该程序将永远不会终止。

我有两个存储区域,可用于输入和输出。我正在尝试在主while循环中使用glBindBufferBase()进行技巧操作,在其中我将其中的两个交换(上一轮的输出成为本轮的输入)。参见main.cpp中的第270-318行。这样一来,我就不会多次在CPU和GPU之间来回复制数据。

我还重新设计了此版本以将IMG_1换回数据,然后使用以下命令调用glBufferData数据。它可以正常工作,但是执行所有这些CPU <-> GPU操作似乎效率很低。

所以,我的问题是:

1)我可以使用glBindBuffers来完成此技巧吗?我可以在其中交换它们,以便可以多次处理数据而无需移动数据回到CPU?在测试较小的问题(仅添加短数组)时,它奏效了。

2)如果技巧很好,那我在哪里出错了?

注意:此代码需要一个称为“ test.pgm”的640 x 400大小的.pgm(黑白图像)。您可以在GIMP中制作一个,但请确保将其另存为二进制而不是ASCII。

此代码是使用以下标志编译的:

g++ -g pgm.cpp main.cpp -lglut -lGLU -lGL -lm -lGLEW -o test


另外,请原谅我使用C ++但做了C风格的技巧。我在C上花费的时间比在C ++中花费的时间多。

main.cpp

// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <errno.h>

//For stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// Include GLEW
#include <GL/glew.h>

//Glut
#include <GL/glut.h>

//Project specific
#include "skeletonize.hpp"
#include "PGM.hpp"

// OpenGL shader info
GLuint programID;
GLuint output_image;

#define IMG_0               0
#define IMG_1               1
#define CMD                 2
#define NUM_BUFS            3

#define CMD_BUF_WIDTH       0
#define CMD_BUF_HEIGHT      1
#define CMD_BUF_CMD         2
#define CMD_BUF_RESPONSE    3
#define CMD_BUF_LEN         4

#define CMD_EXPAND          1
#define CMD_THIN_N          2
#define CMD_THIN_S          3
#define CMD_THIN_E          4
#define CMD_THIN_W          5
#define CMD_NORMALIZE       6
#define CMD_REGULARIZE      7

#define INITIALIZED         0
#define NOT_FINISHED        1

GLuint computeProgram;
GLuint buffers[NUM_BUFS];       //SSBO objects, one for IMG_0, one for IMG_1, and one for commands/response
static GLchar* computeSource;
GLuint shaderProgram;


//TODO: don't really need 2 textures yet, but will eventually when doing overlay of original image.
GLuint textures[2];

GLchar* LoadSource(const char* pFile)
{
    struct stat buf;
    GLchar *source;
    int fd;

    if (stat(pFile, &buf) == -1)
    {
        printf("Error opening file\n");
        printf("Error: %s\n", strerror(errno));
        return NULL;
    }

    fd = open(pFile, O_RDONLY);

    if (fd == -1)
    {
        printf("Error opening file. Error: %s\n", strerror(errno));
        return NULL;
    }

    source = new GLchar[buf.st_size + 1];

    if (read(fd, source, buf.st_size) == -1)
    {
        printf("Error reading file. Error: %s\n", strerror(errno));
        delete[] source;
        return NULL;
    }

    source[buf.st_size] = '
#version 450 core
//#extension GL_NV_shader_buffer_load : enable

#define WIDTH           0    // Width of image
#define HEIGHT          1    // Height of image
#define CMD             2    // Command to execute
#define RESPONSE        3    // Response to command
#define BUF_LEN         4

#define CMD_UNUSED      1    // TODO: remove this. Will have to be mirroed in C code.
#define CMD_THIN_N      2
#define CMD_THIN_S      3
#define CMD_THIN_E      4
#define CMD_THIN_W      5
#define CMD_NORMALIZE   6
#define CMD_REGULARIZE  7

#define NOT_FINISHED 1

layout (local_size_x = 16, local_size_y = 16) in;
//layout (local_size_x = 1) in; //TODO: remove

layout (std430, binding = 0) buffer Cmd {
   uint cmd_buf[BUF_LEN]; //Width, height, command, response
};

layout (std430, binding = 1) buffer Img1 {
   uint image_0[];
};

layout (std430, binding = 2) buffer Img2 {
    uint image_1[];
};


int sigma(uint data[9]) {
    int i;
    int sigma = 0;

    // Assume 9 pixels, A0 (pixel of interest) -> A8
    // In image, A0 is center
    // 1 2 3
    // 8 0 4
    // 7 6 5

    for (i=1; i < 9; i++)
    {
        sigma += int(data[i]);
    }

    return sigma;
}


int chi(uint data[9]) {
    int chi;

    // Assume 9 pixels, A0 (pixel of interest) -> A8
    // 1 2 3
    // 8 0 4
    // 7 6 5

    chi = int(data[1] != data[3]) +
          int(data[3] != data[5]) +
          int(data[5] != data[7]) +
          int(data[7] != data[1]) +

          2 * ( int((data[2] > data[1]) && (data[2] > data[3])) ) +
          int((data[4] > data[3]) && (data[4] > data[5])) +
          int((data[6] > data[5]) && (data[6] > data[7])) +
          int((data[8] > data[7]) && (data[8] > data[1]));

   return chi;
}

// 1 2 3
// 8 0 4
// 7 6 5
int getPos(in int x, int y) {
   return y * int(cmd_buf[WIDTH]) + x;
}

uint getVal(in int pos) {
   return image_0[ uint(pos) ];
}

int removePoint(uint neighborhood[9]) {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);

    if (chi(neighborhood) == 2 && sigma(neighborhood) != 1) {
        image_1[getPos(x, y)] = 0;
        cmd_buf[RESPONSE] = NOT_FINISHED;
        return 1;
    }
    else
    {
        //TODO: needed? Swapping back and forth between input and output should account for this
        image_1[getPos(x,y)] = 1;
    }   
    return 0;
}


void getNeighborhood(inout uint neighborhood[9]) {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);
    int bottom = int(cmd_buf[WIDTH] * (cmd_buf[HEIGHT] - 1));
    int pos = getPos(x, y);
    int width = int(cmd_buf[WIDTH]);
    int height = int(cmd_buf[HEIGHT]);
    uint pixel;
    int i = 0;

    for (i=1; i < 9; i++) {
       neighborhood[i] = 2;
    }

    if (pos < width) {
        // Pixel on top, fill outiside image with zero
       neighborhood[1] = 0;
       neighborhood[2] = 0;
       neighborhood[3] = 0;
    }

    if (pos % width == 0) {
        // Pixel is on left edge. Fill area outside of image with zero
        neighborhood[1] = 0;
        neighborhood[8] = 0;
        neighborhood[7] = 0;
    }

    if ((pos % width) == (width - 1)) {
        // Pixel is on right edge.
        neighborhood[3] = 0;
        neighborhood[4] = 0;
        neighborhood[5] = 0;
    }

    if (pos >= bottom) {
        // Pixel is on bottom edge.
        neighborhood[5] = 0;
        neighborhood[6] = 0;
        neighborhood[7] = 0;
    }

    // Get remaining pixels
    for (i=1; i < 9; i++) {
        if (neighborhood[i] == 2) {
            switch (i) {
                case 1:
                    // Upper left pixel
                    neighborhood[i] = getVal(pos - 1 - width);
                    break;
                case 2:
                    // Upper middle pixel
                    neighborhood[i] = getVal(pos - width);
                    break;
                case 3:
                    // Upper right pixel
                    neighborhood[i] = getVal(pos + 1 - width);
                    break;
                case 4:
                    // Right pixel
                    neighborhood[i] = getVal(pos + 1);
                    break;
                case 5:
                    // Bottom right pixel
                    neighborhood[i] = getVal(pos + width + 1);
                    break;
                case 6:
                    // Bottom middle pixel
                    neighborhood[i] = getVal(pos + width);
                    break;
                case 7:
                    // Bottom left pixel
                    neighborhood[i] = getVal(pos + width - 1);
                    break;
                case 8:
                    // Left pixel
                    neighborhood[i] = getVal(pos - 1);
                    break;
            }
        }
    }
}




void normalize() {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);
    uint val = image_0[getPos(x, y)] == 0x0 ? 0 : 1;

    image_0[getPos(x, y)] = val;
    image_1[getPos(x, y)] = val;

}


void regularize() {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);
    uint val = image_0[getPos(x, y)] == 0x0 ? 0 : 0xFFFFFFFF;

    if (val != 0xFFFFFFFF)
    {
        cmd_buf[RESPONSE] = 99; //Test Value -- TODO: remove
    }

    image_1[getPos(x, y)] = val;
}



// North-South-East-West skeletonization
void skeleton() {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);
    uint neighborhood[9];
    neighborhood[0] = getVal(getPos(x, y));

    // Only consider cases where the center is 1
    if (neighborhood[0] != 1) {
        return;
    }

    getNeighborhood(neighborhood);

    switch (cmd_buf[CMD]) {
        case CMD_THIN_N:
            //north
            if (neighborhood[2] == 0 && neighborhood[6] == 1) {
                removePoint(neighborhood);
            }
            break;
        case CMD_THIN_S:
            //south
            if (neighborhood[2] == 1 && neighborhood[6] == 0) {
                removePoint(neighborhood);
            }
            break;
        case CMD_THIN_E:
            //east
            if (neighborhood[4] == 0 && neighborhood[8] == 1) {
                removePoint(neighborhood);
            }
            break;
        case CMD_THIN_W:
            //west
            if (neighborhood[4] == 1 && neighborhood[8] == 0) {
                removePoint(neighborhood);
            }
            break;
    }
}



void main() {

    switch (cmd_buf[CMD]) {
        case CMD_THIN_N:
        case CMD_THIN_S:
        case CMD_THIN_E:
        case CMD_THIN_W:
            skeleton();
            break;
        case CMD_NORMALIZE:
            normalize();
            break;
        case CMD_REGULARIZE:
            regularize();
            break;
    }
}
'; //Shader compiler needs null to know end of input return source; } // Shader sources const GLchar* vertexSource = "#version 450 core\n" "in vec2 position;" "in vec2 texcoord;" "out vec2 Texcoord;" "void main()" "{" " Texcoord = texcoord;" " gl_Position = vec4(position, 0.0, 1.0);" "}"; const GLchar* fragmentSource = "#version 450 core\n" "in vec2 Texcoord;" "out vec4 outColor;" "uniform sampler2D texData;" "void main()" "{" " vec4 imColor = texture(texData, Texcoord);" " outColor = vec4(0.0, imColor.r, 0.0, 1.0);" //" outColor = texture(texData, Texcoord);" //" outColor = vec4(1.0, 1.0, 0.0, 1.0);" "}"; void checkError(int line) { GLint err; do { err = glGetError(); switch (err) { case GL_NO_ERROR: //printf("%d: No error\n", line); break; case GL_INVALID_ENUM: printf("%d: Invalid enum!\n", line); break; case GL_INVALID_VALUE: printf("%d: Invalid value\n", line); break; case GL_INVALID_OPERATION: printf("%d: Invalid operation\n", line); break; case GL_INVALID_FRAMEBUFFER_OPERATION: printf("%d: Invalid framebuffer operation\n", line); break; case GL_OUT_OF_MEMORY: printf("%d: Out of memory\n", line); break; default: printf("%d: glGetError default case. Should not happen!\n", line); } } while (err != GL_NO_ERROR); } void display() { glClearColor(0.0f, 0.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glFlush(); glutSwapBuffers(); } void reshape(int width,int height) { double w2h = (height>0) ? (double)width/height : 1; // Set viewport as entire window glViewport(0,0, width,height); } void runComputeProgram(uint32_t *data, uint32_t *data2) { int width = 640; int height = 400; uint32_t *ptr; uint32_t cmd[CMD_BUF_LEN]; computeSource = LoadSource("compute.shader"); if (computeSource == NULL) { return; } GLuint computeShader = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(computeShader, 1, &computeSource, NULL); glCompileShader(computeShader); computeProgram = glCreateProgram(); glAttachShader(computeProgram, computeShader); glLinkProgram(computeProgram); GLint status; glGetProgramiv(computeProgram, GL_LINK_STATUS, &status); if (status == GL_TRUE) { printf("link good\n"); } else { printf("link bad\n"); GLchar log[4096]; GLsizei len; glGetProgramInfoLog(computeProgram, 4096, &len, log); printf("%s\n", log); return; } // First action is to transform the image into binary values (0, 1) cmd[CMD_BUF_CMD] = CMD_NORMALIZE; cmd[CMD_BUF_WIDTH] = width; cmd[CMD_BUF_HEIGHT] = height; glGenBuffers(NUM_BUFS, buffers); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[CMD]); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(cmd), cmd, GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffers[IMG_0]); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * width * height, data, GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_1]); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * width * height, data2, GL_DYNAMIC_DRAW); glUseProgram(computeProgram); glDispatchCompute(width / 16, height / 16, 1); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_1]); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); // Rebind ptr for our while loop glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[CMD]); //glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(cmd), cmd, GL_DYNAMIC_DRAW); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); int i = 0; do { printf("iteration: %d", i); glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); cmd[CMD_BUF_RESPONSE] = INITIALIZED; switch (i % 4) { case 0: cmd[CMD_BUF_CMD] = CMD_THIN_N; break; case 1: cmd[CMD_BUF_CMD] = CMD_THIN_S; break; case 2: cmd[CMD_BUF_CMD] = CMD_THIN_E; break; case 3: cmd[CMD_BUF_CMD] = CMD_THIN_W; break; } glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(cmd), cmd, GL_DYNAMIC_DRAW); glDispatchCompute(width / 16, height / 16, 1); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); if (i % 2 == 0) { printf("Input is now img_1. Output is img_0\n"); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffers[IMG_1]); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_0]); checkError(__LINE__); } else { printf("Input is now img_0. Output is img_1\n"); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffers[IMG_0]); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_1]); checkError(__LINE__); } glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[CMD]); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); printf("cmd issued at start: %d response: %d\n", ptr[CMD_BUF_CMD], ptr[CMD_BUF_RESPONSE]); i++; } while(ptr[CMD_BUF_RESPONSE] != INITIALIZED && i < 10); //Using i < 10, otherwise this never terminates glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); // Free ptr // Transform Binary image (0, 1) to (0, 0xFFFFFFFF) values for texture display cmd[CMD_BUF_CMD] = CMD_REGULARIZE; glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[CMD]); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(cmd), cmd, GL_DYNAMIC_DRAW); glDispatchCompute(width / 16, height / 16, 1); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[CMD]); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); printf("Regularize: cmd: %d width: %d height: %d response: %d\n", ptr[CMD_BUF_CMD], ptr[CMD_BUF_WIDTH], ptr[CMD_BUF_HEIGHT], ptr[CMD_BUF_RESPONSE]); // Create texure glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); glGenTextures(2, textures); checkError(__LINE__); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); checkError(__LINE__); if (i % 2 == 0) { printf("output image is img_1\n"); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_1]); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); } else { printf("output image is img_0\n"); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffers[IMG_0]); ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); } glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); glUseProgram(shaderProgram); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED, GL_UNSIGNED_INT, ptr); //TODO: this is wrong. worry about later. checkError(__LINE__); glUniform1i(glGetUniformLocation(shaderProgram, "texData"), 0); checkError(__LINE__); 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_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); checkError(__LINE__); } void initGL() { // Vertices & texture init GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); GLuint vbo; glGenBuffers(1, &vbo); GLfloat vertices[] = { // X Y S T -1.0f, 1.0f, 0.0f, 0.0f, // Top-left 1.0f, 1.0f, 1.0f, 0.0f, // Top-right 1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right -1.0f, -1.0f, 0.0f, 1.0f // Bottom-left }; glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); GLuint ebo; glGenBuffers(1, &ebo); GLuint elements[] = { 0, 1, 2, 2, 3, 0 }; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); // Create shaders GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexSource, NULL); glCompileShader(vertexShader); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentSource, NULL); glCompileShader(fragmentShader); shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glBindFragDataLocation(shaderProgram, 0, "outColor"); glLinkProgram(shaderProgram); glUseProgram(shaderProgram); // Vertex data specification GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); glEnableVertexAttribArray(posAttrib); glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0); GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord"); glEnableVertexAttribArray(texAttrib); glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat))); checkError(__LINE__); } int main(int argc, char** argv) { // Image setup PGM pgmImage; pgmImage.ReadFile("test.pgm"); uint32_t *data = new uint32_t[pgmImage.GetHeight() * pgmImage.GetWidth()]; uint32_t *data2 = new uint32_t[pgmImage.GetHeight() * pgmImage.GetWidth()]; unsigned int size = pgmImage.GetHeight() * pgmImage.GetWidth(); uint8_t *pgmData = pgmImage.GetData(); for (int i=0; i < size; i++) { data[i] = pgmData[i]; } int count = 0; for (int i =0; i < pgmImage.GetHeight() * pgmImage.GetWidth(); i++) { if (data[i] == 0xFF) { count++; } } printf("count: %d\n", count); // Window Setup glutInitWindowSize(640, 400); glutInitWindowPosition (140, 140); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInit(&argc, argv); glutCreateWindow( "OpenGL Application" ); glutDisplayFunc(display); glutReshapeFunc(reshape); glewExperimental = true; if (glewInit() != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW\n"); return -1; } initGL(); runComputeProgram(data, data2); checkError(__LINE__); glutMainLoop(); return 0; }


compute.shader

#include "PGM.hpp"

#define PGM_HEADER "P5"

PGM::PGM()
{
    mpData = NULL;
    Clear();
}

PGM::~PGM()
{
    Clear();
}

uint8_t* PGM::GetData()
{
    return mpImgData;
}


uint16_t PGM::GetWidth()
{
    return mWidth;
}

uint16_t PGM::GetHeight()
{
    return mHeight;
}

uint8_t PGM::GetMaxWhite()
{
    return mMaxWhite;
}

void PGM::Clear()
{
    if (mpData != NULL)
    {
        delete[] mpData;
    }

    mpImgData = NULL;
    mWidth = 0;
    mHeight = 0;
    mMaxWhite = 255;
}

// Finds the 
int PGM::PopulateFields(size_t size)
{
    int i;
    bool EOL = false;
    bool haveWhite = false;
    bool comment = false;

    if (mpData == NULL) { return -1; }

    // Check header
    if ((mpData[0] != 0x50) || (mpData[1] != 0x35)) { return -2; }

    //Ignore the comment
    //Start at 3rd position in file, after "P5" header    
    for (i = 2; i < size; i++)
    {
        if (mpData[i] == '#') 
        { 
            comment = true;
            continue;
        }

        if (mpData[i] == 0x0A && comment == true)
        {
            comment = false;
            break;
        }

        if (comment == true) 
        { 
            continue; 
        }

    }

    // Get width and height
    i++;
    sscanf((char *)&mpData[i], "%4" SCNu16 " %4" SCNu16, &mWidth, &mHeight);

    for (i; i < size; i++)
    {
        //Move past the width and height we just found
        if (mpData[i] == 0x0A && EOL == false)
        {
            EOL = true;
            continue;
        }

        // If past the width and height, now at the range. Save it.
        if (EOL == true && haveWhite == false)
        {
            sscanf((char *)&mpData[i], "%3" SCNu8, &mMaxWhite);
            haveWhite = true;
        }

        if (haveWhite == true && mpData[i] == 0x0A)
        {
            i++; //Move to next element - start of the actual data
            break;
        }
    }

    if (i == size)
    {
        return -3; //Did not find the start of data.
    }

    mpImgData = &mpData[i];

    return 0;
}

// Reads a PGM file. Returns 0 on success, other values on failure
int PGM::ReadFile(const char *pPath)
{
    struct stat st;
    int fd;

    if (this->mpData != NULL)
    {
        Clear();
    }

    if (stat(pPath, &st) != 0)
    {
        return 1;
    }

    fd = open(pPath, O_RDONLY);

    if (fd == -1)
    {
        return 1;
    }

    //this->mpData = (uint8_t *) malloc(st.st_size);
    mpData = new uint8_t[st.st_size];

    if (this->mpData == NULL)
    {
        return 2;
    }

    if (read(fd, this->mpData, st.st_size) == -1)
    {
        Clear();
    }

    close(fd);

    PopulateFields(st.st_size);

    return 0;
}


pgm.cpp

#ifndef __PGM_H__
#define __PGM_H__

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>

class PGM
{
  public:
    int         ReadFile(const char *pPath);
    uint8_t*    GetData();
    uint16_t    GetWidth();
    uint16_t    GetHeight();
    uint8_t     GetMaxWhite();

    PGM();
    ~PGM();

  private:

    void        Clear();
    int         PopulateFields(size_t size);

    uint8_t     *mpData;
    uint8_t     *mpImgData;
    uint16_t    mWidth;
    uint16_t    mHeight;
    uint8_t     mMaxWhite;

};

#endif // __PGM_H__


pgm.hpp

q4312078q

评论

将所有数据保留在GPU上,并在执行操作时换入/换出缓冲区应该没问题。它称为“乒乓”,是图形中非常普遍的技术。我无法在您的代码中发现该错误,但是您的计算着色器非常复杂。我建议注释掉所有内容,除了对缓冲区的简单写操作外,看看可以使它工作。然后逐步将其重新构建起来,并在进行过程中对每块进行测试。这应该有助于缩小问题的范围。

感谢您的关注!我将对其进行更多调查。我认为这是一个交换问题,因为如果我在每次迭代后打印出0x1的像素数,它就会变成(组成数字)1000、900、860、890、860、890、860、890。但是,如果我只需一遍又一遍地运行开关外壳的一部分,它就会单调减少直到不再。很高兴知道我对乒乓球并不疯狂! :)

有关信息:从堆栈溢出中交叉发布

#1 楼

我找到了!问题源于交换中的问题。当我们交换缓冲区时,输出缓冲区成为输入,而输入缓冲区成为输出。但是,现在作为输出的缓冲区未更新为匹配!

To illustrate:

Init:
 In      Out
1 1 1   1 1 1
1 1 1   1 1 1
1 1 1   1 1 1

First Iteration (remove north corners):
 In      Out
1 1 1   0 1 0
1 1 1   1 1 1
1 1 1   1 1 1

Swap 
 In      Out
0 1 0   1 1 1
1 1 1   1 1 1
1 1 1   1 1 1

Second iteration (remove east corners):
 In      Out
0 1 0   1 1 1
1 1 1   1 1 1
1 1 1   1 1 0

... (and so on)


通过在计算着色器中修改skeleton()来将image_0复制到image_1,然后进行任何操作否则,该算法将正常工作。

void skeleton() {
    int x = int(gl_GlobalInvocationID.x);
    int y = int(gl_GlobalInvocationID.y);
    uint neighborhood[9];
    neighborhood[0] = getVal(getPos(x, y));

    image_1[getPos(x, y)] = image_0[getPos(x, y)];

    // Only consider cases where the center is 1
    if (neighborhood[0] != 1) {
        image_1[0] = 0;
        return;
    }
    ...


另外,我还清理了很多代码。例如,您可以在调度调用之前通过glBindBufferBase()设置输入和输出缓冲区。