/*
Copyright (c) 2017-2026 The Khronos Group Inc.
Copyright (c) 2016 Oculus VR, LLC.
Portions of macOS, iOS, functionality copyright (c) 2016 The Brenwill Workshop Ltd.

SPDX-License-Identifier: Apache-2.0
*/

#include "gfxwrapper_opengl.h"
#include "EGL/eglplatform.h"
#include "glad/egl.h"

/*
================================================================================================================================

System level functionality

================================================================================================================================
*/

static void Error(const char *format, ...) {
#if defined(OS_WINDOWS)
    char buffer[4096];
    va_list args;
    va_start(args, format);
    vsnprintf_s(buffer, 4096, _TRUNCATE, format, args);
    va_end(args);

    OutputDebugStringA(buffer);

    // MessageBoxA(NULL, buffer, "ERROR", MB_OK | MB_ICONINFORMATION);
#elif defined(OS_LINUX)
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    printf("\n");
    fflush(stdout);
#elif defined(OS_APPLE_MACOS)
    char buffer[4096];
    va_list args;
    va_start(args, format);
    int length = vsnprintf(buffer, 4096, format, args);
    va_end(args);

    NSLog(@"%s\n", buffer);

    if ([NSThread isMainThread]) {
        NSString *string = [[NSString alloc] initWithBytes:buffer length:length encoding:NSASCIIStringEncoding];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        NSAlert *alert = [[NSAlert alloc] init];
        [alert addButtonWithTitle:@"OK"];
        [alert setMessageText:@"Error"];
        [alert setInformativeText:string];
        [alert setAlertStyle:NSWarningAlertStyle];
        [alert runModal];
#pragma GCC diagnostic pop
    }
#elif defined(OS_APPLE_IOS)
    char buffer[4096];
    va_list args;
    va_start(args, format);
    int length = vsnprintf(buffer, 4096, format, args);
    va_end(args);

    NSLog(@"%s\n", buffer);

    if ([NSThread isMainThread]) {
        NSString *string = [[NSString alloc] initWithBytes:buffer length:length encoding:NSASCIIStringEncoding];
        UIAlertController *alert =
            [UIAlertController alertControllerWithTitle:@"Error" message:string preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"OK"
                                                  style:UIAlertActionStyleDefault
                                                handler:^(UIAlertAction *action){
                                                }]];
        [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
    }
#elif defined(OS_ANDROID)
    char buffer[4096];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, 4096, format, args);
    va_end(args);

    __android_log_print(ANDROID_LOG_ERROR, "atw", "%s", buffer);
#endif
    // Without exiting, the application will likely crash.
    if (format != NULL) {
        exit(1);
    }
}

/*
================================================================================================================================

EGL error checking.

================================================================================================================================
*/

#if defined(XR_USE_PLATFORM_EGL)

#define EGL(func)                                                      \
    do {                                                               \
        if (func == EGL_FALSE) {                                       \
            Error(#func " failed: %s", EglErrorString(eglGetError())); \
        }                                                              \
    } while (0)

static const char *EglErrorString(const EGLint error) {
    switch (error) {
        case EGL_SUCCESS:
            return "EGL_SUCCESS";
        case EGL_NOT_INITIALIZED:
            return "EGL_NOT_INITIALIZED";
        case EGL_BAD_ACCESS:
            return "EGL_BAD_ACCESS";
        case EGL_BAD_ALLOC:
            return "EGL_BAD_ALLOC";
        case EGL_BAD_ATTRIBUTE:
            return "EGL_BAD_ATTRIBUTE";
        case EGL_BAD_CONTEXT:
            return "EGL_BAD_CONTEXT";
        case EGL_BAD_CONFIG:
            return "EGL_BAD_CONFIG";
        case EGL_BAD_CURRENT_SURFACE:
            return "EGL_BAD_CURRENT_SURFACE";
        case EGL_BAD_DISPLAY:
            return "EGL_BAD_DISPLAY";
        case EGL_BAD_SURFACE:
            return "EGL_BAD_SURFACE";
        case EGL_BAD_MATCH:
            return "EGL_BAD_MATCH";
        case EGL_BAD_PARAMETER:
            return "EGL_BAD_PARAMETER";
        case EGL_BAD_NATIVE_PIXMAP:
            return "EGL_BAD_NATIVE_PIXMAP";
        case EGL_BAD_NATIVE_WINDOW:
            return "EGL_BAD_NATIVE_WINDOW";
        case EGL_CONTEXT_LOST:
            return "EGL_CONTEXT_LOST";
        default:
            return "unknown";
    }
}

#endif

/*
================================================================================================================================

OpenGL extensions.

================================================================================================================================
*/

#if defined(OS_ANDROID)

// GL_EXT_disjoint_timer_query without _EXT
#if !defined(GL_TIMESTAMP)
#define GL_QUERY_COUNTER_BITS GL_QUERY_COUNTER_BITS_EXT
#define GL_TIME_ELAPSED GL_TIME_ELAPSED_EXT
#define GL_TIMESTAMP GL_TIMESTAMP_EXT
#define GL_GPU_DISJOINT GL_GPU_DISJOINT_EXT
#endif

// GL_EXT_buffer_storage without _EXT
#if !defined(GL_BUFFER_STORAGE_FLAGS)
#define GL_MAP_READ_BIT 0x0001                          // GL_MAP_READ_BIT_EXT
#define GL_MAP_WRITE_BIT 0x0002                         // GL_MAP_WRITE_BIT_EXT
#define GL_MAP_PERSISTENT_BIT 0x0040                    // GL_MAP_PERSISTENT_BIT_EXT
#define GL_MAP_COHERENT_BIT 0x0080                      // GL_MAP_COHERENT_BIT_EXT
#define GL_DYNAMIC_STORAGE_BIT 0x0100                   // GL_DYNAMIC_STORAGE_BIT_EXT
#define GL_CLIENT_STORAGE_BIT 0x0200                    // GL_CLIENT_STORAGE_BIT_EXT
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000  // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F              // GL_BUFFER_IMMUTABLE_STORAGE_EXT
#define GL_BUFFER_STORAGE_FLAGS 0x8220                  // GL_BUFFER_STORAGE_FLAGS_EXT
#endif

#if !defined(EGL_OPENGL_ES3_BIT)
#define EGL_OPENGL_ES3_BIT 0x0040
#endif

// GL_EXT_texture_cube_map_array
#if !defined(GL_TEXTURE_CUBE_MAP_ARRAY)
#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
#endif

// GL_EXT_texture_filter_anisotropic
#if !defined(GL_TEXTURE_MAX_ANISOTROPY_EXT)
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
#endif

// GL_EXT_texture_border_clamp or GL_OES_texture_border_clamp
#if !defined(GL_CLAMP_TO_BORDER)
#define GL_CLAMP_TO_BORDER 0x812D
#endif

// No 1D textures in OpenGL ES.
#if !defined(GL_TEXTURE_1D)
#define GL_TEXTURE_1D 0x0DE0
#endif

// No 1D texture arrays in OpenGL ES.
#if !defined(GL_TEXTURE_1D_ARRAY)
#define GL_TEXTURE_1D_ARRAY 0x8C18
#endif

// No multi-sampled texture arrays in OpenGL ES.
#if !defined(GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
#endif

#endif

/*
================================================================================================================================

Driver Instance.

================================================================================================================================
*/

bool ksDriverInstance_Create(ksDriverInstance *instance) {
    memset(instance, 0, sizeof(ksDriverInstance));
    return true;
}

void ksDriverInstance_Destroy(ksDriverInstance *instance) { memset(instance, 0, sizeof(ksDriverInstance)); }

/*
================================================================================================================================

GPU Device.

================================================================================================================================
*/

bool ksGpuDevice_Create(ksGpuDevice *device, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo) {
    /*
            Use an extensions to select the appropriate device:
            https://www.opengl.org/registry/specs/NV/gpu_affinity.txt
            https://www.opengl.org/registry/specs/AMD/wgl_gpu_association.txt
            https://www.opengl.org/registry/specs/AMD/glx_gpu_association.txt

            On Linux configure each GPU to use a separate X screen and then select
            the X screen to render to.
    */

    memset(device, 0, sizeof(ksGpuDevice));

    device->instance = instance;
    device->queueInfo = *queueInfo;

    return true;
}

void ksGpuDevice_Destroy(ksGpuDevice *device) { memset(device, 0, sizeof(ksGpuDevice)); }

/*
================================================================================================================================

GPU Context.

================================================================================================================================
*/

static ksGpuSurfaceBits ksGpuContext_BitsForSurfaceFormat(const ksGpuSurfaceColorFormat colorFormat,
                                                          const ksGpuSurfaceDepthFormat depthFormat) {
    ksGpuSurfaceBits bits;
    bits.redBits = ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R8G8B8A8)
                        ? 8
                        : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B8G8R8A8)
                               ? 8
                               : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R5G6B5)
                                      ? 5
                                      : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B5G6R5) ? 5 : 8))));
    bits.greenBits = ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R8G8B8A8)
                          ? 8
                          : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B8G8R8A8)
                                 ? 8
                                 : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R5G6B5)
                                        ? 6
                                        : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B5G6R5) ? 6 : 8))));
    bits.blueBits = ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R8G8B8A8)
                         ? 8
                         : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B8G8R8A8)
                                ? 8
                                : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R5G6B5)
                                       ? 5
                                       : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B5G6R5) ? 5 : 8))));
    bits.alphaBits = ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R8G8B8A8)
                          ? 8
                          : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B8G8R8A8)
                                 ? 8
                                 : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_R5G6B5)
                                        ? 0
                                        : ((colorFormat == KS_GPU_SURFACE_COLOR_FORMAT_B5G6R5) ? 0 : 8))));
    bits.colorBits = bits.redBits + bits.greenBits + bits.blueBits + bits.alphaBits;
    bits.depthBits =
        ((depthFormat == KS_GPU_SURFACE_DEPTH_FORMAT_D16) ? 16 : ((depthFormat == KS_GPU_SURFACE_DEPTH_FORMAT_D24) ? 24 : 0));
    return bits;
}

#if defined(OS_WINDOWS)

static bool ksGpuContext_CreateForSurface(ksGpuContext *context, const ksGpuDevice *device, const int queueIndex,
                                          const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                                          const ksGpuSampleCount sampleCount, HINSTANCE hInstance, HDC hDC) {
    UNUSED_PARM(queueIndex);

    context->device = device;

    const ksGpuSurfaceBits bits = ksGpuContext_BitsForSurfaceFormat(colorFormat, depthFormat);

    PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,                        // version
        PFD_DRAW_TO_WINDOW |      // must support windowed
            PFD_SUPPORT_OPENGL |  // must support OpenGL
            PFD_DOUBLEBUFFER,     // must support double buffering
        PFD_TYPE_RGBA,            // iPixelType
        bits.colorBits,           // cColorBits
        0,
        0,  // cRedBits, cRedShift
        0,
        0,  // cGreenBits, cGreenShift
        0,
        0,  // cBlueBits, cBlueShift
        0,
        0,               // cAlphaBits, cAlphaShift
        0,               // cAccumBits
        0,               // cAccumRedBits
        0,               // cAccumGreenBits
        0,               // cAccumBlueBits
        0,               // cAccumAlphaBits
        bits.depthBits,  // cDepthBits
        0,               // cStencilBits
        0,               // cAuxBuffers
        PFD_MAIN_PLANE,  // iLayerType
        0,               // bReserved
        0,               // dwLayerMask
        0,               // dwVisibleMask
        0                // dwDamageMask
    };

    HWND localWnd = NULL;
    HDC localDC = hDC;

    if (sampleCount > KS_GPU_SAMPLE_COUNT_1) {
        // A valid OpenGL context is needed to get OpenGL extensions including wglChoosePixelFormatARB
        // and wglCreateContextAttribsARB. A device context with a valid pixel format is needed to create
        // an OpenGL context. However, once a pixel format is set on a device context it is final.
        // Therefore a pixel format is set on the device context of a temporary window to create a context
        // to get the extensions for multi-sampling.
        localWnd = CreateWindowA(APPLICATION_NAME, "temp", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
        localDC = GetDC(localWnd);
    }

    int pixelFormat = ChoosePixelFormat(localDC, &pfd);
    if (pixelFormat == 0) {
        Error("Failed to find a suitable pixel format.");
        return false;
    }

    if (!SetPixelFormat(localDC, pixelFormat, &pfd)) {
        Error("Failed to set the pixel format.");
        return false;
    }

    // Now that the pixel format is set, create a temporary context to get the extensions.
    {
        gladLoaderLoadWGL(localDC);
        HGLRC hGLRC = wglCreateContext(localDC);
        wglMakeCurrent(localDC, hGLRC);

        gladLoaderLoadWGL(localDC);

        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(hGLRC);
    }

    if (sampleCount > KS_GPU_SAMPLE_COUNT_1) {
        // Release the device context and destroy the window that were created to get extensions.
        ReleaseDC(localWnd, localDC);
        DestroyWindow(localWnd);

        int pixelFormatAttribs[] = {WGL_DRAW_TO_WINDOW_ARB,
                                    GL_TRUE,
                                    WGL_SUPPORT_OPENGL_ARB,
                                    GL_TRUE,
                                    WGL_DOUBLE_BUFFER_ARB,
                                    GL_TRUE,
                                    WGL_PIXEL_TYPE_ARB,
                                    WGL_TYPE_RGBA_ARB,
                                    WGL_COLOR_BITS_ARB,
                                    bits.colorBits,
                                    WGL_DEPTH_BITS_ARB,
                                    bits.depthBits,
                                    WGL_SAMPLE_BUFFERS_ARB,
                                    1,
                                    WGL_SAMPLES_ARB,
                                    sampleCount,
                                    0};

        unsigned int numPixelFormats = 0;

        if (!wglChoosePixelFormatARB(hDC, pixelFormatAttribs, NULL, 1, &pixelFormat, &numPixelFormats) || numPixelFormats == 0) {
            Error("Failed to find MSAA pixel format.");
            return false;
        }

        memset(&pfd, 0, sizeof(pfd));

        if (!DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
            Error("Failed to describe the pixel format.");
            return false;
        }

        if (!SetPixelFormat(hDC, pixelFormat, &pfd)) {
            Error("Failed to set the pixel format.");
            return false;
        }
    }

    int contextAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
                            OPENGL_VERSION_MAJOR,
                            WGL_CONTEXT_MINOR_VERSION_ARB,
                            OPENGL_VERSION_MINOR,
                            WGL_CONTEXT_PROFILE_MASK_ARB,
                            WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
                            WGL_CONTEXT_FLAGS_ARB,
                            WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB,
                            0};

    context->hDC = hDC;
    context->hGLRC = wglCreateContextAttribsARB(hDC, NULL, contextAttribs);
    if (!context->hGLRC) {
        Error("Failed to create GL context.");
        return false;
    }

    wglMakeCurrent(hDC, context->hGLRC);

    return true;
}

#elif defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX)

static int glxGetFBConfigAttrib2(Display *dpy, GLXFBConfig config, int attribute) {
    int value;
    glXGetFBConfigAttrib(dpy, config, attribute, &value);
    return value;
}

static bool ksGpuContext_CreateForSurface(ksGpuContext *context, const ksGpuDevice *device, const int queueIndex,
                                          const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                                          const ksGpuSampleCount sampleCount, Display *xDisplay, int xScreen) {
    UNUSED_PARM(queueIndex);

    gladLoaderLoadGLX(xDisplay, xScreen);

    context->device = device;

    int glxErrorBase;
    int glxEventBase;
    if (!glXQueryExtension(xDisplay, &glxErrorBase, &glxEventBase)) {
        Error("X display does not support the GLX extension.");
        return false;
    }

    int glxVersionMajor;
    int glxVersionMinor;
    if (!glXQueryVersion(xDisplay, &glxVersionMajor, &glxVersionMinor)) {
        Error("Unable to retrieve GLX version.");
        return false;
    }

    int fbConfigCount = 0;
    GLXFBConfig *fbConfigs = glXGetFBConfigs(xDisplay, xScreen, &fbConfigCount);
    if (fbConfigCount == 0) {
        Error("No valid framebuffer configurations found.");
        return false;
    }

    const ksGpuSurfaceBits bits = ksGpuContext_BitsForSurfaceFormat(colorFormat, depthFormat);

    bool foundFbConfig = false;
    for (int i = 0; i < fbConfigCount; i++) {
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_FBCONFIG_ID) == 0) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_VISUAL_ID) == 0) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_DOUBLEBUFFER) == 0) {
            continue;
        }
        if ((glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_RENDER_TYPE) & GLX_RGBA_BIT) == 0) {
            continue;
        }
        if ((glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT) == 0) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_RED_SIZE) != bits.redBits) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_GREEN_SIZE) != bits.greenBits) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_BLUE_SIZE) != bits.blueBits) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_ALPHA_SIZE) != bits.alphaBits) {
            continue;
        }
        if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_DEPTH_SIZE) != bits.depthBits) {
            continue;
        }
        if (sampleCount > KS_GPU_SAMPLE_COUNT_1) {
            if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_SAMPLE_BUFFERS) != 1) {
                continue;
            }
            if (glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_SAMPLES) != (int)sampleCount) {
                continue;
            }
        }

        context->visualid = glxGetFBConfigAttrib2(xDisplay, fbConfigs[i], GLX_VISUAL_ID);
        context->glxFBConfig = fbConfigs[i];
        foundFbConfig = true;
        break;
    }

    XFree(fbConfigs);

    if (!foundFbConfig) {
        Error("Failed to to find desired framebuffer configuration.");
        return false;
    }

    context->xDisplay = xDisplay;

    int attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB,
                     OPENGL_VERSION_MAJOR,
                     GLX_CONTEXT_MINOR_VERSION_ARB,
                     OPENGL_VERSION_MINOR,
                     GL_CONTEXT_PROFILE_MASK,
                     GL_CONTEXT_CORE_PROFILE_BIT,
                     GLX_CONTEXT_FLAGS_ARB,
                     GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
                     0};

    context->glxContext = glXCreateContextAttribsARB(xDisplay,              // Display *	dpy
                                                     context->glxFBConfig,  // GLXFBConfig	config
                                                     NULL,                  // GLXContext	share_context
                                                     True,                  // Bool			direct
                                                     attribs);              // const int *	attrib_list

    if (context->glxContext == NULL) {
        Error("Unable to create GLX context.");
        return false;
    }

    if (!glXIsDirect(xDisplay, context->glxContext)) {
        Error("Unable to create direct rendering context.");
        return false;
    }

    return true;
}

#elif defined(OS_LINUX_XCB)

static uint32_t xcb_glx_get_property(const uint32_t *properties, const uint32_t numProperties, uint32_t propertyName) {
    for (uint32_t i = 0; i < numProperties; i++) {
        if (properties[i * 2 + 0] == propertyName) {
            return properties[i * 2 + 1];
        }
    }
    return 0;
}

static bool ksGpuContext_CreateForSurface(ksGpuContext *context, const ksGpuDevice *device, const int queueIndex,
                                          const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                                          const ksGpuSampleCount sampleCount, xcb_connection_t *connection, int screen_number) {
    UNUSED_PARM(queueIndex);

    context->device = device;

    xcb_glx_query_version_cookie_t glx_query_version_cookie =
        xcb_glx_query_version(connection, OPENGL_VERSION_MAJOR, OPENGL_VERSION_MINOR);
    xcb_glx_query_version_reply_t *glx_query_version_reply =
        xcb_glx_query_version_reply(connection, glx_query_version_cookie, NULL);
    if (glx_query_version_reply == NULL) {
        Error("Unable to retrieve GLX version.");
        return false;
    }
    free(glx_query_version_reply);

    xcb_glx_get_fb_configs_cookie_t get_fb_configs_cookie = xcb_glx_get_fb_configs(connection, screen_number);
    xcb_glx_get_fb_configs_reply_t *get_fb_configs_reply = xcb_glx_get_fb_configs_reply(connection, get_fb_configs_cookie, NULL);

    if (get_fb_configs_reply == NULL || get_fb_configs_reply->num_FB_configs == 0) {
        Error("No valid framebuffer configurations found.");
        return false;
    }

    const ksGpuSurfaceBits bits = ksGpuContext_BitsForSurfaceFormat(colorFormat, depthFormat);

    const uint32_t *fb_configs_properties = xcb_glx_get_fb_configs_property_list(get_fb_configs_reply);
    const uint32_t fb_configs_num_properties = get_fb_configs_reply->num_properties;

    bool foundFbConfig = false;
    for (uint32_t i = 0; i < get_fb_configs_reply->num_FB_configs; i++) {
        const uint32_t *fb_config = fb_configs_properties + i * fb_configs_num_properties * 2;

        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_FBCONFIG_ID) == 0) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_VISUAL_ID) == 0) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_DOUBLEBUFFER) == 0) {
            continue;
        }
        if ((xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_RENDER_TYPE) & GLX_RGBA_BIT) == 0) {
            continue;
        }
        if ((xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT) == 0) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_RED_SIZE) != bits.redBits) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_GREEN_SIZE) != bits.greenBits) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_BLUE_SIZE) != bits.blueBits) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_ALPHA_SIZE) != bits.alphaBits) {
            continue;
        }
        if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_DEPTH_SIZE) != bits.depthBits) {
            continue;
        }
        if (sampleCount > KS_GPU_SAMPLE_COUNT_1) {
            if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_SAMPLE_BUFFERS) != 1) {
                continue;
            }
            if (xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_SAMPLES) != sampleCount) {
                continue;
            }
        }

        context->fbconfigid = xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_FBCONFIG_ID);
        context->visualid = xcb_glx_get_property(fb_config, fb_configs_num_properties, GLX_VISUAL_ID);
        foundFbConfig = true;
        break;
    }

    free(get_fb_configs_reply);

    if (!foundFbConfig) {
        Error("Failed to to find desired framebuffer configuration.");
        return false;
    }

    context->connection = connection;
    context->screen_number = screen_number;

    // Create the context.
    uint32_t attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB,
                          OPENGL_VERSION_MAJOR,
                          GLX_CONTEXT_MINOR_VERSION_ARB,
                          OPENGL_VERSION_MINOR,
                          GLX_CONTEXT_PROFILE_MASK_ARB,
                          GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
                          GLX_CONTEXT_FLAGS_ARB,
                          GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
                          0};

    context->glxContext = xcb_generate_id(connection);
    xcb_glx_create_context_attribs_arb(connection,           // xcb_connection_t *	connection
                                       context->glxContext,  // xcb_glx_context_t	context
                                       context->fbconfigid,  // xcb_glx_fbconfig_t	fbconfig
                                       screen_number,        // uint32_t				screen
                                       0,                    // xcb_glx_context_t	share_list
                                       1,                    // uint8_t				is_direct
                                       4,                    // uint32_t				num_attribs
                                       attribs);             // const uint32_t *		attribs

    // Make sure the context is direct.
    xcb_generic_error_t *error;
    xcb_glx_is_direct_cookie_t glx_is_direct_cookie = xcb_glx_is_direct_unchecked(connection, context->glxContext);
    xcb_glx_is_direct_reply_t *glx_is_direct_reply = xcb_glx_is_direct_reply(connection, glx_is_direct_cookie, &error);
    const bool is_direct = (glx_is_direct_reply != NULL && glx_is_direct_reply->is_direct);
    free(glx_is_direct_reply);

    if (!is_direct) {
        Error("Unable to create direct rendering context.");
        return false;
    }

    return true;
}

