From a14896f9ed209dd3f9597722e5a5697bd7dbf531 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Mon, 4 Dec 2023 12:18:14 +0100 Subject: meta: Renamed folder containing source --- modules/window-opengl/.nix/derivation.nix | 37 ++++ modules/window-opengl/SConscript | 38 +++++ modules/window-opengl/SConstruct | 72 ++++++++ modules/window-opengl/gl_backends.h | 10 ++ modules/window-opengl/gl_context.h | 43 +++++ modules/window-opengl/gl_window.h | 8 + modules/window-opengl/gl_xcb.cpp | 269 ++++++++++++++++++++++++++++++ modules/window-opengl/gl_xcb.h | 68 ++++++++ 8 files changed, 545 insertions(+) create mode 100644 modules/window-opengl/.nix/derivation.nix create mode 100644 modules/window-opengl/SConscript create mode 100644 modules/window-opengl/SConstruct create mode 100644 modules/window-opengl/gl_backends.h create mode 100644 modules/window-opengl/gl_context.h create mode 100644 modules/window-opengl/gl_window.h create mode 100644 modules/window-opengl/gl_xcb.cpp create mode 100644 modules/window-opengl/gl_xcb.h (limited to 'modules/window-opengl') diff --git a/modules/window-opengl/.nix/derivation.nix b/modules/window-opengl/.nix/derivation.nix new file mode 100644 index 0000000..40c25bb --- /dev/null +++ b/modules/window-opengl/.nix/derivation.nix @@ -0,0 +1,37 @@ +{ lib +, stdenv +, scons +, clang-tools +, version +, forstio +, xorg +, libGL +}: + +let + +in stdenv.mkDerivation { + pname = "forstio-window-opengl"; + inherit version; + src = ./..; + + enableParallelBuilding = true; + + nativeBuildInputs = [ + scons + clang-tools + ]; + + buildInputs = [ + forstio.core + forstio.async + forstio.io + forstio.codec + forstio.window + xorg.libX11 + xorg.libxcb + libGL + ]; + + outputs = ["out" "dev"]; +} diff --git a/modules/window-opengl/SConscript b/modules/window-opengl/SConscript new file mode 100644 index 0000000..7beee1a --- /dev/null +++ b/modules/window-opengl/SConscript @@ -0,0 +1,38 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +window_env = env.Clone(); + +window_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +window_env.headers = sorted(glob.glob(dir_path + "/*.h")) + +env.sources += window_env.sources; +env.headers += window_env.headers; + +## Shared lib +objects_shared = [] +window_env.add_source_files(objects_shared, window_env.sources, shared=True); +window_env.library_shared = window_env.SharedLibrary('#build/forstio-window-opengl', [objects_shared]); + +## Static lib +objects_static = [] +window_env.add_source_files(objects_static, window_env.sources, shared=False); +window_env.library_static = window_env.StaticLibrary('#build/forstio-window-opengl', [objects_static]); + +# Set Alias +env.Alias('library_window_opengl', [window_env.library_shared, window_env.library_static]); + +env.targets += ['library_window_opengl']; + +# Install +env.Install('$prefix/lib/', [window_env.library_shared, window_env.library_static]); +env.Install('$prefix/include/forstio/window/opengl/', [window_env.headers]); diff --git a/modules/window-opengl/SConstruct b/modules/window-opengl/SConstruct new file mode 100644 index 0000000..fc2c398 --- /dev/null +++ b/modules/window-opengl/SConstruct @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +import sys +import os +import os.path +import glob +import re + + +if sys.version_info < (3,): + def isbasestring(s): + return isinstance(s,basestring) +else: + def isbasestring(s): + return isinstance(s, (str,bytes)) + +def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, target_post=""): + + if isbasestring(filetype): + dir_path = self.Dir('.').abspath + filetype = sorted(glob.glob(dir_path+"/"+filetype)) + + for path in filetype: + target_name = re.sub( r'(.*?)(\.cpp|\.c\+\+)', r'\1' + target_post, path ) + if shared: + target_name+='.os' + sources.append( self.SharedObject( target=target_name, source=path ) ) + else: + target_name+='.o' + sources.append( self.StaticObject( target=target_name, source=path ) ) + pass + +def isAbsolutePath(key, dirname, env): + assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,) + +env_vars = Variables( + args=ARGUMENTS +) + +env_vars.Add('prefix', + help='Installation target location of build results and headers', + default='/usr/local/', + validator=isAbsolutePath +) + +env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[], + CPPDEFINES=['SAW_UNIX', 'SAW_UNIX_XCB', 'SAW_OGL'], + CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'], + LIBS=[ + 'forstio-core', + 'forstio-io', + 'forstio-async', + 'forstio-codec' + ] +); +env.__class__.add_source_files = add_kel_source_files +env.Tool('compilation_db'); +env.cdb = env.CompilationDatabase('compile_commands.json'); + +env.objects = []; +env.sources = []; +env.headers = []; +env.targets = []; + +Export('env') +SConscript('SConscript') + +env.Alias('cdb', env.cdb); +env.Alias('all', [env.targets]); +env.Default('all'); + +env.Alias('install', '$prefix') diff --git a/modules/window-opengl/gl_backends.h b/modules/window-opengl/gl_backends.h new file mode 100644 index 0000000..652954f --- /dev/null +++ b/modules/window-opengl/gl_backends.h @@ -0,0 +1,10 @@ +#pragma once + +namespace saw { +namespace gfx { +namespace backend { +struct gl_linux_xcb {}; +struct gl_wasm {}; +} +} +} diff --git a/modules/window-opengl/gl_context.h b/modules/window-opengl/gl_context.h new file mode 100644 index 0000000..685e527 --- /dev/null +++ b/modules/window-opengl/gl_context.h @@ -0,0 +1,43 @@ +#pragma once + +namespace saw { +namespace gfx { +class gl_settings { +public: + 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 +class gpu_context; + + +} +} diff --git a/modules/window-opengl/gl_window.h b/modules/window-opengl/gl_window.h new file mode 100644 index 0000000..3bb9f83 --- /dev/null +++ b/modules/window-opengl/gl_window.h @@ -0,0 +1,8 @@ +#pragma once + +namespace saw { +namespace gfx { +template +class gpu_window; +} +} diff --git a/modules/window-opengl/gl_xcb.cpp b/modules/window-opengl/gl_xcb.cpp new file mode 100644 index 0000000..5ea03f3 --- /dev/null +++ b/modules/window-opengl/gl_xcb.cpp @@ -0,0 +1,269 @@ +#include "gl_xcb.h" + +#include +#include +#include + +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 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( + glXGetProcAddress(reinterpret_cast("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_settings(gl_settings::drawable_type cmp){ + int i = 0; + if (static_cast(cmp) & + static_cast(gl_settings::drawable_type::window_bit)) { + i |= static_cast(GLX_WINDOW_BIT); + } + if (static_cast(cmp) & + static_cast(gl_settings::drawable_type::pixmap_bit)) { + i |= static_cast(GLX_PIXMAP_BIT); + } + if (static_cast(cmp) & + static_cast(gl_settings::drawable_type::pbuffer_bit)) { + i |= static_cast(GLX_PBUFFER_BIT); + } + return i; +} +} + +gpu_context::gpu_context(const glx_library_extensions& ext_lib, + own> dev, int visual_id, GLXContext context, GLXFBConfig fb_config): ext_lib_{ext_lib}, device_{std::move(dev)}, visual_id_{visual_id}, context_{context}, fb_config_{fb_config}{} + +gpu_context::~gpu_context(){ + assert(device_); + assert(device_->get_xcb_display()); + + if(context_){ + /// @todo Check if this context is bound and only unbind if that is the case + // ::glXMakeContextCurrent(device_->get_xcb_display(), None, None, nullptr); + ::glXDestroyContext(device_->get_xcb_display(), context_); + } + device_->flush(); +} + +own> gpu_context::create_window(const video_mode& vid_mode, std::string_view title_view){ + + SAW_ASSERT(device_){ + return nullptr; + } + + own> win = device_->create_xcb_window(vid_mode, title_view, visual_id_); + if(!win){ + return nullptr; + } + + ::GLXWindow glx_win = glXCreateWindow(device_->get_xcb_display(), fb_config_, win->get_xcb_window_handle(), nullptr); + return heap>(std::move(win), *this, glx_win); +} + +void gpu_context::flush(){ + assert(device_); + if(device_){ + device_->flush(); + } +} + +own > create_gl_context(io_provider& prov, const gl_settings& settings){ + auto eodev = create_xcb_device(prov); + if(eodev.is_error()){ + return nullptr; + } + own>& device = eodev.get_value(); + if (!device) { + return nullptr; + } + + /* + * Translate all attributes + */ + std::vector 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_settings(settings.render_t)); + + 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_settings(settings.drawable_t)); + + 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->get_xcb_display(), device->get_xcb_screen())); + + GLXFBConfig *fb_configs = glXChooseFBConfig( + device->get_xcb_display(), device->get_xcb_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 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->get_xcb_display(), fb_config, NULL, True, &glx_attribs[0]); + ::XFree(fb_configs); + if (!context) { + return nullptr; + } + + int visual_id = 0; + glXGetFBConfigAttrib(device->get_xcb_display(), fb_config, GLX_VISUAL_ID, + &visual_id); + return heap>(lib_ext, std::move(device), visual_id, + context, fb_config); + } + + return nullptr; +} + +gpu_window::gpu_window(own> win, gpu_context &ctx, + ::GLXWindow glx_win) + : window_{std::move(win)}, context_{&ctx}, glx_window_handle_{glx_win} {} + +gpu_window::~gpu_window() { + assert(context_->device_); + if (context_->device_) { + ::glXDestroyWindow(context_->device_->get_xcb_display(), glx_window_handle_); + } +} + +void gpu_window::bind() { + assert(window_ && context_->device_ && context_->device_->get_xcb_display()); + if (window_) { + if (context_->device_ && context_->device_->get_xcb_display()) { + ::glXMakeContextCurrent(context_->device_->get_xcb_display(), glx_window_handle_, + glx_window_handle_, context_->context_); + } + } +} + +void gpu_window::show() { + assert(window_); + if (window_) { + window_->show(); + } +} + +void gpu_window::hide() { + assert(window_); + if (window_) { + window_->hide(); + } +} + +void gpu_window::swap() { + assert(context_->device_); + assert(context_->device_->get_xcb_display()); + if (context_->device_ && context_->device_->get_xcb_display()) { + ::glXSwapBuffers(context_->device_->get_xcb_display(), glx_window_handle_); + } +} + +const video_mode &gpu_window::get_video_mode() const { + assert(window_); + return window_->get_video_mode(); +} + +const std::string_view gpu_window::get_title() const { + assert(window_); + if (window_) { + return window_->get_title(); + } + // Kinky + return "Bad window"; +} + +void gpu_window::resize(size_t height, size_t width) { + assert(window_); + if (window_) { + window_->resize(height, width); + } +} + +conveyor> gpu_window::on_event() { + assert(window_); + return window_->on_event(); +} + +} +} diff --git a/modules/window-opengl/gl_xcb.h b/modules/window-opengl/gl_xcb.h new file mode 100644 index 0000000..0d84662 --- /dev/null +++ b/modules/window-opengl/gl_xcb.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#ifndef SAW_OGL +#error "OpenGL is not supported" +#endif + +#include "gl_backends.h" +#include "gl_context.h" +#include "gl_window.h" + +#include + +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 gpu_context final { +private: + glx_library_extensions ext_lib_; + own> device_; + int visual_id_; + GLXContext context_; + GLXFBConfig fb_config_; + + friend class gpu_window; +public: + gpu_context(const glx_library_extensions&, own>, int, GLXContext, GLXFBConfig); + ~gpu_context(); + + own> create_window(const video_mode&, std::string_view); + + void flush(); +}; + +template<> +class gpu_window final { +private: + own> window_; + gpu_context* context_; + + ::GLXWindow glx_window_handle_; +public: + gpu_window(own> window, gpu_context& ctx, + ::GLXWindow); + ~gpu_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> on_event(); +}; +} +} -- cgit v1.2.3