2016-07-29 5 views
2

먼저 아래에 제공하는 코드 양에 대해 사과드립니다. 확실하지 않지만 게시 규칙을 위반할 수 있습니다.Cuda + OpenGL 상호 운용성, glDrawArrays() 액세스 위반

무작위 픽셀을 수정하는 대신 PNG와 같은 사용자 지정 이미지를로드 한 다음 유체 솔버를 적용 할 수 있도록 nvidia의 cuda 샘플 fluidsGL (예 : https://www.youtube.com/watch?v=jU9wgSu4_zw)을 수정하려고합니다. 유체와 같은 방식으로 효과적으로 왜곡됩니다.

다양한 구현을 시도한 후에 유체 솔버 커널에 전송 될 float2 입자에 대해 하나와 색상으로 채워지는 두 개의 vbos를 사용하여 가능할 것이라고 생각했습니다. 이미지의 RGBA 정보와 비교합니다.

glDrawArrays 내에서 액세스 위반이 발생합니다. 이전 시도에서 float2 및 uchar4를 보유한 vertex_data라는 구조체를 사용하여 단일 vbo를 사용하려고 시도한 이유를 알아 냈습니다. glbufferdata 그리고 그것의 float2 부분을 통해 커널이 계산하게하지만, 액세스 위반 예외도 발생했습니다. 누군가가 나를 도울 용의가있는 경우

, 나는 감사

typedef unsigned char ubyte; 

#define DEVICE __device__ 
#define GLOBAL __global__ 

#define MAX(a,b) ((a > b) ? a : b) 
#define DIM 512 
#define DS DIM*DIM 

glm::mat4 m_mat; 

// CUFFT plan handle 
cufftHandle planr2c; 
cufftHandle planc2r; 
static float2 *vxfield = NULL; 
static float2 *vyfield = NULL; 

float2 *hvfield = NULL; 
float2 *dvfield = NULL; 
static int wWidth = MAX(512, DIM); 
static int wHeight = MAX(512, DIM); 

/*-----CUSTOM STRUCT-----------------------------------------------------*/ 

struct GLTexture 
{ 
    GLuint id; 
    int width; 
    int height; 
}; 


vertex_data data[DS]; 

//c linkage 
/*--------------------------------------------------------------------------------------------------------------------------------*/ 
extern "C" void addForces(float2 *v, int dx, int dy, int spx, int spy, float fx, float fy, int r); 
extern "C" void advectVelocity(float2 *v, float *vx, float *vy, int dx, int pdx, int dy, float dt); 
extern "C" void diffuseProject(float2 *vx, float2 *vy, int dx, int dy, float dt, float visc); 
extern "C" void updateVelocity(float2 *v, float *vx, float *vy, int dx, int pdx, int dy); 
extern "C" void advectParticles(GLuint vbo, float2 *v, int dx, int dy, float dt); 
/*--------------------------------------------------------------------------------------------------------------------------------*/ 

GLSLProgram prog; 
IOManager m_manager; 
GLTexture m_tex; 
std::vector<ubyte> in_img; 
std::vector<ubyte> out_img; 
vertex_data vData[6]; 


GLuint positionsVBO; 
GLuint colorsVBO; 
cudaGraphicsResource* positionsVBO_CUDA; 
float2 *particles = NULL; 

float2 *part_cuda = NULL; 

int lastx = 0, lasty = 0; 
int clicked = 0; 
size_t tPitch = 0; 

float myrand(void) 
{ 
    return rand()/(float)RAND_MAX; 
} 

void initParticles(float2 *p, int dx, int dy) 
{ 
    int i, j; 

    for (i = 0; i < dy; i++) 
    { 
     for (j = 0; j < dx; j++) 
     { 
      p[i*dx + j].x = (j + 0.5f + (myrand() - 0.5f))/dx; 
      p[i*dx + j].y = (i + 0.5f + (myrand() - 0.5f))/dy; 
     } 
    } 

} 




void keyboard(unsigned char key, int x, int y) 
{ 
    switch (key) 
    { 
    case 27: 

     glutDestroyWindow(glutGetWindow()); 
     exit(0); 
     return; 


    default: 
     break; 
    } 
} 

void click(int button, int updown, int x, int y) 
{ 
    lastx = x; 
    lasty = y; 
    clicked = !clicked; 
} 

void motion(int x, int y) 
{ 
    // Convert motion coordinates to domain 
    float fx = (lastx/(float)wWidth); 
    float fy = (lasty/(float)wHeight); 
    int nx = (int)(fx * DIM); 
    int ny = (int)(fy * DIM); 

    if (clicked && nx < DIM - FR && nx > FR - 1 && ny < DIM - FR && ny > FR - 1) 
    { 
     int ddx = x - lastx; 
     int ddy = y - lasty; 
     fx = ddx/(float)wWidth; 
     fy = ddy/(float)wHeight; 
     int spy = ny - FR; 
     int spx = nx - FR; 
     addForces(dvfield, DIM, DIM, spx, spy, FORCE * DT * fx, FORCE * DT * fy, FR); 
     lastx = x; 
     lasty = y; 
    } 

    glutPostRedisplay(); 
} 

void cleanup(void) 
{ 
    cudaGraphicsUnregisterResource(positionsVBO_CUDA); 

    unbindTexture(); 
    deleteTexture(); 

    // Free all host and device resources 
    free(hvfield); 
    free(particles); 
    cudaFree(dvfield); 
    cudaFree(vxfield); 
    cudaFree(vyfield); 
    cufftDestroy(planr2c); 
    cufftDestroy(planc2r); 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 
    glDeleteBuffersARB(1, &positionsVBO); 
} 

void run_simulation(void){ 

    //Execute kernel 

    advectVelocity(dvfield, (float *)vxfield, (float *)vyfield, DIM, RPADW, DIM, DT); 
    diffuseProject(vxfield, vyfield, CPADW, DIM, DT, VIS); 
    updateVelocity(dvfield, (float *)vxfield, (float *)vyfield, DIM, RPADW, DIM); 
    advectParticles(positionsVBO, dvfield, DIM, DIM, DT); 



} 


void initShaders(){ 
    prog.compileShaders("vShader.vertex", "fShader.frag"); 
    prog.addAttribute("vertexPos"); 
    prog.addAttribute("vertexColor"); 

    prog.linkShaders(); 
} 



void pre_display() 
{ 

    glViewport(0, 0, 512, 512); 
    glutPostRedisplay(); 

} 

void display() 
{ 
    pre_display(); 

    // render points from vertex buffer 
    glClear(GL_COLOR_BUFFER_BIT); 

    initShaders(); 

    run_simulation(); 

    prog.use(); 

    //GLint textureUniform = prog.getUniformLocation("mySampler"); 
    //glUniform1i(textureUniform, 0); 
    //glActiveTexture(GL_TEXTURE0); 

    GLint pUniform = prog.getUniformLocation("P"); 
    glUniformMatrix4fv(pUniform, 1, GL_FALSE, &m_mat[0][0]); 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, positionsVBO); 

    glPointSize(1); 

    glEnable(GL_POINT_SMOOTH); 
    glEnable(GL_BLEND); 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

    //glEnableVertexAttribArray(0); tried to manually enable the arrays 
    //glEnableVertexAttribArray(1); 


    glDisable(GL_DEPTH_TEST); 
    glDisable(GL_CULL_FACE); 

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, sizeof(float2), 0); 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); //dont need this but access violaton persists without it anyway 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorsVBO); 

    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(vertex_data) ,(void*)(offsetof(vertex_data, col))); 


    glDrawArrays(GL_POINTS, 0, DS); 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 

    prog.unuse(); 


    glDisable(GL_TEXTURE_2D); //from nvidia's probably linked to the cudaarray_t 


    // Swap buffers 
    glutSwapBuffers(); 

} 

