2016-10-15 15 views
4

OpenGLでスケルトン化アルゴリズムを実行するために計算シェーダを構築しようとしています。私はアルゴリズムをCPUのみのバージョンでテストしましたが、それは正しいものでした。しかし、シェーダコードを計算するためにそれを移植する際に問題があります。bindBufferBaseとOpenGL計算シェーダの再利用

問題は、私が実行した計算シェーダの呼び出し回数に関係なく、出力は最初の呼び出しを超えて変化しないということです。実際、whileループの終わりにチェックを外すと、プログラムは決して終了しません。

私は入出力用に2つのメモリ領域を持っています。私はglBindBufferBase()のメインwhileループで2つのスワップ(最後のラウンドの出力は現在のラウンドの入力となります)でトリックをしようとしています。 main.cppの行270〜318を参照してください。これは私がCPUとGPUの間でデータを前後にコピーしないようにするためです。

だから、私の質問は以下のとおりです。

1)私はCPUに戻ってそれを移動せずにデータを複数回に操作できるように、私は周りにそれらを交換glBindBuffers、このトリックを行うことができますか?小さな問題(短い配列を追加するだけ)でテストすると、うまくいきました。

2)トリックがうまくいけば、どこが間違っていますか?

注:このコードでは、「test.pgm」という640 x 400サイズの.pgm(白黒画像)が必要です。 GIMPで作成できますが、ASCII形式ではなくバイナリ形式で保存してください。

このコードは、C++を使用したが、Cスタイルのトリックを行うための私を許して、以下のフラグ

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

またしてコンパイルされます。私は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] = '\0'; //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

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

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__ 
+0

更新:IMG_1の出力を常にデータにコピーし、IMG_0用のglBindBufferBaseとそれに続くデータ付きのglBufferDataを使用してIMG_0にデータをリバウンドするようにコードを修正しました。このバージョンは正常に動作しますが、データがCPU <--> GPUから数回送信されるため、ひどく非効率です。 glBindBufferBaseやその他のトリックを使用して、GPUにデータを保持することは可能ですか? – Maxthecat

+0

詳細については:[クロスコンピューターグラフィックス.SEに投稿](http://computergraphics.stackexchange.com/questions/4147/can-i-reuse-glbindbufferbase-in-compute-shaders-to-keep-data-on- gpu) – trichoplax

答えて

0

(回答もクロス掲示されたサイトに掲載)

私はそれを見つけました!この問題は、スワップの問題が原因です。バッファを交換すると、出力バッファが入力になり、入力バッファが出力になります。しかし、出力されたバッファは一致するように更新されませんでした。前何かに、IMAGE_1にimage_0をコピーするコンピュートシェーダで骨格を()変更することにより

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) 

、アルゴリズムが正しく動作します。

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()を使用してインバッファとアウトバッファを設定できます。

関連する問題