#elif defined(OS_LINUX_WAYLAND)

static bool ksGpuContext_CreateForSurface(ksGpuContext *context, const ksGpuDevice *device, struct wl_display *native_display) {
    context->device = device;

    if (gladLoaderLoadEGL(NULL) == 0) {
        return false;
    }

    EGLint numConfigs;
    EGLint majorVersion;
    EGLint minorVersion;

    // clang-format off
    EGLint fbAttribs[] = {
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RENDERABLE_TYPE, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_NONE,
    };

    EGLint contextAttribs[] = {
        EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
        EGL_CONTEXT_CLIENT_VERSION, OPENGL_VERSION_MAJOR,
        EGL_CONTEXT_MINOR_VERSION, OPENGL_VERSION_MINOR,
        EGL_NONE,
    };
    // clang-format on

    context->dpy = eglGetDisplay(native_display);
    if (context->dpy == EGL_NO_DISPLAY) {
        Error("Could not create EGL Display.");
        return false;
    }

    if (!eglInitialize(context->dpy, &majorVersion, &minorVersion)) {
        Error("eglInitialize failed.");
        return false;
    }

    printf("Initialized EGL context version %d.%d\n", majorVersion, minorVersion);
    if (gladLoaderLoadEGL(context->dpy) == 0) {
        return false;
    }

    EGLBoolean ret = eglGetConfigs(context->dpy, NULL, 0, &numConfigs);
    if (ret != EGL_TRUE || numConfigs == 0) {
        Error("eglGetConfigs failed.");
        return false;
    }

    EGLConfig config;
    ret = eglChooseConfig(context->dpy, fbAttribs, &config, 1, &numConfigs);
    if (ret != EGL_TRUE || numConfigs != 1) {
        Error("eglChooseConfig failed.");
        return false;
    }

    eglBindAPI(EGL_OPENGL_API);

    context->ctx = eglCreateContext(context->dpy, config, EGL_NO_CONTEXT, contextAttribs);
    if (context->ctx == EGL_NO_CONTEXT) {
        Error("Could not create OpenGL context.");
        return false;
    }

    if (!eglMakeCurrent(context->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context->ctx)) {
        Error("Could not make the current context current.");
        return false;
    }

    return true;
}

#elif defined(OS_APPLE_MACOS)

static bool ksGpuContext_CreateForSurface(ksGpuContext *context, const ksGpuDevice *device, const int queueIndex,
                                          const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                                          const ksGpuSampleCount sampleCount, CGDirectDisplayID display) {
    UNUSED_PARM(queueIndex);

    context->device = device;

    const ksGpuSurfaceBits bits = ksGpuContext_BitsForSurfaceFormat(colorFormat, depthFormat);

    NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = {NSOpenGLPFAMinimumPolicy,
                                                            1,
                                                            NSOpenGLPFAScreenMask,
                                                            CGDisplayIDToOpenGLDisplayMask(display),
                                                            NSOpenGLPFAAccelerated,
                                                            NSOpenGLPFAOpenGLProfile,
                                                            NSOpenGLProfileVersion3_2Core,
                                                            NSOpenGLPFADoubleBuffer,
                                                            NSOpenGLPFAColorSize,
                                                            bits.colorBits,
                                                            NSOpenGLPFADepthSize,
                                                            bits.depthBits,
                                                            NSOpenGLPFASampleBuffers,
                                                            (sampleCount > KS_GPU_SAMPLE_COUNT_1),
                                                            NSOpenGLPFASamples,
                                                            sampleCount,
                                                            0};

    NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes] autorelease];
    if (pixelFormat == nil) {
        Error("Failed : NSOpenGLPixelFormat.");
        return false;
    }
    context->nsContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
    if (context->nsContext == nil) {
        Error("Failed : NSOpenGLContext.");
        return false;
    }

    context->cglContext = [context->nsContext CGLContextObj];

    return true;
}
#endif

void ksGpuContext_Destroy(ksGpuContext *context) {
#if defined(OS_WINDOWS)
    if (context->hGLRC) {
        // Only detach if the current context is the same as the context being destroyed. Driver will give error otherwise.
        if (wglGetCurrentContext() == context->hGLRC) {
            if (!wglMakeCurrent(NULL, NULL)) {
                DWORD error = GetLastError();
                Error("Failed to release context error code (%d).", error);
            }
        }

        if (!wglDeleteContext(context->hGLRC)) {
            DWORD error = GetLastError();
            Error("Failed to delete context error code (%d).", error);
        }
        context->hGLRC = NULL;
    }
    context->hDC = NULL;
#elif defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX)
    glXDestroyContext(context->xDisplay, context->glxContext);
    context->xDisplay = NULL;
    context->visualid = 0;
    context->glxFBConfig = NULL;
    context->glxDrawable = 0;
    context->glxContext = NULL;
#elif defined(OS_LINUX_XCB)
    xcb_glx_destroy_context(context->connection, context->glxContext);
    context->connection = NULL;
    context->screen_number = 0;
    context->fbconfigid = 0;
    context->visualid = 0;
    context->glxDrawable = 0;
    context->glxContext = 0;
    context->glxContextTag = 0;
#elif defined(OS_APPLE_MACOS)
    CGLSetCurrentContext(NULL);
    if (context->nsContext != NULL) {
        [context->nsContext clearDrawable];
        [context->nsContext release];
        context->nsContext = nil;
    } else {
        CGLDestroyContext(context->cglContext);
    }
    context->cglContext = nil;
#elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND)
    if (context->ctx != EGL_NO_CONTEXT) {
        EGL(eglDestroyContext(context->dpy, context->ctx));
    }

    if (context->dpy != EGL_NO_DISPLAY) {
        EGL(eglTerminate(context->dpy));
    }

    context->dpy = EGL_NO_DISPLAY;
    context->ctx = EGL_NO_CONTEXT;

#else
    UNUSED_PARM(context);
#endif
}

void ksGpuContext_SetCurrent(ksGpuContext *context) {
#if defined(OS_WINDOWS)
    wglMakeCurrent(context->hDC, context->hGLRC);
#elif defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX)
    glXMakeCurrent(context->xDisplay, context->glxDrawable, context->glxContext);
#elif defined(OS_LINUX_XCB)
    xcb_glx_make_current_cookie_t glx_make_current_cookie =
        xcb_glx_make_current(context->connection, context->glxDrawable, context->glxContext, 0);
    xcb_glx_make_current_reply_t *glx_make_current_reply =
        xcb_glx_make_current_reply(context->connection, glx_make_current_cookie, NULL);
    context->glxContextTag = glx_make_current_reply->context_tag;
    free(glx_make_current_reply);
#elif defined(OS_APPLE_MACOS)
    CGLSetCurrentContext(context->cglContext);
#elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND)
    EGL(eglMakeCurrent(context->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context->ctx));
#else
    UNUSED_PARM(context);
#endif
}