void initGL() 
{ 
    int foo = 1; 
    char *bar = "bar"; 
    glutInit(&foo, &bar); 
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); 
    glutInitWindowSize(DIM, DIM); 
    glutCreateWindow("mate21"); 

    glClearColor(0.0, 0.0, 0.0, 1.0); 


    glutKeyboardFunc(keyboard); 
    glutMouseFunc(click); 
    glutMotionFunc(motion); 



    glutDisplayFunc(display); 

    glewInit(); 
} 

void setGLDevice(){ 
    cudaDeviceProp prop; 
    int dev; 

    memset(&prop, 0, sizeof(cudaDeviceProp)); 
    prop.major = 1; 
    prop.minor = 0; 
    cudaChooseDevice(&dev, &prop); 
    cudaGLSetGLDevice(dev); 
} 



void createVBO(){ 

    //reading rgba information from image to out_img 
    unsigned long width, height; 
    IOManager::readFileToBuffer("jojo_test.png", in_img); 
    decodePNG(out_img, width, height, &(in_img[0]), in_img.size()); 


    //data.resize(DS); data used to be a vector, gave up on that 
    for (int i = 0; i < DS; ++i){ 

     //data[i].pos = particles[i]; edited vertex_data struct for rgba only 
     data[i].col.x = out_img[i * 4 + 0]; 
     data[i].col.y = out_img[i * 4 + 1]; 
     data[i].col.z = out_img[i * 4 + 2]; 
     data[i].col.w = out_img[i * 4 + 3]; 

    } 


    glGenBuffers(1, &positionsVBO); 
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, positionsVBO); 

    glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float2)*DS, particles , GL_DYNAMIC_DRAW_ARB); 
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 

    cudaGraphicsGLRegisterBuffer(&positionsVBO_CUDA, positionsVBO, cudaGraphicsMapFlagsNone); 

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 

    glGenBuffers(1, &colorsVBO); 
    glBindBuffer(GL_ARRAY_BUFFER_ARB, colorsVBO); 
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertex_data)*DS, data, GL_DYNAMIC_DRAW_ARB); 
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 



} 

