加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 重用bindBufferBase和OpenGL计算着色器

发布时间:2020-12-16 06:52:37 所属栏目:百科 来源:网络整理
导读:我正在尝试在OpenGL中构建一个计算着色器来执行骨架化算法.我在仅CPU版本中测试了算法,并且它在那里是正确的.但是,我在移植它以计算着色器代码时遇到了一些麻烦. 问题是无论我运行多少次计算着色器调用,输出都不会在第一次调用之后发生变化.事实上,如果我在w
我正在尝试在OpenGL中构建一个计算着色器来执行骨架化算法.我在仅CPU版本中测试了算法,并且它在那里是正确的.但是,我在移植它以计算着色器代码时遇到了一些麻烦.

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

我有两个用于输入和输出的内存区域.我试图在主循环中使用glBindBufferBase()进行一次技巧,我将它们中的两个交换掉(最后一轮的输出成为当前轮次的输入).见main.cpp中的第270-318行.这样我就不会在CPU和GPU之间来回复制数据了很多次.

所以,我的问题是:

1)我可以使用glBindBuffers做这个技巧,我交换它们以便我可以多次操作数据而不将其移回CPU吗?在测试较小的问题(只是添加短数组)时,它起作用了.

2)如果诀窍很好,我哪里错了?

注意:此代码需要640 x 400大小的.pgm(黑白图像),称为“test.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 filen");
        printf("Error: %sn",strerror(errno));
        return NULL;
    }

    fd = open(pFile,O_RDONLY);

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

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

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

    source[buf.st_size] = ''; //Shader compiler needs null to know end of input

    return source;
}


// Shader sources
const GLchar* vertexSource =
    "#version 450 coren"
    "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 coren"
    "in vec2 Texcoord;"
    "out vec4 outColor;"
    "uniform sampler2D texData;"
    "void main()"
    "{"
    "   vec4 imColor = texture(texData,Texcoord);"
    "   outColor = vec4(0.0,imColor.r,1.0);"
    //"    outColor = texture(texData,Texcoord);"
    //"    outColor = vec4(1.0,1.0,1.0);"
    "}";


void checkError(int line)
{
    GLint err;

    do
    {
        err = glGetError();
        switch (err)
        {
            case GL_NO_ERROR:
                //printf("%d: No errorn",line);
                break;
            case GL_INVALID_ENUM:
                printf("%d: Invalid enum!n",line);
                break;
            case GL_INVALID_VALUE:
                printf("%d: Invalid valuen",line);
                break;
            case GL_INVALID_OPERATION:
                printf("%d: Invalid operationn",line);
                break;
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                printf("%d: Invalid framebuffer operationn",line);
                break;
            case GL_OUT_OF_MEMORY:
                printf("%d: Out of memoryn",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,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 goodn");
    }
    else
    {
        printf("link badn");
        GLchar log[4096];
        GLsizei len;

        glGetProgramInfoLog(computeProgram,4096,&len,log);

        printf("%sn",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,buffers[CMD]);
    glBufferData(GL_SHADER_STORAGE_BUFFER,sizeof(cmd),cmd,GL_DYNAMIC_DRAW);

    glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_0]);
    glBufferData(GL_SHADER_STORAGE_BUFFER,sizeof(uint32_t) * width * height,data,2,buffers[IMG_1]);
    glBufferData(GL_SHADER_STORAGE_BUFFER,data2,GL_DYNAMIC_DRAW);


    glUseProgram(computeProgram);

    glDispatchCompute(width / 16,height / 16,1);
    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);



    glBindBufferBase(GL_SHADER_STORAGE_BUFFER,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,buffers[CMD]);
    //glBufferData(GL_SHADER_STORAGE_BUFFER,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,GL_DYNAMIC_DRAW);

        glDispatchCompute(width / 16,1);
        glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

        if (i % 2 == 0)
        {
            printf("Input is now img_1. Output is img_0n");
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_1]);
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_0]);
            checkError(__LINE__);
        }
        else
        {
            printf("Input is now img_0. Output is img_1n");
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_0]);
            glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_1]);
            checkError(__LINE__);
        }


        glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[CMD]);
        ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_READ_ONLY);
        printf("cmd issued at start: %d response: %dn",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,GL_DYNAMIC_DRAW);

    glDispatchCompute(width / 16,1);
    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

    glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[CMD]);
    ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_READ_ONLY);
    printf("Regularize: cmd: %d  width: %d  height: %d response: %dn",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_1n");
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER,buffers[IMG_1]);
        ptr = (uint32_t *)glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_READ_ONLY);

    }
    else
    {        
        printf("output image is img_0n");
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER,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,GL_RGB,height,GL_RED,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_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,// Top-left
         1.0f,// Top-right
         1.0f,-1.0f,// Bottom-right
        -1.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,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,&vertexSource,NULL);
    glCompileShader(vertexShader);

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader,&fragmentSource,NULL);
    glCompileShader(fragmentShader);

    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram,vertexShader);
    glAttachShader(shaderProgram,fragmentShader);
    glBindFragDataLocation(shaderProgram,"outColor");
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    // Vertex data specification
    GLint posAttrib = glGetAttribLocation(shaderProgram,"position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib,GL_FLOAT,GL_FALSE,4 * sizeof(GLfloat),0);

    GLint texAttrib = glGetAttribLocation(shaderProgram,"texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib,(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: %dn",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 GLEWn");
        return -1;
    }

    initGL();
    runComputeProgram(data,data2);
    checkError(__LINE__);
    glutMainLoop();
    return 0;


}

compute.shader

#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,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;
    }
}

pgm.cpp

#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.hpp

#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__

解决方法

(答案也张贴在交叉发布的网站上)

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

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()设置输入和输出缓冲区.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读