CUDA與OpenGL互操作之頂點緩存映射

引言

CUDA相比GLSL更加靈活疲憋,逐漸成為主流的GPGPU編程技術(shù)。CUDA加速計算后的結(jié)果往往需要在顯示器中繪制出來埃脏,如果我們將在顯存中的計算結(jié)果拷貝到主存秋忙,然后使用QPainter繪制到窗口中,這中間的顯存-主存堵幽,主存-顯存的數(shù)據(jù)拷貝會顯得冗余弹澎。既然CUDA計算的結(jié)果和圖形繪制的內(nèi)容都在顯存里,那么可以通過一些技術(shù)手段直接將CUDA計算結(jié)果繪制到顯示器上殴胧,即CUDA與Graphics的互操作佩迟。

相關(guān)接口介紹

注冊顯卡資源

__host__ cudaError_t cudaGraphicsGLRegisterBuffer(struct cudaGraphicsResource **resource, GLuint buffer, unsigned int flags);

注冊一個OpenGL緩沖對象,參數(shù)說明:

  • resource - 指向返回的對象句柄
    *buffer - 被注冊的緩沖對象名
  • flags - 注冊標識
    • cudaGraphicsRegisterFlagsNone: 注冊的資源在CUDA程序可以進行讀寫惫撰,默認為該枚舉
    • cudaGraphicsRegisterFlagsReadOnly: 指定CUDA程序只能讀該資源
    • cudaGraphicsRegisterFlagsWriteDiscard: 指定CUDA程序不會讀該資源對象躺涝,每次寫資源時資源的內(nèi)容完全被覆蓋,不會保留之前的任何數(shù)據(jù)

取消注冊函數(shù)

cudaError_t cudaGraphicsUnregisterResource(cudaGraphicsResource_t resource);

映射顯卡資源

cudaError_t cudaGraphicsMapResources(int count, cudaGraphicsResource_t *resources, cudaStream_t stream __dv(0));

映射已經(jīng)注冊的資源到CUDA流中夯膀,參數(shù)說明:

  • count:映射的資源數(shù)
  • resources:映射的資源
  • stream:映射的CUDA同步流
    該函數(shù)具備默認同步動作苍蔬。

取消映射函數(shù)

cudaError_t cudaGraphicsUnmapResources(int count, cudaGraphicsResource_t *resources, cudaStream_t stream __dv(0));

獲取設(shè)備指針

cudaError_t cudaGraphicsResourceGetMappedPointer(void **devPtr, size_t *size, cudaGraphicsResource_t resource);

獲取已映射資源的設(shè)備指針碟绑,參數(shù)說明:

  • devPtr:設(shè)備指針茎匠,CUDA程序可以使用該指針進行數(shù)據(jù)更新
  • size:緩沖數(shù)據(jù)尺寸
  • resources:已映射的資源

使用示例

參照CUDA simpleGL示例押袍,該示例是使用CUDA對頂點數(shù)據(jù)進行操作后,再將頂點繪制到窗口上汽馋。使用Qt進行改寫:

class CuGl : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    CuGl(QWidget* parent = nullptr);
    ~CuGl();

protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();

private:
    void runCuda();
    void cleanup();

private:
    float m_fAnim;
    Shader *m_shader;
    QOpenGLBuffer m_vbo;
    QOpenGLVertexArrayObject m_vao;
    cudaGraphicsResource_t m_vboResource;   
};
static const int DIM = 512;
static __global__ void kernel(float3* pos, unsigned int width, unsigned int height, float time)
{
    unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
    unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;

    // calculate uv coordinates
    float u = x / (float)width;
    float v = y / (float)height;
    u = u * 2.0f - 1.0f;
    v = v * 2.0f - 1.0f;

    // calculate simple sine wave pattern
    float freq = 4.0f;
    float w = sinf(u*freq + time) * cosf(v*freq + time) * 0.5f;

    // write output vertex
    pos[y*width + x] = make_float3(u, w, v);
}

CuGl::CuGl(QWidget* parent) : QOpenGLWidget(parent), m_fAnim(0.0f)
{
    resize(DIM, DIM);
}

CuGl::~CuGl()
{
    
}