int main() 
{ 
    setGLDevice(); 

    initGL(); 

    //orthogonal view matrix with glm 
    m_mat = glm::ortho(0, 1, 1, 0, 0, 1); 





    hvfield = (float2 *)malloc(sizeof(float2) * DS); 
    memset(hvfield, 0, sizeof(float2) * DS); 

    // Allocate and initialize device data 
    cudaMallocPitch((void **)&dvfield, &tPitch, sizeof(float2)*DIM, DIM); 

    cudaMemcpy(dvfield, hvfield, sizeof(float2) * DS, 
     cudaMemcpyHostToDevice); 
    // Temporary complex velocity field data 
    cudaMalloc((void **)&vxfield, sizeof(float2) * PDS); 
    cudaMalloc((void **)&vyfield, sizeof(float2) * PDS); 

    setupTexture(DIM, DIM); 
    bindTexture(); 

    // Create particle array 
    particles = (float2 *)malloc(sizeof(float2) * DS); 
    memset(particles, 0, sizeof(float2) * DS); 

    initParticles(particles, DIM, DIM); 

    // Create CUFFT transform plan configuration 
    cufftPlan2d(&planr2c, DIM, DIM, CUFFT_R2C); 
    cufftPlan2d(&planc2r, DIM, DIM, CUFFT_C2R); 

    cufftSetCompatibilityMode(planr2c, CUFFT_COMPATIBILITY_FFTW_PADDING); 
    cufftSetCompatibilityMode(planc2r, CUFFT_COMPATIBILITY_FFTW_PADDING); 


    createVBO(); 

    //cleanup 
    glutCloseFunc(cleanup); 
    //Launch rendering loop 
    glutMainLoop(); 
} 

