diff options
author | Claudius "keldu" Holeksa <mail@keldu.de> | 2023-08-09 20:25:16 +0200 |
---|---|---|
committer | Claudius "keldu" Holeksa <mail@keldu.de> | 2023-08-09 20:25:16 +0200 |
commit | b49d590153658e77d284e0b87d3cabe65fd37730 (patch) | |
tree | a9a4269921d6011d6dacf4b2a843ca7545e5bb0d /c++/window-opengl | |
parent | b04f831e7bc9513183127d1c3918789fb0696fff (diff) |
c++,window-opengl: Initial module commit
Diffstat (limited to 'c++/window-opengl')
-rw-r--r-- | c++/window-opengl/gl_backends.h | 12 | ||||
-rw-r--r-- | c++/window-opengl/gl_context.h | 42 | ||||
-rw-r--r-- | c++/window-opengl/gl_window.h | 7 | ||||
-rw-r--r-- | c++/window-opengl/gl_xcb.cpp | 265 | ||||
-rw-r--r-- | c++/window-opengl/gl_xcb.h | 65 |
5 files changed, 391 insertions, 0 deletions
diff --git a/c++/window-opengl/gl_backends.h b/c++/window-opengl/gl_backends.h new file mode 100644 index 0000000..0af10fc --- /dev/null +++ b/c++/window-opengl/gl_backends.h @@ -0,0 +1,12 @@ +#pragma once + +namespace saw { +namespace gfx { +namespace gl { +namespace backend { +struct linux_xcb {}; +struct wasm {}; +} +} +} +} diff --git a/c++/window-opengl/gl_context.h b/c++/window-opengl/gl_context.h new file mode 100644 index 0000000..8821650 --- /dev/null +++ b/c++/window-opengl/gl_context.h @@ -0,0 +1,42 @@ +#pragma once + +namespace saw { +namespace gfx { +class gl_settings { + uint8_t gl_major = 3; + uint8_t gl_minor = 3; + + enum class render_type : int32_t { rgba }; + + render_type render_t = render_type::rgba; + + bool renderable = true; + + bool window_type = true; + + enum class drawable_type : int32_t { + window_bit = 0x01, + pixmap_bit = 0x02, + pbuffer_bit = 0x04 + }; + + drawable_type drawable_t = drawable_type.:window_bit; + + bool double_buffer = true; + int red_bits = 8; + int green_bits = 8; + int blue_bits = 8; + int alpha_bits = 8; + + int depth_bits = 24; + int stencil_bits = 8; + + bool core_profile = true; +}; + +template<typename T> +class gl_context; + + +} +} diff --git a/c++/window-opengl/gl_window.h b/c++/window-opengl/gl_window.h new file mode 100644 index 0000000..e4ee6aa --- /dev/null +++ b/c++/window-opengl/gl_window.h @@ -0,0 +1,7 @@ +#pragma once + +namespace saw { +namespace gfx { +class gl_window; +} +} 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(); +} + +} +} diff --git a/c++/window-opengl/gl_xcb.h b/c++/window-opengl/gl_xcb.h new file mode 100644 index 0000000..128733b --- /dev/null +++ b/c++/window-opengl/gl_xcb.h @@ -0,0 +1,65 @@ +#pragma once + +#include <forstio/window/xcb.h> + +#ifndef SAW_OGL +#error "OpenGL is not supported" +#endif + +#include "gl_backends.h" + +#include <GL/glx.h> + +namespace saw { +namespace gfx { + +struct glx_library_extensions { +public: + std::string_view raw_extension_string; + GLXContext (*glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*) = nullptr; +}; + +template<> +class gl_context<gl::backend::linux_xcb> final { +private: + glx_library_extensions ext_lib_; + own<device<backend::linux_xcb>> device_; + int visual_id_; + GLXContext context_; + GLXFBConfig fb_config_; +public: + gl_context(const glx_library_extensions&, own<device<backend::linux_xcb>>, int, GLXContext, GLXFBConfig); + ~gl_context(); + + own<gl_window<gl::backend::linux_xcb>> create_window(const video_mode&, std::string_view); + + void flush(); +}; + +template<> +class gl_window<gl::backend::linux_xcb> final { +private: + own<window<backend::linux_xcb>> window_; + gl_context<gl::backend::linux_xcb>* context_; + + ::GLXWindow glx_window_handle_; + +public: + gl_window(own<window<backend::linux_xcb>> window, gl_context<gl::backend::linux_xcb>& ctx, + ::GLXWindow); + ~gl_window(); + + void bind(); + void swap(); + void show(); + void hide(); + + const video_mode& get_video_mode() const; + const std::string_view get_title() const; + + void resize(size_t height, size_t width); + + conveyor<data<schema::WindowEvents>> on_event(); +}; +} +} |