我的VAO不起作用,如何使用Cuda更改它?

时间:2019-05-13 15:02:30

标签: c++ opengl cuda interop vao

我正在尝试使用Cuda 10.1和OpenGL 4.6互操作在屏幕上绘制一堆点。但是,现在我只是从CPU加载一个三角形进行测试。但是,我是OpenGL的新手,这是我第一次编写顶点数组对象。所以我想我要问的第一个问题是:我的VAO代码有什么问题?为什么我的三角形没有画?我试图尽我所能解决这个问题。 我的第二个问题: 如果我通过Cuda更改了与VAO关联的两个VBO内部的数据,VAO仍会更新并绘制更改吗?

这是我的代码(很抱歉,它没有被注释,我正处于时间紧迫状态):

GPUmain.h:

#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/remove.h>
#include <curand.h>
#include <GL/glew.h>
#include <SDL_opengl.h>
#include <cuda_gl_interop.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct pos {

    GLint x, y, z;

};

struct col {

    GLubyte r, g, b, a;

};

struct phy {

    GLdouble spd;

    GLdouble dir;

};

struct ver {

    pos p;

    col c;

};

class GPU {

public:

    static int nParticles;

    static GLuint vboidP;

    static GLuint vboidC;

    static GLuint vaoid;

    static GLuint vrshaderid;

    static GLuint frshaderid;

    static GLuint lkshaderid;

    static cudaGraphicsResource *CGRp;

    static cudaGraphicsResource *CGRc;

    static const char* shaders[2];

    static thrust::device_vector<ver> verts;

    static void init(int w, int h);

    static void compute();

    static void render();

    static void GPUmain();

    static void free();

};

GPUmain.cu:

#include "GPUmain.cuh"

__global__ void uploadVerts(ver *ve, pos *po, col *co) {
    int id = threadIdx.x + (blockDim.x * blockIdx.x);
    po[id].x = ve[id].p.x;
    po[id].y = ve[id].p.y;
    po[id].z = ve[id].p.z;
    co[id].r = ve[id].c.r;
    co[id].g = ve[id].c.g;
    co[id].b = ve[id].c.b;
    co[id].a = ve[id].c.a;
}

__global__ void genGrid(ver *v) {
    int i = threadIdx.x + (blockDim.x * blockIdx.x);
    int x = i % 1920;
    int y = i / 1920;

    v[i].p.x = x;
    v[i].p.y = y;
    v[i].p.z = 0;

    v[i].c.r = 127;
    v[i].c.g = 255;
    v[i].c.b = 0;
    v[i].c.a = 255;
}

int GPU::nParticles;

GLuint GPU::vboidP;

GLuint GPU::vboidC;

GLuint GPU::vaoid;

GLuint GPU::vrshaderid;

GLuint GPU::frshaderid;

GLuint GPU::lkshaderid;

cudaGraphicsResource *GPU::CGRp;

cudaGraphicsResource *GPU::CGRc;

const char* GPU::shaders[2] = {
    "#version 460\n"
    "layout(location = 0) in vec3 vertex_position;"
    "layout(location = 1) in vec4 vertex_colour;"
    "out vec4 colour;"
    "void main() {"
    "   colour = vertex_colour;"
    "   gl_Position = vec4(vertex_position, 1.0);"
    "}"
    ,
    "#version 460\n"
    "in vec4 colour;"
    "out vec4 frag_colour;"
    "void main() {"
    "   frag_colour = colour;"
    "}"
};

//collection of vertices to be simulated and rendered
thrust::device_vector<ver> GPU::verts;