것 그리고 이것은 효과적으로 유체

extern "C" 
void advectParticles(GLuint vbo, float2 *v, int dx, int dy, float dt) 
{ 
    dim3 grid((dx/TILEX)+(!(dx%TILEX)?0:1), (dy/TILEY)+(!(dy%TILEY)?0:1)); 
    dim3 tids(TIDSX, TIDSY); 

    float2 *p; 
    cudaGraphicsMapResources(1, &positionsVBO_CUDA, 0); 


    size_t num_bytes; 
    cudaGraphicsResourceGetMappedPointer((void **)&p, &num_bytes,positionsVBO_CUDA); 


    advectParticles_k<<<grid, tids>>>(p, v, dx, dy, dt, TILEY/TIDSY, tPitch); 


    cudaGraphicsUnmapResources(1, &positionsVBO_CUDA, 0); 

} 

및 시뮬레이션 float2 입자에서 운영하는 관련 커널 advectParticles_k :

__global__ void 
advectParticles_k(float2 *part, float2 *v, int dx, int dy, 
        float dt, int lb, size_t pitch) 
{ 

    int gtidx = blockIdx.x * blockDim.x + threadIdx.x; 
    int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb; 
    int p; 

    // gtidx is the domain location in x for this thread 
    float2 pterm, vterm; 

    if (gtidx < dx) 
    { 
     for (p = 0; p < lb; p++) 
     { 
      // fi is the domain location in y for this thread 
      int fi = gtidy + p; 

      if (fi < dy) 
      { 
       int fj = fi * dx + gtidx; 
       pterm = part[fj]; 

       int xvi = ((int)(pterm.x * dx)); 
       int yvi = ((int)(pterm.y * dy)); 
       vterm = *((float2 *)((char *)v + yvi * pitch) + xvi); 

       pterm.x += dt * vterm.x; 
       pterm.x = pterm.x - (int)pterm.x; 
       pterm.x += 1.f; 
       pterm.x = pterm.x - (int)pterm.x; 
       pterm.y += dt * vterm.y; 
       pterm.y = pterm.y - (int)pterm.y; 
       pterm.y += 1.f; 
       pterm.y = pterm.y - (int)pterm.y; 

       part[fj] = pterm; 
      } 
     } // If this thread is inside the domain in Y 
    } // If this thread is inside the domain in X 
} 

당신에게

012 감사

답변

0

입자에 버퍼에 충분한 메모리를 할당하지 않았다고 생각합니다. 당신은 그런

이 함수를 호출하는 메모리의 4 * 10 = 40 바이트를 할당 한

glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float2)*DS, particles , GL_DYNAMIC_DRAW_ARB); 

:

sizeof(float2) = 4 
DS = 10 

이를 호출 할 때 :

는 가정 수 있습니다 :

glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, sizeof(float2), 0); 

하나의 입자에 대해 2 * 4 = 바이트의 메모리가 필요하다고 말합니다. 그런 다음

당신이 렌더링되어이와

glDrawArrays(GL_POINTS, 0, DS); 

전화하는 메모리의 10 * 8 = 80 바이트를 소모 (10 개) 입자를 렌더링하려고

그리고 이와

은 점점 전화 바이트의 메모리 만 할당했기 때문에 액세스 위반이 발생했습니다.

+0

흠, 처음에는 float2 cuda 네이티브 형식이 두 개의 float 값 x 및 y를 보유하는 struct입니다. OpenGL과의 호환성을 위해 glVertexAttribPointer 호출을 사용하여 잘 작동해야합니다. 사용자의 의견을 고려하여 추가로 확인해보십시오. 나는 긍정적 인 결과를 얻을 수 있다면 다시 게시 할 것입니다. 감사합니다 Amadeusz. – Kareshi

+1

왜 'sizeof (float2) = 4'라고 가정할까요? 그것은 8이며, 사소한 테스트가 그것을 증명할 것입니다. –