void ksGpuContext_UnsetCurrent(ksGpuContext *context) {
#if defined(OS_WINDOWS)
    wglMakeCurrent(context->hDC, NULL);
#elif defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX)
    glXMakeCurrent(context->xDisplay, /* None */ 0L, NULL);
#elif defined(OS_LINUX_XCB)
    xcb_glx_make_current(context->connection, 0, 0, 0);
#elif defined(OS_APPLE_MACOS)
    (void)context;
    CGLSetCurrentContext(NULL);
#elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND)
    EGL(eglMakeCurrent(context->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
#else
    UNUSED_PARM(context);
#endif
}

bool ksGpuContext_CheckCurrent(ksGpuContext *context) {
#if defined(OS_WINDOWS)
    return (wglGetCurrentContext() == context->hGLRC);
#elif defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX)
    return (glXGetCurrentContext() == context->glxContext);
#elif defined(OS_LINUX_XCB)
    return true;
#elif defined(OS_APPLE_MACOS)
    return (CGLGetCurrentContext() == context->cglContext);
#elif defined(OS_APPLE_IOS)
    return (false);  // TODO: pick current context off the UIView
#elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND)
    return (eglGetCurrentContext() == context->ctx);
#else
    UNUSED_PARM(context);
    return false;
#endif
}

/*
================================================================================================================================

GPU Window.

================================================================================================================================
*/

#if defined(OS_WINDOWS)

typedef enum {
    KEY_A = 0x41,
    KEY_B = 0x42,
    KEY_C = 0x43,
    KEY_D = 0x44,
    KEY_E = 0x45,
    KEY_F = 0x46,
    KEY_G = 0x47,
    KEY_H = 0x48,
    KEY_I = 0x49,
    KEY_J = 0x4A,
    KEY_K = 0x4B,
    KEY_L = 0x4C,
    KEY_M = 0x4D,
    KEY_N = 0x4E,
    KEY_O = 0x4F,
    KEY_P = 0x50,
    KEY_Q = 0x51,
    KEY_R = 0x52,
    KEY_S = 0x53,
    KEY_T = 0x54,
    KEY_U = 0x55,
    KEY_V = 0x56,
    KEY_W = 0x57,
    KEY_X = 0x58,
    KEY_Y = 0x59,
    KEY_Z = 0x5A,
    KEY_RETURN = VK_RETURN,
    KEY_TAB = VK_TAB,
    KEY_ESCAPE = VK_ESCAPE,
    KEY_SHIFT_LEFT = VK_LSHIFT,
    KEY_CTRL_LEFT = VK_LCONTROL,
    KEY_ALT_LEFT = VK_LMENU,
    KEY_CURSOR_UP = VK_UP,
    KEY_CURSOR_DOWN = VK_DOWN,
    KEY_CURSOR_LEFT = VK_LEFT,
    KEY_CURSOR_RIGHT = VK_RIGHT
} ksKeyboardKey;

typedef enum { MOUSE_LEFT = 0, MOUSE_RIGHT = 1 } ksMouseButton;

static LRESULT APIENTRY WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    ksGpuWindow *window = (ksGpuWindow *)GetWindowLongPtrA(hWnd, GWLP_USERDATA);

    switch (message) {
        case WM_SIZE: {
            if (window != NULL) {
                window->windowWidth = (int)LOWORD(lParam);
                window->windowHeight = (int)HIWORD(lParam);
            }
            return 0;
        }
        case WM_ACTIVATE: {
            if (window != NULL) {
                window->windowActiveState = !HIWORD(wParam);
            }
            return 0;
        }
        case WM_ERASEBKGND: {
            return 0;
        }
        case WM_CLOSE: {
            PostQuitMessage(0);
            return 0;
        }
        case WM_KEYDOWN: {
            if (window != NULL) {
                if ((int)wParam >= 0 && (int)wParam < 256) {
                    if ((int)wParam != KEY_SHIFT_LEFT && (int)wParam != KEY_CTRL_LEFT && (int)wParam != KEY_ALT_LEFT &&
                        (int)wParam != KEY_CURSOR_UP && (int)wParam != KEY_CURSOR_DOWN && (int)wParam != KEY_CURSOR_LEFT &&
                        (int)wParam != KEY_CURSOR_RIGHT) {
                        window->input.keyInput[(int)wParam] = true;
                    }
                }
            }
            break;
        }
        case WM_LBUTTONDOWN: {
            window->input.mouseInput[MOUSE_LEFT] = true;
            window->input.mouseInputX[MOUSE_LEFT] = LOWORD(lParam);
            window->input.mouseInputY[MOUSE_LEFT] = window->windowHeight - HIWORD(lParam);
            break;
        }
        case WM_RBUTTONDOWN: {
            window->input.mouseInput[MOUSE_RIGHT] = true;
            window->input.mouseInputX[MOUSE_RIGHT] = LOWORD(lParam);
            window->input.mouseInputY[MOUSE_RIGHT] = window->windowHeight - HIWORD(lParam);
            break;
        }
    }
    return DefWindowProcA(hWnd, message, wParam, lParam);
}

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);

    if (window->windowFullscreen) {
        ChangeDisplaySettingsA(NULL, 0);
        ShowCursor(TRUE);
    }

    if (window->hDC) {
        if (!ReleaseDC(window->hWnd, window->hDC)) {
            Error("Failed to release device context.");
        }
        window->hDC = NULL;
    }

    if (window->hWnd) {
        if (!DestroyWindow(window->hWnd)) {
            Error("Failed to destroy the window.");
        }
        window->hWnd = NULL;
    }

    if (window->hInstance) {
        if (!UnregisterClassA(APPLICATION_NAME, window->hInstance)) {
            Error("Failed to unregister window class.");
        }
        window->hInstance = NULL;
    }
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, int queueIndex,
                        ksGpuSurfaceColorFormat colorFormat, ksGpuSurfaceDepthFormat depthFormat, ksGpuSampleCount sampleCount,
                        int width, int height, bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;
    window->windowActiveState = false;

    const LPCSTR displayDevice = NULL;

    if (window->windowFullscreen) {
        DEVMODEA dmScreenSettings;
        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
        dmScreenSettings.dmSize = sizeof(dmScreenSettings);
        dmScreenSettings.dmPelsWidth = width;
        dmScreenSettings.dmPelsHeight = height;
        dmScreenSettings.dmBitsPerPel = 32;
        dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;

        if (ChangeDisplaySettingsExA(displayDevice, &dmScreenSettings, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) {
            Error("The requested fullscreen mode is not supported.");
            return false;
        }
    }

    DEVMODEA lpDevMode;
    memset(&lpDevMode, 0, sizeof(DEVMODEA));
    lpDevMode.dmSize = sizeof(DEVMODEA);
    lpDevMode.dmDriverExtra = 0;

    if (EnumDisplaySettingsA(displayDevice, ENUM_CURRENT_SETTINGS, &lpDevMode) != FALSE) {
        window->windowRefreshRate = (float)lpDevMode.dmDisplayFrequency;
    }

    window->hInstance = GetModuleHandleA(NULL);

    WNDCLASSA wc;
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = (WNDPROC)WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = window->hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = APPLICATION_NAME;

    if (!RegisterClassA(&wc)) {
        Error("Failed to register window class.");
        return false;
    }

    DWORD dwExStyle = 0;
    DWORD dwStyle = 0;
    if (window->windowFullscreen) {
        dwExStyle = WS_EX_APPWINDOW;
        dwStyle = WS_POPUP;
        ShowCursor(FALSE);
    } else {
        // Fixed size window.
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
    }

    RECT windowRect;
    windowRect.left = (long)0;
    windowRect.right = (long)width;
    windowRect.top = (long)0;
    windowRect.bottom = (long)height;

    AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);

    if (!window->windowFullscreen) {
        RECT desktopRect;
        GetWindowRect(GetDesktopWindow(), &desktopRect);

        const int offsetX = (desktopRect.right - (windowRect.right - windowRect.left)) / 2;
        const int offsetY = (desktopRect.bottom - (windowRect.bottom - windowRect.top)) / 2;

        windowRect.left += offsetX;
        windowRect.right += offsetX;
        windowRect.top += offsetY;
        windowRect.bottom += offsetY;
    }

    window->hWnd = CreateWindowExA(dwExStyle,                           // Extended style for the window
                                   APPLICATION_NAME,                    // Class name
                                   WINDOW_TITLE,                        // Window title
                                   dwStyle |                            // Defined window style
                                       WS_CLIPSIBLINGS |                // Required window style
                                       WS_CLIPCHILDREN,                 // Required window style
                                   windowRect.left,                     // Window X position
                                   windowRect.top,                      // Window Y position
                                   windowRect.right - windowRect.left,  // Window width
                                   windowRect.bottom - windowRect.top,  // Window height
                                   NULL,                                // No parent window
                                   NULL,                                // No menu
                                   window->hInstance,                   // Instance
                                   NULL);                               // No WM_CREATE parameter
    if (!window->hWnd) {
        ksGpuWindow_Destroy(window);
        Error("Failed to create window.");
        return false;
    }

    SetWindowLongPtrA(window->hWnd, GWLP_USERDATA, (LONG_PTR)window);

    window->hDC = GetDC(window->hWnd);
    if (!window->hDC) {
        ksGpuWindow_Destroy(window);
        Error("Failed to acquire device context.");
        return false;
    }

    ksGpuDevice_Create(&window->device, instance, queueInfo);
    ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
                                  window->hInstance, window->hDC);
    ksGpuContext_SetCurrent(&window->context);

    gladLoaderLoadGL();

    ShowWindow(window->hWnd, SW_SHOW);
    SetForegroundWindow(window->hWnd);
    SetFocus(window->hWnd);

    return true;
}

#elif defined(OS_LINUX_XLIB)

typedef enum  // keysym.h
{ KEY_A = XK_a,
  KEY_B = XK_b,
  KEY_C = XK_c,
  KEY_D = XK_d,
  KEY_E = XK_e,
  KEY_F = XK_f,
  KEY_G = XK_g,
  KEY_H = XK_h,
  KEY_I = XK_i,
  KEY_J = XK_j,
  KEY_K = XK_k,
  KEY_L = XK_l,
  KEY_M = XK_m,
  KEY_N = XK_n,
  KEY_O = XK_o,
  KEY_P = XK_p,
  KEY_Q = XK_q,
  KEY_R = XK_r,
  KEY_S = XK_s,
  KEY_T = XK_t,
  KEY_U = XK_u,
  KEY_V = XK_v,
  KEY_W = XK_w,
  KEY_X = XK_x,
  KEY_Y = XK_y,
  KEY_Z = XK_z,
  KEY_RETURN = (XK_Return & 0xFF),
  KEY_TAB = (XK_Tab & 0xFF),
  KEY_ESCAPE = (XK_Escape & 0xFF),
  KEY_SHIFT_LEFT = (XK_Shift_L & 0xFF),
  KEY_CTRL_LEFT = (XK_Control_L & 0xFF),
  KEY_ALT_LEFT = (XK_Alt_L & 0xFF),
  KEY_CURSOR_UP = (XK_Up & 0xFF),
  KEY_CURSOR_DOWN = (XK_Down & 0xFF),
  KEY_CURSOR_LEFT = (XK_Left & 0xFF),
  KEY_CURSOR_RIGHT = (XK_Right & 0xFF) } ksKeyboardKey;

typedef enum { MOUSE_LEFT = Button1, MOUSE_RIGHT = Button2 } ksMouseButton;

/*
        Change video mode using the XFree86-VidMode X extension.

        While the XFree86-VidMode X extension should be superseded by the XRandR X extension,
        this still appears to be the most reliable way to change video modes for a single
        monitor configuration.
*/
static bool ChangeVideoMode_XF86VidMode(Display *xDisplay, int xScreen, int *currentWidth, int *currentHeight,
                                        float *currentRefreshRate, int *desiredWidth, int *desiredHeight,
                                        float *desiredRefreshRate) {
    int videoModeCount;
    XF86VidModeModeInfo **videoModeInfos;

    XF86VidModeGetAllModeLines(xDisplay, xScreen, &videoModeCount, &videoModeInfos);

    if (currentWidth != NULL && currentHeight != NULL && currentRefreshRate != NULL) {
        XF86VidModeModeInfo *mode = videoModeInfos[0];
        *currentWidth = mode->hdisplay;
        *currentHeight = mode->vdisplay;
        *currentRefreshRate = (mode->dotclock * 1000.0f) / (mode->htotal * mode->vtotal);
    }

    if (desiredWidth != NULL && desiredHeight != NULL && desiredRefreshRate != NULL) {
        XF86VidModeModeInfo *bestMode = NULL;
        int bestModeWidth = 0;
        int bestModeHeight = 0;
        float bestModeRefreshRate = 0.0f;
        int bestSizeError = 0x7FFFFFFF;
        float bestRefreshRateError = 1e6f;
        for (int j = 0; j < videoModeCount; j++) {
            XF86VidModeModeInfo *mode = videoModeInfos[j];
            const int modeWidth = mode->hdisplay;
            const int modeHeight = mode->vdisplay;
            const float modeRefreshRate = (mode->dotclock * 1000.0f) / (mode->htotal * mode->vtotal);

            const int dw = modeWidth - *desiredWidth;
            const int dh = modeHeight - *desiredHeight;
            const int sizeError = dw * dw + dh * dh;
            const float refreshRateError = fabsf(modeRefreshRate - *desiredRefreshRate);
            if (sizeError < bestSizeError || (sizeError == bestSizeError && refreshRateError < bestRefreshRateError)) {
                bestSizeError = sizeError;
                bestRefreshRateError = refreshRateError;
                bestMode = mode;
                bestModeWidth = modeWidth;
                bestModeHeight = modeHeight;
                bestModeRefreshRate = modeRefreshRate;
            }
        }

        XF86VidModeSwitchToMode(xDisplay, xScreen, bestMode);
        XF86VidModeSetViewPort(xDisplay, xScreen, 0, 0);

        *desiredWidth = bestModeWidth;
        *desiredHeight = bestModeHeight;
        *desiredRefreshRate = bestModeRefreshRate;
    }

    for (int i = 0; i < videoModeCount; i++) {
        if (videoModeInfos[i]->privsize > 0) {
            XFree(videoModeInfos[i]->private);
        }
    }
    XFree(videoModeInfos);

    return true;
}

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);

    if (window->windowFullscreen) {
        ChangeVideoMode_XF86VidMode(window->xDisplay, window->xScreen, NULL, NULL, NULL, &window->desktopWidth,
                                    &window->desktopHeight, &window->desktopRefreshRate);

        XUngrabPointer(window->xDisplay, CurrentTime);
        XUngrabKeyboard(window->xDisplay, CurrentTime);
    }

    if (window->xWindow) {
        XUnmapWindow(window->xDisplay, window->xWindow);
        XDestroyWindow(window->xDisplay, window->xWindow);
        window->xWindow = 0;
    }

    if (window->xColormap) {
        XFreeColormap(window->xDisplay, window->xColormap);
        window->xColormap = 0;
    }

    if (window->xVisual) {
        XFree(window->xVisual);
        window->xVisual = NULL;
    }

    XFlush(window->xDisplay);
    XCloseDisplay(window->xDisplay);
    window->xDisplay = NULL;
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;

    const char *displayName = NULL;
    window->xDisplay = XOpenDisplay(displayName);
    if (!window->xDisplay) {
        Error("Unable to open X Display.");
        return false;
    }

    window->xScreen = XDefaultScreen(window->xDisplay);
    window->xRoot = XRootWindow(window->xDisplay, window->xScreen);

    if (window->windowFullscreen) {
        ChangeVideoMode_XF86VidMode(window->xDisplay, window->xScreen, &window->desktopWidth, &window->desktopHeight,
                                    &window->desktopRefreshRate, &window->windowWidth, &window->windowHeight,
                                    &window->windowRefreshRate);
    } else {
        ChangeVideoMode_XF86VidMode(window->xDisplay, window->xScreen, &window->desktopWidth, &window->desktopHeight,
                                    &window->desktopRefreshRate, NULL, NULL, NULL);
        window->windowRefreshRate = window->desktopRefreshRate;
    }

    ksGpuDevice_Create(&window->device, instance, queueInfo);
    ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
                                  window->xDisplay, window->xScreen);

    window->xVisual = glXGetVisualFromFBConfig(window->xDisplay, window->context.glxFBConfig);
    if (window->xVisual == NULL) {
        Error("Failed to retrieve visual for framebuffer config.");
        ksGpuWindow_Destroy(window);
        return false;
    }

    window->xColormap = XCreateColormap(window->xDisplay, window->xRoot, window->xVisual->visual, AllocNone);

    const unsigned long wamask = CWColormap | CWEventMask | (window->windowFullscreen ? 0 : CWBorderPixel);

    XSetWindowAttributes wa;
    memset(&wa, 0, sizeof(wa));
    wa.colormap = window->xColormap;
    wa.border_pixel = 0;
    wa.event_mask = StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask | KeyPressMask | KeyReleaseMask |
                    ButtonPressMask | ButtonReleaseMask | FocusChangeMask | ExposureMask | VisibilityChangeMask | EnterWindowMask |
                    LeaveWindowMask;

    window->xWindow = XCreateWindow(window->xDisplay,         // Display * display
                                    window->xRoot,            // Window parent
                                    0,                        // int x
                                    0,                        // int y
                                    window->windowWidth,      // unsigned int width
                                    window->windowHeight,     // unsigned int height
                                    0,                        // unsigned int border_width
                                    window->xVisual->depth,   // int depth
                                    InputOutput,              // unsigned int class
                                    window->xVisual->visual,  // Visual * visual
                                    wamask,                   // unsigned long valuemask
                                    &wa);                     // XSetWindowAttributes * attributes

    if (!window->xWindow) {
        Error("Failed to create window.");
        ksGpuWindow_Destroy(window);
        return false;
    }

    // Change the window title.
    Atom _NET_WM_NAME = XInternAtom(window->xDisplay, "_NET_WM_NAME", False);
    XChangeProperty(window->xDisplay, window->xWindow, _NET_WM_NAME, XA_STRING, 8, PropModeReplace,
                    (const unsigned char *)WINDOW_TITLE, strlen(WINDOW_TITLE));

    if (window->windowFullscreen) {
        // Bypass the compositor in fullscreen mode.
        const unsigned long bypass = 1;
        Atom _NET_WM_BYPASS_COMPOSITOR = XInternAtom(window->xDisplay, "_NET_WM_BYPASS_COMPOSITOR", False);
        XChangeProperty(window->xDisplay, window->xWindow, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace,
                        (const unsigned char *)&bypass, 1);

        // Completely disassociate window from window manager.
        XSetWindowAttributes attributes;
        attributes.override_redirect = True;
        XChangeWindowAttributes(window->xDisplay, window->xWindow, CWOverrideRedirect, &attributes);

        // Make the window visible.
        XMapRaised(window->xDisplay, window->xWindow);
        XMoveResizeWindow(window->xDisplay, window->xWindow, 0, 0, window->windowWidth, window->windowHeight);
        XFlush(window->xDisplay);

        // Grab mouse and keyboard input now that the window is disassociated from the window manager.
        XGrabPointer(window->xDisplay, window->xWindow, True, 0, GrabModeAsync, GrabModeAsync, window->xWindow, 0L, CurrentTime);
        XGrabKeyboard(window->xDisplay, window->xWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
    } else {
        // Make the window fixed size.
        XSizeHints *hints = XAllocSizeHints();
        hints->flags = (PMinSize | PMaxSize);
        hints->min_width = window->windowWidth;
        hints->max_width = window->windowWidth;
        hints->min_height = window->windowHeight;
        hints->max_height = window->windowHeight;
        XSetWMNormalHints(window->xDisplay, window->xWindow, hints);
        XFree(hints);

        // First map the window and then center the window on the screen.
        XMapRaised(window->xDisplay, window->xWindow);
        const int x = (window->desktopWidth - window->windowWidth) / 2;
        const int y = (window->desktopHeight - window->windowHeight) / 2;
        XMoveResizeWindow(window->xDisplay, window->xWindow, x, y, window->windowWidth, window->windowHeight);
        XFlush(window->xDisplay);
    }

    window->context.glxDrawable = window->xWindow;

    ksGpuContext_SetCurrent(&window->context);

    gladLoaderLoadGL();

    return true;
}

