I started working on a github project (a logic gate simulator) with gtkmm and epoxy. I have an optimus laptop with debian buster and nvidia-bumblebee drivers installed and everything works fine except that if I start the program using optirun or primusrun, neither the glArea->queue_render
, nor glArea->queue_draw
function seems to work. I have to resize the window in order to rerender the glArea widget. Also sometimes when I restart the system and compile the program it won't start with bumblebee at all and outputs the following error:
311-0-no gl implementation is available
It might be something with my system, but optirun and primusrun usually work fine.
Any Idea what might be the cause of this problem?
the renderer class:
#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 //
implementation:
//#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));
}
Full project on github: LinuxGameGeek/logix
OpenGL is poorly integrated with GTK+3, for example on OS X, you'll have this error displayed because OpenGL is simply not implemented. Maybe this is the same case for you
In addition in gtkmm-3.18 a bug (fixed since this version) displaying this error when GLArea class was derived. But this is not your case.
If that may help you I have a similar application mixing OpenGL/GTKmm in Lecrapouille/SimTaDyn I guess this will give you the same error.