Gtk/gtkmm glarea 队列渲染不适用于专用图形

Posted

技术标签:

【中文标题】Gtk/gtkmm glarea 队列渲染不适用于专用图形【英文标题】:Gtk/gtkmm glarea queue render doesnt work with dedicated graphics 【发布时间】:2020-08-21 06:18:54 【问题描述】:

我开始使用 gtkmm 和环氧树脂处理一个 github 项目(一个逻辑门模拟器)。我有一台安装了 debian buster 和 nvidia-bumblebee 驱动程序的 optimus 笔记本电脑,一切正常,除了如果我使用 optirun 或 primusrun 启动程序,glArea->queue_renderglArea->queue_draw 函数似乎都不起作用。我必须调整窗口大小才能重新呈现 glArea 小部件。有时当我重新启动系统并编译程序时,它根本不会以 bumblebee 启动并输出以下错误:

311-0-没有可用的 gl 实现

这可能与我的系统有关,但 optirun 和 primusrun 通常可以正常工作。

知道这个问题的原因可能是什么吗?

渲染器类:

#ifndef RENDERER_DATA_H
#define RENDERER_DATA_H
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <glm/vec2.hpp>
struct scene               //viewport data
    glm::mat4 proj;
    glm::mat4 view;
    glm::mat4 model;
    glm::mat4 mvp;
    float zoom = 1.0f;
    glm::vec2 dim;
    glm::vec3 pos = 0, 0, 1.0f;
;

struct pointer             //mouse data
    int button;
    int x, y;
;

struct keyboard            //keyboard data

;

#endif

#ifndef RENDERER_H
#define RENDERER_H
/*
 This is the renderer of the viewport
*/
#include "viewport/shader.hpp"
#include "viewport/vertexbuffer.hpp"
#include "viewport/indexbuffer.hpp"
#include "viewport/vertexarray.hpp"
#include "viewport/objects/grid.hpp"
#include <gtkmm-3.0/gtkmm.h>
#include <gtkmm-3.0/gtkmm/glarea.h>
#include <glm/glm.hpp>
//#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
//#include <gdkmm-3.0/gdkmm/glcontext.h>
//#include <glibmm-2.4/glibmm/refptr.h>
//#include <epoxy/gl.h>
//#include <epoxy/glx.h>
#include <iostream>

class Renderer
    public:
        Renderer(Gtk::GLArea*);                             //constructor connects the following callbacks:
        void realize();                                     //called when widget glArea is created
        void unrealize();                                   //called when widget glArea is destroyed
        void resize(int width, int height);                 //called when the glArea is resized
        bool render(const Glib::RefPtr<Gdk::GLContext>&);   //called when the viewport should render itself
        bool mouse_move(GdkEventMotion* event);             //called when both mouse button pressed and mouse moved
        bool mouse_scroll(GdkEventScroll* event);           //called when the mouse is wheel is rotated
        bool button_press(GdkEventButton* button);          //called when a button is pressed
        bool button_release(GdkEventButton* button);        //called when a button is released
    private:
        Gtk::GLArea* glArea;                                //pointer to the glArea widget, created in ui object
        GLuint vao;
        IndexBuffer* ibptr;
        VertexBuffer* vbptr;
        VertexArray* vaptr;
        VertexBufferLayout* vblptr;
        Shader* shader_program;
        Grid* grid;

        pointer mouse;                                      //mouse variable obj
        scene viewport;                                     //viewport variable obj

        void update_view();                                 //This function is resposible for paning and zooming the viewport
        glm::vec3 mouse_translate(glm::vec3);               //translates screen coords to world coords

;

#endif //

实现:

    //#include <ui.hpp>
#include "./renderer.hpp"

Renderer::Renderer(Gtk::GLArea* glarea)
/*:glArea(glarea)*/
    glArea = glarea;

    glArea->add_events(Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON2_MOTION_MASK | Gdk::BUTTON3_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK);

    glArea->signal_realize().connect(sigc::mem_fun(*this, &Renderer::realize));
    glArea->signal_unrealize().connect(sigc::mem_fun(*this, &Renderer::unrealize), false);
    glArea->signal_render().connect(sigc::mem_fun(*this, &Renderer::render), false);
    glArea->signal_resize().connect(sigc::mem_fun(*this, &Renderer::resize));
    glArea->signal_motion_notify_event().connect(sigc::mem_fun(*this, &Renderer::mouse_move));
    glArea->signal_scroll_event().connect(sigc::mem_fun(*this, &Renderer::mouse_scroll));
    glArea->signal_button_press_event().connect(sigc::mem_fun(*this, &Renderer::button_press));
    glArea->signal_button_release_event().connect(sigc::mem_fun(*this, &Renderer::button_release));


void Renderer::realize()
    std::clog<<"realize"<<std::endl;
    //glArea->set_required_version(4, 5);
    glArea->make_current();
    glArea->set_auto_render(true);
    std::clog<<"make current"<<std::endl;
    //std::clog<<epoxy_gl_version()<<"\n";
    //std::clog<<epoxy_glsl_version()<<"\n";


    glArea->make_current();
    std::cout<<glGetString(GL_VERSION)<<std::endl;
    std::cout<<"realize\n";
    try
        glArea->throw_if_error();
        std::clog<<glGetString(GL_VERSION)<<"\n";
        std::clog<<glGetString(GL_VENDOR)<<"\n";
        char path[] = "./src/res/shaders";
        shader_program = new Shader(path);
        shader_program->bind();
        //shader_program = Shader::create_shader_program(nullptr);
        //glUseProgram(shader_program);

        GLfloat pos[] = 
            -0.5f, -0.5f, -1,
            0.5f, -0.5f, -1,
            0.5f, 0.5f, -1,
            -0.5f, 0.5f, -1
        ;
        GLuint ind[] = 
            0, 1, 2,
            2, 3, 0
        ;


        vaptr = new VertexArray();

        //glGenVertexArrays(1, &vao);
        //glBindVertexArray(vao);

        vbptr = new VertexBuffer(pos, 4 * 3 * sizeof(GLfloat));

        vblptr = new VertexBufferLayout;
        vblptr->add(3, GL_FLOAT);
        //vblptr->add(3, GL_FLOAT);
        //vblptr->add(2, GL_FLOAT);
        vaptr->addBuffer(*vbptr, *vblptr);
        //glEnableVertexAttribArray(0);
        //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);

        ibptr = new IndexBuffer(ind, 6);
        //int location = epoxy_glGetUniformLocation(shader_program->get_program(), "u_Color");
        //glUniform4f(location, 0.2f, 0.3f, 0.8f, 1.0f);
        //glm::vec4 data = 0.2f, 0.3f, 0.8f, 1.0f;
        shader_program->set_uniform4f ("u_Color", 0.2f, 0.3f, 0.8f, 1.0f);
        //viewport.proj = glm::ortho(-width/height/2, width/height/2, -height/width/2, height/width/2);
        //shader_program->set_uniform_mat4f ("mvp", viewport.proj);
        //glBindVertexArray(0);
        //glUseProgram(0);
        //glBindBuffer(GL_ARRAY_BUFFER, 0);
        //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    catch(const Gdk::GLError& gle)
        std::cerr << "An error occured making the context current during realize:" << std::endl;
        std::cerr << gle.domain() << "-" << gle.code() << "-" << gle.what() << std::endl;
    
    grid = new Grid(glm::vec3(-3.0, 0.0, -1.0), glm::vec3(3.0, 0.0, -1.0));


void Renderer::unrealize()
    glArea->make_current();
    delete vbptr;
    delete ibptr;
    delete vaptr;
    delete vblptr;
    delete shader_program;
    try
    
        glArea->throw_if_error();
    
    catch(const Gdk::GLError& gle)
    
        std::cerr << "An error occured making the context current during unrealize" << std::endl;
        std::cerr << gle.domain() << "-" << gle.code() << "-" << gle.what() << std::endl;
    


void Renderer::resize(int width, int height)
    viewport.dim.x = width;
    viewport.dim.y = height;


bool Renderer::render(const Glib::RefPtr<Gdk::GLContext>&  context )
    std::clog<<"render\n";
    update_view();
    //glArea->attach_buffers();
    glClear(GL_COLOR_BUFFER_BIT);
    grid->draw();
    grid->m_shader->set_uniform_mat4f("mvp", viewport.mvp);
    grid->draw();

    shader_program->bind();

    vaptr->bind();
    //ibptr->bind();
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

    glBindVertexArray(0);
    glUseProgram(0);
    return true;


bool Renderer::mouse_move(GdkEventMotion* event)
    glm::vec3 diff = mouse_translate(glm::vec3(mouse.x, mouse.y, 0.0)) - mouse_translate(glm::vec3(event->x, event->y, 0.0));
    std::clog<<diff.x<<" "<<diff.y<<"\n";
    if(mouse.button == 1)
        viewport.pos = viewport.pos - diff;
        std::clog<<viewport.pos .x<<" "<<viewport.pos.y<<" "<<viewport.pos.z<<"\n";
        //glArea->queue_draw();
        //glArea->queue_draw();
        glArea->queue_render();
        //glArea->signal_render();
    
    mouse.x = event->x;
    mouse.y = event->y;
    return true;


bool Renderer::mouse_scroll(GdkEventScroll* event)
    if(event->direction == GDK_SCROLL_DOWN && viewport.zoom>1)
        viewport.zoom = viewport.zoom - 0.1;
    else if(event->direction == GDK_SCROLL_UP && viewport.zoom<10)
        viewport.zoom = viewport.zoom + 0.1;
    
    glArea->queue_render();
    std::clog<<viewport.zoom<<"\n";
    return true;



bool Renderer::button_press(GdkEventButton* event)
    std::clog<<event->button<<"\n";
    mouse.button = event->button;
    mouse.x = event->x;
    mouse.y = event->y;
    //if(event->mouse.button == 1) //left mouse button
    //
    //
    return true;


bool Renderer::button_release(GdkEventButton* button)
    mouse.button = 0;
    return true;


void Renderer::update_view()
    std::clog<<"update view\n";
    viewport.view = glm::translate(glm::mat4(1.0f), glm::vec3(viewport.pos.x, -viewport.pos.y, -viewport.pos.z));
    viewport.model = glm::translate(glm::mat4(1.0f), glm::vec3( 0, 0, 1.0));
    if(viewport.dim.x<viewport.dim.y)
        viewport.proj =  glm::ortho(-viewport.dim.x/viewport.dim.y/viewport.zoom, viewport.dim.x/viewport.dim.y/viewport.zoom, -1.0f/viewport.zoom, 1.0f/viewport.zoom);
    else
        viewport.proj =  glm::ortho(-1.0f/viewport.zoom, 1.0f/viewport.zoom, -viewport.dim.y/viewport.dim.x/viewport.zoom, viewport.dim.y/viewport.dim.x/viewport.zoom);
    
    viewport.mvp = viewport.proj * viewport.view * viewport.model;

    shader_program->bind();
    shader_program->set_uniform_mat4f ("mvp", viewport.mvp);


glm::vec3 Renderer::mouse_translate(glm::vec3 pos)
    return glm::unProject(pos, viewport.model, viewport.proj, glm::vec4(0.0f, 0.0f, viewport.dim.x, viewport.dim.y));

github 上的完整项目:LinuxGameGeek/logix

【问题讨论】:

【参考方案1】:

OpenGL 与 GTK+3 的集成很差,例如在 OS X 上,您会看到此错误,因为 OpenGL 根本没有实现。也许这对你来说是同样的情况

此外,在 gtkmm-3.18 中,当 GLArea 类派生时,一个错误(自此版本以来已修复)显示此错误。但这不是你的情况。

如果这可能对您有所帮助,我在 Lecrapouille/SimTaDyn 中有一个混合 OpenGL/GTKmm 的类似应用程序,我想这会给您同样的错误。

【讨论】:

感谢您的回答,是的,我看到 gtkmm 和 opengl 不能很好地协同工作。我在使用专用图形时也遇到了鼠标事件的问题,我认为这些事件函数有一些执行时间限制 bcs 如果我写一个更长的程序开始以意想不到的方式工作。可能会迁移到 IamGUI 或 QT。

以上是关于Gtk/gtkmm glarea 队列渲染不适用于专用图形的主要内容,如果未能解决你的问题,请参考以下文章

为 gtk、gtkmm 和 opencv 更正 CMakeLists.txt 文件

Gtk+/Gtkmm介绍与安装(有继承关系图)

Ajax 更新/渲染不适用于具有渲染属性的组件

队列不适用于线程?

Vue 指令不适用于渲染

在 Windows 下打包具有依赖关系的应用程序