#elif defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX)

typedef enum  // keysym.h
{ KEY_A = XK_a,
  KEY_B = XK_b,
  KEY_C = XK_c,
  KEY_D = XK_d,
  KEY_E = XK_e,
  KEY_F = XK_f,
  KEY_G = XK_g,
  KEY_H = XK_h,
  KEY_I = XK_i,
  KEY_J = XK_j,
  KEY_K = XK_k,
  KEY_L = XK_l,
  KEY_M = XK_m,
  KEY_N = XK_n,
  KEY_O = XK_o,
  KEY_P = XK_p,
  KEY_Q = XK_q,
  KEY_R = XK_r,
  KEY_S = XK_s,
  KEY_T = XK_t,
  KEY_U = XK_u,
  KEY_V = XK_v,
  KEY_W = XK_w,
  KEY_X = XK_x,
  KEY_Y = XK_y,
  KEY_Z = XK_z,
  KEY_RETURN = (XK_Return & 0xFF),
  KEY_TAB = (XK_Tab & 0xFF),
  KEY_ESCAPE = (XK_Escape & 0xFF),
  KEY_SHIFT_LEFT = (XK_Shift_L & 0xFF),
  KEY_CTRL_LEFT = (XK_Control_L & 0xFF),
  KEY_ALT_LEFT = (XK_Alt_L & 0xFF),
  KEY_CURSOR_UP = (XK_Up & 0xFF),
  KEY_CURSOR_DOWN = (XK_Down & 0xFF),
  KEY_CURSOR_LEFT = (XK_Left & 0xFF),
  KEY_CURSOR_RIGHT = (XK_Right & 0xFF) } ksKeyboardKey;

typedef enum { MOUSE_LEFT = 0, MOUSE_RIGHT = 1 } ksMouseButton;

typedef enum {
    XCB_SIZE_HINT_US_POSITION = 1 << 0,
    XCB_SIZE_HINT_US_SIZE = 1 << 1,
    XCB_SIZE_HINT_P_POSITION = 1 << 2,
    XCB_SIZE_HINT_P_SIZE = 1 << 3,
    XCB_SIZE_HINT_P_MIN_SIZE = 1 << 4,
    XCB_SIZE_HINT_P_MAX_SIZE = 1 << 5,
    XCB_SIZE_HINT_P_RESIZE_INC = 1 << 6,
    XCB_SIZE_HINT_P_ASPECT = 1 << 7,
    XCB_SIZE_HINT_BASE_SIZE = 1 << 8,
    XCB_SIZE_HINT_P_WIN_GRAVITY = 1 << 9
} xcb_size_hints_flags_t;

static const int _NET_WM_STATE_ADD = 1;  // add/set property

/*
        Change video mode using the RandR X extension version 1.4

        The following code does not necessarily work out of the box, because on
        some configurations the modes list returned by XRRGetScreenResources()
        is populated with nothing other than the maximum display resolution,
        even though XF86VidModeGetAllModeLines() and XRRConfigSizes() *will*
        list all resolutions for the same display.

        The user can manually add new modes from the command-line using the
        xrandr utility:

        xrandr --newmode <modeline>

        Where <modeline> is generated with a utility that implements either
        the General Timing Formula (GTF) or the Coordinated Video Timing (CVT)
        standard put forth by the Video Electronics Standards Association (VESA):

        gft <width> <height> <Hz>	// http://gtf.sourceforge.net/
        cvt <width> <height> <Hz>	// http://www.uruk.org/~erich/projects/cvt/

        Alternatively, new modes can be added in code using XRRCreateMode().
        However, this requires calculating all the timing information in code
        because there is no standard library that implements the GTF or CVT.
*/
static bool ChangeVideoMode_XcbRandR_1_4(xcb_connection_t *connection, xcb_screen_t *screen, int *currentWidth, int *currentHeight,
                                         float *currentRefreshRate, int *desiredWidth, int *desiredHeight,
                                         float *desiredRefreshRate) {
    /*
            Screen	- virtual screenspace which may be covered by multiple CRTCs
            CRTC	- display controller
            Output	- display/monitor connected to a CRTC
            Clones	- outputs that are simultaneously connected to the same CRTC
    */

    xcb_randr_get_screen_resources_cookie_t screen_resources_cookie = xcb_randr_get_screen_resources(connection, screen->root);
    xcb_randr_get_screen_resources_reply_t *screen_resources_reply =
        xcb_randr_get_screen_resources_reply(connection, screen_resources_cookie, 0);
    if (screen_resources_reply == NULL) {
        return false;
    }

    xcb_randr_mode_info_t *mode_info = xcb_randr_get_screen_resources_modes(screen_resources_reply);
    const int modes_length = xcb_randr_get_screen_resources_modes_length(screen_resources_reply);
    assert(modes_length > 0);

    xcb_randr_crtc_t *crtcs = xcb_randr_get_screen_resources_crtcs(screen_resources_reply);
    const int crtcs_length = xcb_randr_get_screen_resources_crtcs_length(screen_resources_reply);
    assert(crtcs_length > 0);
    UNUSED_PARM(crtcs_length);

    const int PRIMARY_CRTC_INDEX = 0;
    const int PRIMARY_OUTPUT_INDEX = 0;

    xcb_randr_get_crtc_info_cookie_t primary_crtc_info_cookie = xcb_randr_get_crtc_info(connection, crtcs[PRIMARY_CRTC_INDEX], 0);
    xcb_randr_get_crtc_info_reply_t *primary_crtc_info_reply =
        xcb_randr_get_crtc_info_reply(connection, primary_crtc_info_cookie, NULL);

    xcb_randr_output_t *crtc_outputs = xcb_randr_get_crtc_info_outputs(primary_crtc_info_reply);

    xcb_randr_get_output_info_cookie_t primary_output_info_cookie =
        xcb_randr_get_output_info(connection, crtc_outputs[PRIMARY_OUTPUT_INDEX], 0);
    xcb_randr_get_output_info_reply_t *primary_output_info_reply =
        xcb_randr_get_output_info_reply(connection, primary_output_info_cookie, NULL);

    if (currentWidth != NULL && currentHeight != NULL && currentRefreshRate != NULL) {
        for (int i = 0; i < modes_length; i++) {
            if (mode_info[i].id == primary_crtc_info_reply->mode) {
                *currentWidth = mode_info[i].width;
                *currentHeight = mode_info[i].height;
                *currentRefreshRate = mode_info[i].dot_clock / ((float)mode_info[i].htotal * (float)mode_info[i].vtotal);
                break;
            }
        }
    }

    if (desiredWidth != NULL && desiredHeight != NULL && desiredRefreshRate != NULL) {
        xcb_randr_mode_t bestMode = 0;
        int bestModeWidth = 0;
        int bestModeHeight = 0;
        float bestModeRefreshRate = 0.0f;
        int bestSizeError = 0x7FFFFFFF;
        float bestRefreshRateError = 1e6f;
        for (int i = 0; i < modes_length; i++) {
            if (mode_info[i].mode_flags & XCB_RANDR_MODE_FLAG_INTERLACE) {
                continue;
            }

            xcb_randr_mode_t *primary_output_info_modes = xcb_randr_get_output_info_modes(primary_output_info_reply);
            int primary_output_info_modes_length = xcb_randr_get_output_info_modes_length(primary_output_info_reply);

            bool validOutputMode = false;
            for (int j = 0; j < primary_output_info_modes_length; j++) {
                if (mode_info[i].id == primary_output_info_modes[j]) {
                    validOutputMode = true;
                    break;
                }
            }
            if (!validOutputMode) {
                continue;
            }

            const int modeWidth = mode_info[i].width;
            const int modeHeight = mode_info[i].height;
            const float modeRefreshRate = mode_info[i].dot_clock / ((float)mode_info[i].htotal * (float)mode_info[i].vtotal);

            const int dw = modeWidth - *desiredWidth;
            const int dh = modeHeight - *desiredHeight;
            const int sizeError = dw * dw + dh * dh;
            const float refreshRateError = fabs(modeRefreshRate - *desiredRefreshRate);
            if (sizeError < bestSizeError || (sizeError == bestSizeError && refreshRateError < bestRefreshRateError)) {
                bestSizeError = sizeError;
                bestRefreshRateError = refreshRateError;
                bestMode = mode_info[i].id;
                bestModeWidth = modeWidth;
                bestModeHeight = modeHeight;
                bestModeRefreshRate = modeRefreshRate;
            }
        }

        xcb_randr_output_t *primary_crtc_info_outputs = xcb_randr_get_crtc_info_outputs(primary_crtc_info_reply);
        int primary_crtc_info_outputs_length = xcb_randr_get_crtc_info_outputs_length(primary_crtc_info_reply);

        xcb_randr_set_crtc_config(connection, primary_output_info_reply->crtc, XCB_TIME_CURRENT_TIME, XCB_TIME_CURRENT_TIME,
                                  primary_crtc_info_reply->x, primary_crtc_info_reply->y, bestMode,
                                  primary_crtc_info_reply->rotation, primary_crtc_info_outputs_length, primary_crtc_info_outputs);

        *desiredWidth = bestModeWidth;
        *desiredHeight = bestModeHeight;
        *desiredRefreshRate = bestModeRefreshRate;
    }

    free(primary_output_info_reply);
    free(primary_crtc_info_reply);
    free(screen_resources_reply);

    return true;
}

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);

#if defined(OS_LINUX_XCB_GLX)
    glXDestroyWindow(window->xDisplay, window->glxWindow);
    XFlush(window->xDisplay);
    XCloseDisplay(window->xDisplay);
    window->xDisplay = NULL;
#else
    xcb_glx_delete_window(window->connection, window->glxWindow);
#endif

    if (window->windowFullscreen) {
        ChangeVideoMode_XcbRandR_1_4(window->connection, window->screen, NULL, NULL, NULL, &window->desktopWidth,
                                     &window->desktopHeight, &window->desktopRefreshRate);
    }

    xcb_destroy_window(window->connection, window->window);
    xcb_free_colormap(window->connection, window->colormap);
    xcb_flush(window->connection);
    xcb_disconnect(window->connection);
    xcb_key_symbols_free(window->key_symbols);
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;

    const char *displayName = NULL;
    int screen_number = 0;
    window->connection = xcb_connect(displayName, &screen_number);
    if (xcb_connection_has_error(window->connection)) {
        ksGpuWindow_Destroy(window);
        Error("Failed to open XCB connection.");
        return false;
    }

    const xcb_setup_t *setup = xcb_get_setup(window->connection);
    xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
    for (int i = 0; i < screen_number; i++) {
        xcb_screen_next(&iter);
    }
    window->screen = iter.data;

    if (window->windowFullscreen) {
        ChangeVideoMode_XcbRandR_1_4(window->connection, window->screen, &window->desktopWidth, &window->desktopHeight,
                                     &window->desktopRefreshRate, &window->windowWidth, &window->windowHeight,
                                     &window->windowRefreshRate);
    } else {
        ChangeVideoMode_XcbRandR_1_4(window->connection, window->screen, &window->desktopWidth, &window->desktopHeight,
                                     &window->desktopRefreshRate, NULL, NULL, NULL);
        window->windowRefreshRate = window->desktopRefreshRate;
    }

    ksGpuDevice_Create(&window->device, instance, queueInfo);
#if defined(OS_LINUX_XCB_GLX)
    window->xDisplay = XOpenDisplay(displayName);
    ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
                                  window->xDisplay, screen_number);
#else
    ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
                                  window->connection, screen_number);
#endif

    // Create the color map.
    window->colormap = xcb_generate_id(window->connection);
    xcb_create_colormap(window->connection, XCB_COLORMAP_ALLOC_NONE, window->colormap, window->screen->root,
                        window->context.visualid);

    // Create the window.
    uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
    uint32_t value_list[5];
    value_list[0] = window->screen->black_pixel;
    value_list[1] = 0;
    value_list[2] = XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_BUTTON_PRESS;
    value_list[3] = window->colormap;
    value_list[4] = 0;

    window->window = xcb_generate_id(window->connection);
    xcb_create_window(window->connection,             // xcb_connection_t *	connection
                      XCB_COPY_FROM_PARENT,           // uint8_t				depth
                      window->window,                 // xcb_window_t			wid
                      window->screen->root,           // xcb_window_t			parent
                      0,                              // int16_t				x
                      0,                              // int16_t				y
                      window->windowWidth,            // uint16_t				width
                      window->windowHeight,           // uint16_t				height
                      0,                              // uint16_t				border_width
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,  // uint16_t				_class
                      window->context.visualid,       // xcb_visualid_t		visual
                      value_mask,                     // uint32_t				value_mask
                      value_list);                    // const uint32_t *		value_list

    // Change the window title.
    xcb_change_property(window->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
                        strlen(WINDOW_TITLE), WINDOW_TITLE);

    // Setup code that will send a notification when the window is destroyed.
    xcb_intern_atom_cookie_t wm_protocols_cookie = xcb_intern_atom(window->connection, 1, 12, "WM_PROTOCOLS");
    xcb_intern_atom_cookie_t wm_delete_window_cookie = xcb_intern_atom(window->connection, 0, 16, "WM_DELETE_WINDOW");
    xcb_intern_atom_reply_t *wm_protocols_reply = xcb_intern_atom_reply(window->connection, wm_protocols_cookie, 0);
    xcb_intern_atom_reply_t *wm_delete_window_reply = xcb_intern_atom_reply(window->connection, wm_delete_window_cookie, 0);

    window->wm_delete_window_atom = wm_delete_window_reply->atom;
    xcb_change_property(window->connection, XCB_PROP_MODE_REPLACE, window->window, wm_protocols_reply->atom, XCB_ATOM_ATOM, 32, 1,
                        &wm_delete_window_reply->atom);

    free(wm_protocols_reply);
    free(wm_delete_window_reply);

    if (window->windowFullscreen) {
        // Change the window to fullscreen
        xcb_intern_atom_cookie_t wm_state_cookie = xcb_intern_atom(window->connection, 0, 13, "_NET_WM_STATE");
        xcb_intern_atom_cookie_t wm_state_fullscreen_cookie =
            xcb_intern_atom(window->connection, 0, 24, "_NET_WM_STATE_FULLSCREEN");
        xcb_intern_atom_reply_t *wm_state_reply = xcb_intern_atom_reply(window->connection, wm_state_cookie, 0);
        xcb_intern_atom_reply_t *wm_state_fullscreen_reply =
            xcb_intern_atom_reply(window->connection, wm_state_fullscreen_cookie, 0);

        xcb_client_message_event_t ev;
        ev.response_type = XCB_CLIENT_MESSAGE;
        ev.format = 32;
        ev.sequence = 0;
        ev.window = window->window;
        ev.type = wm_state_reply->atom;
        ev.data.data32[0] = _NET_WM_STATE_ADD;
        ev.data.data32[1] = wm_state_fullscreen_reply->atom;
        ev.data.data32[2] = XCB_ATOM_NONE;
        ev.data.data32[3] = 0;
        ev.data.data32[4] = 0;

        xcb_send_event(window->connection, 1, window->window,
                       XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)(&ev));

        free(wm_state_reply);
        free(wm_state_fullscreen_reply);

        xcb_map_window(window->connection, window->window);
        xcb_flush(window->connection);
    } else {
        // Make the window fixed size.
        xcb_size_hints_t hints;
        memset(&hints, 0, sizeof(hints));
        hints.flags = XCB_SIZE_HINT_US_SIZE | XCB_SIZE_HINT_P_SIZE | XCB_SIZE_HINT_P_MIN_SIZE | XCB_SIZE_HINT_P_MAX_SIZE;
        hints.min_width = window->windowWidth;
        hints.max_width = window->windowWidth;
        hints.min_height = window->windowHeight;
        hints.max_height = window->windowHeight;

        xcb_change_property(window->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NORMAL_HINTS,
                            XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) / 4, &hints);

        // First map the window and then center the window on the screen.
        xcb_map_window(window->connection, window->window);
        const uint32_t coords[] = {(window->desktopWidth - window->windowWidth) / 2,
                                   (window->desktopHeight - window->windowHeight) / 2};
        xcb_configure_window(window->connection, window->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
        xcb_flush(window->connection);
    }

    window->key_symbols = xcb_key_symbols_alloc(window->connection);

#if defined(OS_LINUX_XCB_GLX)
    window->glxWindow = glXCreateWindow(window->xDisplay, window->context.glxFBConfig, window->window, NULL);
#else
    window->glxWindow = xcb_generate_id(window->connection);
    xcb_glx_create_window(window->connection, screen_number, window->context.fbconfigid, window->window, window->glxWindow, 0,
                          NULL);
#endif

    window->context.glxDrawable = window->glxWindow;

    ksGpuContext_SetCurrent(&window->context);

    gladLoaderLoadGL();

    return true;
}

#elif defined(OS_LINUX_WAYLAND)

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
static void _keyboard_keymap_cb(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { close(fd); }
static void _keyboard_modifiers_cb(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed,
                                   uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {}

static void _keyboard_enter_cb(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface,
                               struct wl_array *keys) {}

static void _keyboard_leave_cb(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {}

static void _pointer_leave_cb(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {}

static void _pointer_enter_cb(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
                              wl_fixed_t sy) {
    wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
}

static void _pointer_motion_cb(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
    ksGpuWindow *window = (ksGpuWindow *)data;
    window->input.mouseInputX[0] = wl_fixed_to_int(x);
    window->input.mouseInputY[0] = wl_fixed_to_int(y);
}

static void _pointer_button_cb(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button,
                               uint32_t state) {
    ksGpuWindow *window = (ksGpuWindow *)data;

    uint32_t button_id = 0;
    switch (button) {
        case BTN_LEFT:
            button_id = 0;
            break;
        case BTN_MIDDLE:
            button_id = 1;
            break;
        case BTN_RIGHT:
            button_id = 2;
            break;
    }

    window->input.mouseInput[button_id] = state;
}

static void _pointer_axis_cb(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {}

static void _keyboard_key_cb(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key,
                             uint32_t state) {
    ksGpuWindow *window = (ksGpuWindow *)data;
    if (key == KEY_ESC) window->windowExit = true;

    if (state) window->input.keyInput[key] = state;
}

const struct wl_pointer_listener pointer_listener = {
    _pointer_enter_cb, _pointer_leave_cb, _pointer_motion_cb, _pointer_button_cb, _pointer_axis_cb,
};

const struct wl_keyboard_listener keyboard_listener = {
    _keyboard_keymap_cb, _keyboard_enter_cb, _keyboard_leave_cb, _keyboard_key_cb, _keyboard_modifiers_cb,
};

static void _seat_capabilities_cb(void *data, struct wl_seat *seat, uint32_t caps) {
    ksGpuWindow *window = (ksGpuWindow *)data;
    if ((caps & WL_SEAT_CAPABILITY_POINTER) && !window->pointer) {
        window->pointer = wl_seat_get_pointer(seat);
        wl_pointer_add_listener(window->pointer, &pointer_listener, window);
    } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && window->pointer) {
        wl_pointer_destroy(window->pointer);
        window->pointer = NULL;
    }

    if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !window->keyboard) {
        window->keyboard = wl_seat_get_keyboard(seat);
        wl_keyboard_add_listener(window->keyboard, &keyboard_listener, window);
    } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && window->keyboard) {
        wl_keyboard_destroy(window->keyboard);
        window->keyboard = NULL;
    }
}

const struct wl_seat_listener seat_listener = {
    _seat_capabilities_cb,
};

static void _xdg_surface_configure_cb(void *data, struct zxdg_surface_v6 *surface, uint32_t serial) {
    zxdg_surface_v6_ack_configure(surface, serial);
}

const struct zxdg_surface_v6_listener xdg_surface_listener = {
    _xdg_surface_configure_cb,
};

static void _xdg_shell_ping_cb(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) { zxdg_shell_v6_pong(shell, serial); }

const struct zxdg_shell_v6_listener xdg_shell_listener = {
    _xdg_shell_ping_cb,
};

static void _xdg_toplevel_configure_cb(void *data, struct zxdg_toplevel_v6 *toplevel, int32_t width, int32_t height,
                                       struct wl_array *states) {
    ksGpuWindow *window = (ksGpuWindow *)data;

    window->windowActive = false;

    enum zxdg_toplevel_v6_state *state;
    wl_array_for_each(state, states) {
        switch (*state) {
            case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
                break;
            case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
                window->windowWidth = width;
                window->windowWidth = height;
                break;
            case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
                break;
            case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
                window->windowActive = true;
                break;
        }
    }
}

static void _xdg_toplevel_close_cb(void *data, struct zxdg_toplevel_v6 *toplevel) {
    ksGpuWindow *window = (ksGpuWindow *)data;
    window->windowExit = true;
}

const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
    _xdg_toplevel_configure_cb,
    _xdg_toplevel_close_cb,
};

static void _registry_cb(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) {
    ksGpuWindow *window = (ksGpuWindow *)data;

    if (strcmp(interface, "wl_compositor") == 0) {
        window->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
    } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
        window->shell = wl_registry_bind(registry, id, &zxdg_shell_v6_interface, 1);
        zxdg_shell_v6_add_listener(window->shell, &xdg_shell_listener, NULL);
    } else if (strcmp(interface, "wl_seat") == 0) {
        window->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
        wl_seat_add_listener(window->seat, &seat_listener, window);
    }
}

static void _registry_remove_cb(void *data, struct wl_registry *registry, uint32_t id) {}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

const struct wl_registry_listener registry_listener = {_registry_cb, _registry_remove_cb};

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
    (void)queueIndex;
    memset(window, 0, sizeof(ksGpuWindow));

    window->display = NULL;
    window->surface = NULL;
    window->registry = NULL;
    window->compositor = NULL;
    window->shell = NULL;
    window->shell_surface = NULL;

    window->keyboard = NULL;
    window->pointer = NULL;
    window->seat = NULL;

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;

    window->display = wl_display_connect(NULL);
    if (window->display == NULL) {
        Error("Can't connect to wayland display.");
        return false;
    }

    window->registry = wl_display_get_registry(window->display);
    wl_registry_add_listener(window->registry, &registry_listener, window);

    wl_display_roundtrip(window->display);

    if (window->compositor == NULL) {
        Error("Compositor protocol failed to bind");
        return false;
    }

    if (window->shell == NULL) {
        Error("Compositor is missing support for zxdg_shell_v6.");
        return false;
    }

    window->surface = wl_compositor_create_surface(window->compositor);
    if (window->surface == NULL) {
        Error("Could not create compositor surface.");
        return false;
    }

    window->shell_surface = zxdg_shell_v6_get_xdg_surface(window->shell, window->surface);
    if (window->shell_surface == NULL) {
        Error("Could not get shell surface.");
        return false;
    }

    zxdg_surface_v6_add_listener(window->shell_surface, &xdg_surface_listener, window);

    struct zxdg_toplevel_v6 *toplevel = zxdg_surface_v6_get_toplevel(window->shell_surface);
    if (toplevel == NULL) {
        Error("Could not get surface toplevel.");
        return false;
    }

    zxdg_toplevel_v6_add_listener(toplevel, &xdg_toplevel_listener, window);

    zxdg_toplevel_v6_set_title(toplevel, WINDOW_TITLE);
    zxdg_toplevel_v6_set_app_id(toplevel, APPLICATION_NAME);
    zxdg_toplevel_v6_set_min_size(toplevel, width, height);
    zxdg_toplevel_v6_set_max_size(toplevel, width, height);

    wl_surface_commit(window->surface);

    window->context.native_window = wl_egl_window_create(window->surface, width, height);

    if (window->context.native_window == EGL_NO_SURFACE) {
        ksGpuWindow_Destroy(window);
        Error("Could not create wayland egl window.");
        return false;
    }

    ksGpuDevice_Create(&window->device, instance, queueInfo);

    ksGpuContext_CreateForSurface(&window->context, &window->device, window->display);

    ksGpuContext_SetCurrent(&window->context);

    gladLoaderLoadGL();

    return true;
}

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    if (window->pointer != NULL) wl_pointer_destroy(window->pointer);
    if (window->keyboard != NULL) wl_keyboard_destroy(window->keyboard);
    if (window->seat != NULL) wl_seat_destroy(window->seat);

    wl_egl_window_destroy(window->context.native_window);

    if (window->compositor != NULL) wl_compositor_destroy(window->compositor);
    if (window->registry != NULL) wl_registry_destroy(window->registry);
    if (window->shell_surface != NULL) zxdg_surface_v6_destroy(window->shell_surface);
    if (window->shell != NULL) zxdg_shell_v6_destroy(window->shell);
    if (window->surface != NULL) wl_surface_destroy(window->surface);
    if (window->display != NULL) wl_display_disconnect(window->display);

    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);
}

/*
 * TODO:
 * This is a work around for ksKeyboardKey naming collision
 * with the definitions from <linux/input.h>.
 * The proper fix for this is to rename the key enums.
 */

#undef KEY_A
#undef KEY_B
#undef KEY_C
#undef KEY_D
#undef KEY_E
#undef KEY_F
#undef KEY_G
#undef KEY_H
#undef KEY_I
#undef KEY_J
#undef KEY_K
#undef KEY_L
#undef KEY_M
#undef KEY_N
#undef KEY_O
#undef KEY_P
#undef KEY_Q
#undef KEY_R
#undef KEY_S
#undef KEY_T
#undef KEY_U
#undef KEY_V
#undef KEY_W
#undef KEY_X
#undef KEY_Y
#undef KEY_Z
#undef KEY_TAB

typedef enum  // from <linux/input.h>
{ KEY_A = 30,
  KEY_B = 48,
  KEY_C = 46,
  KEY_D = 32,
  KEY_E = 18,
  KEY_F = 33,
  KEY_G = 34,
  KEY_H = 35,
  KEY_I = 23,
  KEY_J = 36,
  KEY_K = 37,
  KEY_L = 38,
  KEY_M = 50,
  KEY_N = 49,
  KEY_O = 24,
  KEY_P = 25,
  KEY_Q = 16,
  KEY_R = 19,
  KEY_S = 31,
  KEY_T = 20,
  KEY_U = 22,
  KEY_V = 47,
  KEY_W = 17,
  KEY_X = 45,
  KEY_Y = 21,
  KEY_Z = 44,
  KEY_TAB = 15,
  KEY_RETURN = KEY_ENTER,
  KEY_ESCAPE = KEY_ESC,
  KEY_SHIFT_LEFT = KEY_LEFTSHIFT,
  KEY_CTRL_LEFT = KEY_LEFTCTRL,
  KEY_ALT_LEFT = KEY_LEFTALT,
  KEY_CURSOR_UP = KEY_UP,
  KEY_CURSOR_DOWN = KEY_DOWN,
  KEY_CURSOR_LEFT = KEY_LEFT,
  KEY_CURSOR_RIGHT = KEY_RIGHT } ksKeyboardKey;

typedef enum { MOUSE_LEFT = BTN_LEFT, MOUSE_MIDDLE = BTN_MIDDLE, MOUSE_RIGHT = BTN_RIGHT } ksMouseButton;

#elif defined(OS_APPLE_MACOS)

typedef enum {
    KEY_A = 0x00,
    KEY_B = 0x0B,
    KEY_C = 0x08,
    KEY_D = 0x02,
    KEY_E = 0x0E,
    KEY_F = 0x03,
    KEY_G = 0x05,
    KEY_H = 0x04,
    KEY_I = 0x22,
    KEY_J = 0x26,
    KEY_K = 0x28,
    KEY_L = 0x25,
    KEY_M = 0x2E,
    KEY_N = 0x2D,
    KEY_O = 0x1F,
    KEY_P = 0x23,
    KEY_Q = 0x0C,
    KEY_R = 0x0F,
    KEY_S = 0x01,
    KEY_T = 0x11,
    KEY_U = 0x20,
    KEY_V = 0x09,
    KEY_W = 0x0D,
    KEY_X = 0x07,
    KEY_Y = 0x10,
    KEY_Z = 0x06,
    KEY_RETURN = 0x24,
    KEY_TAB = 0x30,
    KEY_ESCAPE = 0x35,
    KEY_SHIFT_LEFT = 0x38,
    KEY_CTRL_LEFT = 0x3B,
    KEY_ALT_LEFT = 0x3A,
    KEY_CURSOR_UP = 0x7E,
    KEY_CURSOR_DOWN = 0x7D,
    KEY_CURSOR_LEFT = 0x7B,
    KEY_CURSOR_RIGHT = 0x7C
} ksKeyboardKey;

typedef enum { MOUSE_LEFT = 0, MOUSE_RIGHT = 1 } ksMouseButton;

NSAutoreleasePool *autoReleasePool;

@interface MyNSWindow : NSWindow
- (BOOL)canBecomeMainWindow;
- (BOOL)canBecomeKeyWindow;
- (BOOL)acceptsFirstResponder;
- (void)keyDown:(NSEvent *)event;
@end

@implementation MyNSWindow
- (BOOL)canBecomeMainWindow {
    return YES;
}
- (BOOL)canBecomeKeyWindow {
    return YES;
}
- (BOOL)acceptsFirstResponder {
    return YES;
}
- (void)keyDown:(NSEvent *)event {
    (void)event;
}
@end

@interface MyNSView : NSView
- (BOOL)acceptsFirstResponder;
- (void)keyDown:(NSEvent *)event;
@end

@implementation MyNSView
- (BOOL)acceptsFirstResponder {
    return YES;
}
- (void)keyDown:(NSEvent *)event {
    (void)event;
}
@end

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);

    if (window->windowFullscreen) {
        CGDisplaySetDisplayMode(window->display, window->desktopDisplayMode, NULL);
        CGDisplayModeRelease(window->desktopDisplayMode);
        window->desktopDisplayMode = NULL;
    }
    if (window->nsWindow) {
        [window->nsWindow release];
        window->nsWindow = nil;
    }
    if (window->nsView) {
        [window->nsView release];
        window->nsView = nil;
    }
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;

    // Get a list of all available displays.
    CGDirectDisplayID displays[32];
    CGDisplayCount displayCount = 0;
    CGDisplayErr err = CGGetActiveDisplayList(32, displays, &displayCount);
    if (err != CGDisplayNoErr) {
        return false;
    }
    // Use the main display.
    window->display = displays[0];
    window->desktopDisplayMode = CGDisplayCopyDisplayMode(window->display);

    // If fullscreen then switch to the best matching display mode.
    if (window->windowFullscreen) {
        CFArrayRef displayModes = CGDisplayCopyAllDisplayModes(window->display, NULL);
        CFIndex displayModeCount = CFArrayGetCount(displayModes);
        CGDisplayModeRef bestDisplayMode = nil;
        size_t bestDisplayWidth = 0;
        size_t bestDisplayHeight = 0;
        float bestDisplayRefreshRate = 0;
        size_t bestError = 0x7FFFFFFF;
        for (CFIndex i = 0; i < displayModeCount; i++) {
            CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(displayModes, i);

            const size_t modeWidth = CGDisplayModeGetWidth(mode);
            const size_t modeHeight = CGDisplayModeGetHeight(mode);
            const double modeRefreshRate = CGDisplayModeGetRefreshRate(mode);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
            CFStringRef modePixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
#pragma GCC diagnostic pop
            const bool modeBitsPerPixelIs32 =
                (CFStringCompare(modePixelEncoding, CFSTR(IO32BitDirectPixels), 0) == kCFCompareEqualTo);
            CFRelease(modePixelEncoding);

            if (modeBitsPerPixelIs32) {
                const size_t dw = modeWidth - width;
                const size_t dh = modeHeight - height;
                const size_t error = dw * dw + dh * dh;
                if (error < bestError) {
                    bestError = error;
                    bestDisplayMode = mode;
                    bestDisplayWidth = modeWidth;
                    bestDisplayHeight = modeHeight;
                    bestDisplayRefreshRate = (float)modeRefreshRate;
                }
            }
        }
        CGDisplayErr cgderr = CGDisplaySetDisplayMode(window->display, bestDisplayMode, NULL);
        if (cgderr != CGDisplayNoErr) {
            CFRelease(displayModes);
            return false;
        }
        CFRelease(displayModes);
        window->windowWidth = (int)bestDisplayWidth;
        window->windowHeight = (int)bestDisplayHeight;
        window->windowRefreshRate = (bestDisplayRefreshRate > 0.0f) ? bestDisplayRefreshRate : 60.0f;
    } else {
        const float desktopDisplayRefreshRate = (float)CGDisplayModeGetRefreshRate(window->desktopDisplayMode);
        window->windowRefreshRate = (desktopDisplayRefreshRate > 0.0f) ? desktopDisplayRefreshRate : 60.0f;
    }

    if (window->windowFullscreen) {
        NSScreen *screen = [NSScreen mainScreen];
        NSRect screenRect = [screen frame];

        window->nsView = [MyNSView alloc];
        [window->nsView initWithFrame:screenRect];

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        const int style = NSBorderlessWindowMask;
#pragma GCC diagnostic pop

        window->nsWindow = [MyNSWindow alloc];
        [window->nsWindow initWithContentRect:screenRect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
        [window->nsWindow setOpaque:YES];
        [window->nsWindow setLevel:NSMainMenuWindowLevel + 1];
        [window->nsWindow setContentView:window->nsView];
        [window->nsWindow makeMainWindow];
        [window->nsWindow makeKeyAndOrderFront:nil];
        [window->nsWindow makeFirstResponder:nil];
    } else {
        NSScreen *screen = [NSScreen mainScreen];
        NSRect screenRect = [screen frame];

        NSRect windowRect;
        windowRect.origin.x = (screenRect.size.width - width) / 2;
        windowRect.origin.y = (screenRect.size.height - height) / 2;
        windowRect.size.width = width;
        windowRect.size.height = height;

        window->nsView = [MyNSView alloc];
        [window->nsView initWithFrame:windowRect];

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        // Fixed size window.
        const int style = NSTitledWindowMask;  // | NSClosableWindowMask | NSResizableWindowMask;
#pragma GCC diagnostic pop

        window->nsWindow = [MyNSWindow alloc];
        [window->nsWindow initWithContentRect:windowRect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
        [window->nsWindow setTitle:@WINDOW_TITLE];
        [window->nsWindow setOpaque:YES];
        [window->nsWindow setContentView:window->nsView];
        [window->nsWindow makeMainWindow];
        [window->nsWindow makeKeyAndOrderFront:nil];
        [window->nsWindow makeFirstResponder:nil];
    }

    ksGpuDevice_Create(&window->device, instance, queueInfo);
    ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
                                  window->display);

    [window->context.nsContext setView:window->nsView];

    ksGpuContext_SetCurrent(&window->context);

    gladLoaderLoadGL();

    // The color buffers are not cleared by default.
    for (int i = 0; i < 2; i++) {
        GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
        GL(glClear(GL_COLOR_BUFFER_BIT));
        CGLFlushDrawable(window->context.cglContext);
    }

    return true;
}

#elif defined(OS_APPLE_IOS)

typedef enum {
    KEY_A = 0x00,
    KEY_B = 0x0B,
    KEY_C = 0x08,
    KEY_D = 0x02,
    KEY_E = 0x0E,
    KEY_F = 0x03,
    KEY_G = 0x05,
    KEY_H = 0x04,
    KEY_I = 0x22,
    KEY_J = 0x26,
    KEY_K = 0x28,
    KEY_L = 0x25,
    KEY_M = 0x2E,
    KEY_N = 0x2D,
    KEY_O = 0x1F,
    KEY_P = 0x23,
    KEY_Q = 0x0C,
    KEY_R = 0x0F,
    KEY_S = 0x01,
    KEY_T = 0x11,
    KEY_U = 0x20,
    KEY_V = 0x09,
    KEY_W = 0x0D,
    KEY_X = 0x07,
    KEY_Y = 0x10,
    KEY_Z = 0x06,
    KEY_RETURN = 0x24,
    KEY_TAB = 0x30,
    KEY_ESCAPE = 0x35,
    KEY_SHIFT_LEFT = 0x38,
    KEY_CTRL_LEFT = 0x3B,
    KEY_ALT_LEFT = 0x3A,
    KEY_CURSOR_UP = 0x7E,
    KEY_CURSOR_DOWN = 0x7D,
    KEY_CURSOR_LEFT = 0x7B,
    KEY_CURSOR_RIGHT = 0x7C
} ksKeyboardKey;

typedef enum { MOUSE_LEFT = 0, MOUSE_RIGHT = 1 } ksMouseButton;

static UIView *myUIView;
static UIWindow *myUIWindow;

@interface MyUIView : UIView
@end

@implementation MyUIView

- (instancetype)initWithFrame:(CGRect)frameRect {
    self = [super initWithFrame:frameRect];
    if (self) {
        self.contentScaleFactor = UIScreen.mainScreen.nativeScale;
    }
    return self;
}

+ (Class)layerClass {
    return [CAEAGLLayer class];
}

@end

@interface MyUIViewController : UIViewController
@end

@implementation MyUIViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return TRUE;
}

@end

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);
    window->uiWindow = nil;
    window->uiView = nil;
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = fullscreen;
    window->windowActive = false;
    window->windowExit = false;
    window->uiView = myUIView;
    window->uiWindow = myUIWindow;

    ksGpuDevice_Create(&window->device, instance, queueInfo);
    // ksGpuContext_CreateForSurface(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount,
    //                              window->display);

    return true;
}

#elif defined(OS_ANDROID)

void ksGpuWindow_Destroy(ksGpuWindow *window) {
    ksGpuContext_Destroy(&window->context);
    ksGpuDevice_Destroy(&window->device);
}

bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex,
                        const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                        const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) {
#ifdef XR_USE_PLATFORM_EGL
    return ksGpuWindow_CreateEGL(window, instance, queueInfo, queueIndex, colorFormat, depthFormat, sampleCount, width, height,
                                 fullscreen);
#else
    return false;
#endif
}

#endif

#ifdef XR_USE_PLATFORM_EGL

static bool ksGpuContext_CreateForSurfaceEGL(ksGpuContext *context, const ksGpuDevice *device, const int queueIndex,
                                             const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat,
                                             const ksGpuSampleCount sampleCount, EGLDisplay dpy) {
    (void)sampleCount;
    context->device = device;
    context->dpy = dpy;

    // clang-format off
    EGLint glesContextAttribs[] = {
        EGL_CONTEXT_CLIENT_VERSION, OPENGLES_VERSION_MAJOR,
        EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
        EGL_NONE,
    };
    // clang-format on
    // Use the default priority if KS_GPU_QUEUE_PRIORITY_MEDIUM is selected.
    const ksGpuQueuePriority priority = device->queueInfo.queuePriorities[queueIndex];
    if (priority != KS_GPU_QUEUE_PRIORITY_MEDIUM) {
        glesContextAttribs[3] =
            (priority == KS_GPU_QUEUE_PRIORITY_LOW) ? EGL_CONTEXT_PRIORITY_LOW_IMG : EGL_CONTEXT_PRIORITY_HIGH_IMG;
    }

    const ksGpuSurfaceBits bits = ksGpuContext_BitsForSurfaceFormat(colorFormat, depthFormat);

    // clang-format off
    const EGLint configAttribs[] = {
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
        EGL_RED_SIZE, bits.redBits,
        EGL_GREEN_SIZE, bits.greenBits,
        EGL_BLUE_SIZE, bits.blueBits,
        EGL_ALPHA_SIZE, bits.alphaBits,
        EGL_NONE,
    };
    // clang-format on

    EGLConfig config = 0;
    EGLint numConfigs;
    EGL(eglChooseConfig(context->dpy, configAttribs, &config, 1, &numConfigs));

    context->ctx = eglCreateContext(context->dpy, config, EGL_NO_CONTEXT, glesContextAttribs);
    if (context->ctx == EGL_NO_CONTEXT) {
        Error("eglCreateContext() failed: %s", EglErrorString(eglGetError()));
        return false;
    }

    EGL(eglBindAPI(EGL_OPENGL_ES_API));

    return true;
}

bool ksGpuWindow_CreateEGL(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, int queueIndex,
                           ksGpuSurfaceColorFormat colorFormat, ksGpuSurfaceDepthFormat depthFormat, ksGpuSampleCount sampleCount,
                           int width, int height, bool fullscreen) {
    memset(window, 0, sizeof(ksGpuWindow));
    (void)fullscreen;

    window->colorFormat = colorFormat;
    window->depthFormat = depthFormat;
    window->sampleCount = sampleCount;
    window->windowWidth = width;
    window->windowHeight = height;
    window->windowSwapInterval = 1;
    window->windowRefreshRate = 60.0f;
    window->windowFullscreen = true;
    window->windowActive = false;
    window->windowExit = false;

    int eglVersion = gladLoaderLoadEGL(EGL_DEFAULT_DISPLAY);
    if (!eglVersion) {
        Error("Failed to load EGL");
        return false;
    }

    printf("Loaded EGL %d.%d on first load\n", GLAD_VERSION_MAJOR(eglVersion), GLAD_VERSION_MINOR(eglVersion));

    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    EGL(eglInitialize(dpy, NULL, NULL));

    // need second load now that EGL is initialized - bootstrapping problem
    eglVersion = gladLoaderLoadEGL(dpy);
    if (!eglVersion) {
        Error("Failed to reload EGL\n");
        return false;
    }

    printf("Loaded EGL %d.%d after reload.\n", GLAD_VERSION_MAJOR(eglVersion), GLAD_VERSION_MINOR(eglVersion));

    ksGpuDevice_Create(&window->device, instance, queueInfo);
    ksGpuContext_CreateForSurfaceEGL(&window->context, &window->device, queueIndex, colorFormat, depthFormat, sampleCount, dpy);

    ksGpuContext_SetCurrent(&window->context);

#if defined(OS_ANDROID)
    gladLoaderLoadGLES2();
#else
    return false;
#endif
    return true;
}

#endif
