Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //#define COMPILE_ON_WIN
- #define fpl_internal static
- #define fpl_constant constexpr
- #define fpl_inline inline
- #define FPL_ARRAYCOUNT(arr) (sizeof(arr) / sizeof((arr)[0]))
- #include <assert.h>
- #define FPL_ASSERT(exp) assert(exp)
- #include <stdint.h> // uint32_t, int64_t etc.
- #include <stdio.h> // fprintf
- #include <stdlib.h> // getenv
- #include <string.h> // strcpy
- #include <malloc.h> // malloc, free
- #define FPL_LOG_FORMAT(what, format) "[" what "] " format "\n"
- #define FPL_LOG(what, format, ...) do { \
- ::fprintf(stdout, FPL_LOG_FORMAT(what, format), ## __VA_ARGS__); \
- } while (0)
- // Subplatform POSIX
- #if !defined(COMPILE_ON_WIN)
- #include <sys/mman.h> // mmap, munmap
- #include <sys/types.h> // data types
- #include <sys/stat.h> // mkdir
- #include <sys/errno.h> // errno
- #include <signal.h> // pthread_kill
- #include <time.h> // clock_gettime, nanosleep
- #include <dlfcn.h> // dlopen, dlclose
- #include <fcntl.h> // open
- #include <unistd.h> // read, write, close, access, rmdir
- // Subplatform X11
- #include <X11/X.h> // Window
- #include <X11/Xlib.h> // Display
- #undef None
- #undef Success
- // GLX
- #include <GL/glx.h> // XVisualInfo, GLXContext, GLXDrawable
- #else
- // Fake types to get it compile on windows
- #define RTLD_NOW 1337
- #define AllocNone 0
- #define CopyFromParent 0
- // @TODO(final): Event loop!
- goto success;
- failed:
- retCode = -1;
- goto release;
- success:
- retCode = 0;
- goto release;
- release:
- return retCode;
- #define InputOutput 0x4
- #define CWEventMask 0x10
- #define CWBorderPixel 0x11
- #define CWColormap 0x12
- #define StructureNotifyMask 0x20
- typedef int XID;
- typedef XID Colormap;
- typedef XID Visual;
- struct Display {
- int dummy;
- };
- struct XVisualInfo {
- int depth;
- Visual *visual;
- };
- typedef XID Window;
- struct XSetWindowAttributes {
- Colormap colormap;
- int event_mask;
- };
- struct XErrorEvent {
- int type;
- Display *display; /* Display the event was read from */
- unsigned long serial; /* serial number of failed request */
- unsigned char error_code; /* error code of failed request */
- unsigned char request_code; /* Major op-code of failed request */
- unsigned char minor_code; /* Minor op-code of failed request */
- XID resourceid; /* resource id */
- };
- #define XERRORHANDLER(name) int name(Display *display, XErrorEvent *ev)
- typedef XERRORHANDLER(__XErrorHandler);
- typedef __XErrorHandler *XErrorHandler;
- typedef unsigned char GLubyte;
- typedef int GLint;
- #define GL_TRUE 1
- #define GL_FALSE 0
- #ifndef True
- # define True 1
- # define False 0
- #endif
- #ifndef Bool
- # define Bool int
- #endif
- #define GLX_VENDOR 1
- #define GLX_RGBA_BIT 0x00000001
- #define GLX_WINDOW_BIT 0x00000001
- #define GLX_DRAWABLE_TYPE 0x8010
- #define GLX_RENDER_TYPE 0x8011
- #define GLX_RGBA_TYPE 0x8014
- #define GLX_DOUBLEBUFFER 5
- #define GLX_STEREO 6
- #define GLX_AUX_BUFFERS 7
- #define GLX_RED_SIZE 8
- #define GLX_GREEN_SIZE 9
- #define GLX_BLUE_SIZE 10
- #define GLX_ALPHA_SIZE 11
- #define GLX_DEPTH_SIZE 12
- #define GLX_STENCIL_SIZE 13
- #define GLX_ACCUM_RED_SIZE 14
- #define GLX_ACCUM_GREEN_SIZE 15
- #define GLX_ACCUM_BLUE_SIZE 16
- #define GLX_ACCUM_ALPHA_SIZE 17
- #define GLX_SAMPLES 0x186a1
- #define GLX_VISUAL_ID 0x800b
- #define GLX_X_VISUAL_TYPE 0x22
- #define GLX_TRUE_COLOR 0x8002
- typedef XID GLXWindow;
- typedef XID GLXDrawable;
- struct __GLXFBConfig {
- int dummy;
- };
- struct __GLXcontext {
- int dummy;
- };
- typedef __GLXFBConfig* GLXFBConfig;
- typedef __GLXcontext* GLXContext;
- static void *dlopen(const char *filepath, int loadtype) {
- return nullptr;
- }
- static void dlclose(void *handle) {
- }
- static void *dlsym(void *handle, const char *name) {
- return nullptr;
- }
- static const char *getenv(const char *name) {
- return nullptr;
- }
- #endif
- #define FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, target, type, name) \
- target = (type *)::dlsym(libHandle, name); \
- if (target == nullptr) { \
- break; \
- }
- namespace fpl {
- namespace subplatform_posix {
- fpl_constant int DL_LOADTYPE = RTLD_NOW;
- }
- namespace subplatform_x11 {
- //
- // X11 Api
- //
- # define FPL_FUNC_X11_X_FREE(name) int name(void *data)
- typedef FPL_FUNC_X11_X_FREE(fpl_func_x11_XFree);
- # define FPL_FUNC_X11_X_FLUSH(name) void name(Display *display)
- typedef FPL_FUNC_X11_X_FLUSH(fpl_func_x11_XFlush);
- # define FPL_FUNC_X11_X_OPEN_DISPLAY(name) Display *name(char *display_name)
- typedef FPL_FUNC_X11_X_OPEN_DISPLAY(fpl_func_x11_XOpenDisplay);
- # define FPL_FUNC_X11_X_CLOSE_DISPLAY(name) int name(Display *display)
- typedef FPL_FUNC_X11_X_CLOSE_DISPLAY(fpl_func_x11_XCloseDisplay);
- # define FPL_FUNC_X11_X_DEFAULT_SCREEN(name) int name(Display *display)
- typedef FPL_FUNC_X11_X_DEFAULT_SCREEN(fpl_func_x11_XDefaultScreen);
- # define FPL_FUNC_X11_X_ROOT_WINDOW(name) Window name(Display *display, int screen_number)
- typedef FPL_FUNC_X11_X_ROOT_WINDOW(fpl_func_x11_XRootWindow);
- # define FPL_FUNC_X11_X_CREATE_WINDOW(name) Window name(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int clazz, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes)
- typedef FPL_FUNC_X11_X_CREATE_WINDOW(fpl_func_x11_XCreateWindow);
- # define FPL_FUNC_X11_X_DESTROY_WINDOW(name) int name(Display *display, Window w)
- typedef FPL_FUNC_X11_X_DESTROY_WINDOW(fpl_func_x11_XDestroyWindow);
- # define FPL_FUNC_X11_X_CREATE_COLORMAP(name) Colormap name(Display *display, Window w, Visual *visual, int alloc)
- typedef FPL_FUNC_X11_X_CREATE_COLORMAP(fpl_func_x11_XCreateColormap);
- # define FPL_FUNC_X11_X_DEFAULT_COLORMAP(name) Colormap name(Display *display, int screen_number)
- typedef FPL_FUNC_X11_X_DEFAULT_COLORMAP(fpl_func_x11_XDefaultColormap);
- # define FPL_FUNC_X11_X_FREE_COLORMAP(name) void name(Display *display, Colormap colormap)
- typedef FPL_FUNC_X11_X_FREE_COLORMAP(fpl_func_x11_XFreeColormap);
- # define FPL_FUNC_X11_X_MAP_WINDOW(name) void name(Display *display, Window w)
- typedef FPL_FUNC_X11_X_MAP_WINDOW(fpl_func_x11_XMapWindow);
- # define FPL_FUNC_X11_X_UNMAP_WINDOW(name) void name(Display *display, Window w)
- typedef FPL_FUNC_X11_X_UNMAP_WINDOW(fpl_func_x11_XUnmapWindow);
- # define FPL_FUNC_X11_X_STORE_NAME(name) void name(Display *display, Window w, char *windowName)
- typedef FPL_FUNC_X11_X_STORE_NAME(fpl_func_x11_XStoreName);
- //# define FPL_FUNC_X11_X_RENDER_FIND_VISUAL_FORMAT(name) XRenderPictFormat* name(Display* display, Visual const* visual)
- // typedef FPL_FUNC_X11_X_RENDER_FIND_VISUAL_FORMAT(fpl_func_x11_XRenderFindVisualFormat);
- # define FPL_FUNC_X11_X_DEFAULT_VISUAL(name) Visual *name(Display *display, int screen_number)
- typedef FPL_FUNC_X11_X_DEFAULT_VISUAL(fpl_func_x11_XDefaultVisual);
- # define FPL_FUNC_X11_X_SET_ERROR_HANDLER(name) XErrorHandler name(XErrorHandler handler)
- typedef FPL_FUNC_X11_X_SET_ERROR_HANDLER(fpl_func_x11_XSetErrorHandler);
- struct X11Api {
- void *libHandle;
- fpl_func_x11_XFlush *XFlush;
- fpl_func_x11_XFree *XFree;
- fpl_func_x11_XOpenDisplay *XOpenDisplay;
- fpl_func_x11_XCloseDisplay *XCloseDisplay;
- fpl_func_x11_XDefaultScreen *XDefaultScreen;
- fpl_func_x11_XRootWindow *XRootWindow;
- fpl_func_x11_XCreateWindow *XCreateWindow;
- fpl_func_x11_XDestroyWindow *XDestroyWindow;
- fpl_func_x11_XCreateColormap *XCreateColormap;
- fpl_func_x11_XFreeColormap *XFreeColormap;
- fpl_func_x11_XDefaultColormap *XDefaultColormap;
- fpl_func_x11_XMapWindow *XMapWindow;
- fpl_func_x11_XUnmapWindow *XUnmapWindow;
- fpl_func_x11_XStoreName *XStoreName;
- //fpl_func_x11_XRenderFindVisualFormat *XRenderFindVisualFormat;
- fpl_func_x11_XDefaultVisual *XDefaultVisual;
- fpl_func_x11_XSetErrorHandler *XSetErrorHandler;
- };
- fpl_internal void UnloadX11Api(X11Api &x11Api) {
- if (x11Api.libHandle != nullptr) {
- ::dlclose(x11Api.libHandle);
- }
- x11Api = {};
- }
- fpl_internal bool LoadX11Api(X11Api &x11Api) {
- const char* libFileNames[] = {
- "libX11.so",
- "libX11.so.7",
- "libX11.so.6",
- "libX11.so.5",
- };
- bool result = false;
- for (uint32_t index = 0; index < FPL_ARRAYCOUNT(libFileNames); ++index) {
- const char *libName = libFileNames[index];
- void *libHandle = x11Api.libHandle = ::dlopen(libName, subplatform_posix::DL_LOADTYPE);
- if (libHandle != nullptr) {
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFlush, fpl_func_x11_XFlush, "XFlush");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFree, fpl_func_x11_XFree, "XFree");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XOpenDisplay, fpl_func_x11_XOpenDisplay, "XOpenDisplay");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCloseDisplay, fpl_func_x11_XCloseDisplay, "XCloseDisplay");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultScreen, fpl_func_x11_XDefaultScreen, "XDefaultScreen");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XRootWindow, fpl_func_x11_XRootWindow, "XRootWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCreateWindow, fpl_func_x11_XCreateWindow, "XCreateWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDestroyWindow, fpl_func_x11_XDestroyWindow, "XDestroyWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCreateColormap, fpl_func_x11_XCreateColormap, "XCreateColormap");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFreeColormap, fpl_func_x11_XFreeColormap, "XFreeColormap");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultColormap, fpl_func_x11_XDefaultColormap, "XDefaultColormap");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XMapWindow, fpl_func_x11_XMapWindow, "XMapWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XUnmapWindow, fpl_func_x11_XUnmapWindow, "XUnmapWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XStoreName, fpl_func_x11_XStoreName, "XStoreName");
- //FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XRenderFindVisualFormat, fpl_func_x11_XRenderFindVisualFormat, "XRenderFindVisualFormat");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultVisual, fpl_func_x11_XDefaultVisual, "XDefaultVisual");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XSetErrorHandler, fpl_func_x11_XSetErrorHandler, "XSetErrorHandler");
- result = true;
- break;
- }
- UnloadX11Api(x11Api);
- }
- return(result);
- }
- struct X11AppState {
- X11Api api;
- };
- struct X11WindowState {
- Window root;
- Window window;
- Colormap colorMap;
- XErrorHandler originalErrorHandler;
- Display *display;
- int32_t screen;
- };
- struct X11WindowAttributesInput {
- X11AppState *appState;
- X11WindowState *windowState;
- };
- struct X11WindowAttributesOutput {
- Colormap colorMap;
- Visual *visual;
- int colorDepth;
- };
- } // subplatform_x11
- } // fpl
- namespace fpl {
- namespace platform {
- struct PlatformWindowState {
- subplatform_x11::X11WindowState x11;
- };
- struct PlatformVideoState {
- void *mem;
- size_t size;
- };
- struct PlatformAppState {
- subplatform_x11::X11AppState x11;
- PlatformWindowState window;
- PlatformVideoState video;
- };
- struct WindowAttributesInput {
- subplatform_x11::X11WindowAttributesInput x11;
- PlatformVideoState *video;
- };
- struct WindowAttributesOutput {
- subplatform_x11::X11WindowAttributesOutput x11;
- };
- # define FPL_FUNC_GET_WINDOW_ATTRIBUTES(name) bool name(const platform::WindowAttributesInput &input, platform::WindowAttributesOutput &output)
- typedef FPL_FUNC_GET_WINDOW_ATTRIBUTES(GetWindowAttributes_callback);
- }
- }
- namespace fpl {
- namespace strings {
- char *CopyAnsiString(const char *sourceStr, char *destStr, size_t destLength) {
- char *result = strncpy(destStr, sourceStr, destLength);
- return(result);
- }
- }
- namespace subplatform_x11 {
- fpl_internal void X11ReleaseSubplatform(X11AppState &appState) {
- UnloadX11Api(appState.api);
- }
- fpl_internal bool X11InitSubplatform(X11AppState &appState) {
- if (!LoadX11Api(appState.api)) {
- return false;
- }
- return true;
- }
- fpl_internal void X11ReleaseWindow(const X11AppState &x11AppState, X11WindowState &windowState) {
- const X11Api &x11Api = x11AppState.api;
- if (windowState.window) {
- FPL_LOG("X11", "Unmap Window '%d' on Display '%p'", (int)windowState.window, windowState.display);
- x11Api.XUnmapWindow(windowState.display, windowState.window);
- FPL_LOG("X11", "Destroy Window '%d' on Display '%p'", (int)windowState.window, windowState.display);
- x11Api.XDestroyWindow(windowState.display, windowState.window);
- windowState.window = (Window)0;
- }
- if (windowState.colorMap) {
- FPL_LOG("X11", "Free Colormap '%d' on Display '%p'", (int)windowState.colorMap, windowState.display);
- x11Api.XFreeColormap(windowState.display, windowState.colorMap);
- windowState.colorMap = (Colormap)0;
- }
- if (windowState.display != nullptr) {
- FPL_LOG("X11", "Flush Display '%p'", windowState.display);
- x11Api.XFlush(windowState.display);
- FPL_LOG("X11", "Close Display '%p'", windowState.display);
- x11Api.XCloseDisplay(windowState.display);
- windowState.display = nullptr;
- }
- FPL_LOG("X11", "Clear Window State");
- windowState = {};
- }
- fpl_internal int X11ErrorHandler(Display *display, XErrorEvent *ev) {
- return 0;
- }
- fpl_internal bool X11InitWindow(platform::GetWindowAttributes_callback *getWindowAttributesCallback, const platform::WindowAttributesInput &winAttribInput, X11AppState &x11AppState, X11WindowState &windowState) {
- const X11Api &x11Api = x11AppState.api;
- // @TODO(final): Implement this!
- // See: https://www.khronos.org/opengl/wiki/Programming_OpenGL_in_Linux:_GLX_and_Xlib
- // Get display with fallback from environment variable
- const char *displayStrings[] = {
- nullptr,
- getenv("DISPLAY")
- };
- char displayStringBuffer[256];
- for (uint32_t displayStringIndex = 0; displayStringIndex < FPL_ARRAYCOUNT(displayStrings); ++displayStringIndex) {
- // @NOTE(final): Nonsense we have to copy the constant display string to a variable buffer to satisfy the compiler
- const char *displayString = displayStrings[displayStringIndex];
- const char *notNullDisplayString = (displayString == nullptr ? "nullptr" : displayString);
- if (displayString != nullptr) {
- strings::CopyAnsiString(displayString, displayStringBuffer, FPL_ARRAYCOUNT(displayStringBuffer));
- windowState.display = x11Api.XOpenDisplay(displayStringBuffer);
- } else {
- windowState.display = x11Api.XOpenDisplay(nullptr);
- }
- FPL_LOG("X11", "Open Display from String '%s'", notNullDisplayString);
- if (windowState.display != nullptr) {
- FPL_LOG("X11", "Successfully opened Display: '%p' from String '%s'", windowState.display, notNullDisplayString);
- break;
- }
- FPL_LOG("X11", "Failed opening Display from String '%s'!", notNullDisplayString);
- }
- if (windowState.display == nullptr) {
- return false;
- }
- // Set error handler
- windowState.originalErrorHandler = x11Api.XSetErrorHandler(X11ErrorHandler);
- // Get screen
- FPL_LOG("X11", "Get Screen from Display '%p'", windowState.display);
- windowState.screen = x11Api.XDefaultScreen(windowState.display);
- FPL_LOG("X11", "Successfully got Screen: '%d' from Display '%p'", windowState.screen, windowState.display);
- // Get root window
- FPL_LOG("X11", "Get Root Window From Display '%p' and Screen '%d'", windowState.display, windowState.screen);
- windowState.root = x11Api.XRootWindow(windowState.display, windowState.screen);
- FPL_LOG("X11", "Successfully got Root Window '%d' from Display '%p' and Screen '%d'", (int)windowState.root, windowState.display, windowState.screen);
- // @TODO(final): This entire thing about getting the visual info is just bullshit and need to replaced by a much more sane implementation!
- FPL_LOG("X11", "Get Window Attributes from Callback '%p':", getWindowAttributesCallback);
- platform::WindowAttributesOutput winAttribOutput = {};
- bool gotWindowAttributes = getWindowAttributesCallback(winAttribInput, winAttribOutput);
- if (!gotWindowAttributes) {
- FPL_LOG("X11", "Failed getting Window Attributes from Callback '%p'!", getWindowAttributesCallback);
- } else {
- FPL_LOG("X11", "Successfully got Window Attributes");
- }
- // Set window attributes
- XSetWindowAttributes swa = {};
- unsigned long valueMask;
- if (gotWindowAttributes) {
- FPL_LOG("X11", "Using Colormap from Window Attributes");
- swa.colormap = winAttribOutput.x11.colorMap;
- valueMask = CWEventMask | CWBorderPixel | CWColormap;
- } else {
- FPL_LOG("X11", "Not using a Colormap");
- winAttribOutput.x11.colorMap = x11Api.XDefaultColormap(windowState.display, windowState.screen);
- winAttribOutput.x11.visual = x11Api.XDefaultVisual(windowState.display, windowState.root);
- winAttribOutput.x11.colorDepth = CopyFromParent;
- valueMask = CWEventMask | CWBorderPixel;
- }
- swa.event_mask = StructureNotifyMask;
- // @TODO(final): Get window width from settings (Either window or fullscreen)
- uint32_t windowWidth = 800;
- uint32_t windowHeight = 600;
- // Create window
- FPL_LOG("X11", "Create Window with Display('%p'), Root('%d'), Dimension(%d x %d), ColorDepth(%d)", windowState.display, (int)windowState.root, windowWidth, windowHeight, winAttribOutput.x11.colorDepth);
- windowState.colorMap = winAttribOutput.x11.colorMap;
- windowState.window = x11Api.XCreateWindow(windowState.display, windowState.root, 0, 0, windowWidth, windowHeight, 0, winAttribOutput.x11.colorDepth, InputOutput, winAttribOutput.x11.visual, valueMask, &swa);
- if (!windowState.window) {
- FPL_LOG("X11", "Failed creating Window from Display '%p' and Root '%d'", windowState.display, (int)windowState.root);
- X11ReleaseWindow(x11AppState, windowState);
- return false;
- }
- FPL_LOG("X11", "Successfully created Window '%d'", (int)windowState.window);
- // Show window
- FPL_LOG("X11", "Map Window '%d' on Display '%p'", (int)windowState.window, windowState.display);
- x11Api.XMapWindow(windowState.display, windowState.window);
- // Set title
- char windowTitleBuffer[256];
- strings::CopyAnsiString("Unnamed FPL X Window", windowTitleBuffer, FPL_ARRAYCOUNT(windowTitleBuffer));
- FPL_LOG("X11", "Set window title to '%s'", windowTitleBuffer);
- x11Api.XStoreName(windowState.display, windowState.window, windowTitleBuffer);
- return true;
- }
- } // subplatform_x11
- namespace drivers {
- // GLX function prototypes
- # define FPL_FUNC_GL_X_CHOOSE_VISUAL(name) XVisualInfo* name(Display *dpy, int screen, int *attribList)
- typedef FPL_FUNC_GL_X_CHOOSE_VISUAL(fpl_func_glx_glXChooseVisual);
- # define FPL_FUNC_GL_X_CREATE_CONTEXT(name) GLXContext name(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct)
- typedef FPL_FUNC_GL_X_CREATE_CONTEXT(fpl_func_glx_glXCreateContext);
- # define FPL_FUNC_GL_X_CREATE_NEW_CONTEXT(name) GLXContext name(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
- typedef FPL_FUNC_GL_X_CREATE_NEW_CONTEXT(fpl_func_glx_glXCreateNewContext);
- # define FPL_FUNC_GL_X_DESTROY_CONTEXT(name) void name(Display *dpy, GLXContext ctx)
- typedef FPL_FUNC_GL_X_DESTROY_CONTEXT(fpl_func_glx_glXDestroyContext);
- # define FPL_FUNC_GL_X_MAKE_CURRENT(name) Bool name(Display *dpy, GLXDrawable drawable, GLXContext ctx)
- typedef FPL_FUNC_GL_X_MAKE_CURRENT(fpl_func_glx_glXMakeCurrent);
- # define FPL_FUNC_GL_X_SWAP_BUFFERS(name) void name(Display *dpy, GLXDrawable drawable)
- typedef FPL_FUNC_GL_X_SWAP_BUFFERS(fpl_func_glx_glXSwapBuffers);
- # define FPL_FUNC_GL_X_GET_PROC_ADDRESS(name) void *name(const GLubyte *procname)
- typedef FPL_FUNC_GL_X_GET_PROC_ADDRESS(fpl_func_glx_glXGetProcAddress);
- # define FPL_FUNC_GL_X_CHOOSE_FB_CONFIG(name) GLXFBConfig *name(Display *dpy, int screen, const int *attrib_list, int *nelements)
- typedef FPL_FUNC_GL_X_CHOOSE_FB_CONFIG(fpl_func_glx_glXChooseFBConfig);
- # define FPL_FUNC_GL_X_GET_FB_CONFIGS(name) GLXFBConfig *name(Display *dpy, int screen, int *nelements)
- typedef FPL_FUNC_GL_X_GET_FB_CONFIGS(fpl_func_glx_glXGetFBConfigs);
- # define FPL_FUNC_GL_X_GET_VISUAL_FROM_FB_CONFIG(name) XVisualInfo *name(Display *dpy, GLXFBConfig config)
- typedef FPL_FUNC_GL_X_GET_VISUAL_FROM_FB_CONFIG(fpl_func_glx_glXGetVisualFromFBConfig);
- # define FPL_FUNC_GL_X_GET_FB_CONFIG_ATTRIB(name) int name(Display *dpy, GLXFBConfig config, int attribute, int *value)
- typedef FPL_FUNC_GL_X_GET_FB_CONFIG_ATTRIB(fpl_func_glx_glXGetFBConfigAttrib);
- # define FPL_FUNC_GL_X_CREATE_WINDOW(name) GLXWindow name(Display *dpy, GLXFBConfig config, Window win, const int *attrib_list)
- typedef FPL_FUNC_GL_X_CREATE_WINDOW(fpl_func_glx_glXCreateWindow);
- # define FPL_FUNC_GL_X_QUERY_EXTENSION(name) Bool name(Display *dpy, int *errorBase, int *eventBase)
- typedef FPL_FUNC_GL_X_QUERY_EXTENSION(fpl_func_glx_glXQueryExtension);
- struct GLXApi {
- void *libHandle;
- fpl_func_glx_glXChooseVisual *glXChooseVisual;
- fpl_func_glx_glXCreateContext *glXCreateContext;
- fpl_func_glx_glXDestroyContext *glXDestroyContext;
- fpl_func_glx_glXCreateNewContext *glXCreateNewContext;
- fpl_func_glx_glXMakeCurrent *glXMakeCurrent;
- fpl_func_glx_glXSwapBuffers *glXSwapBuffers;
- fpl_func_glx_glXGetProcAddress *glXGetProcAddress;
- fpl_func_glx_glXChooseFBConfig *glXChooseFBConfig;
- fpl_func_glx_glXGetFBConfigs *glXGetFBConfigs;
- fpl_func_glx_glXGetVisualFromFBConfig *glXGetVisualFromFBConfig;
- fpl_func_glx_glXGetFBConfigAttrib *glXGetFBConfigAttrib;
- fpl_func_glx_glXCreateWindow *glXCreateWindow;
- fpl_func_glx_glXQueryExtension *glXQueryExtension;
- };
- fpl_internal void UnloadGLXApi(GLXApi &glxApi) {
- if (glxApi.libHandle != nullptr) {
- FPL_LOG("GLX", "Unload Api (Library '%p')", glxApi.libHandle);
- ::dlclose(glxApi.libHandle);
- }
- glxApi = {};
- }
- fpl_internal bool LoadGLXApi(GLXApi &glxApi) {
- const char* libFileNames[] = {
- "libGLX.so",
- "libGLX.so.0",
- };
- bool result = false;
- for (uint32_t index = 0; index < FPL_ARRAYCOUNT(libFileNames); ++index) {
- const char *libName = libFileNames[index];
- FPL_LOG("GLX", "Load GLX Api from Library: %s", libName);
- void *libHandle = glxApi.libHandle = ::dlopen(libName, subplatform_posix::DL_LOADTYPE);
- if (libHandle != nullptr) {
- FPL_LOG("GLX", "Library Found: '%s', Resolving Procedures", libName);
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXChooseVisual, fpl_func_glx_glXChooseVisual, "glXChooseVisual");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXCreateContext, fpl_func_glx_glXCreateContext, "glXCreateContext");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXDestroyContext, fpl_func_glx_glXDestroyContext, "glXDestroyContext");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXCreateNewContext, fpl_func_glx_glXCreateNewContext, "glXCreateNewContext");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXMakeCurrent, fpl_func_glx_glXMakeCurrent, "glXMakeCurrent");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXSwapBuffers, fpl_func_glx_glXSwapBuffers, "glXSwapBuffers");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXGetProcAddress, fpl_func_glx_glXGetProcAddress, "glXGetProcAddress");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXChooseFBConfig, fpl_func_glx_glXChooseFBConfig, "glXChooseFBConfig");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXGetFBConfigs, fpl_func_glx_glXGetFBConfigs, "glXGetFBConfigs");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXGetVisualFromFBConfig, fpl_func_glx_glXGetVisualFromFBConfig, "glXGetVisualFromFBConfig");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXGetFBConfigAttrib, fpl_func_glx_glXGetFBConfigAttrib, "glXGetFBConfigAttrib");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXCreateWindow, fpl_func_glx_glXCreateWindow, "glXCreateWindow");
- FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, glxApi.glXQueryExtension, fpl_func_glx_glXQueryExtension, "glXQueryExtension");
- FPL_LOG("GLX", "Successfully loaded GLX Api from Library '%s'", libName);
- result = true;
- break;
- }
- UnloadGLXApi(glxApi);
- }
- return (result);
- }
- struct X11VideoOpenGLState {
- GLXApi glxApi;
- XVisualInfo *visualInfo;
- GLXContext glxContext;
- bool isActivated;
- };
- fpl_inline int GLXGetFrameBufferConfigAttrib(const GLXApi &glxApi, Display *display, GLXFBConfig fbConfig, int attrib) {
- int result;
- glxApi.glXGetFBConfigAttrib(display, fbConfig, attrib, &result);
- return(result);
- }
- fpl_internal XVisualInfo *GLXGetVisualInfo(const subplatform_x11::X11AppState &x11AppState, const X11VideoOpenGLState &glState, Display *display, int screen) {
- XVisualInfo *result = nullptr;
- const GLXApi &glxApi = glState.glxApi;
- const subplatform_x11::X11Api &x11Api = x11AppState.api;
- GLint attributes[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
- GLX_RED_SIZE, 8,
- GLX_GREEN_SIZE, 8,
- GLX_BLUE_SIZE, 8,
- GLX_ALPHA_SIZE, 8,
- GLX_STENCIL_SIZE, 8,
- GLX_DEPTH_SIZE, 24,
- GLX_DOUBLEBUFFER, True,
- 0
- };
- // Find all frame buffer configs
- FPL_LOG("GLX", "Get FrameBuffer Configs for Display '%p' and Screen '%d':", display, screen);
- int fbAllConfigCount = 0;
- GLXFBConfig *fbAllConfigs = glxApi.glXChooseFBConfig(display, screen, attributes, &fbAllConfigCount);
- if (!fbAllConfigs || !fbAllConfigCount) {
- FPL_LOG("GLX", "Failed getting FrameBuffer Configs from Display '%p' and Screen '%d'!", display, screen);
- return nullptr;
- }
- FPL_LOG("GLX", "Successfully got '%d' FrameBuffer Configs from Display '%p' and Screen '%d'", fbAllConfigCount, display, screen);
- XVisualInfo *foundVisualInfo = nullptr;
- GLXFBConfig foundFBConfig = nullptr;
- for (int fbConfigIndex = 0; fbConfigIndex < fbAllConfigCount; ++fbConfigIndex) {
- GLXFBConfig testFBConfig = fbAllConfigs[fbConfigIndex];
- // Get visual info from frame buffer config
- XVisualInfo *visualInfo = (XVisualInfo*)glxApi.glXGetVisualFromFBConfig(display, testFBConfig);
- if (!visualInfo) {
- continue;
- }
- // Get alpha bits
- int testAlphaBits = GLXGetFrameBufferConfigAttrib(glxApi, display, testFBConfig, GLX_ALPHA_SIZE);
- // Found a suitable frame buffer config with visual
- if (testAlphaBits > 0) {
- foundFBConfig = testFBConfig;
- foundVisualInfo = visualInfo;
- break;
- }
- // Release unused visual info (Important!)
- x11Api.XFree(visualInfo);
- }
- if (foundFBConfig != nullptr) {
- FPL_ASSERT(foundVisualInfo != nullptr);
- int doubleBuffer = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_DOUBLEBUFFER);
- int redBits = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_RED_SIZE);
- int greenBits = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_GREEN_SIZE);
- int blueBits = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_BLUE_SIZE);
- int alphaBits = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_ALPHA_SIZE);
- int depthBits = GLXGetFrameBufferConfigAttrib(glxApi, display, foundFBConfig, GLX_DEPTH_SIZE);
- int colorDepth = redBits + greenBits + blueBits + alphaBits;
- FPL_LOG("GLX", "Successfully found a suitable Frame Buffer Config (Doublebuffer: %s, Color bits: %d, Depth bits: %d) with Visual '%p'", (doubleBuffer == True ? "Yes" : "No"), colorDepth, depthBits, foundVisualInfo);
- result = foundVisualInfo;
- } else {
- FPL_LOG("GLX", "Failed finding a suitable Frame Buffer Config for Display '%p'!", display);
- }
- // Release frame buffer configs (Important!)
- x11Api.XFree(fbAllConfigs);
- return(result);
- }
- fpl_internal bool GLXGetWindowAttributes(const subplatform_x11::X11AppState &x11AppState, const subplatform_x11::X11WindowState &windowState, X11VideoOpenGLState &glState, subplatform_x11::X11WindowAttributesOutput &outAttributes) {
- const GLXApi &glxApi = glState.glxApi;
- const subplatform_x11::X11Api &x11Api = x11AppState.api;
- Display *display = windowState.display;
- Window root = windowState.root;
- int screen = windowState.screen;
- FPL_LOG("GLX", "Get Visual Info for Display '%p' and Screen '%d':", windowState.display, windowState.screen);
- XVisualInfo *visualInfo = GLXGetVisualInfo(x11AppState, glState, display, screen);
- if (visualInfo == nullptr) {
- FPL_LOG("GLX", "Failed getting Visual Info for Display '%p' and Screen '%d'!", windowState.display, windowState.screen);
- return false;
- }
- FPL_LOG("GLX", "Successfully got Visual Info '%p' for Display '%p' and Screen '%d'", windowState.display, windowState.screen, visualInfo);
- FPL_LOG("GLX", "Create Colormap on Display '%p' and Screen '%d'", display, screen);
- Colormap colorMap = x11Api.XCreateColormap(display, root, visualInfo->visual, AllocNone);
- outAttributes.visual = visualInfo->visual;
- outAttributes.colorMap = colorMap;
- outAttributes.colorDepth = visualInfo->depth;
- // @BAD(final): Really bad design here, a get function should not change anything at all
- glState.visualInfo = visualInfo;
- return(true);
- }
- fpl_internal bool X11InitVideoOpenGL(const subplatform_x11::X11AppState &x11AppState, const subplatform_x11::X11WindowState &windowState, X11VideoOpenGLState &glState) {
- const GLXApi &glxApi = glState.glxApi;
- glState.isActivated = false;
- if (glState.visualInfo == nullptr) {
- FPL_LOG("GLX", "VisualInfo was not set!");
- return false;
- }
- FPL_LOG("GLX", "Create Context for Display '%p' and VisualInfo '%p':", windowState.display, glState.visualInfo);
- glState.glxContext = glxApi.glXCreateContext(windowState.display, glState.visualInfo, nullptr, GL_TRUE);
- if (glState.glxContext == nullptr) {
- FPL_LOG("GLX", "Failed creating Context for Display '%p' and VisualInfo '%p'!", windowState.display, glState.visualInfo);
- return false;
- }
- FPL_LOG("GLX", "Successfully created Context for Display '%p' and VisualInfo '%p': %p", windowState.display, glState.visualInfo, glState.glxContext);
- FPL_LOG("GLX", "Activate Context for Display '%p' and Context '%p':", windowState.display, glState.glxContext);
- if (!glxApi.glXMakeCurrent(windowState.display, windowState.window, glState.glxContext)) {
- FPL_LOG("GLX", "Failed activating Context for Display '%p' and Context '%p'!", windowState.display, glState.glxContext);
- return false;
- }
- FPL_LOG("GLX", "Successfully activated Context for Display '%p' and Context '%p'", windowState.display, glState.glxContext);
- glState.isActivated = true;
- return true;
- }
- fpl_internal void X11ReleaseVideoOpenGL(const subplatform_x11::X11Api &x11Api, const subplatform_x11::X11WindowState &windowState, X11VideoOpenGLState &glState) {
- GLXApi &glxApi = glState.glxApi;
- if (glState.isActivated) {
- FPL_LOG("GLX", "Disable Context for Display '%p'", windowState.display);
- glxApi.glXMakeCurrent(windowState.display, 0L, nullptr);
- glState.isActivated = false;
- }
- if (glState.glxContext != nullptr) {
- FPL_LOG("GLX", "Destroy Context '%p' for Display '%p'", glState.glxContext, windowState.display);
- glxApi.glXDestroyContext(windowState.display, glState.glxContext);
- glState.glxContext = nullptr;
- }
- // @TODO(final): Do we want to free it before we destroy the context???
- if (glState.visualInfo != nullptr) {
- x11Api.XFree(glState.visualInfo);
- glState.visualInfo = nullptr;
- }
- }
- } // drivers
- namespace common_video {
- struct VideoState {
- drivers::X11VideoOpenGLState x11_opengl;
- };
- // @NOTE(final): The window has no access to the video driver directly, so we use callback to access it.
- fpl_internal FPL_FUNC_GET_WINDOW_ATTRIBUTES(DefaultGetWindowAttributes) {
- FPL_ASSERT(input.x11.appState != nullptr);
- FPL_ASSERT(input.x11.windowState != nullptr);
- VideoState *videoState = (VideoState *)input.video->mem;
- bool result = drivers::GLXGetWindowAttributes(*input.x11.appState, *input.x11.windowState, videoState->x11_opengl, output.x11);
- return(result);
- }
- } // common_video
- } // fpl
- int ReleaseAppState(fpl::platform::PlatformAppState *appState) {
- // Release rendering context
- fpl::common_video::VideoState *videoState = (fpl::common_video::VideoState *)appState->video.mem;
- if (videoState != nullptr) {
- fpl::drivers::X11ReleaseVideoOpenGL(appState->x11.api, appState->window.x11, videoState->x11_opengl);
- }
- // Release window
- fpl::subplatform_x11::X11ReleaseWindow(appState->x11, appState->window.x11);
- // Unload OpenGL library
- if (videoState != nullptr) {
- fpl::drivers::UnloadGLXApi(videoState->x11_opengl.glxApi);
- }
- // Unload X11 library
- fpl::subplatform_x11::UnloadX11Api(appState->x11.api);
- // Free app state
- free(appState);
- }
- int main(int argc, char *args[]) {
- // Allocate all state
- fpl::platform::PlatformAppState *appState = (fpl::platform::PlatformAppState *)malloc(sizeof(fpl::platform::PlatformAppState));
- memset(appState, 0, sizeof(fpl::platform::PlatformAppState));
- // Setup get window attributes callback and input
- fpl::platform::GetWindowAttributes_callback *getWinAttribsCallback = fpl::common_video::DefaultGetWindowAttributes;
- fpl::platform::WindowAttributesInput winAttribInput = {};
- winAttribInput.video = &appState->video;
- winAttribInput.x11.appState = &appState->x11;
- winAttribInput.x11.windowState = &appState->window.x11;
- // Init video state
- appState->video.size = sizeof(fpl::common_video::VideoState);
- appState->video.mem = malloc(appState->video.size);
- if (!appState->video.mem) {
- ReleaseAppState(appState);
- return -1;
- }
- memset(appState->video.mem, 0, appState->video.size);
- fpl::common_video::VideoState *videoState = (fpl::common_video::VideoState *)appState->video.mem;
- // Load X11 library
- fpl::subplatform_x11::X11AppState &x11AppState = appState->x11;
- if (!fpl::subplatform_x11::X11InitSubplatform(x11AppState)) {
- ReleaseAppState(appState);
- return -1;
- }
- // Load OpenGL library
- if (!fpl::drivers::LoadGLXApi(videoState->x11_opengl.glxApi)) {
- ReleaseAppState(appState);
- return -1;
- }
- // Create window
- if (!fpl::subplatform_x11::X11InitWindow(getWinAttribsCallback, winAttribInput, appState->x11, appState->window.x11)) {
- ReleaseAppState(appState);
- return -1;
- }
- // Create rendering context
- if (!fpl::drivers::X11InitVideoOpenGL(appState->x11, appState->window.x11, videoState->x11_opengl)) {
- ReleaseAppState(appState);
- return -1;
- }
- ReleaseAppState(appState);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement