summaryrefslogtreecommitdiff
path: root/c++/window-opengl/gl_xcb.cpp
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2023-08-09 20:25:16 +0200
committerClaudius "keldu" Holeksa <mail@keldu.de>2023-08-09 20:25:16 +0200
commitb49d590153658e77d284e0b87d3cabe65fd37730 (patch)
treea9a4269921d6011d6dacf4b2a843ca7545e5bb0d /c++/window-opengl/gl_xcb.cpp
parentb04f831e7bc9513183127d1c3918789fb0696fff (diff)
c++,window-opengl: Initial module commit
Diffstat (limited to 'c++/window-opengl/gl_xcb.cpp')
-rw-r--r--c++/window-opengl/gl_xcb.cpp265
1 files changed, 265 insertions, 0 deletions
diff --git a/c++/window-opengl/gl_xcb.cpp b/c++/window-opengl/gl_xcb.cpp
new file mode 100644
index 0000000..f93e9a9
--- /dev/null
+++ b/c++/window-opengl/gl_xcb.cpp
@@ -0,0 +1,265 @@
+#include "gl_xcb.h"
+
+#include <cassert>
+#include <cstdint>
+#include <set>
+
+namespace saw {
+namespace gfx {
+namespace {
+glx_library_extensions load_glx_library_extensions(const char* extension_string){
+ std::string_view extensions_view{extension_string};
+
+ std::set<std::string_view> extensions;
+
+ for(;;){
+ size_t n = extensions_view.find_first_of(' ');
+ if( n != extensions_view.npos && n < extensions_view.size()){
+ std::string_view sub_glx_ext = extensions_view.substr(0,n);
+ extensions.insert(sub_glx_ext);
+ extensions_view.remove_prefix(n+1);
+ } else {
+ break;
+ }
+ }
+
+ auto find = extensions.find("GLX_ARB_create_context");
+ GLXContext (*glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*) = nullptr;
+ if(find != extensions.end()){
+ glXCreateContextAttribsARB = reinterpret_cast<GLXContext(*)(
+ Display*, GLXConfig, GLXContext, Bool, const int*)>(
+ glxGetProcAddress(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")));
+ }
+
+ return {extensions_view, glXCreateContextAttribsARB};
+}
+
+int translate_render_type_settings(gl_settings::render_type cmp){
+ switch(cmp){
+ case gl_settings::render_type::rgba:
+ return GLX_RGBA_BIT;
+ }
+ return 0;
+}
+
+int translate_drawable_type_setting(gl_settings::drawable_type cmp){
+ int i = 0;
+ if (static_cast<int32_t>(cmp) &
+ static_cast<int32_t>(GlSettings::DrawableType::windowBit)) {
+ i |= static_cast<int32_t>(GLX_WINDOW_BIT);
+ }
+ if (static_cast<int32_t>(cmp) &
+ static_cast<int32_t>(GlSettings::DrawableType::PixMapBit)) {
+ i |= static_cast<int32_t>(GLX_PIXMAP_BIT);
+ }
+ if (static_cast<int32_t>(cmp) &
+ static_cast<int32_t>(GlSettings::DrawableType::PBufferBit)) {
+ i |= static_cast<int32_t>(GLX_PBUFFER_BIT);
+ }
+ return i;
+}
+}
+
+gl_context<gl::backend::linux_xcb>::gl_context(const glx_library_extensions& ext_lib,
+ own<device<backend::linux_xcb>> dev, int visual_id, GLXContext context, GLXFBConfig fb_config): ext_lib_{ext_lib}, device_{std::move(device)}, visual_id_{visual_id}, context_{context}, fb_config_{fb_config}{}
+
+gl_context<gl::backend::linux_xcb>::~gl_context(){
+ assert(device_);
+ assert(device_->display_);
+
+ if(context_){
+ /// @todo Check if this context is bound and only unbind if that is the case
+ // ::glXMakeContextCurrent(device_->display_, None, None, nullptr);
+ ::glXMakeDestroyContext(device_->display_, context_);
+ }
+ device_->flush();
+}
+
+own<gl_window<gl::backnd::linux_xcb>> gl_context<gl::backend::linux_xcb>::create_window(const video_mode& vid_mode, std::string_view title_view){
+
+ SAW_ASSERT(device_){
+ return nullptr;
+ }
+
+ own<window<backend::linux_xcb>> win = device_->create_xcb_window(vid_mode, title_view, visual_id_);
+ if(!win){
+ return nullptr;
+ }
+
+ ::GLXWindow glx_win = glXCreateWindow(device_->display_, fb_config_, win->xcb_window_, nullptr);
+ return heap<gl_window<gl::backend::linux_xcb>>(std::move(win), *this, glx_win);
+}
+
+void gl_context<gl::backend::linux_xcb>::flush(){
+ assert(device_);
+ if(device_){
+ device_->flush();
+ }
+}
+
+own<gl_context<gl::backend::linux_xcb> > create_gl_context(io_provider& prov, const gl_settings& settings){
+ own<device<backend::linux_xcb>> device = create_xcb_device(prov);
+ if (!device) {
+ return nullptr;
+ }
+
+ /*
+ * Translate all attributes
+ */
+ std::vector<int> attributes;
+ attributes.reserve(33);
+
+ attributes.push_back(GLX_X_RENDERABLE);
+ attributes.push_back(settings.renderable ? True : False);
+
+ attributes.push_back(GLX_RENDER_TYPE);
+ attributes.push_back(translate_render_type_setting(settings.render_type));
+
+ attributes.push_back(GLX_RED_SIZE);
+ attributes.push_back(settings.red_bits);
+
+ attributes.push_back(GLX_GREEN_SIZE);
+ attributes.push_back(settings.green_bits);
+
+ attributes.push_back(GLX_BLUE_SIZE);
+ attributes.push_back(settings.blue_bits);
+
+ attributes.push_back(GLX_ALPHA_SIZE);
+ attributes.push_back(settings.alpha_bits);
+
+ attributes.push_back(GLX_DEPTH_SIZE);
+ attributes.push_back(settings.depth_bits);
+
+ attributes.push_back(GLX_STENCIL_SIZE);
+ attributes.push_back(settings.stencil_bits);
+
+ attributes.push_back(GLX_DOUBLEBUFFER);
+ attributes.push_back(settings.double_buffer ? True : False);
+
+ attributes.push_back(GLX_DRAWABLE_TYPE);
+ attributes.push_back(
+ translate_drawable_type_setting(settings.drawable_type));
+
+ attributes.push_back(GLX_X_VISUAL_TYPE);
+ attributes.push_back(GLX_TRUE_COLOR);
+
+ attributes.push_back(None);
+
+ int num_fb_configs = 0;
+
+ glx_library_extensions lib_ext = load_glx_library_extensions(
+ glXQueryExtensionsString(device->display_, device->screen_));
+
+ GLXFBConfig *fb_configs = glXChooseFBConfig(
+ device->display_, device->screen_, &attributes[0], &num_fb_configs);
+ if (!fb_configs || num_fb_configs == 0) {
+ /// @todo log errors
+ return nullptr;
+ }
+
+ if (lib_ext.glXCreateContextAttribsARB) {
+ ::GLXFBConfig fb_config = fb_configs[0];
+
+ ::GLXContext context;
+
+ std::vector<int> glx_attribs;
+ glx_attribs.reserve(11);
+
+ glx_attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
+ glx_attribs.push_back(settings.gl_major);
+ glx_attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
+ glx_attribs.push_back(settings.gl_minor);
+ glx_attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
+ glx_attribs.push_back(settings.core_profile
+ ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB
+ : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
+ glx_attribs.push_back(None);
+
+ context = lib_ext.glXCreateContextAttribsARB(
+ device->display, fb_config, NULL, True, &glx_attribs[0]);
+ ::XFree(fb_configs);
+ if (!context) {
+ return nullptr;
+ }
+
+ int visual_id = 0;
+ glXGetFBConfigAttrib(device->display, fb_config, GLX_VISUAL_ID,
+ &visual_id);
+ return heap<xcb_gl_context>(lib_ext, std::move(device), visual_id,
+ context, fb_config);
+ }
+
+ return nullptr;
+}
+
+gl_window<gl::backend::linux_xcb>::gl_window(own<xcb_window> &&win, gl_context<gl::backend::linux_xcb> &ctx,
+ ::GLXWindow glx_win)
+ : window_{std::move(win)}, context_{&ctx}, glx_window_{glx_win} {}
+
+gl_window<gl::backend::linux_xcb>::~gl_window() {
+ assert(context.device);
+ if (context.device) {
+ ::glXDestroyWindow(context_->device_->display, glx_window_);
+ }
+}
+
+void gl_window<gl::backend::linux_xcb>::bind() {
+ assert(window_ && context_->device && context_->device_->display);
+ if (window) {
+ if (context_->device_ && context_->device_->display) {
+ ::glXMakeContextCurrent(context_->device_->display, glx_window_,
+ glx_window_, context_->context);
+ }
+ }
+}
+
+void gl_window<gl::backend::linux_xcb>::show() {
+ assert(window_);
+ if (window_) {
+ window->show();
+ }
+}
+
+void gl_window<gl::backend::linux_xcb>::hide() {
+ assert(window_);
+ if (window_) {
+ window->hide();
+ }
+}
+
+void gl_window<gl::backend::linux_xcb>::swap() {
+ assert(context_->device_);
+ assert(context_->device_->display);
+ if (context_->device && context_->device_->display) {
+ ::glXSwapBuffers(context_->device_->display, glx_window_);
+ }
+}
+
+const video_mode &gl_window<gl::backend::linux_xcb>::get_video_mode() const {
+ assert(window_);
+ return window_->get_video_mode();
+}
+
+const std::string_view gl_window<gl::backend::linux_xcb>::title() const {
+ assert(window_);
+ if (window_) {
+ return window_->get_title();
+ }
+ // Kinky
+ return "Bad window";
+}
+
+void gl_window<gl::backend::linux_xcb>::resize(size_t height, size_t width) {
+ assert(window_);
+ if (window_) {
+ window->resize(height, width);
+ }
+}
+
+conveyor<window::variant_event> gl_window<gl::backend::linux_xcb>::on_event() {
+ assert(window_);
+ return window_->on_event();
+}
+
+}
+}