void CuGl::initializeGL()
{   
    initializeOpenGLFunctions();

    m_shader = new Shader("shaders/cuda.vert", "shaders/cuda.frag", this);
    
    // 創(chuàng)建VAO/VBO
    if (m_vao.create())
    {
        m_vao.bind();
        m_vbo.create();
        m_vbo.bind();

        unsigned int nbytes = DIM * DIM * 3 * sizeof(GLfloat);
        m_vbo.allocate(nbytes);

        m_shader->setAttributeBuffer("aPos", GL_FLOAT, 0, 3, 3 * sizeof(float));
        m_shader->enableAttributeArray("aPos");
    }

    // 注冊cuda資源
    checkCudaErrors(cudaGraphicsGLRegisterBuffer(&m_vboResource, m_vbo.bufferId(), cudaGraphicsMapFlagsWriteDiscard));
        
    // 設(shè)置清屏顏色
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &CuGl::cleanup);
}


void CuGl::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);

    QMatrix4x4 model, view, projection;
    view.lookAt(QVector3D(0, 0, 3), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
    projection.perspective(45.0f, (float)w / h, 0.1f, 100.0f);

    m_shader->bind();
    m_shader->setUniformValue("model", model);
    m_shader->setUniformValue("view", view);
    m_shader->setUniformValue("projection", projection);
}


void CuGl::paintGL()
{
    // 使用CUDA進行計算
    runCuda();

    // 使用OPenGL進行繪制
    glClear(GL_COLOR_BUFFER_BIT);
    m_shader->bind();
    m_vao.bind();
    glDrawArrays(GL_POINTS, 0, DIM*DIM);

    update();
}


void CuGl::runCuda()
{
    float3* glPtr;
    size_t size;
    // 映射已注冊的資源
    checkCudaErrors(cudaGraphicsMapResources(1, &m_vboResource, 0));

    // 獲取映射后的資源的設(shè)備指針
    checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void**)&glPtr, &size, m_vboResource));

    // 利用設(shè)備指針對數(shù)據(jù)做計算
    dim3 blocks(16, 16);
    dim3 grids((DIM - 1) / 16 + 1, (DIM - 1) / 16 + 1);
    kernel << <grids, blocks >> > (glPtr, DIM, DIM, m_fAnim);
    m_fAnim += 0.01f;

    // 取消資源映射
    checkCudaErrors(cudaGraphicsUnmapResources(1, &m_vboResource, 0));
}

void CuGl::cleanup()
{
    // 取消資源注冊
    checkCudaErrors(cudaGraphicsUnregisterResource(m_vboResource));

    // 銷毀VAO/VBO
    m_vao.destroy();
    m_vbo.destroy();
}

頂點著色器和片段著色器程序:

#version 330 core
layout(location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main() 
{
    gl_Position = projection * view * model * vec4(aPos,1.0f);
}
#version 330 core
out vec4 fragColor;
void main() 
{ 
    fragColor = vec4(0.4, 0.7, 0.6, 1.0);
}

運行效果:


Cuda&OpenGL.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驱敲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子握牧,更是在濱河造成了極大的恐慌围辙,老刑警劉巖放案,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吱殉,死亡現(xiàn)場離奇詭異,居然都是意外死亡友雳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門饺藤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來流礁,“玉大人,你說我怎么就攤上這事再姑≌矣” “怎么了绍填?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵讨永,是天一觀的道長蔽挠。 經(jīng)常有香客問我,道長澳淑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任量窘,我火速辦了婚禮氢拥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冬殃。我一直安慰自己叁怪,他們只是感情好,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布涣觉。 她就那樣靜靜地躺著血柳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪难捌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天昆汹,我揣著相機與錄音婴栽,去河邊找鬼。 笑死映皆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的捅彻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼从隆,長吁一口氣:“原來是場噩夢啊……” “哼缭裆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辛燥,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤缝其,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后榴都,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漠其,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年阳惹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片快鱼。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抹竹,死狀恐怖线罕,靈堂內(nèi)的尸體忽然破棺而出窃判,到底是詐尸還是另有隱情,我是刑警寧澤询件,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站刻蟹,受9級特大地震影響嘿辟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜红伦,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一色建、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧箕戳,春花似錦、人聲如沸玻墅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剩拢。三九已至饶唤,卻和暖如春徐伐,著一層夾襖步出監(jiān)牢的瞬間募狂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工性穿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雷滚,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓呆万,卻偏偏與公主長得像,于是被迫代替她去往敵國和親桑嘶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354