void GPU::init(int w, int h)
{

    /*nParticles = w * h;
    verts.resize(nParticles, ver{ pos{0,0,0}, col{255,0,0,255} });
    genGrid<<<nParticles/1024,1024>>>(thrust::raw_pointer_cast(&verts[0]));
    cudaDeviceSynchronize();*/

    pos vp[3] = {
        pos{0,0,0},
        pos{200,0,4},
        pos{100,200,3}

    };
    col vc[3] = {
        col{255,0,0,255},
        col{0,255,0,255},
        col{0,0,255,255}
    };

    vrshaderid = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vrshaderid, 1, &shaders[0], NULL);
    glCompileShader(vrshaderid);
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vrshaderid, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vrshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    frshaderid = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frshaderid, 1, &shaders[1], NULL);
    glCompileShader(frshaderid);
    glGetShaderiv(frshaderid, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(frshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    lkshaderid = glCreateProgram();
    glAttachShader(lkshaderid, vrshaderid);
    glAttachShader(lkshaderid, frshaderid);
    glLinkProgram(lkshaderid);
    glGetProgramiv(lkshaderid, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(lkshaderid, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }

    glGenVertexArrays(1, &vaoid);
    glGenBuffers(1,&vboidP);
    glGenBuffers(1, &vboidC);
    glBindVertexArray(vaoid);

    glBindBuffer(GL_ARRAY_BUFFER,vboidP);
    glBufferData(GL_ARRAY_BUFFER,3*sizeof(pos),vp,GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_INT, GL_TRUE, 3 * sizeof(pos), NULL);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vboidC);
    glBufferData(GL_ARRAY_BUFFER,3*sizeof(col),vc, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 3 * sizeof(col), NULL);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    /*cudaGraphicsGLRegisterBuffer(&CGRp,vboidP,cudaGraphicsMapFlagsWriteDiscard);
    cudaGraphicsGLRegisterBuffer(&CGRc,vboidC, cudaGraphicsMapFlagsWriteDiscard);*/

    glBindVertexArray(0);

}

void GPU::compute()
{

}

void GPU::render()
{
    /*pos *posi;
    col *cols;

    size_t sizep;
    size_t sizec;

    cudaGraphicsMapResources(1, &CGRp, 0);
    cudaGraphicsMapResources(1, &CGRc, 0);

    cudaGraphicsResourceGetMappedPointer((void**)&posi, &sizep, CGRp);
    cudaGraphicsResourceGetMappedPointer((void**)&cols, &sizec, CGRc);

    uploadVerts<<<nParticles/1024, 1024>>>(thrust::raw_pointer_cast(&verts[0]), posi, cols);
    cudaDeviceSynchronize();

    cudaGraphicsUnmapResources(1, &CGRp, 0);
    cudaGraphicsUnmapResources(1, &CGRc, 0);*/

    glClearColor(0, 0, 0, 0); // we clear the screen with black (else, frames would overlay...)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the buffer

    glUseProgram(lkshaderid);

    glBindVertexArray(vaoid);

    glDrawArrays(GL_TRIANGLES,0,3);

    glBindVertexArray(0);
}

void GPU::GPUmain()
{

    compute();

    render();

}

void GPU::free()
{
    /*cudaGraphicsUnregisterResource(CGRp);
    cudaGraphicsUnregisterResource(CGRc);*/
    glDeleteVertexArrays(1,&vaoid);
    glDeleteBuffers(1, &vboidP);
    glDeleteBuffers(1, &vboidC);
    verts.clear();
    thrust::device_vector<ver>().swap(verts);
}

window.cpp:

bool Window::init()
{
    //initialize SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {

        log << "Failed to initialize SDL!\n";
        return false;

    }

    //set window atributes
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);

    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);



    //creat window
    window = SDL_CreateWindow(
        name.c_str(),
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        width,
        height,
        SDL_WINDOW_OPENGL

    );

    //create opengl context in the window
    glcontext = SDL_GL_CreateContext(window);

    SDL_GL_SetSwapInterval(1);

    //check if the window was created
    if (window == nullptr) {

        log << "Failed to create window!\n";
        return false;

    }

    //turn on experimental features
    glewExperimental = GL_TRUE;

    //initiallize glew
    if (glewInit() != GLEW_OK) {

        log << "Failed to Init GLEW";

        return false;

    }



    //set drawing parameters
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, 0, height, -255, 0);
    glPointSize(1);
    glEnable(GL_BLEND);                                // Allow Transparency
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  // how transparency acts

    std::cout << sizeof(ver);

    GPU::init(width, height);

    return true;
}

void Window::renderFrame()
{

    GPU::render();

    SDL_GL_SwapWindow(window); //swap buffers
}

1 个答案:

答案 0 :(得分:3)

属性的类型是整数数据类型:

struct pos {
    GLint x, y, z;
};

struct col {
    GLubyte r, g, b, a;
};

因此,当您设置通用顶点属性数据的数组而不是I时,必须使用glVertexAttribIPointer(着重于 glVertexAttribPointer )。
顶点着色器属性的数据类型也必须是整数数据类型:

layout(location = 0) in vec3 vertex_position
layout(location = 1) in vec4 vertex_colour;

layout(location = 0) in ivec3 vertex_position;
layout(location = 1) in ivec4 vertex_colour;

stride / glVertexAttribIPointer的{​​{1}}参数在连续的通用顶点属性之间的字节偏移。因此它必须分别是glVertexAttribPointer sizeof(pos),而不是sizeof(col)3*sizeof(pos)
如果将通用顶点属性紧密压缩,则可以将3*sizeof(col)设置为0。这是一种特殊情况,其中,步幅由stridesize参数自动计算:

type

核心配置文件上下文(glBindBuffer(GL_ARRAY_BUFFER,vboidP); // [...] glVertexAttribIPointer(0, 3, GL_INT, 0, NULL); // [...] glBindBuffer(GL_ARRAY_BUFFER, vboidC); // [...] glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, 0, NULL); // [...] )不支持固定功能矩阵堆栈。

SDL_GL_CONTEXT_PROFILE_CORE

请参见Fixed Function PipelineLegacy OpenGL
OpenGL gluLookat not working with shaders on的答案也可能有帮助。

我建议使用OpenGL Mathematics之类的库通过ortho()和一个uniform变量来计算视图矩阵:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -255, 0);
version 460
layout(location = 0) in ivec3 vertex_position;

layout(location = 7) uniform mat4 prj_matrix;

void main()
{  
    // [...]

    gl_Position = prj_matrix * vec4(vertex_position, 1.0);"
}

统一位置由Layout qualifier#include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> // [...] void GPU::render() { // [...] glUseProgram(lkshaderid); glm::mat4 prj = glm::ortho(0.0f, (float)width, 0.0f, (float)height, -255.0f, 0.0f); glUniformMatrix4fv(7, 1, GL_FALSE, glm::value_ptr(prj)); // [...] } )显式设置。
glUniformMatrix4fv在默认的统一块中的指定位置设置统一的值。这必须在glUseProgram安装了progroam之后完成。


使用Raw string literal的完整着色器代码:

location = 7

如果应用建议的更改,则会看到以下三角形: