Skip to content
Snippets Groups Projects
Commit 42b420c0 authored by Joseph Walton-Rivers's avatar Joseph Walton-Rivers
Browse files

start of work on raw EGL support

parent 9df7ccca
Branches feature-egl
No related tags found
No related merge requests found
Pipeline #3343 failed
...@@ -14,6 +14,9 @@ target_include_directories(demo ...@@ -14,6 +14,9 @@ target_include_directories(demo
${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include
) )
find_package(OpenGL)
target_link_libraries(demo OpenGL::EGL)
target_link_libraries(demo fggl) target_link_libraries(demo fggl)
#target_include_directories(FgglDemo PUBLIC ${PROJECT_BINARY_DIR}) #target_include_directories(FgglDemo PUBLIC ${PROJECT_BINARY_DIR})
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "fggl/gfx/compat.hpp" #include "fggl/gfx/compat.hpp"
#include "fggl/gfx/ogl/compat.hpp" #include "fggl/gfx/ogl/compat.hpp"
#include "fggl/platform/platform.hpp"
#include "fggl/data/storage.hpp" #include "fggl/data/storage.hpp"
#include "fggl/util/service.h" #include "fggl/util/service.h"
...@@ -83,6 +85,9 @@ static void setup_service_locators(fggl::util::ServiceLocator& locator) { ...@@ -83,6 +85,9 @@ static void setup_service_locators(fggl::util::ServiceLocator& locator) {
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
fggl::platform::wayland::initWayland();
fggl::platform::egl::setup();
auto& locator = fggl::util::ServiceLocator::instance(); auto& locator = fggl::util::ServiceLocator::instance();
setup_service_locators(locator); setup_service_locators(locator);
...@@ -93,7 +98,7 @@ int main(int argc, const char* argv[]) { ...@@ -93,7 +98,7 @@ int main(int argc, const char* argv[]) {
auto& windowing = app.use<fggl::gfx::ecsGlfwModule>(locator.get<fggl::input::Input>()); auto& windowing = app.use<fggl::gfx::ecsGlfwModule>(locator.get<fggl::input::Input>());
// -- should not be our problem - this is a broken api // -- should not be our problem - this is a broken api
auto window = windowing.createWindow("Demo Game"); /*auto window = windowing.createWindow("Demo Game");
window->make_graphics<fggl::gfx::OpenGL4>(); window->make_graphics<fggl::gfx::OpenGL4>();
window->fullscreen( true ); window->fullscreen( true );
app.setWindow( std::move(window) ); app.setWindow( std::move(window) );
...@@ -129,5 +134,7 @@ int main(int argc, const char* argv[]) { ...@@ -129,5 +134,7 @@ int main(int argc, const char* argv[]) {
app.add_state<GameScene>("game"); app.add_state<GameScene>("game");
app.add_state<demo::RollBall>("rollball"); app.add_state<demo::RollBall>("rollball");
return app.run(argc, argv); return app.run(argc, argv); */
return 0;
} }
...@@ -71,6 +71,8 @@ target_link_libraries(${PROJECT_NAME} PUBLIC freetype) ...@@ -71,6 +71,8 @@ target_link_libraries(${PROJECT_NAME} PUBLIC freetype)
add_subdirectory(gfx) add_subdirectory(gfx)
add_subdirectory(audio) add_subdirectory(audio)
add_subdirectory(platform/wayland)
# physics integration # physics integration
add_subdirectory(phys/bullet) add_subdirectory(phys/bullet)
......
find_package(wayland-client++)
# include wayland headers
include(FindPkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules (WAYLAND_CLIENT REQUIRED wayland-client)
pkg_check_modules (WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
if(WAYLAND_PROTOCOLS_FOUND)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
endif()
pkg_check_modules (WAYLAND_SCANNER_TOOL REQUIRED wayland-scanner)
if(WAYLAND_SCANNER_TOOL_FOUND)
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
endif()
endif()
# generate protocol files
set(PROTOCOLS
${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml
)
foreach(XML ${PROTOCOLS})
get_filename_component(BASENAME ${XML} NAME_WE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.c
COMMAND wayland-scanner private-code ${XML} ${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.c
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.h
COMMAND wayland-scanner client-header ${XML} ${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.h
)
list(APPEND PROTOCOL_SRC
${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.c
)
list(APPEND PROTOCOL_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/wayland-${BASENAME}-protocol.h
)
endforeach()
# create a custom target for the protocol generation
set(WAYLAND_PROTOCOL_SRC ${PROTOCOL_SRC} CACHE INTERNAL "Wayland sources" FORCE)
set(WAYLAND_PROTOCOL_HEADERS ${PROTOCOL_HEADERS} CACHE INTERNAL "Wayland headers" FORCE)
add_custom_target(wayland_protocols DEPENDS ${WAYLAND_PROTOCOL_SRC} ${WAYLAND_PROTOCOL_HEADERS})
# let everyone know we need this to build
add_dependencies(fggl wayland_protocols)
target_include_directories(fggl PUBLIC ${CMAKE_BINARY_DIR}/exports)
target_sources(fggl
PRIVATE
memory.cpp
)
/**
* Code snippet derrived from the wayland book.
* the licence for the below snippet is CC0
*/
#define _POSIX_C_SOURCE 200112L
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
static void
randname(char *buf)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
static int
create_shm_file(void)
{
int retries = 100;
do {
char name[] = "/wl_shm-XXXXXX";
randname(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
int
allocate_shm_file(size_t size)
{
int fd = create_shm_file();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
/*
* ${license.title}
* Copyright (C) 2022 ${license.owner}
* ${license.mailto}
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//
// Created by webpigeon on 02/05/22.
//
#ifndef FGGL_PLATFORM_EGL_WINDOW_H
#define FGGL_PLATFORM_EGL_WINDOW_H
#include "fggl/gfx/ogl/common.hpp"
#include "fggl/platform/wayland/wayland.hpp"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <iostream>
#include <array>
#include <string>
namespace fggl::platform::egl {
enum class AttrType {
ENUM,
INTEGER,
BOOLEAN,
BITMASK_GL,
BITMASK_SURF
};
struct Attribute {
EGLint val;
const char* name;
AttrType type = AttrType::INTEGER;
};
constexpr static std::array<Attribute, 33> attrs {{
{EGL_BUFFER_SIZE, "buffer size"},
{EGL_RED_SIZE, "red size"},
{EGL_GREEN_SIZE, "green size"},
{EGL_BLUE_SIZE, "blue size"},
{EGL_LUMINANCE_SIZE, "luminance size"},
{EGL_ALPHA_SIZE, "alpha size"},
{EGL_ALPHA_MASK_SIZE, "alpha mask size"},
{EGL_BIND_TO_TEXTURE_RGB, "Bind To Texture RGB", AttrType::BOOLEAN},
{EGL_BIND_TO_TEXTURE_RGBA, "Bind To Texture RGBA", AttrType::BOOLEAN},
{EGL_COLOR_BUFFER_TYPE, "Colour buffer Type", AttrType::ENUM},
{EGL_CONFIG_CAVEAT, "Config Caveat", AttrType::ENUM},
{EGL_CONFIG_ID, "Config ID"},
{EGL_CONFORMANT, "Conformant", AttrType::BITMASK_GL},
{EGL_DEPTH_SIZE, "Depth size"},
{EGL_LEVEL, "level"},
{EGL_MATCH_NATIVE_PIXMAP, "Match negative pixmap"},
{EGL_MAX_PBUFFER_WIDTH, "Max pbuffer width"},
{EGL_MAX_PBUFFER_HEIGHT, "Max pbuffer height"},
{EGL_MAX_PBUFFER_PIXELS, "Max pbuffer pixels"},
{EGL_MAX_SWAP_INTERVAL, "Max swap interval"},
{EGL_MIN_SWAP_INTERVAL, "Min swap interval"},
{EGL_NATIVE_RENDERABLE, "Native renderable", AttrType::BOOLEAN},
{EGL_NATIVE_VISUAL_ID, "Native visual ID"},
{EGL_NATIVE_VISUAL_TYPE, "Native visual type"},
{EGL_RENDERABLE_TYPE, "Renderable type", AttrType::BITMASK_GL},
{EGL_SAMPLE_BUFFERS, "Sample buffers"},
{EGL_SAMPLES, "Samples"},
{EGL_STENCIL_SIZE, "Stencil Size"},
{EGL_SURFACE_TYPE, "Surface Type", AttrType::BITMASK_SURF},
{EGL_TRANSPARENT_TYPE, "Transparent type"},
{EGL_TRANSPARENT_RED_VALUE, "Transparent red"},
{EGL_TRANSPARENT_BLUE_VALUE, "Transparent blue"},
{EGL_TRANSPARENT_GREEN_VALUE, "Transparent green"}
}};
std::string getEnumValue(EGLint value) {
if ( value == EGL_RGB_BUFFER ) {
return "RGB buffer";
} else if ( value == EGL_LUMINANCE_BUFFER ) {
return "Luminance buffer";
} else if ( value == EGL_DONT_CARE ) {
return "Don't care";
} else if ( value == EGL_NONE ) {
return "None";
} else if ( value == EGL_SLOW_CONFIG ) {
return "Slow Config";
} else if ( value == EGL_NON_CONFORMANT_CONFIG ) {
return "Non-Conformant config";
} else if ( value == EGL_TRANSPARENT_RGB ) {
return "Transparent RGB";
} else {
return "Unknown value";
}
}
std::string getBoolValue(EGLint value) {
std::string valueBool = "unknown";
if ( value == EGL_TRUE) {
valueBool = "True";
} else if ( value == EGL_FALSE ) {
valueBool = "False";
} else if ( value == EGL_DONT_CARE) {
valueBool = "Don't care";
}
return valueBool;
}
std::string getBitmaskGL(EGLint value) {
std::string result = "";
if ((value & EGL_OPENGL_BIT) != 0) {
result += "OpenGL 1.x or 2.x,";
}
if ((value & EGL_OPENGL_ES_BIT) != 0) {
result += "OpenGL ES 1.x,";
}
if ( (value & EGL_OPENGL_ES2_BIT) != 0) {
result += "OpenGL ES 2.x,";
}
if ( (value & EGL_OPENGL_ES3_BIT) != 0) {
result += "OpenGL ES 3.x,";
}
if ( (value & EGL_OPENVG_BIT) != 0 ) {
result += "OpenVG 1.x";
}
return result;
}
void printConfig(EGLDisplay& display, EGLConfig& config) {
std::cerr << "EGL Configuration" << std::endl;
for ( auto& attr : attrs ) {
EGLint value;
eglGetConfigAttrib(display, config, attr.val, &value);
if ( attr.type == AttrType::INTEGER ) {
std::cerr << "\t" << attr.name << ": " << value << std::endl;
} else if ( attr.type == AttrType::BOOLEAN ) {
std::cerr << "\t" << attr.name << ": " << getBoolValue(value) << std::endl;
} else if ( attr.type == AttrType::ENUM ) {
std::cerr << "\t" << attr.name << ": " << getEnumValue(value) << std::endl;
} else if ( attr.type == AttrType::BITMASK_GL ) {
std::cerr << "\t" << attr.name << ": " << getBitmaskGL(value) << std::endl;
}
}
}
inline void setup() {
auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
auto result = eglInitialize(display, nullptr, nullptr);
if ( !result ) {
std::cerr << "something went bang when asking EGL to do it's thing" << std::endl;
return;
}
// platform stuff
auto* extentions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
std::cerr << "Supported extentions: " << extentions << std::endl;
// configs
std::array<EGLConfig, 256> configs;
EGLint returnedSize;
result = eglGetConfigs( display, configs.data(), configs.size(), &returnedSize);
if ( !result ) {
std::cerr << "something went bang when asking EGL about configs" << std::endl;
return;
}
std::cerr << "EGL reported " << returnedSize << " possible configurations" << std::endl;
for (int i = 0; i < returnedSize; i++) {
auto& config = configs[i];
printConfig(display, config);
}
// create an EGL context
//auto context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, nullptr);
// create a surface
//auto surface = eglCreatePlatformWindowSurface(display, configs[0], windowPtr, NULL);
}
} // namespace fggl::platform::egl
#endif //FGGL_PLATFORM_EGL_WINDOW_H
/*
* ${license.title}
* Copyright (C) 2022 ${license.owner}
* ${license.mailto}
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//
// Created by webpigeon on 02/05/22.
//
#ifndef FGGL_PLATFORM_PLATFORM_HPP
#define FGGL_PLATFORM_PLATFORM_HPP
#include "fggl/platform/wayland/client.hpp"
#include "fggl/platform/wayland/wayland.hpp"
#include "fggl/platform/egl/window.h"
#endif //FGGL_PLATFORM_PLATFORM_HPP
/*
* ${license.title}
* Copyright (C) 2022 ${license.owner}
* ${license.mailto}
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//
// Created by webpigeon on 02/05/22.
//
#ifndef FGGL_PLATFORM_WAYLAND_CLIENT_HPP
#define FGGL_PLATFORM_WAYLAND_CLIENT_HPP
#include <wayland-client.h>
#include "fggl/platform/wayland/wayland-xdg-shell-protocol.h"
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <iostream>
#include <cstring>
#include <sys/mman.h>
// wayland to cpp glue
struct WaylandState {
wl_compositor* compositor;
};
static void registryHandleGlobal(void* userData, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
std::cerr << "saw item: " << interface << ", Version: " << version << std::endl;
auto* state = static_cast<WaylandState*>(userData);
if ( strcmp(interface, wl_compositor_interface.name) == 0 ) {
state->compositor = static_cast<wl_compositor *>(wl_registry_bind(registry, name, &wl_compositor_interface, version));
}
if (strcmp(interface, xdg_))
if ( strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = static_cast<wl_shm *>(wl_registry_bind(registry, name, &wl_shm_interface, version));
}
}
static void registeryHandleGlobalRemove(void* userData, struct wl_registry* registry, uint32_t name) {
std::cerr << "something was removed" << std::endl;
}
static const struct wl_registry_listener registryListener{
registryHandleGlobal,
registeryHandleGlobalRemove
};
namespace fggl::platform::wayland {
void initWayland() {
auto* display = wl_display_connect(nullptr);
if ( display == nullptr ) {
std::cerr << "abort! couldn't connect to wayland display" << std::endl;
return;
}
WaylandState wlState;
auto* registry= wl_display_get_registry(display);
wl_registry_add_listener(registry, &registryListener, &wlState);
wl_display_roundtrip(display);
wl_display_roundtrip(display);
wl_surface* surface = wl_compositor_create_surface(wlState.compositor);
wl_egl_window* window = wl_egl_window_create(surface, 800, 600);
std::array<EGLConfig, 256> configs;
EGLint returnedSize;
eglGetConfigs( display, configs.data(), configs.size(), &returnedSize);
// egl display
EGLAttrib displayAttrs[]{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLDisplay eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, display, displayAttrs);
// egl surface
EGLAttrib surfaceAttrs[] {
EGL_NONE
};
EGLSurface eglSurface = eglCreatePlatformWindowSurface(eglDisplay, configs[0], window, surfaceAttrs);
// egl openGL
EGLint contextAttrs[] {
EGL_CONTEXT_MAJOR_VERSION, 4,
EGL_CONTEXT_MINOR_VERSION, 3,
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE,
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_FALSE,
EGL_NONE
};
eglBindAPI(EGL_OPENGL_API);
EGLContext context = eglCreateContext(eglDisplay, configs[0], EGL_NO_CONTEXT, contextAttrs);
eglMakeCurrent(display, surface, surface, context);
eglSwapBuffers(eglDisplay, eglSurface);
}
} // namespace fggl::platform::wayland
#endif //FGGL_PLATFORM_WAYLAND_CLIENT_HPP
/*
* ${license.title}
* Copyright (C) 2022 ${license.owner}
* ${license.mailto}
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//
// Created by webpigeon on 02/05/22.
//
#ifndef FGGL_PLATFORM_WAYLAND_WAYLAND_HPP
#define FGGL_PLATFORM_WAYLAND_WAYLAND_HPP
#include "wayland-egl.h"
#include "fggl/gfx/windowing.hpp"
namespace fggl::platform::wayland {
class WaylandWindow : public gfx::Window {
public:
WaylandWindow() {
m_window = wl_egl_window_create(m_surface, 800, 600);
}
void frameStart() override;
void frameEnd() override;
bool wantClose() const override;
math::vec2i frameSize() const override;
private:
wl_egl_window* m_window;
wl_surface* m_surface;
};
} // namespace fggl::platform::wayland
#endif //FGGL_PLATFORM_WAYLAND_WAYLAND_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment