├── .github └── workflows │ └── build.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── inc ├── client │ ├── glimpl.h │ ├── memory.h │ ├── pb.h │ ├── platform │ │ ├── egl.h │ │ ├── gldrv.h │ │ ├── glx.h │ │ ├── icd.h │ │ ├── wgl.h │ │ └── windrv.h │ ├── scratch.h │ └── spinlock.h ├── commongl.h ├── lzav.h ├── network │ ├── LICENSE │ ├── enet.h │ └── packet.h ├── server │ ├── context.h │ ├── dynarr.h │ ├── overlay.h │ ├── overlay_font.h │ └── processor.h ├── sgldebug.h └── sharedgl.h ├── kernel ├── linux │ ├── Makefile │ ├── install.sh │ ├── sharedgl.c │ └── uninstall.sh └── windows │ ├── Device.c │ ├── Device.h │ ├── Driver.c │ ├── Driver.h │ ├── LICENSE │ ├── Public.h │ ├── Queue.c │ ├── Queue.h │ └── findwdk │ ├── FindWdk.cmake │ └── LICENSE ├── scripts ├── kcertify.bat ├── ksgldrv.inf ├── wininstall.bat └── winuninstall.bat └── src ├── client ├── glimpl.c ├── main.c ├── memory.c ├── pb.c ├── platform │ ├── egl.c │ ├── glx.c │ ├── wgl.c │ └── windrv.c ├── scratch.c ├── spinlock.c └── winmain.c └── server ├── context.c ├── dynarr.c ├── main.c ├── overlay.c ├── processor.c └── sgldebug.c /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build SharedGL for Linux and Windows 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | fail-fast: false 15 | 16 | matrix: 17 | os: [ubuntu-latest, windows-latest] 18 | build_type: [Release, RelWithDebInfo] 19 | c_compiler: [clang, cl] 20 | arch: [x64, Win32] 21 | include: 22 | - os: windows-latest 23 | c_compiler: cl 24 | cpp_compiler: cl 25 | arch: x64 26 | - os: windows-latest 27 | c_compiler: cl 28 | cpp_compiler: cl 29 | arch: Win32 30 | - os: ubuntu-latest 31 | c_compiler: clang 32 | cpp_compiler: clang++ 33 | exclude: 34 | - os: windows-latest 35 | c_compiler: clang 36 | - os: ubuntu-latest 37 | c_compiler: cl 38 | 39 | steps: 40 | - uses: actions/checkout@v3 41 | 42 | - name: Set reusable strings 43 | id: strings 44 | shell: bash 45 | run: | 46 | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" 47 | 48 | - name: Install dependenices 49 | if: matrix.os == 'ubuntu-latest' 50 | run: | 51 | sudo apt-get update && sudo apt-get install -y libepoxy-dev libsdl2-dev libx11-dev 52 | 53 | - name: Configure CMake for Linux 54 | if: matrix.os == 'ubuntu-latest' 55 | run: > 56 | cmake -B ${{ steps.strings.outputs.build-output-dir }} 57 | -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} 58 | -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} 59 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 60 | -S ${{ github.workspace }} 61 | 62 | - name: Configure CMake for Windows 63 | if: matrix.os == 'windows-latest' 64 | run: > 65 | cmake -B ${{ steps.strings.outputs.build-output-dir }} 66 | -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} 67 | -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} 68 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 69 | -DCMAKE_GENERATOR_PLATFORM=${{ matrix.arch }} 70 | -S ${{ github.workspace }} 71 | 72 | - name: Build 73 | run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(sharedgl VERSION 0.9.0 LANGUAGES C) 3 | 4 | include_directories(${CMAKE_SOURCE_DIR}/inc) 5 | 6 | # set(CMAKE_C_COMPILER "clang") 7 | 8 | option(LINUX_LIB32 "Compile 32-bit libGL. Does not affect server." OFF) 9 | 10 | IF(WIN32) 11 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 12 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gz") 13 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded" CACHE STRING "Select MSVC runtime library.") 14 | set_property(GLOBAL PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") 15 | ELSE() 16 | # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") 17 | ENDIF(WIN32) 18 | 19 | file(GLOB GLOBBED_SERVER_SOURCES CONFIGURE_DEPENDS "src/server/*.c" "src/network/*.c" "src/client/scratch.c") 20 | 21 | # client stuff 22 | IF(UNIX) 23 | file(GLOB GLOBBED_CLIENT_SOURCES CONFIGURE_DEPENDS "src/client/*.c" "src/network/*.c") 24 | file(GLOB GLOBBED_CLIENT_P_SOURCES CONFIGURE_DEPENDS "src/client/platform/*.c") 25 | ELSEIF(WIN32) 26 | file(GLOB GLOBBED_CLIENT_SOURCES CONFIGURE_DEPENDS "src/client/winmain.c" "src/client/pb.c" "src/client/spinlock.c" "src/client/glimpl.c" "src/client/scratch.c" "src/network/*.c") 27 | file(GLOB GLOBBED_CLIENT_P_SOURCES CONFIGURE_DEPENDS "src/client/platform/windrv.c") 28 | ENDIF(UNIX) 29 | 30 | # server 31 | IF(UNIX) 32 | add_executable(sglrenderer ${GLOBBED_SERVER_SOURCES}) 33 | target_link_libraries(sglrenderer SDL2 epoxy) 34 | ENDIF(UNIX) 35 | 36 | # client 37 | IF(UNIX) 38 | add_library(sharedgl-core SHARED ${GLOBBED_CLIENT_SOURCES} ${GLOBBED_CLIENT_P_SOURCES}) 39 | target_link_libraries(sharedgl-core X11) 40 | set_target_properties(sharedgl-core PROPERTIES OUTPUT_NAME "GL") 41 | set_target_properties(sharedgl-core PROPERTIES VERSION 1) 42 | IF(LINUX_LIB32) 43 | target_compile_options(sharedgl-core PRIVATE "-m32") 44 | target_link_options(sharedgl-core PRIVATE "-m32") 45 | ENDIF(LINUX_LIB32) 46 | ELSEIF(WIN32) 47 | add_library(sharedgl-core SHARED ${GLOBBED_CLIENT_SOURCES} ${GLOBBED_CLIENT_P_SOURCES}) 48 | IF(CMAKE_GENERATOR_PLATFORM MATCHES "Win32") 49 | set_target_properties(sharedgl-core PROPERTIES OUTPUT_NAME "sharedgl32") 50 | target_link_options(sharedgl-core PRIVATE /machine:x86) 51 | ELSE() 52 | set_target_properties(sharedgl-core PROPERTIES OUTPUT_NAME "sharedgl64") 53 | target_link_options(sharedgl-core PRIVATE /machine:x64) 54 | ENDIF() 55 | ENDIF(UNIX) 56 | 57 | # windows driver 58 | IF(WIN32 AND WINKERNEL) 59 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/kernel/windows/findwdk/") 60 | find_package(WDK REQUIRED) 61 | 62 | file(GLOB GLOBBED_KERNEL_SOURCES CONFIGURE_DEPENDS "kernel/windows/*.c") 63 | wdk_add_driver(ksgldrv KMDF 1.15 ${GLOBBED_KERNEL_SOURCES}) 64 | ENDIF(WIN32 AND WINKERNEL) 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 dmaivel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # SharedGL ![license](https://img.shields.io/badge/license-MIT-blue) 4 | 5 | SharedGL is an OpenGL 4.6 implementation that enables 3D acceleration for Windows and Linux guests within QEMU/KVM by streaming OpenGL commands over shared memory or sockets. 6 | 7 |
8 | Click to hide: Preview 9 | 10 | ![preview](https://github.com/user-attachments/assets/fbcd62ac-090d-4ad1-b37c-bd1f0432866a) 11 | 12 |
13 | 14 |
15 | Click to reveal: Table of contents 16 | 17 | 1. [Getting started](#getting-started) 18 | 2. [Usage](#usage) 19 | - [Environment variables](#environment-variables) 20 | - [Windows in a VM](#windows-in-a-vm) 21 | - [Linux (client debugging)](#linux) 22 | - [Linux in a VM](#linux-in-a-vm) 23 | 3. [Networking](#networking) 24 | 4. [Known issues](#known-issues) 25 | 5. [Troubleshooting](#troubleshooting) 26 | 6. [Showcase](#showcase) 27 | 28 |
29 | 30 | # Getting started 31 | 32 | ## Dependencies 33 | 34 | | Name | Version | 35 | | ---- | ------- | 36 | | [CMake](https://cmake.org/) | 3.15+ | 37 | | [libepoxy](https://github.com/anholt/libepoxy) | Latest | 38 | | [SDL2](https://www.libsdl.org/) | 2.24.0+ | 39 | 40 | ## Building 41 | 42 | ```bash 43 | git clone https://github.com/dmaivel/sharedgl.git 44 | cd sharedgl 45 | mkdir build 46 | cd build 47 | cmake .. 48 | cmake --build . --target sglrenderer --config Release 49 | ``` 50 | 51 | If you also wish to build the client library `libGL` for Linux, `libx11` is required. Build with `--target sharedgl-core`. 52 | 53 | For detailed build instructions for Windows, visit the [Windows section](#windows-in-a-vm). The renderer/server is only supported on Linux hosts. 54 | 55 | ### Build options 56 | 57 | These CMake options are accessible by either: 58 | 1. Using `ccmake` on `build` folder 59 | 2. Configuring with `-D...` 60 | 61 | | **Option** | **Legal values** | **Default** | **Description** | 62 | |-|-|-|-| 63 | | LINUX_LIB32 | ON/OFF | OFF | Enable if you wish to build the Linux client library (libGL) as 32-bit. This does not affect the server. | 64 | 65 | # Usage 66 | The server must be started on the host before running any clients. Note that the server can only be ran on Linux. 67 | 68 | ```bash 69 | usage: sglrenderer [-h] [-v] [-o] [-n] [-x] [-g MAJOR.MINOR] [-r WIDTHxHEIGHT] [-m SIZE] [-p PORT] 70 | 71 | options: 72 | -h display help information 73 | -v display virtual machine arguments 74 | -o enables fps overlay on clients 75 | -n enable networking instead of shared memory 76 | -x remove shared memory file 77 | -g [MAJOR.MINOR] report specific opengl version (default: 4.6) 78 | -r [WIDTHxHEIGHT] set max resolution (default: 1920x1080) 79 | -m [SIZE] max amount of megabytes program may allocate (default: 32mib) 80 | -p [PORT] if networking is enabled, specify which port to use (default: 3000) 81 | ``` 82 | 83 | Your virtual machine must also be configured with a shared memory device *(unless you are using the sockets version, in which case see [networking](#networking))*. You can get the configurations from `sglrenderer` if you run it with `-v`. Sample configurations are provided below: 84 | 85 | **libvirt:** 86 | ```xml 87 | THIS IS A SAMPLE; ONLY USE THIS AS A GUIDE ON WHERE TO PLACE THE OUTPUT <--> 88 | ... 89 | 90 | ... 91 | 92 | 93 | ?? 94 | 95 | 96 | ``` 97 | 98 | **qemu:** 99 | ```bash 100 | # THIS IS A SAMPLE; ONLY USE THIS AS A GUIDE ON WHERE TO PLACE THE OUTPUT 101 | qemu-system-x86_64 -object memory-backend-file,size=??M,share,mem-path=/dev/shm/sharedgl_shared_memory,id=sharedgl_shared_memory 102 | ``` 103 | 104 | For installation of the client driver inside the virtual machine, refer to one of these: 105 | - [Windows as the guest](#windows-in-a-vm) 106 | - [Linux as the guest](#linux-in-a-vm) 107 | 108 | ### Environment variables 109 | 110 | Variables labeled with `host` get their values from the host/server when their override isn't set. 111 | 112 | | **Option** | **Legal values** | **Default** | **Description** | 113 | |-|-|-|-| 114 | | SGL_WINED3D_DONT_VFLIP | Boolean | false | If running a DirectX application via WineD3D, ensure this variable is set to `true` in order for the application to render the framebuffer in the proper orientation. Only available for Windows clients. | 115 | | SGL_NETWORK_ENDPOINT | Ip:Port | | If networking is enabled, this environment variable must exist on the guest. Available for both Windows and Linux clients. | 116 | | SGL_RUN_WITH_LOW_PRIORITY | Boolean | false | Potentially improve performance by setting the process priority to low / `IDLE_PRIORITY_CLASS`; applications will run smoother as the kernel is given more CPU time. This benefits those with a VCPU count lower than the hosts or if using the network feature. Only available for Windows clients. | 117 | | GL_VERSION_OVERRIDE | Digit.Digit | `host` | Override the OpenGL version on the client side. Available for both Windows and Linux clients. | 118 | | GLX_VERSION_OVERRIDE | Digit.Digit | 1.4 | Override the GLX version on the client side. Only available for Linux clients. | 119 | | GLSL_VERSION_OVERRIDE | Digit.Digit | | Override the GLSL version on the client side. Available for both Windows and Linux clients. | 120 | 121 | ## Windows (in a VM) 122 | 123 | Two things must be done for the windows installation: 124 | 1. Install a compatible driver 125 | 2. Install the clients 126 | 127 | ### Kernel driver 128 | 129 | There are two possible drivers one may use: 130 | 1. VirtIO's IVSHMEM driver (no multiclient support) 131 | 1. Download and extract the upstream virtio win drivers, found [here](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/upstream-virtio/). 132 | 2. Navigate into `...\virtio-win-upstream\Win10\amd64\`. 133 | 3. Right click on `ivshmem.inf` and press `Install`. 134 | 135 | > [!WARNING]\ 136 | > If you use the included driver, test signing must be on. Enable it by running the following command in an elevated command prompt: `bcdedit.exe -set testsigning on` and restart. 137 | 138 | > [!NOTE]\ 139 | > If you are looking for multiclient support but do not wish to install the patched driver, take a look into the networking feature which requires no drivers. 140 | 141 | 2. Included driver (multiclient support) 142 | 1. Use the release (>= `0.4.0`) **(Windows 10 only)** 143 | 1. Download the latest release for windows and extract the zip file. 144 | 2. Navigate into the extracted folder. 145 | 3. Right click on `ksgldrv.inf` and press `Install`. 146 | 2. Compile from source (use Visual Studio Developer Command Prompt) 147 | 1. Ensure you have installed the `WDK`, which can be found [here](https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads). 148 | 2. ```bat 149 | :: git clone https://github.com/dmaivel/sharedgl.git 150 | :: cd sharedgl 151 | mkdir build 152 | cd build 153 | cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DWINKERNEL=ON .. 154 | cmake --build . --target ksgldrv --config Release 155 | cd .. 156 | xcopy .\scripts\kcertify.bat .\build\Release\kcertify.bat 157 | xcopy .\scripts\ksgldrv.inf .\build\Release\ksgldrv.inf 158 | cd build\Release 159 | call kcertify.bat 10_X64 160 | 161 | :: requires admin privs, you may right click on the file and press install instead 162 | pnputil -i -a ksgldrv.inf 163 | ``` 164 | 3. By default, this builds for Windows 10 x64 (`10_X64`). If you wish to compile for a different version or multiple versions, you must provide it through the command line like so: `kcertify.bat 10_X64,10_NI_X64`. A list of OS versions is provided on MSDN [here](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/inf2cat). 165 | 166 | ### Library / ICD 167 | 168 | There are two ways to install the library on windows: 169 | 1. Use a release (>= `0.3.1`) 170 | 1. Download the latest release for windows and extract the zip file. 171 | 2. Navigate into the extracted folder and run `wininstall.bat` and allow admin privledges. 172 | 3. The libraries should now be installed, meaning any application that uses OpenGL (32-bit and 64-bit) will use SharedGL. 173 | 2. Compile from source (use Visual Studio Developer Command Prompt) 174 | 1. ```bat 175 | :: git clone https://github.com/dmaivel/sharedgl.git 176 | :: cd sharedgl 177 | mkdir build 178 | cd build 179 | :: if you get errors regarding wdk, also use -DWINKERNEL=OFF 180 | cmake -DCMAKE_GENERATOR_PLATFORM=x64 .. 181 | cmake --build . --target sharedgl-core --config Release 182 | cmake -DCMAKE_GENERATOR_PLATFORM=Win32 .. 183 | cmake --build . --target sharedgl-core --config Release 184 | cd .. 185 | xcopy .\scripts\wininstall.bat .\build\Release\wininstall.bat 186 | cd build\Release 187 | call wininstall.bat 188 | ``` 189 | 190 | ## Linux 191 | 192 | > [!CAUTION] 193 | > The following sections discuss using the *client library*, not the *renderer/server*. If your intention is to only accelerate Windows guests, you may disregard this section as all you need to do is run the renderer, no additional libraries required (other than the dependencies). 194 | 195 | For your OpenGL application to communicate with the server, the client library must be specified in your library path. Upon exporting, any program you run in the terminal where you inputted this command will run with the SGL binary. 196 | 197 | ```bash 198 | $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/sharedgl/build 199 | $ glxgears 200 | $ ... 201 | ``` 202 | 203 | Some applications may require adding the library to the `LD_PRELOAD` environment variable aswell, which is done the same way as shown above. 204 | 205 | Note that the Linux library does not need to be used in a virtual machine, allowing users to debug the library entirely on the host. 206 | 207 | Some applications may require an explicit `libGLX`, so run `ln -s libGL.so.1 libGLX.so.0` in `build` to make a symlink. 208 | 209 | ## Linux in a VM 210 | 211 | For virtual Linux clients, an additional kernel module needs to be compiled in the virtual machine, resulting in a binary `sharedgl.ko` which needs to be loaded. Loading/installing can be done by running the provided script (`./kernel/linux/install.sh`), following compilation. If the module doesn't load on boot, it is recommended that you add `sharedgl` to your modprobe config. 212 | 213 | ```bash 214 | # within 'sharedgl' directory 215 | cd kernel/linux 216 | make 217 | ``` 218 | 219 | > [!WARNING]\ 220 | > If you move the client library to the guest from the host instead of compiling it in the guest, you may encounter the `SIGILL` exception in the virtual machine as the build compiles with the native (host) architecture. To fix, either change your cpu model to `host-model`/`host-passthrough` or comment out the `-march=native` line in the cmake script (will most likely reduce performance). 221 | 222 | # Networking 223 | 224 | No drivers are required for the network feature, meaning if you wish to have a driverless experience in your virtual machine, networking is the given alternative. If the networking feature is used exclusively, the kernel drivers do not need be compiled or installed. However, installation of the ICD for either Linux or Windows is still required. 225 | - Start the server using `-n` (and provide a port if the default is not available through `-p PORT`) 226 | - Ensure the ICD is installed 227 | - Ensure that the environment variable `SGL_NETWORK_ENDPOINT=ADDRESS:PORT` exists in the guest (`ADDRESS` being the host's IP address) 228 | 229 | The networking feature is not restricted to only virtual machines. 230 | 231 | # Known issues 232 | - **Linux clients:** New GLX FB configs may cause applications using `freeglut` or `glad` to no longer run (only tested on Linux clients). 233 | 234 | # Troubleshooting 235 | 236 | 1. If you encounter "Entry point retrieval is broken" on applications that use GLFW, use `LD_PRELOAD`. 237 | 2. If you encounter weird crashes/faults/errors such as `IOT instruction` or `No provider of glXXX found.`: 238 | - Try changing the GL version (i.e `-g 2.0`) 239 | - Allocate more memory (i.e `-m 256`) 240 | 3. Application shows a blank window in the virtual machine? 241 | - Make sure the shared memory device passes through all the memory (check the size) 242 | 4. Application doesn't run in the virtual machine? (Process exists but stalls) 243 | - Make sure the server is running 244 | - If you start the server and it still won't run, shut down the VM, run `sudo ./sglrenderer -x`, start the server, start the VM 245 | - Make sure the drivers are installed (VirtIO IVSHMEM for Windows, custom kernel must be compiled for Linux) 246 | 5. Server reports, `err: failed to open shared memory 'sharedgl_shared_memory'` 247 | - This (usually) happens when the shared memory file is created before the server runs, meaning the file was created with different privileges. You may either: 248 | - Run the server as `sudo` 249 | - Shutdown the VM, run `sudo ./sglrenderer -x`, start the server, then start the VM 250 | 6. Client outputs, `glimpl_init: failed to find memory` to the terminal 251 | - This occurs in VMs when you do not pass a shared memory device, which is required for the clients to see the shared memory 252 | 253 | # Showcase 254 | 255 |
256 | Click to reveal: Running SuperTuxKart in a Windows virtual machine 257 | 258 | https://github.com/dmaivel/sharedgl/assets/38770072/c302f546-2c05-4cb7-b415-8f01ad1dce7a 259 | 260 |
261 | 262 |
263 | Click to reveal: Running DirectX sample using WineD3D in a Windows virtual machine 264 | 265 | https://github.com/dmaivel/sharedgl/assets/38770072/f2ae2825-79d6-4c1b-813f-c826586642e2 266 | 267 |
268 | 269 |
270 | Click to reveal: Running minetest in a Windows virtual machine (old) 271 | 272 | https://github.com/dmaivel/sharedgl/assets/38770072/26c6216d-72f7-45b4-9c4f-1734de0d1c6d 273 | 274 |
275 | 276 |
277 | Click to reveal: Running glxgears in a Windows virtual machine (old) 278 | 279 | https://github.com/dmaivel/sharedgl/assets/38770072/a774db97-807e-46b9-a453-fa2ee3f4ea84 280 | 281 |
282 | 283 |
284 | Click to reveal: Running glxgears in a Linux virtual machine (old) 285 | 286 | https://github.com/dmaivel/sharedgl/assets/38770072/0d46bf46-5693-4842-a81f-2f186c396e26 287 | 288 |
289 | 290 |
291 | Click to reveal: Running a compute shader in a Linux virtual machine (old) 292 | 293 | https://github.com/dmaivel/sharedgl/assets/38770072/ded179b8-23dc-491d-ba34-4108e014f296 294 | 295 |
296 | -------------------------------------------------------------------------------- /inc/client/glimpl.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_GLIMPL_H_ 2 | #define _SGL_GLIMPL_H_ 3 | 4 | #include 5 | 6 | void glimpl_init(); 7 | void glimpl_submit(); 8 | void glimpl_goodbye(); 9 | void glimpl_report(int width, int height); 10 | void glimpl_swap_buffers(int width, int height, int vflip, int format); 11 | void *glimpl_fb_address(); 12 | 13 | /* 14 | * gl... functions don't need to be public, however 15 | * for windows icd we seemingly need to get a proc 16 | * table for 1.1 17 | */ 18 | #ifdef _WIN32 19 | #include 20 | PGLCLTPROCTABLE glimpl_GetProcTable(); 21 | #endif 22 | 23 | #endif -------------------------------------------------------------------------------- /inc/client/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_MEMORY_H_ 2 | #define _SGL_MEMORY_H_ 3 | 4 | int sgl_detect_device_memory(const char *path); 5 | 6 | #endif -------------------------------------------------------------------------------- /inc/client/pb.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_PB_H_ 2 | #define _SGL_PB_H_ 3 | 4 | #ifndef _WIN32 5 | #include 6 | #include 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | struct pb_net_hooks { 14 | int(*_pb_read)(int s); 15 | int64_t(*_pb_read64)(int s); 16 | void(*_pb_write)(int s, int c); 17 | void(*_pb_copy)(void *data, int s, size_t length); 18 | void(*_pb_memcpy)(void *src, size_t length); 19 | void*(*_pb_ptr)(size_t offs); 20 | void(*_pb_copy_to_shared)(); 21 | }; 22 | 23 | void pb_set_net(struct pb_net_hooks hooks, size_t internal_alloc_size); 24 | 25 | #ifndef _WIN32 26 | /* 27 | * to-do: determine if direct_access is really unneeded 28 | */ 29 | void pb_set(int pb, bool direct_access); 30 | #else 31 | void pb_set(bool direct_access); 32 | void pb_unset(void); 33 | #endif 34 | 35 | void pb_reset(); 36 | void pb_push(int c); 37 | void pb_pushf(float c); 38 | 39 | int pb_read(int s); 40 | int64_t pb_read64(int s); 41 | void pb_write(int s, int c); 42 | 43 | void pb_memcpy(const void *src, size_t length); 44 | void pb_memcpy_unaligned(const void *src, size_t length); 45 | void pb_realign(); 46 | 47 | void *pb_ptr(size_t offs); 48 | 49 | /* 50 | * special case: return pointer within internal space 51 | * only used for networking junk 52 | * basically, todo: organize everything !! 53 | */ 54 | void *pb_iptr(size_t offs); 55 | 56 | size_t pb_size(); 57 | 58 | void pb_copy_to_shared(); 59 | 60 | #endif -------------------------------------------------------------------------------- /inc/client/platform/egl.h: -------------------------------------------------------------------------------- 1 | // stub -------------------------------------------------------------------------------- /inc/client/platform/gldrv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Microsoft Corporation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice (including the next 12 | * paragraph) shall be included in all copies or substantial portions of the 13 | * Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | */ 23 | #ifdef _WIN32 24 | 25 | #ifndef _GLDRV_ 26 | #define _GLDRV_ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | // Number of entries expected for various versions of OpenGL 33 | #define OPENGL_VERSION_100_ENTRIES 306 34 | #define OPENGL_VERSION_110_ENTRIES 336 35 | 36 | typedef struct _GLDISPATCHTABLE { 37 | void (APIENTRY *glNewList )( GLuint list, GLenum mode ); 38 | void (APIENTRY *glEndList )( void ); 39 | void (APIENTRY *glCallList )( GLuint list ); 40 | void (APIENTRY *glCallLists )( GLsizei n, GLenum type, const GLvoid *lists ); 41 | void (APIENTRY *glDeleteLists )( GLuint list, GLsizei range ); 42 | GLuint (APIENTRY *glGenLists )( GLsizei range ); 43 | void (APIENTRY *glListBase )( GLuint base ); 44 | void (APIENTRY *glBegin )( GLenum mode ); 45 | void (APIENTRY *glBitmap )( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap ); 46 | void (APIENTRY *glColor3b )( GLbyte red, GLbyte green, GLbyte blue ); 47 | void (APIENTRY *glColor3bv )( const GLbyte *v ); 48 | void (APIENTRY *glColor3d )( GLdouble red, GLdouble green, GLdouble blue ); 49 | void (APIENTRY *glColor3dv )( const GLdouble *v ); 50 | void (APIENTRY *glColor3f )( GLfloat red, GLfloat green, GLfloat blue ); 51 | void (APIENTRY *glColor3fv )( const GLfloat *v ); 52 | void (APIENTRY *glColor3i )( GLint red, GLint green, GLint blue ); 53 | void (APIENTRY *glColor3iv )( const GLint *v ); 54 | void (APIENTRY *glColor3s )( GLshort red, GLshort green, GLshort blue ); 55 | void (APIENTRY *glColor3sv )( const GLshort *v ); 56 | void (APIENTRY *glColor3ub )( GLubyte red, GLubyte green, GLubyte blue ); 57 | void (APIENTRY *glColor3ubv )( const GLubyte *v ); 58 | void (APIENTRY *glColor3ui )( GLuint red, GLuint green, GLuint blue ); 59 | void (APIENTRY *glColor3uiv )( const GLuint *v ); 60 | void (APIENTRY *glColor3us )( GLushort red, GLushort green, GLushort blue ); 61 | void (APIENTRY *glColor3usv )( const GLushort *v ); 62 | void (APIENTRY *glColor4b )( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha ); 63 | void (APIENTRY *glColor4bv )( const GLbyte *v ); 64 | void (APIENTRY *glColor4d )( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha ); 65 | void (APIENTRY *glColor4dv )( const GLdouble *v ); 66 | void (APIENTRY *glColor4f )( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); 67 | void (APIENTRY *glColor4fv )( const GLfloat *v ); 68 | void (APIENTRY *glColor4i )( GLint red, GLint green, GLint blue, GLint alpha ); 69 | void (APIENTRY *glColor4iv )( const GLint *v ); 70 | void (APIENTRY *glColor4s )( GLshort red, GLshort green, GLshort blue, GLshort alpha ); 71 | void (APIENTRY *glColor4sv )( const GLshort *v ); 72 | void (APIENTRY *glColor4ub )( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ); 73 | void (APIENTRY *glColor4ubv )( const GLubyte *v ); 74 | void (APIENTRY *glColor4ui )( GLuint red, GLuint green, GLuint blue, GLuint alpha ); 75 | void (APIENTRY *glColor4uiv )( const GLuint *v ); 76 | void (APIENTRY *glColor4us )( GLushort red, GLushort green, GLushort blue, GLushort alpha ); 77 | void (APIENTRY *glColor4usv )( const GLushort *v ); 78 | void (APIENTRY *glEdgeFlag )( GLboolean flag ); 79 | void (APIENTRY *glEdgeFlagv )( const GLboolean *flag ); 80 | void (APIENTRY *glEnd )( void ); 81 | void (APIENTRY *glIndexd )( GLdouble c ); 82 | void (APIENTRY *glIndexdv )( const GLdouble *c ); 83 | void (APIENTRY *glIndexf )( GLfloat c ); 84 | void (APIENTRY *glIndexfv )( const GLfloat *c ); 85 | void (APIENTRY *glIndexi )( GLint c ); 86 | void (APIENTRY *glIndexiv )( const GLint *c ); 87 | void (APIENTRY *glIndexs )( GLshort c ); 88 | void (APIENTRY *glIndexsv )( const GLshort *c ); 89 | void (APIENTRY *glNormal3b )( GLbyte nx, GLbyte ny, GLbyte nz ); 90 | void (APIENTRY *glNormal3bv )( const GLbyte *v ); 91 | void (APIENTRY *glNormal3d )( GLdouble nx, GLdouble ny, GLdouble nz ); 92 | void (APIENTRY *glNormal3dv )( const GLdouble *v ); 93 | void (APIENTRY *glNormal3f )( GLfloat nx, GLfloat ny, GLfloat nz ); 94 | void (APIENTRY *glNormal3fv )( const GLfloat *v ); 95 | void (APIENTRY *glNormal3i )( GLint nx, GLint ny, GLint nz ); 96 | void (APIENTRY *glNormal3iv )( const GLint *v ); 97 | void (APIENTRY *glNormal3s )( GLshort nx, GLshort ny, GLshort nz ); 98 | void (APIENTRY *glNormal3sv )( const GLshort *v ); 99 | void (APIENTRY *glRasterPos2d )( GLdouble x, GLdouble y ); 100 | void (APIENTRY *glRasterPos2dv )( const GLdouble *v ); 101 | void (APIENTRY *glRasterPos2f )( GLfloat x, GLfloat y ); 102 | void (APIENTRY *glRasterPos2fv )( const GLfloat *v ); 103 | void (APIENTRY *glRasterPos2i )( GLint x, GLint y ); 104 | void (APIENTRY *glRasterPos2iv )( const GLint *v ); 105 | void (APIENTRY *glRasterPos2s )( GLshort x, GLshort y ); 106 | void (APIENTRY *glRasterPos2sv )( const GLshort *v ); 107 | void (APIENTRY *glRasterPos3d )( GLdouble x, GLdouble y, GLdouble z ); 108 | void (APIENTRY *glRasterPos3dv )( const GLdouble *v ); 109 | void (APIENTRY *glRasterPos3f )( GLfloat x, GLfloat y, GLfloat z ); 110 | void (APIENTRY *glRasterPos3fv )( const GLfloat *v ); 111 | void (APIENTRY *glRasterPos3i )( GLint x, GLint y, GLint z ); 112 | void (APIENTRY *glRasterPos3iv )( const GLint *v ); 113 | void (APIENTRY *glRasterPos3s )( GLshort x, GLshort y, GLshort z ); 114 | void (APIENTRY *glRasterPos3sv )( const GLshort *v ); 115 | void (APIENTRY *glRasterPos4d )( GLdouble x, GLdouble y, GLdouble z, GLdouble w ); 116 | void (APIENTRY *glRasterPos4dv )( const GLdouble *v ); 117 | void (APIENTRY *glRasterPos4f )( GLfloat x, GLfloat y, GLfloat z, GLfloat w ); 118 | void (APIENTRY *glRasterPos4fv )( const GLfloat *v ); 119 | void (APIENTRY *glRasterPos4i )( GLint x, GLint y, GLint z, GLint w ); 120 | void (APIENTRY *glRasterPos4iv )( const GLint *v ); 121 | void (APIENTRY *glRasterPos4s )( GLshort x, GLshort y, GLshort z, GLshort w ); 122 | void (APIENTRY *glRasterPos4sv )( const GLshort *v ); 123 | void (APIENTRY *glRectd )( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 ); 124 | void (APIENTRY *glRectdv )( const GLdouble *v1, const GLdouble *v2 ); 125 | void (APIENTRY *glRectf )( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ); 126 | void (APIENTRY *glRectfv )( const GLfloat *v1, const GLfloat *v2 ); 127 | void (APIENTRY *glRecti )( GLint x1, GLint y1, GLint x2, GLint y2 ); 128 | void (APIENTRY *glRectiv )( const GLint *v1, const GLint *v2 ); 129 | void (APIENTRY *glRects )( GLshort x1, GLshort y1, GLshort x2, GLshort y2 ); 130 | void (APIENTRY *glRectsv )( const GLshort *v1, const GLshort *v2 ); 131 | void (APIENTRY *glTexCoord1d )( GLdouble s ); 132 | void (APIENTRY *glTexCoord1dv )( const GLdouble *v ); 133 | void (APIENTRY *glTexCoord1f )( GLfloat s ); 134 | void (APIENTRY *glTexCoord1fv )( const GLfloat *v ); 135 | void (APIENTRY *glTexCoord1i )( GLint s ); 136 | void (APIENTRY *glTexCoord1iv )( const GLint *v ); 137 | void (APIENTRY *glTexCoord1s )( GLshort s ); 138 | void (APIENTRY *glTexCoord1sv )( const GLshort *v ); 139 | void (APIENTRY *glTexCoord2d )( GLdouble s, GLdouble t ); 140 | void (APIENTRY *glTexCoord2dv )( const GLdouble *v ); 141 | void (APIENTRY *glTexCoord2f )( GLfloat s, GLfloat t ); 142 | void (APIENTRY *glTexCoord2fv )( const GLfloat *v ); 143 | void (APIENTRY *glTexCoord2i )( GLint s, GLint t ); 144 | void (APIENTRY *glTexCoord2iv )( const GLint *v ); 145 | void (APIENTRY *glTexCoord2s )( GLshort s, GLshort t ); 146 | void (APIENTRY *glTexCoord2sv )( const GLshort *v ); 147 | void (APIENTRY *glTexCoord3d )( GLdouble s, GLdouble t, GLdouble r ); 148 | void (APIENTRY *glTexCoord3dv )( const GLdouble *v ); 149 | void (APIENTRY *glTexCoord3f )( GLfloat s, GLfloat t, GLfloat r ); 150 | void (APIENTRY *glTexCoord3fv )( const GLfloat *v ); 151 | void (APIENTRY *glTexCoord3i )( GLint s, GLint t, GLint r ); 152 | void (APIENTRY *glTexCoord3iv )( const GLint *v ); 153 | void (APIENTRY *glTexCoord3s )( GLshort s, GLshort t, GLshort r ); 154 | void (APIENTRY *glTexCoord3sv )( const GLshort *v ); 155 | void (APIENTRY *glTexCoord4d )( GLdouble s, GLdouble t, GLdouble r, GLdouble q ); 156 | void (APIENTRY *glTexCoord4dv )( const GLdouble *v ); 157 | void (APIENTRY *glTexCoord4f )( GLfloat s, GLfloat t, GLfloat r, GLfloat q ); 158 | void (APIENTRY *glTexCoord4fv )( const GLfloat *v ); 159 | void (APIENTRY *glTexCoord4i )( GLint s, GLint t, GLint r, GLint q ); 160 | void (APIENTRY *glTexCoord4iv )( const GLint *v ); 161 | void (APIENTRY *glTexCoord4s )( GLshort s, GLshort t, GLshort r, GLshort q ); 162 | void (APIENTRY *glTexCoord4sv )( const GLshort *v ); 163 | void (APIENTRY *glVertex2d )( GLdouble x, GLdouble y ); 164 | void (APIENTRY *glVertex2dv )( const GLdouble *v ); 165 | void (APIENTRY *glVertex2f )( GLfloat x, GLfloat y ); 166 | void (APIENTRY *glVertex2fv )( const GLfloat *v ); 167 | void (APIENTRY *glVertex2i )( GLint x, GLint y ); 168 | void (APIENTRY *glVertex2iv )( const GLint *v ); 169 | void (APIENTRY *glVertex2s )( GLshort x, GLshort y ); 170 | void (APIENTRY *glVertex2sv )( const GLshort *v ); 171 | void (APIENTRY *glVertex3d )( GLdouble x, GLdouble y, GLdouble z ); 172 | void (APIENTRY *glVertex3dv )( const GLdouble *v ); 173 | void (APIENTRY *glVertex3f )( GLfloat x, GLfloat y, GLfloat z ); 174 | void (APIENTRY *glVertex3fv )( const GLfloat *v ); 175 | void (APIENTRY *glVertex3i )( GLint x, GLint y, GLint z ); 176 | void (APIENTRY *glVertex3iv )( const GLint *v ); 177 | void (APIENTRY *glVertex3s )( GLshort x, GLshort y, GLshort z ); 178 | void (APIENTRY *glVertex3sv )( const GLshort *v ); 179 | void (APIENTRY *glVertex4d )( GLdouble x, GLdouble y, GLdouble z, GLdouble w ); 180 | void (APIENTRY *glVertex4dv )( const GLdouble *v ); 181 | void (APIENTRY *glVertex4f )( GLfloat x, GLfloat y, GLfloat z, GLfloat w ); 182 | void (APIENTRY *glVertex4fv )( const GLfloat *v ); 183 | void (APIENTRY *glVertex4i )( GLint x, GLint y, GLint z, GLint w ); 184 | void (APIENTRY *glVertex4iv )( const GLint *v ); 185 | void (APIENTRY *glVertex4s )( GLshort x, GLshort y, GLshort z, GLshort w ); 186 | void (APIENTRY *glVertex4sv )( const GLshort *v ); 187 | void (APIENTRY *glClipPlane )( GLenum plane, const GLdouble *equation ); 188 | void (APIENTRY *glColorMaterial )( GLenum face, GLenum mode ); 189 | void (APIENTRY *glCullFace )( GLenum mode ); 190 | void (APIENTRY *glFogf )( GLenum pname, GLfloat param ); 191 | void (APIENTRY *glFogfv )( GLenum pname, const GLfloat *params ); 192 | void (APIENTRY *glFogi )( GLenum pname, GLint param ); 193 | void (APIENTRY *glFogiv )( GLenum pname, const GLint *params ); 194 | void (APIENTRY *glFrontFace )( GLenum mode ); 195 | void (APIENTRY *glHint )( GLenum target, GLenum mode ); 196 | void (APIENTRY *glLightf )( GLenum light, GLenum pname, GLfloat param ); 197 | void (APIENTRY *glLightfv )( GLenum light, GLenum pname, const GLfloat *params ); 198 | void (APIENTRY *glLighti )( GLenum light, GLenum pname, GLint param ); 199 | void (APIENTRY *glLightiv )( GLenum light, GLenum pname, const GLint *params ); 200 | void (APIENTRY *glLightModelf )( GLenum pname, GLfloat param ); 201 | void (APIENTRY *glLightModelfv )( GLenum pname, const GLfloat *params ); 202 | void (APIENTRY *glLightModeli )( GLenum pname, GLint param ); 203 | void (APIENTRY *glLightModeliv )( GLenum pname, const GLint *params ); 204 | void (APIENTRY *glLineStipple )( GLint factor, GLushort pattern ); 205 | void (APIENTRY *glLineWidth )( GLfloat width ); 206 | void (APIENTRY *glMaterialf )( GLenum face, GLenum pname, GLfloat param ); 207 | void (APIENTRY *glMaterialfv )( GLenum face, GLenum pname, const GLfloat *params ); 208 | void (APIENTRY *glMateriali )( GLenum face, GLenum pname, GLint param ); 209 | void (APIENTRY *glMaterialiv )( GLenum face, GLenum pname, const GLint *params ); 210 | void (APIENTRY *glPointSize )( GLfloat size ); 211 | void (APIENTRY *glPolygonMode )( GLenum face, GLenum mode ); 212 | void (APIENTRY *glPolygonStipple )( const GLubyte *mask ); 213 | void (APIENTRY *glScissor )( GLint x, GLint y, GLsizei width, GLsizei height ); 214 | void (APIENTRY *glShadeModel )( GLenum mode ); 215 | void (APIENTRY *glTexParameterf )( GLenum target, GLenum pname, GLfloat param ); 216 | void (APIENTRY *glTexParameterfv )( GLenum target, GLenum pname, const GLfloat *params ); 217 | void (APIENTRY *glTexParameteri )( GLenum target, GLenum pname, GLint param ); 218 | void (APIENTRY *glTexParameteriv )( GLenum target, GLenum pname, const GLint *params ); 219 | void (APIENTRY *glTexImage1D )( GLenum target, GLint level, GLint components, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); 220 | void (APIENTRY *glTexImage2D )( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); 221 | void (APIENTRY *glTexEnvf )( GLenum target, GLenum pname, GLfloat param ); 222 | void (APIENTRY *glTexEnvfv )( GLenum target, GLenum pname, const GLfloat *params ); 223 | void (APIENTRY *glTexEnvi )( GLenum target, GLenum pname, GLint param ); 224 | void (APIENTRY *glTexEnviv )( GLenum target, GLenum pname, const GLint *params ); 225 | void (APIENTRY *glTexGend )( GLenum coord, GLenum pname, GLdouble param ); 226 | void (APIENTRY *glTexGendv )( GLenum coord, GLenum pname, const GLdouble *params ); 227 | void (APIENTRY *glTexGenf )( GLenum coord, GLenum pname, GLfloat param ); 228 | void (APIENTRY *glTexGenfv )( GLenum coord, GLenum pname, const GLfloat *params ); 229 | void (APIENTRY *glTexGeni )( GLenum coord, GLenum pname, GLint param ); 230 | void (APIENTRY *glTexGeniv )( GLenum coord, GLenum pname, const GLint *params ); 231 | void (APIENTRY *glFeedbackBuffer )( GLsizei size, GLenum type, GLfloat *buffer ); 232 | void (APIENTRY *glSelectBuffer )( GLsizei size, GLuint *buffer ); 233 | GLint (APIENTRY *glRenderMode )( GLenum mode ); 234 | void (APIENTRY *glInitNames )( void ); 235 | void (APIENTRY *glLoadName )( GLuint name ); 236 | void (APIENTRY *glPassThrough )( GLfloat token ); 237 | void (APIENTRY *glPopName )( void ); 238 | void (APIENTRY *glPushName )( GLuint name ); 239 | void (APIENTRY *glDrawBuffer )( GLenum mode ); 240 | void (APIENTRY *glClear )( GLbitfield mask ); 241 | void (APIENTRY *glClearAccum )( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); 242 | void (APIENTRY *glClearIndex )( GLfloat c ); 243 | void (APIENTRY *glClearColor )( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ); 244 | void (APIENTRY *glClearStencil )( GLint s ); 245 | void (APIENTRY *glClearDepth )( GLclampd depth ); 246 | void (APIENTRY *glStencilMask )( GLuint mask ); 247 | void (APIENTRY *glColorMask )( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ); 248 | void (APIENTRY *glDepthMask )( GLboolean flag ); 249 | void (APIENTRY *glIndexMask )( GLuint mask ); 250 | void (APIENTRY *glAccum )( GLenum op, GLfloat value ); 251 | void (APIENTRY *glDisable )( GLenum cap ); 252 | void (APIENTRY *glEnable )( GLenum cap ); 253 | void (APIENTRY *glFinish )( void ); 254 | void (APIENTRY *glFlush )( void ); 255 | void (APIENTRY *glPopAttrib )( void ); 256 | void (APIENTRY *glPushAttrib )( GLbitfield mask ); 257 | void (APIENTRY *glMap1d )( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points ); 258 | void (APIENTRY *glMap1f )( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points ); 259 | void (APIENTRY *glMap2d )( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points ); 260 | void (APIENTRY *glMap2f )( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points ); 261 | void (APIENTRY *glMapGrid1d )( GLint un, GLdouble u1, GLdouble u2 ); 262 | void (APIENTRY *glMapGrid1f )( GLint un, GLfloat u1, GLfloat u2 ); 263 | void (APIENTRY *glMapGrid2d )( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 ); 264 | void (APIENTRY *glMapGrid2f )( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 ); 265 | void (APIENTRY *glEvalCoord1d )( GLdouble u ); 266 | void (APIENTRY *glEvalCoord1dv )( const GLdouble *u ); 267 | void (APIENTRY *glEvalCoord1f )( GLfloat u ); 268 | void (APIENTRY *glEvalCoord1fv )( const GLfloat *u ); 269 | void (APIENTRY *glEvalCoord2d )( GLdouble u, GLdouble v ); 270 | void (APIENTRY *glEvalCoord2dv )( const GLdouble *u ); 271 | void (APIENTRY *glEvalCoord2f )( GLfloat u, GLfloat v ); 272 | void (APIENTRY *glEvalCoord2fv )( const GLfloat *u ); 273 | void (APIENTRY *glEvalMesh1 )( GLenum mode, GLint i1, GLint i2 ); 274 | void (APIENTRY *glEvalPoint1 )( GLint i ); 275 | void (APIENTRY *glEvalMesh2 )( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 ); 276 | void (APIENTRY *glEvalPoint2 )( GLint i, GLint j ); 277 | void (APIENTRY *glAlphaFunc )( GLenum func, GLclampf ref ); 278 | void (APIENTRY *glBlendFunc )( GLenum sfactor, GLenum dfactor ); 279 | void (APIENTRY *glLogicOp )( GLenum opcode ); 280 | void (APIENTRY *glStencilFunc )( GLenum func, GLint ref, GLuint mask ); 281 | void (APIENTRY *glStencilOp )( GLenum fail, GLenum zfail, GLenum zpass ); 282 | void (APIENTRY *glDepthFunc )( GLenum func ); 283 | void (APIENTRY *glPixelZoom )( GLfloat xfactor, GLfloat yfactor ); 284 | void (APIENTRY *glPixelTransferf )( GLenum pname, GLfloat param ); 285 | void (APIENTRY *glPixelTransferi )( GLenum pname, GLint param ); 286 | void (APIENTRY *glPixelStoref )( GLenum pname, GLfloat param ); 287 | void (APIENTRY *glPixelStorei )( GLenum pname, GLint param ); 288 | void (APIENTRY *glPixelMapfv )( GLenum map, GLint mapsize, const GLfloat *values ); 289 | void (APIENTRY *glPixelMapuiv )( GLenum map, GLint mapsize, const GLuint *values ); 290 | void (APIENTRY *glPixelMapusv )( GLenum map, GLint mapsize, const GLushort *values ); 291 | void (APIENTRY *glReadBuffer )( GLenum mode ); 292 | void (APIENTRY *glCopyPixels )( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type ); 293 | void (APIENTRY *glReadPixels )( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ); 294 | void (APIENTRY *glDrawPixels )( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); 295 | void (APIENTRY *glGetBooleanv )( GLenum pname, GLboolean *params ); 296 | void (APIENTRY *glGetClipPlane )( GLenum plane, GLdouble *equation ); 297 | void (APIENTRY *glGetDoublev )( GLenum pname, GLdouble *params ); 298 | GLenum (APIENTRY *glGetError )( void ); 299 | void (APIENTRY *glGetFloatv )( GLenum pname, GLfloat *params ); 300 | void (APIENTRY *glGetIntegerv )( GLenum pname, GLint *params ); 301 | void (APIENTRY *glGetLightfv )( GLenum light, GLenum pname, GLfloat *params ); 302 | void (APIENTRY *glGetLightiv )( GLenum light, GLenum pname, GLint *params ); 303 | void (APIENTRY *glGetMapdv )( GLenum target, GLenum query, GLdouble *v ); 304 | void (APIENTRY *glGetMapfv )( GLenum target, GLenum query, GLfloat *v ); 305 | void (APIENTRY *glGetMapiv )( GLenum target, GLenum query, GLint *v ); 306 | void (APIENTRY *glGetMaterialfv )( GLenum face, GLenum pname, GLfloat *params ); 307 | void (APIENTRY *glGetMaterialiv )( GLenum face, GLenum pname, GLint *params ); 308 | void (APIENTRY *glGetPixelMapfv )( GLenum map, GLfloat *values ); 309 | void (APIENTRY *glGetPixelMapuiv )( GLenum map, GLuint *values ); 310 | void (APIENTRY *glGetPixelMapusv )( GLenum map, GLushort *values ); 311 | void (APIENTRY *glGetPolygonStipple )( GLubyte *mask ); 312 | const GLubyte * (APIENTRY *glGetString )( GLenum name ); 313 | void (APIENTRY *glGetTexEnvfv )( GLenum target, GLenum pname, GLfloat *params ); 314 | void (APIENTRY *glGetTexEnviv )( GLenum target, GLenum pname, GLint *params ); 315 | void (APIENTRY *glGetTexGendv )( GLenum coord, GLenum pname, GLdouble *params ); 316 | void (APIENTRY *glGetTexGenfv )( GLenum coord, GLenum pname, GLfloat *params ); 317 | void (APIENTRY *glGetTexGeniv )( GLenum coord, GLenum pname, GLint *params ); 318 | void (APIENTRY *glGetTexImage )( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ); 319 | void (APIENTRY *glGetTexParameterfv )( GLenum target, GLenum pname, GLfloat *params ); 320 | void (APIENTRY *glGetTexParameteriv )( GLenum target, GLenum pname, GLint *params ); 321 | void (APIENTRY *glGetTexLevelParameterfv )( GLenum target, GLint level, GLenum pname, GLfloat *params ); 322 | void (APIENTRY *glGetTexLevelParameteriv )( GLenum target, GLint level, GLenum pname, GLint *params ); 323 | GLboolean (APIENTRY *glIsEnabled )( GLenum cap ); 324 | GLboolean (APIENTRY *glIsList )( GLuint list ); 325 | void (APIENTRY *glDepthRange )( GLclampd zNear, GLclampd zFar ); 326 | void (APIENTRY *glFrustum )( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar ); 327 | void (APIENTRY *glLoadIdentity )( void ); 328 | void (APIENTRY *glLoadMatrixf )( const GLfloat *m ); 329 | void (APIENTRY *glLoadMatrixd )( const GLdouble *m ); 330 | void (APIENTRY *glMatrixMode )( GLenum mode ); 331 | void (APIENTRY *glMultMatrixf )( const GLfloat *m ); 332 | void (APIENTRY *glMultMatrixd )( const GLdouble *m ); 333 | void (APIENTRY *glOrtho )( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar ); 334 | void (APIENTRY *glPopMatrix )( void ); 335 | void (APIENTRY *glPushMatrix )( void ); 336 | void (APIENTRY *glRotated )( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ); 337 | void (APIENTRY *glRotatef )( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ); 338 | void (APIENTRY *glScaled )( GLdouble x, GLdouble y, GLdouble z ); 339 | void (APIENTRY *glScalef )( GLfloat x, GLfloat y, GLfloat z ); 340 | void (APIENTRY *glTranslated )( GLdouble x, GLdouble y, GLdouble z ); 341 | void (APIENTRY *glTranslatef )( GLfloat x, GLfloat y, GLfloat z ); 342 | void (APIENTRY *glViewport )( GLint x, GLint y, GLsizei width, GLsizei height ); 343 | // OpenGL version 1.0 entries end here 344 | 345 | // OpenGL version 1.1 entries begin here 346 | void (APIENTRY *glArrayElement )(GLint i); 347 | void (APIENTRY *glBindTexture )(GLenum target, GLuint texture); 348 | void (APIENTRY *glColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); 349 | void (APIENTRY *glDisableClientState )(GLenum array); 350 | void (APIENTRY *glDrawArrays )(GLenum mode, GLint first, GLsizei count); 351 | void (APIENTRY *glDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); 352 | void (APIENTRY *glEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); 353 | void (APIENTRY *glEnableClientState )(GLenum array); 354 | void (APIENTRY *glIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); 355 | void (APIENTRY *glIndexub )(GLubyte c); 356 | void (APIENTRY *glIndexubv )(const GLubyte *c); 357 | void (APIENTRY *glInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); 358 | void (APIENTRY *glNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); 359 | void (APIENTRY *glPolygonOffset )(GLfloat factor, GLfloat units); 360 | void (APIENTRY *glTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); 361 | void (APIENTRY *glVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); 362 | GLboolean (APIENTRY *glAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); 363 | void (APIENTRY *glCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); 364 | void (APIENTRY *glCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); 365 | void (APIENTRY *glCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); 366 | void (APIENTRY *glCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); 367 | void (APIENTRY *glDeleteTextures )(GLsizei n, const GLuint *textures); 368 | void (APIENTRY *glGenTextures )(GLsizei n, GLuint *textures); 369 | void (APIENTRY *glGetPointerv )(GLenum pname, GLvoid* *params); 370 | GLboolean (APIENTRY *glIsTexture )(GLuint texture); 371 | void (APIENTRY *glPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); 372 | void (APIENTRY *glTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); 373 | void (APIENTRY *glTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); 374 | void (APIENTRY *glPopClientAttrib )(void); 375 | void (APIENTRY *glPushClientAttrib )(GLbitfield mask); 376 | } GLDISPATCHTABLE, *PGLDISPATCHTABLE; 377 | 378 | // OpenGL Client/Driver Procedure Table. 379 | 380 | typedef struct _GLCLTPROCTABLE { 381 | _In_range_(0,OPENGL_VERSION_110_ENTRIES) int cEntries; // Number of function entries in table 382 | GLDISPATCHTABLE glDispatchTable; // OpenGL function dispatch table 383 | } GLCLTPROCTABLE, *PGLCLTPROCTABLE; 384 | 385 | // Driver GLRC handle. 386 | 387 | typedef ULONG DHGLRC; 388 | 389 | // SetProcTable function prototype for DrvSetContext. 390 | 391 | typedef VOID (APIENTRY *PFN_SETPROCTABLE)(PGLCLTPROCTABLE); 392 | 393 | // DrvSetCallbackProcs prototypes 394 | typedef VOID (APIENTRY *PFN_SETCURRENTVALUE)(VOID *pv); 395 | typedef VOID *(APIENTRY *PFN_GETCURRENTVALUE)(VOID); 396 | typedef DHGLRC (APIENTRY *PFN_GETDHGLRC)(HGLRC hrc); 397 | #if WINVER >= 0x600 398 | typedef struct _PRESENTBUFFERSCB { 399 | IN UINT nVersion; 400 | IN UINT syncType; // See PRESCB_SYNCTYPE_NONE and PRESCB_SYNCTYPE_VSYNC 401 | IN LUID luidAdapter; 402 | IN LPVOID pPrivData; 403 | IN RECT updateRect; // Update rectangle in the coordinate system of the window, whose HDC is passed to PFN_PRESENTBUFFERS 404 | } PRESENTBUFFERSCB, *LPPRESENTBUFFERSCB; 405 | typedef BOOL (APIENTRY *PFN_PRESENTBUFFERS)(HDC hdc, LPPRESENTBUFFERSCB pprsbcbData); 406 | #endif 407 | #if WINVER >= 0xA00 408 | typedef VOID (APIENTRY *PFN_GETADAPTERLUID)(HDC hdc, OUT LUID* pLuid); 409 | typedef struct _CHECKFULLSCREENSUPPORTCB { 410 | IN UINT nVersion; 411 | IN LUID luidAdapter; 412 | IN UINT hDevice; 413 | IN HMONITOR hMonitor; 414 | OUT UINT VidPnSourceId; 415 | } CHECKFULLSCREENSUPPORTCB, *LPCHECKFULLSCREENSUPPORTCB; 416 | typedef BOOL (APIENTRY *PFN_CHECKFULLSCREENSUPPORT)(HDC hdc, LPCHECKFULLSCREENSUPPORTCB pArgs); 417 | typedef struct _PRESENTTOREDIRECTIONSURFACECB { 418 | IN UINT nVersion; 419 | IN UINT hContext; 420 | IN UINT hSource; 421 | IN UINT hDestination; 422 | IN HANDLE hSharedHandle; 423 | IN UINT64 updateId; 424 | IN RECT updateRect; 425 | IN UINT broadcastContextCount; 426 | IN UINT broadcastContext[64]; 427 | IN UINT broadcastSrcAllocation[64]; 428 | IN UINT broadcastDstAllocation[64]; 429 | IN UINT cbPrivateDriverDataSize; 430 | IN VOID *pPrivateDriverData; 431 | } PRESENTTOREDIRECTIONSURFACECB, *LPPRESENTTOREDIRECTIONSURFACECB; 432 | typedef BOOL (APIENTRY *PFN_PRESENTTOREDIRECTIONSURFACE)(HDC hdc, LPPRESENTTOREDIRECTIONSURFACECB pArgs); 433 | typedef struct _SUBMITPRESENTTOREDIRECTIONSURFACECB { 434 | IN UINT nVersion; 435 | IN HANDLE hSharedHandle; 436 | IN UINT64 updateId; 437 | IN RECT updateRect; 438 | IN UINT broadcastHwQueueCount; 439 | 440 | _Field_size_(broadcastHwQueueCount) 441 | IN UINT *broadcastHwQueue; 442 | 443 | _Field_size_(broadcastHwQueueCount) 444 | IN UINT *broadcastSrcAllocation; 445 | 446 | _Field_size_opt_(broadcastHwQueueCount) 447 | IN UINT *broadcastDstAllocation; 448 | 449 | IN UINT cbPrivateDriverDataSize; 450 | IN VOID *pPrivateDriverData; 451 | } SUBMITPRESENTTOREDIRECTIONSURFACECB, *LPSUBMITPRESENTTOREDIRECTIONSURFACECB; 452 | typedef BOOL (APIENTRY *PFN_SUBMITPRESENTTOREDIRECTIONSURFACE)(HDC hdc, LPSUBMITPRESENTTOREDIRECTIONSURFACECB pArgs); 453 | #endif 454 | 455 | // Note: Structure not referenced directly, simply present to document the expected order/count of 456 | // callbacks received through DrvSetCallbackProcs. 457 | struct WGLCALLBACKS 458 | { 459 | PFN_SETCURRENTVALUE pfnSetCurrentValue; 460 | PFN_GETCURRENTVALUE pfnGetCurrentValue; 461 | PFN_GETDHGLRC pfnGetDhglrc; 462 | PROC pfnUnused; 463 | #if WINVER >= 0x600 464 | PFN_PRESENTBUFFERS pfnPresentBuffers; 465 | #endif 466 | #if WINVER >= 0xA00 467 | PFN_GETADAPTERLUID pfnGetAdapterLuid; 468 | PFN_CHECKFULLSCREENSUPPORT pfnCheckFullscreenSupport; 469 | PFN_PRESENTTOREDIRECTIONSURFACE pfnPresentToRedirectionSurface; 470 | PFN_SUBMITPRESENTTOREDIRECTIONSURFACE pfnSubmitPresentToRedirectionSurface; 471 | #endif 472 | }; 473 | 474 | // Driver context function prototypes. 475 | 476 | BOOL APIENTRY DrvCopyContext(DHGLRC, DHGLRC, UINT); 477 | DHGLRC APIENTRY DrvCreateContext(HDC); 478 | DHGLRC APIENTRY DrvCreateLayerContext(HDC, int); 479 | BOOL APIENTRY DrvDeleteContext(DHGLRC); 480 | PGLCLTPROCTABLE APIENTRY DrvSetContext(HDC,DHGLRC,PFN_SETPROCTABLE); 481 | BOOL APIENTRY DrvReleaseContext(DHGLRC); 482 | BOOL APIENTRY DrvValidateVersion(ULONG); 483 | BOOL APIENTRY DrvShareLists(DHGLRC, DHGLRC); 484 | PROC APIENTRY DrvGetProcAddress(LPCSTR); 485 | VOID APIENTRY DrvSetCallbackProcs(INT, PROC *); // See WGLCALLBACKS for expected order/count per OS. 486 | BOOL APIENTRY DrvDescribeLayerPlane(HDC, INT, INT, UINT, 487 | LPLAYERPLANEDESCRIPTOR); 488 | INT APIENTRY DrvSetLayerPaletteEntries(HDC, INT, INT, INT, 489 | CONST COLORREF *); 490 | INT APIENTRY DrvGetLayerPaletteEntries(HDC, INT, INT, INT, 491 | COLORREF *); 492 | BOOL APIENTRY DrvRealizeLayerPalette(HDC, INT, BOOL); 493 | BOOL APIENTRY DrvSwapLayerBuffers(HDC, UINT); 494 | 495 | #if WINVER >= 0x500 496 | 497 | typedef struct IDirectDrawSurface *LPDIRECTDRAWSURFACE; 498 | typedef struct _DDSURFACEDESC *LPDDSURFACEDESC; 499 | 500 | DHGLRC APIENTRY DrvCreateDirectDrawContext(HDC, LPDIRECTDRAWSURFACE, 501 | int); 502 | int APIENTRY DrvEnumTextureFormats(int, LPDDSURFACEDESC); 503 | BOOL APIENTRY DrvBindDirectDrawTexture(LPDIRECTDRAWSURFACE); 504 | DWORD APIENTRY DrvSwapMultipleBuffers(UINT cBuffers, 505 | CONST WGLSWAP *pgswap); 506 | 507 | LONG APIENTRY DrvDescribePixelFormat(HDC, INT, ULONG, PIXELFORMATDESCRIPTOR*); 508 | BOOL APIENTRY DrvSetPixelFormat(HDC, LONG); 509 | BOOL APIENTRY DrvSwapBuffers(HDC); 510 | 511 | #endif // WINVER >= 0x500 512 | 513 | #if WINVER >= 0x600 514 | typedef struct _PRESENTBUFFERS { 515 | IN HANDLE hSurface; 516 | IN LUID luidAdapter; 517 | IN ULONGLONG ullPresentToken; 518 | IN LPVOID pPrivData; 519 | } PRESENTBUFFERS, *LPPRESENTBUFFERS; 520 | typedef BOOL (APIENTRY *PFN_PRESENTBUFFERS)(HDC hdc, LPPRESENTBUFFERSCB pprsbcbData); 521 | 522 | #define PRESCB_SYNCTYPE_NONE 0 523 | #define PRESCB_SYNCTYPE_VSYNC 1 524 | 525 | BOOL APIENTRY DrvPresentBuffers(HDC hdc, LPPRESENTBUFFERS pprsbData); 526 | 527 | #endif 528 | 529 | // Input structure for OPENGL_CMD ExtEscape. 530 | 531 | typedef struct _WNDOBJ WNDOBJ; 532 | typedef struct _XLATEOBJ XLATEOBJ; 533 | 534 | typedef struct _OPENGLCMD 535 | { 536 | ULONG ulSubEsc; 537 | FLONG fl; 538 | WNDOBJ *pwo; 539 | XLATEOBJ *pxo; 540 | } OPENGLCMD, *POPENGLCMD; 541 | 542 | #if WINVER >= 0x500 543 | 544 | #define OPENGLCMD_MAXMULTI WGL_SWAPMULTIPLE_MAX 545 | 546 | typedef struct _OPENGLCMDMULTI 547 | { 548 | ULONG ulSubEsc; 549 | FLONG fl; 550 | ULONG cMulti; 551 | XLATEOBJ *pxo; 552 | } OPENGLCMDMULTI, *POPENGLCMDMULTI; 553 | 554 | #endif // WINVER >= 0x500 555 | 556 | // Flags for OPENGL_CMD ExtEscape. 557 | 558 | #define OGLCMD_NEEDWNDOBJ 0x01 559 | #define OGLCMD_NEEDXLATEOBJ 0x02 560 | 561 | #if WINVER >= 0x500 562 | #define OGLCMD_MULTIWNDOBJ 0x04 563 | #endif // WINVER >= 0x500 564 | 565 | // OPENGL_GETINFO ExtEscape sub-escape numbers. They are defined by Microsoft. 566 | 567 | #define OPENGL_GETINFO_DRVNAME 0 568 | 569 | // Input structure for OPENGL_GETINFO ExtEscape. 570 | 571 | typedef struct _OPENGLGETINFO 572 | { 573 | ULONG ulSubEsc; 574 | } OPENGLGETINFO, *POPENGLGETINFO; 575 | 576 | // Input structure for OPENGL_GETINFO_DRVNAME ExtEscape. 577 | 578 | typedef struct _GLDRVNAME 579 | { 580 | OPENGLGETINFO oglget; 581 | } GLDRVNAME, *PGLDRVNAME; 582 | 583 | // Output structure for OPENGL_GETINFO_DRVNAME ExtEscape. 584 | 585 | typedef struct _GLDRVNAMERET 586 | { 587 | ULONG ulVersion; // must be 1 for this version 588 | ULONG ulDriverVersion; // driver specific version number 589 | WCHAR awch[MAX_PATH+1]; 590 | } GLDRVNAMERET, *PGLDRVNAMERET; 591 | 592 | #endif /* _GLDRV_ */ 593 | 594 | #endif /* _WIN32 */ -------------------------------------------------------------------------------- /inc/client/platform/glx.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_GLX_H_ 2 | #define _SGL_GLX_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define GLX_VENDOR 1 9 | #define GLX_VERSION 2 10 | #define GLX_EXTENSIONS 3 11 | 12 | #define GLX_USE_GL 1 13 | #define GLX_BUFFER_SIZE 2 14 | #define GLX_LEVEL 3 15 | #define GLX_RGBA 4 16 | #define GLX_DOUBLEBUFFER 5 17 | #define GLX_STEREO 6 18 | #define GLX_AUX_BUFFERS 7 19 | #define GLX_RED_SIZE 8 20 | #define GLX_GREEN_SIZE 9 21 | #define GLX_BLUE_SIZE 10 22 | #define GLX_ALPHA_SIZE 11 23 | #define GLX_DEPTH_SIZE 12 24 | #define GLX_STENCIL_SIZE 13 25 | #define GLX_ACCUM_RED_SIZE 14 26 | #define GLX_ACCUM_GREEN_SIZE 15 27 | #define GLX_ACCUM_BLUE_SIZE 16 28 | #define GLX_ACCUM_ALPHA_SIZE 17 29 | 30 | #define GLX_CONFIG_CAVEAT 0x20 31 | #define GLX_DONT_CARE 0xFFFFFFFF 32 | #define GLX_X_VISUAL_TYPE 0x22 33 | #define GLX_TRANSPARENT_TYPE 0x23 34 | #define GLX_TRANSPARENT_INDEX_VALUE 0x24 35 | #define GLX_TRANSPARENT_RED_VALUE 0x25 36 | #define GLX_TRANSPARENT_GREEN_VALUE 0x26 37 | #define GLX_TRANSPARENT_BLUE_VALUE 0x27 38 | #define GLX_TRANSPARENT_ALPHA_VALUE 0x28 39 | #define GLX_WINDOW_BIT 0x00000001 40 | #define GLX_PIXMAP_BIT 0x00000002 41 | #define GLX_PBUFFER_BIT 0x00000004 42 | #define GLX_AUX_BUFFERS_BIT 0x00000010 43 | #define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 44 | #define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 45 | #define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 46 | #define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 47 | #define GLX_DEPTH_BUFFER_BIT 0x00000020 48 | #define GLX_STENCIL_BUFFER_BIT 0x00000040 49 | #define GLX_ACCUM_BUFFER_BIT 0x00000080 50 | #define GLX_NONE 0x8000 51 | #define GLX_SLOW_CONFIG 0x8001 52 | #define GLX_TRUE_COLOR 0x8002 53 | #define GLX_DIRECT_COLOR 0x8003 54 | #define GLX_PSEUDO_COLOR 0x8004 55 | #define GLX_STATIC_COLOR 0x8005 56 | #define GLX_GRAY_SCALE 0x8006 57 | #define GLX_STATIC_GRAY 0x8007 58 | #define GLX_TRANSPARENT_RGB 0x8008 59 | #define GLX_TRANSPARENT_INDEX 0x8009 60 | #define GLX_VISUAL_ID 0x800B 61 | #define GLX_SCREEN 0x800C 62 | #define GLX_NON_CONFORMANT_CONFIG 0x800D 63 | #define GLX_DRAWABLE_TYPE 0x8010 64 | #define GLX_RENDER_TYPE 0x8011 65 | #define GLX_X_RENDERABLE 0x8012 66 | #define GLX_FBCONFIG_ID 0x8013 67 | #define GLX_RGBA_TYPE 0x8014 68 | #define GLX_COLOR_INDEX_TYPE 0x8015 69 | #define GLX_MAX_PBUFFER_WIDTH 0x8016 70 | #define GLX_MAX_PBUFFER_HEIGHT 0x8017 71 | #define GLX_MAX_PBUFFER_PIXELS 0x8018 72 | #define GLX_PRESERVED_CONTENTS 0x801B 73 | #define GLX_LARGEST_PBUFFER 0x801C 74 | #define GLX_WIDTH 0x801D 75 | #define GLX_HEIGHT 0x801E 76 | #define GLX_EVENT_MASK 0x801F 77 | #define GLX_DAMAGED 0x8020 78 | #define GLX_SAVED 0x8021 79 | #define GLX_WINDOW 0x8022 80 | #define GLX_PBUFFER 0x8023 81 | #define GLX_PBUFFER_HEIGHT 0x8040 82 | #define GLX_PBUFFER_WIDTH 0x8041 83 | #define GLX_RGBA_BIT 0x00000001 84 | #define GLX_COLOR_INDEX_BIT 0x00000002 85 | #define GLX_PBUFFER_CLOBBER_MASK 0x08000000 86 | 87 | #define GLX_SAMPLE_BUFFERS 0x186a0 88 | #define GLX_SAMPLES 0x186a1 89 | 90 | #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2 91 | #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 92 | #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 93 | #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 94 | #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 95 | #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 96 | #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 97 | #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 98 | #define GLX_CONTEXT_FLAGS_ARB 0x2094 99 | #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 100 | #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 101 | #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 102 | #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 103 | #define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 104 | #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 105 | #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 106 | #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 107 | #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 108 | 109 | typedef struct __GLXcontextRec *GLXContext; 110 | typedef XID GLXPixmap; 111 | typedef XID GLXDrawable; 112 | 113 | typedef struct __GLXFBConfigRec *GLXFBConfig; 114 | typedef XID GLXFBConfigID; 115 | typedef XID GLXContextID; 116 | typedef XID GLXWindow; 117 | typedef XID GLXPbuffer; 118 | 119 | void glximpl_init(); 120 | 121 | #endif -------------------------------------------------------------------------------- /inc/client/platform/icd.h: -------------------------------------------------------------------------------- 1 | #ifndef _ICD_H_ 2 | #define _ICD_H_ 3 | 4 | #define ICD_SET_MAX_DIMENSIONS_DEFINITION(mw, mh, rw, rh) \ 5 | void icd_set_max_dimensions(int width, int height) \ 6 | { \ 7 | mw = width; \ 8 | mh = height; \ 9 | rw = 16; \ 10 | rh = 16; \ 11 | } 12 | 13 | #define ICD_RESIZE_DEFINITION(rw, rh) \ 14 | void icd_resize(int width, int height) \ 15 | { \ 16 | rw = width; \ 17 | rh = height; \ 18 | } \ 19 | 20 | void icd_set_max_dimensions(int width, int height); 21 | void icd_resize(int width, int height); 22 | 23 | #endif -------------------------------------------------------------------------------- /inc/client/platform/wgl.h: -------------------------------------------------------------------------------- 1 | #ifdef OVERRIDE_OPENGL32 2 | #ifndef _SGL_WGL_H_ 3 | #define _SGL_WGL_H_ 4 | 5 | #include 6 | 7 | void WglInit(); 8 | 9 | #endif 10 | #endif -------------------------------------------------------------------------------- /inc/client/platform/windrv.h: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #ifndef _WINDRV_H_ 3 | #define _WINDRV_H_ 4 | 5 | void windrv_set_module_address(HMODULE module); 6 | void windrv_set_vflip(BOOL flip); 7 | 8 | #endif 9 | #endif -------------------------------------------------------------------------------- /inc/client/scratch.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCRATCH_H_ 2 | #define _SCRATCH_H_ 3 | 4 | #include 5 | 6 | void *scratch_buffer_get(size_t size); 7 | 8 | #endif -------------------------------------------------------------------------------- /inc/client/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPINLOCK_H_ 2 | #define _SPINLOCK_H_ 3 | 4 | void spin_lock(int *lock); 5 | void spin_unlock(int volatile *lock); 6 | 7 | #endif -------------------------------------------------------------------------------- /inc/network/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2002-2016 Lee Salzman 4 | Copyright (c) 2017-2022 Vladyslav Hrytsenko, Dominik Madarász 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /inc/network/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_PACKET_H_ 2 | #define _SGL_PACKET_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef _WIN32 9 | #define PACKED __attribute__((packed)) 10 | #else 11 | #define PACKED 12 | #endif 13 | 14 | #ifdef _WIN32 15 | __pragma( pack(push, 1) ) 16 | #endif 17 | struct PACKED sgl_packet_connect { 18 | uint32_t client_id; 19 | uint64_t framebuffer_size; 20 | uint64_t fifo_size; 21 | uint32_t gl_major; 22 | uint32_t gl_minor; 23 | uint32_t max_width; 24 | uint32_t max_height; 25 | }; 26 | 27 | struct PACKED sgl_packet_retval { 28 | union { 29 | uint32_t retval_split[2]; 30 | uint64_t retval; 31 | }; 32 | uint32_t retval_v[256 / sizeof(uint32_t)]; 33 | }; 34 | #ifdef _WIN32 35 | __pragma( pack(pop)) 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /inc/server/context.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_CONTEXT_H_ 2 | #define _SGL_CONTEXT_H_ 3 | 4 | #include 5 | 6 | struct sgl_host_context { 7 | SDL_Window *window; 8 | SDL_GLContext gl_context; 9 | }; 10 | 11 | void sgl_set_max_resolution(int width, int height); 12 | void sgl_get_max_resolution(int *width, int *height); 13 | 14 | struct sgl_host_context *sgl_context_create(); 15 | void sgl_context_destroy(struct sgl_host_context *ctx); 16 | void sgl_set_current(struct sgl_host_context *ctx); 17 | void *sgl_read_pixels(unsigned int width, unsigned int height, void *data, int vflip, int format, size_t mem_usage); 18 | 19 | #endif -------------------------------------------------------------------------------- /inc/server/dynarr.h: -------------------------------------------------------------------------------- 1 | #ifndef _DYNARR_H_ 2 | #define _DYNARR_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef bool(*dynarr_match_fn)(void *elem, void *data); 8 | 9 | void *dynarr_alloc(void **root, size_t next_offset, size_t size); 10 | void dynarr_free_element(void **root, size_t next_offset, dynarr_match_fn matcher, void *data); 11 | void dynarr_free(void **root, size_t next_offset); 12 | 13 | #endif -------------------------------------------------------------------------------- /inc/server/overlay.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_OVERLAY_H_ 2 | #define _SGL_OVERLAY_H_ 3 | 4 | #include 5 | 6 | struct overlay_context { 7 | clock_t current_ticks, delta_ticks; 8 | clock_t fps; 9 | }; 10 | 11 | void overlay_set_renderer_string(char *string); 12 | void overlay_enable(); 13 | void overlay_stage1(struct overlay_context *ctx); 14 | void overlay_stage2(struct overlay_context *ctx, int *frame, int width, size_t mem_usage); 15 | 16 | #endif -------------------------------------------------------------------------------- /inc/server/overlay_font.h: -------------------------------------------------------------------------------- 1 | #ifndef _OVERLAY_FONT_H_ 2 | #define _OVERLAY_FONT_H_ 3 | 4 | #define CHAR_WIDTH 8 5 | #define CHAR_HEIGHT 16 6 | 7 | static const unsigned char IBM[4096] = 8 | { 9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 43 | 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x7e, 0x24, 0x24, 0x7e, 0x48, 0x48, 0x48, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x3e, 0x49, 0x48, 0x38, 0x0e, 0x09, 0x49, 0x3e, 0x08, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x31, 0x4a, 0x4a, 0x34, 0x08, 0x08, 0x16, 0x29, 0x29, 0x46, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x14, 0x18, 0x29, 0x45, 0x42, 0x46, 0x39, 0x00, 0x00, 48 | 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 50 | 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x2a, 0x1c, 0x2a, 0x49, 0x08, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x10, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x24, 0x18, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x0c, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x1c, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x10, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 72 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x4a, 0x56, 0x52, 0x52, 0x52, 0x4e, 0x20, 0x1e, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 75 | 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 76 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 77 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x60, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x66, 0x66, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 89 | 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x66, 0x3c, 0x03, 0x00, 91 | 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x44, 0x42, 0x42, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x5a, 0x66, 0x66, 0x42, 0x42, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x42, 0x42, 0x00, 0x00, 98 | 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 99 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 103 | 0x00, 0x00, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 105 | 0x00, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 107 | 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00, 108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 109 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3a, 0x44, 0x44, 0x44, 0x38, 0x20, 0x3c, 0x42, 0x42, 0x3c, 113 | 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 114 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 115 | 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x48, 0x30, 116 | 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 117 | 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 119 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x3c, 0x00, 0x00, 125 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, 129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x42, 0x00, 0x00, 130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x02, 0x3c, 131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 132 | 0x00, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x08, 0x08, 0x10, 0x20, 0x10, 0x08, 0x08, 0x10, 0x10, 0x0c, 133 | 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 134 | 0x00, 0x00, 0x00, 0x30, 0x08, 0x08, 0x10, 0x10, 0x08, 0x04, 0x08, 0x10, 0x10, 0x08, 0x08, 0x30, 135 | 0x00, 0x00, 0x00, 0x31, 0x49, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x73, 0xca, 0x4b, 0xca, 0x73, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 137 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x71, 0xca, 0x73, 0xc2, 0x42, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 138 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x49, 0xca, 0x7a, 0xca, 0x49, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 139 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x73, 0xca, 0x73, 0xca, 0x72, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 140 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x4b, 0xea, 0x5b, 0xca, 0x4b, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 141 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x74, 0xa6, 0x25, 0xa4, 0x74, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 142 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x4b, 0xea, 0x5b, 0xca, 0x4b, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 143 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x31, 0x88, 0x73, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 144 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x79, 0xc2, 0x79, 0xc0, 0x7b, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 145 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x4b, 0xc9, 0x79, 0xc9, 0x49, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 146 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x25, 0xa4, 0x3c, 0xa4, 0x24, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 147 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x45, 0xc4, 0x44, 0xa8, 0x10, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 148 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x72, 0xca, 0x72, 0xc2, 0x43, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 149 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x72, 0xca, 0x72, 0xc2, 0x43, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 150 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x0e, 0x89, 0x0e, 0x8a, 0x09, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 151 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x31, 0x88, 0x73, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 152 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x31, 0x88, 0x73, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 153 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x71, 0xca, 0x4a, 0xca, 0x71, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 154 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x72, 0xca, 0x72, 0xc2, 0x41, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 155 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x72, 0xca, 0x72, 0xc2, 0x41, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 156 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x3b, 0xc1, 0x31, 0x89, 0x71, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 157 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x42, 0xc2, 0x39, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 158 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x22, 0xb6, 0x2a, 0xa2, 0x22, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 159 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x3b, 0xc2, 0x33, 0x8a, 0x72, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 160 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x7b, 0xc2, 0x7b, 0xc2, 0x7a, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 161 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x32, 0x8a, 0x71, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 162 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x33, 0xc4, 0x25, 0x94, 0x63, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 163 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x32, 0x8a, 0x71, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 164 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x39, 0xc2, 0x41, 0xc0, 0x3b, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 165 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x0e, 0x90, 0x0c, 0x82, 0x1c, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 166 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x31, 0xca, 0x49, 0xc8, 0x33, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 167 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x1c, 0x92, 0x1c, 0x90, 0x10, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 168 | 0xaa, 0x00, 0x80, 0x00, 0x80, 0x33, 0xca, 0x7b, 0xca, 0x4a, 0x80, 0x00, 0x80, 0x00, 0x80, 0x55, 169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 170 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 171 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x49, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x08, 0x00, 0x00, 172 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x3e, 0x61, 0x00, 0x00, 173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x24, 0x42, 0x42, 0x24, 0x3c, 0x42, 0x00, 0x00, 0x00, 174 | 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x7f, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x00, 175 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 176 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x3c, 0x42, 0x42, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 177 | 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 178 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x99, 0xa5, 0xa1, 0xa1, 0xa5, 0x99, 0x42, 0x3c, 0x00, 0x00, 179 | 0x00, 0x00, 0x1c, 0x02, 0x1e, 0x22, 0x1e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x24, 0x24, 0x48, 0x24, 0x24, 0x12, 0x12, 0x00, 0x00, 181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x00, 0x00, 182 | 0xaa, 0x00, 0x80, 0x3a, 0xc2, 0x33, 0x8a, 0x72, 0x80, 0x00, 0x80, 0x03, 0x80, 0x00, 0x80, 0x55, 183 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0xb9, 0xa5, 0xa5, 0xb9, 0xa9, 0xa5, 0x42, 0x3c, 0x00, 0x00, 184 | 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 185 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 186 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 187 | 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 188 | 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 189 | 0x00, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x66, 0x59, 0x40, 0x80, 191 | 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7a, 0x7a, 0x7a, 0x3a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 194 | 0x00, 0x00, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 195 | 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x24, 0x24, 0x12, 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, 197 | 0x00, 0x00, 0x00, 0x00, 0x22, 0x62, 0x24, 0x28, 0x28, 0x12, 0x16, 0x2a, 0x4e, 0x42, 0x00, 0x00, 198 | 0x00, 0x00, 0x00, 0x00, 0x22, 0x62, 0x24, 0x28, 0x28, 0x14, 0x1a, 0x22, 0x44, 0x4e, 0x00, 0x00, 199 | 0x00, 0x00, 0x00, 0x00, 0x62, 0x12, 0x24, 0x18, 0x68, 0x12, 0x16, 0x2a, 0x4e, 0x42, 0x00, 0x00, 200 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x20, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 201 | 0x30, 0x0c, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 202 | 0x0c, 0x30, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 203 | 0x18, 0x24, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 204 | 0x32, 0x4c, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 205 | 0x24, 0x24, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 206 | 0x18, 0x24, 0x18, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 207 | 0x00, 0x00, 0x00, 0x00, 0x1f, 0x28, 0x48, 0x48, 0x7f, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x00, 0x00, 208 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x08, 0x30, 209 | 0x30, 0x0c, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 210 | 0x0c, 0x30, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 211 | 0x18, 0x24, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 212 | 0x24, 0x24, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 213 | 0x18, 0x06, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 214 | 0x0c, 0x30, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 215 | 0x18, 0x24, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 216 | 0x24, 0x24, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 217 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0xf2, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 218 | 0x32, 0x4c, 0x00, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 219 | 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 220 | 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 221 | 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 222 | 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 223 | 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, 225 | 0x00, 0x00, 0x00, 0x02, 0x3a, 0x44, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x22, 0x5c, 0x40, 0x00, 226 | 0x30, 0x0c, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 227 | 0x0c, 0x30, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 228 | 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 229 | 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 230 | 0x0c, 0x30, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 231 | 0x00, 0x00, 0x00, 0x40, 0x40, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 232 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x48, 0x58, 0x44, 0x42, 0x42, 0x52, 0x4c, 0x00, 0x00, 233 | 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 234 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 235 | 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 236 | 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 237 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 238 | 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x49, 0x09, 0x3f, 0x48, 0x48, 0x49, 0x3e, 0x00, 0x00, 240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x08, 0x30, 241 | 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 242 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 243 | 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 244 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 245 | 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 246 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 247 | 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 248 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 249 | 0x00, 0x00, 0x32, 0x0c, 0x14, 0x22, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 250 | 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 251 | 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 252 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 253 | 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 254 | 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 255 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x3c, 0x40, 0x00, 258 | 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 259 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 260 | 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 261 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 262 | 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x02, 0x3c, 263 | 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 264 | 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x02, 0x3c, 265 | }; 266 | 267 | #endif -------------------------------------------------------------------------------- /inc/server/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGL_PROCESSOR_H_ 2 | #define _SGL_PROCESSOR_H_ 3 | 4 | #include 5 | #include 6 | 7 | struct sgl_cmd_processor_args { 8 | /* 9 | * shared memory information 10 | */ 11 | void *base_address; 12 | size_t memory_size; 13 | 14 | /* 15 | * use network instead of shared memory 16 | */ 17 | bool network_over_shared; 18 | int port; 19 | 20 | /* 21 | * opengl version 22 | */ 23 | int gl_major; 24 | int gl_minor; 25 | 26 | /* 27 | * for debugging; in the event of an exception, 28 | * this pointer will contain a pointer to the 29 | * current command in execution 30 | */ 31 | int **internal_cmd_ptr; 32 | }; 33 | 34 | void sgl_cmd_processor_start(struct sgl_cmd_processor_args args); 35 | 36 | #endif -------------------------------------------------------------------------------- /inc/sgldebug.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGLDEBUG_H_ 2 | #define _SGLDEBUG_H_ 3 | 4 | const char *sgl_cmd2str(int c); 5 | 6 | #endif -------------------------------------------------------------------------------- /kernel/linux/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | obj-m += sharedgl.o 3 | 4 | sharedgl_mod: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean -------------------------------------------------------------------------------- /kernel/linux/install.sh: -------------------------------------------------------------------------------- 1 | mkdir /lib/modules/$(uname -r)/kernel/drivers/pci/sharedgl 2 | zstd sharedgl.ko 3 | mv sharedgl.ko.zst /lib/modules/$(uname -r)/kernel/drivers/pci/sharedgl/sharedgl.ko.zst 4 | depmod -a 5 | modprobe sharedgl -------------------------------------------------------------------------------- /kernel/linux/sharedgl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | struct bar_t { 17 | resource_size_t len; 18 | void __iomem *addr; 19 | resource_size_t phys; 20 | }; 21 | 22 | struct pci_char { 23 | struct bar_t bar[6]; 24 | dev_t major; 25 | struct cdev cdev; 26 | }; 27 | 28 | static struct class *pchar_class; 29 | 30 | static int dev_open(struct inode *inode, struct file *file) 31 | { 32 | unsigned int num = iminor(file->f_path.dentry->d_inode); 33 | struct pci_char *pchar = container_of(inode->i_cdev, struct pci_char, cdev); 34 | 35 | if (num > 5) 36 | return -ENXIO; 37 | if (pchar->bar[num].len == 0) 38 | return -EIO; 39 | 40 | file->private_data = pchar; 41 | return 0; 42 | } 43 | 44 | int dev_mmap(struct file *file, struct vm_area_struct *vma) 45 | { 46 | struct pci_char *pchar = file->private_data; 47 | 48 | if (io_remap_pfn_range(vma, vma->vm_start, 49 | pchar->bar[2].phys >> PAGE_SHIFT, vma->vm_end - vma->vm_start, 50 | vma->vm_page_prot)) 51 | return -EAGAIN; 52 | 53 | return 0; 54 | } 55 | 56 | static const struct file_operations fops = { 57 | .owner = THIS_MODULE, 58 | .open = dev_open, 59 | .mmap = dev_mmap 60 | }; 61 | 62 | static int my_dev_uevent(const struct device *dev, struct kobj_uevent_env *env) 63 | { 64 | add_uevent_var(env, "DEVMODE=%#o", 0666); 65 | return 0; 66 | } 67 | 68 | static int pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 69 | { 70 | int err = 0, i; 71 | int mem_bars; 72 | struct pci_char *pchar; 73 | struct device *dev; 74 | dev_t dev_num; 75 | 76 | pchar = kmalloc(sizeof(struct pci_char), GFP_KERNEL); 77 | if (!pchar) { 78 | err = -ENOMEM; 79 | goto failure_kmalloc; 80 | } 81 | 82 | err = pci_enable_device_mem(pdev); 83 | if (err) 84 | goto failure_pci_enable; 85 | 86 | mem_bars = pci_select_bars(pdev, IORESOURCE_MEM); 87 | err = pci_request_selected_regions(pdev, mem_bars, "sharedgl"); 88 | if (err) 89 | goto failure_pci_regions; 90 | 91 | for (i = 0; i < 6; i++) { 92 | if (mem_bars & (1 << i)) { 93 | pchar->bar[i].addr = ioremap(pci_resource_start(pdev, i), pci_resource_len(pdev, i)); 94 | if (IS_ERR(pchar->bar[i].addr)) { 95 | err = PTR_ERR(pchar->bar[i].addr); 96 | break; 97 | } else { 98 | pchar->bar[i].phys = pci_resource_start(pdev, i); 99 | pchar->bar[i].len = pci_resource_len(pdev, i); 100 | } 101 | } else { 102 | pchar->bar[i].addr = NULL; 103 | pchar->bar[i].len = 0; 104 | } 105 | } 106 | 107 | if (err) { 108 | for (i--; i >= 0; i--) 109 | if (pchar->bar[i].len) 110 | iounmap(pchar->bar[i].addr); 111 | goto failure_ioremap; 112 | } 113 | 114 | err = alloc_chrdev_region(&dev_num, 0, 6, "sharedgl"); 115 | if (err) 116 | goto failure_alloc_chrdev_region; 117 | 118 | pchar->major = MAJOR(dev_num); 119 | 120 | cdev_init(&pchar->cdev, &fops); 121 | pchar->cdev.owner = THIS_MODULE; 122 | 123 | err = cdev_add(&pchar->cdev, MKDEV(pchar->major, 0), 6); 124 | if (err) 125 | goto failure_cdev_add; 126 | 127 | pchar_class->dev_uevent = my_dev_uevent; 128 | for (i = 0; i < 6; i++) { 129 | if (pchar->bar[i].len) { 130 | dev = device_create(pchar_class, &pdev->dev, 131 | MKDEV(pchar->major, i), 132 | NULL, "b%xd%xf%x_bar%d", 133 | pdev->bus->number, 134 | PCI_SLOT(pdev->devfn), 135 | PCI_FUNC(pdev->devfn), i); 136 | if (IS_ERR(dev)) { 137 | err = PTR_ERR(dev); 138 | break; 139 | } 140 | } 141 | } 142 | 143 | if (err) { 144 | for (i--; i >= 0; i--) 145 | if (pchar->bar[i].len) 146 | device_destroy(pchar_class, 147 | MKDEV(pchar->major, i)); 148 | goto failure_device_create; 149 | } 150 | 151 | pci_set_drvdata(pdev, pchar); 152 | dev_info(&pdev->dev, "claimed by sharedgl\n"); 153 | 154 | return 0; 155 | 156 | failure_device_create: 157 | cdev_del(&pchar->cdev); 158 | 159 | failure_cdev_add: 160 | unregister_chrdev_region(MKDEV(pchar->major, 0), 6); 161 | 162 | failure_alloc_chrdev_region: 163 | for (i = 0; i < 6; i++) 164 | if (pchar->bar[i].len) 165 | iounmap(pchar->bar[i].addr); 166 | 167 | failure_ioremap: 168 | pci_release_selected_regions(pdev, 169 | pci_select_bars(pdev, IORESOURCE_MEM)); 170 | 171 | failure_pci_regions: 172 | pci_disable_device(pdev); 173 | 174 | failure_pci_enable: 175 | kfree(pchar); 176 | 177 | failure_kmalloc: 178 | return err; 179 | } 180 | 181 | static void pci_remove(struct pci_dev *pdev) 182 | { 183 | int i; 184 | struct pci_char *pchar = pci_get_drvdata(pdev); 185 | 186 | for (i = 0; i < 6; i++) 187 | if (pchar->bar[i].len) 188 | device_destroy(pchar_class, 189 | MKDEV(pchar->major, i)); 190 | 191 | cdev_del(&pchar->cdev); 192 | 193 | unregister_chrdev_region(MKDEV(pchar->major, 0), 6); 194 | 195 | for (i = 0; i < 6; i++) 196 | if (pchar->bar[i].len) 197 | iounmap(pchar->bar[i].addr); 198 | 199 | pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); 200 | pci_disable_device(pdev); 201 | kfree(pchar); 202 | } 203 | 204 | static struct pci_device_id pci_ids[] = { 205 | { 206 | .vendor = 0x1af4, 207 | .device = 0x1110, 208 | .subvendor = PCI_ANY_ID, 209 | .subdevice = PCI_ANY_ID, 210 | }, 211 | { 0, } 212 | }; 213 | 214 | static struct pci_driver pchar_driver = { 215 | .name = "sharedgl", 216 | .id_table = pci_ids, 217 | .probe = pci_probe, 218 | .remove = pci_remove, 219 | }; 220 | 221 | static char *pci_char_devnode(const struct device *dev, umode_t *mode) 222 | { 223 | struct pci_dev *pdev = to_pci_dev(dev->parent); 224 | return kasprintf( 225 | GFP_KERNEL, "sharedgl/%02x:%02x.%02x/bar%d", 226 | pdev->bus->number, 227 | PCI_SLOT(pdev->devfn), 228 | PCI_FUNC(pdev->devfn), 229 | MINOR(dev->devt) 230 | ); 231 | } 232 | 233 | static int __init pci_init(void) 234 | { 235 | int err; 236 | 237 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) 238 | pchar_class = class_create("sharedgl"); 239 | #else 240 | pchar_class = class_create(THIS_MODULE, "sharedgl"); 241 | #endif 242 | 243 | if (IS_ERR(pchar_class)) { 244 | err = PTR_ERR(pchar_class); 245 | return err; 246 | } 247 | 248 | pchar_class->devnode = pci_char_devnode; 249 | 250 | err = pci_register_driver(&pchar_driver); 251 | if (err) 252 | goto failure_register_driver; 253 | 254 | return 0; 255 | 256 | failure_register_driver: 257 | class_destroy(pchar_class); 258 | 259 | return err; 260 | } 261 | 262 | static void __exit pci_exit(void) 263 | { 264 | pci_unregister_driver(&pchar_driver); 265 | class_destroy(pchar_class); 266 | } 267 | 268 | module_init(pci_init); 269 | module_exit(pci_exit); 270 | 271 | MODULE_LICENSE("Dual MIT/GPL"); 272 | MODULE_DESCRIPTION("Driver to expose sharedgl memory"); 273 | MODULE_AUTHOR("dmaivel"); -------------------------------------------------------------------------------- /kernel/linux/uninstall.sh: -------------------------------------------------------------------------------- 1 | rmmod sharedgl 2 | rm -rf /lib/modules/$(uname -r)/kernel/drivers/pci/sharedgl 3 | depmod -a -------------------------------------------------------------------------------- /kernel/windows/Device.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | #ifdef ALLOC_PRAGMA 4 | #pragma alloc_text (PAGE, IVSHMEMCreateDevice) 5 | #pragma alloc_text (PAGE, IVSHMEMEvtDevicePrepareHardware) 6 | #pragma alloc_text (PAGE, IVSHMEMEvtD0Exit) 7 | #endif 8 | 9 | NTSTATUS IVSHMEMCreateDevice(_Inout_ PWDFDEVICE_INIT DeviceInit) 10 | { 11 | WDF_OBJECT_ATTRIBUTES deviceAttributes; 12 | PDEVICE_CONTEXT deviceContext; 13 | WDFDEVICE device; 14 | NTSTATUS status; 15 | 16 | PAGED_CODE(); 17 | DEBUG_INFO("%s", __FUNCTION__); 18 | 19 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); 20 | 21 | WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; 22 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); 23 | pnpPowerCallbacks.EvtDevicePrepareHardware = IVSHMEMEvtDevicePrepareHardware; 24 | pnpPowerCallbacks.EvtDeviceReleaseHardware = IVSHMEMEvtDeviceReleaseHardware; 25 | pnpPowerCallbacks.EvtDeviceD0Entry = IVSHMEMEvtD0Entry; 26 | pnpPowerCallbacks.EvtDeviceD0Exit = IVSHMEMEvtD0Exit; 27 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); 28 | 29 | WDF_FILEOBJECT_CONFIG fileConfig; 30 | WDF_FILEOBJECT_CONFIG_INIT(&fileConfig, NULL, NULL, IVSHMEMEvtDeviceFileCleanup); 31 | WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); 32 | 33 | status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); 34 | 35 | if (!NT_SUCCESS(status)) 36 | { 37 | DEBUG_ERROR("%s", "Call to WdfDeviceCreate failed"); 38 | return status; 39 | } 40 | 41 | deviceContext = DeviceGetContext(device); 42 | RtlZeroMemory(deviceContext, sizeof(DEVICE_CONTEXT)); 43 | KeInitializeSpinLock(&deviceContext->eventListLock); 44 | InitializeListHead(&deviceContext->eventList); 45 | 46 | status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_IVSHMEM, NULL); 47 | 48 | if (!NT_SUCCESS(status)) 49 | { 50 | DEBUG_ERROR("%s", "Call to WdfDeviceCreateDeviceInterface failed"); 51 | return status; 52 | } 53 | 54 | status = IVSHMEMQueueInitialize(device); 55 | if (!NT_SUCCESS(status)) 56 | { 57 | DEBUG_ERROR("%s", "IVSHMEMQueueInitialize failed"); 58 | return status; 59 | } 60 | 61 | return status; 62 | } 63 | 64 | PVOID IVSHMEMMmMapIoSpace( 65 | _In_ PHYSICAL_ADDRESS PhysicalAddress, 66 | _In_ SIZE_T NumberOfBytes 67 | ) 68 | { 69 | typedef 70 | PVOID 71 | (*PFN_MM_MAP_IO_SPACE_EX) ( 72 | _In_ PHYSICAL_ADDRESS PhysicalAddress, 73 | _In_ SIZE_T NumberOfBytes, 74 | _In_ ULONG Protect 75 | ); 76 | 77 | UNICODE_STRING name; 78 | PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx; 79 | 80 | RtlInitUnicodeString(&name, L"MmMapIoSpaceEx"); 81 | pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name); 82 | 83 | if (pMmMapIoSpaceEx != NULL){ 84 | // Call WIN10 API if available 85 | return pMmMapIoSpaceEx(PhysicalAddress, 86 | NumberOfBytes, 87 | PAGE_READWRITE | PAGE_NOCACHE); 88 | } 89 | 90 | #pragma warning(suppress: 30029) 91 | return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached); 92 | } 93 | 94 | 95 | NTSTATUS IVSHMEMEvtDevicePrepareHardware(_In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated) 96 | { 97 | PAGED_CODE(); 98 | DEBUG_INFO("%s", __FUNCTION__); 99 | PDEVICE_CONTEXT deviceContext; 100 | deviceContext = DeviceGetContext(Device); 101 | 102 | #if (NTDDI_VERSION < NTDDI_WIN8) 103 | UNREFERENCED_PARAMETER(ResourcesRaw); 104 | #endif 105 | NTSTATUS result = STATUS_SUCCESS; 106 | int memIndex = 0; 107 | 108 | const ULONG resCount = WdfCmResourceListGetCount(ResourcesTranslated); 109 | for (ULONG i = 0; i < resCount; ++i) 110 | { 111 | PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; 112 | descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); 113 | if (!descriptor) 114 | { 115 | DEBUG_ERROR("%s", "Call to WdfCmResourceListGetDescriptor failed"); 116 | return STATUS_DEVICE_CONFIGURATION_ERROR; 117 | } 118 | 119 | if (descriptor->Type == CmResourceTypeInterrupt && descriptor->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) 120 | ++deviceContext->interruptCount; 121 | } 122 | 123 | if (deviceContext->interruptCount > 0) 124 | { 125 | deviceContext->interrupts = (WDFINTERRUPT*)ExAllocatePoolUninitialized(IVSHMEM_NONPAGED_POOL, 126 | sizeof(WDFINTERRUPT) * deviceContext->interruptCount, 'sQRI'); 127 | 128 | if (!deviceContext->interrupts) 129 | { 130 | DEBUG_ERROR("Failed to allocate space for %d interrupts", deviceContext->interrupts); 131 | return STATUS_INSUFFICIENT_RESOURCES; 132 | } 133 | } 134 | 135 | for (ULONG i = 0; i < resCount; ++i) 136 | { 137 | PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; 138 | descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); 139 | if (!descriptor) 140 | { 141 | DEBUG_ERROR("%s", "Call to WdfCmResourceListGetDescriptor failed"); 142 | return STATUS_DEVICE_CONFIGURATION_ERROR; 143 | } 144 | 145 | if (descriptor->Type == CmResourceTypeMemory) 146 | { 147 | // control registers 148 | if (memIndex == 0) 149 | { 150 | if (descriptor->u.Memory.Length != sizeof(IVSHMEMDeviceRegisters)) 151 | { 152 | DEBUG_ERROR("Resource size was %u long when %u was expected", 153 | descriptor->u.Memory.Length, sizeof(IVSHMEMDeviceRegisters)); 154 | result = STATUS_DEVICE_HARDWARE_ERROR; 155 | break; 156 | } 157 | 158 | deviceContext->devRegisters = (PIVSHMEMDeviceRegisters)IVSHMEMMmMapIoSpace( 159 | descriptor->u.Memory.Start, 160 | descriptor->u.Memory.Length); 161 | 162 | if (!deviceContext->devRegisters) 163 | { 164 | DEBUG_ERROR("%s", "Call to MmMapIoSpace failed"); 165 | result = STATUS_DEVICE_HARDWARE_ERROR; 166 | break; 167 | } 168 | } 169 | else 170 | // shared memory resource 171 | if ((deviceContext->interruptCount == 0 && memIndex == 1) || memIndex == 2) 172 | { 173 | deviceContext->shmemAddr.PhysicalAddress = descriptor->u.Memory.Start; 174 | deviceContext->shmemAddr.NumberOfBytes = descriptor->u.Memory.Length; 175 | DEBUG_INFO("memIndex = %d pa = %llx (%llx) size = %lx (%lx)", memIndex, descriptor->u.Memory.Start.QuadPart, deviceContext->shmemAddr.PhysicalAddress.QuadPart, descriptor->u.Memory.Length, deviceContext->shmemAddr.NumberOfBytes); 176 | 177 | #if (NTDDI_VERSION >= NTDDI_WIN8) 178 | result = MmAllocateMdlForIoSpace(&deviceContext->shmemAddr, 1, &deviceContext->shmemMDL); 179 | #else 180 | deviceContext->shmemAddr.VirtualAddress = MmMapIoSpace(deviceContext->shmemAddr.PhysicalAddress, deviceContext->shmemAddr.NumberOfBytes, MmNonCached); 181 | if (deviceContext->shmemAddr.VirtualAddress) { 182 | deviceContext->shmemMDL = IoAllocateMdl(deviceContext->shmemAddr.VirtualAddress, (ULONG)deviceContext->shmemAddr.NumberOfBytes, FALSE, FALSE, NULL); 183 | if (!deviceContext->shmemMDL) { 184 | DEBUG_INFO("%s", "Call to IoAllocateMdl failed"); 185 | result = STATUS_INSUFFICIENT_RESOURCES; 186 | } 187 | 188 | MmBuildMdlForNonPagedPool(deviceContext->shmemMDL); 189 | } 190 | else { 191 | DEBUG_INFO("%s", "Call to MmMapIoSpace failed"); 192 | result = STATUS_INSUFFICIENT_RESOURCES; 193 | } 194 | #endif 195 | if (!NT_SUCCESS(result)) 196 | { 197 | DEBUG_ERROR("%s", "Call to MmAllocateMdlForIoSpace failed"); 198 | break; 199 | } 200 | } 201 | DEBUG_INFO("memIndex = %d va = %p mdl = %p", memIndex, deviceContext->shmemAddr.VirtualAddress, deviceContext->shmemMDL); 202 | ++memIndex; 203 | continue; 204 | } 205 | 206 | if (descriptor->Type == CmResourceTypeInterrupt && 207 | (descriptor->Flags & CM_RESOURCE_INTERRUPT_MESSAGE)) 208 | { 209 | WDF_INTERRUPT_CONFIG irqConfig; 210 | WDF_INTERRUPT_CONFIG_INIT(&irqConfig, 211 | IVSHMEMInterruptISR, 212 | IVSHMEMInterruptDPC); 213 | #if (NTDDI_VERSION >= NTDDI_WIN8) 214 | irqConfig.InterruptTranslated = descriptor; 215 | irqConfig.InterruptRaw = WdfCmResourceListGetDescriptor(ResourcesRaw, i); 216 | #endif 217 | NTSTATUS status = WdfInterruptCreate(Device, &irqConfig, WDF_NO_OBJECT_ATTRIBUTES, 218 | &deviceContext->interrupts[deviceContext->interruptsUsed]); 219 | 220 | if (!NT_SUCCESS(status)) 221 | { 222 | DEBUG_ERROR("Call to WdfInterruptCreate failed: %08x", status); 223 | result = status; 224 | break; 225 | } 226 | 227 | if (++deviceContext->interruptsUsed == 65) 228 | DEBUG_INFO("%s", "This driver does not support > 64 interrupts, they will be ignored in the ISR."); 229 | 230 | continue; 231 | } 232 | } 233 | 234 | if (NT_SUCCESS(result)) 235 | { 236 | if (!deviceContext->shmemMDL) { 237 | DEBUG_ERROR("%s", "shmemMDL == NULL"); 238 | result = STATUS_DEVICE_HARDWARE_ERROR; 239 | } 240 | else 241 | { 242 | DEBUG_INFO("Shared Memory: %llx, %lx bytes", deviceContext->shmemAddr.PhysicalAddress.QuadPart, deviceContext->shmemAddr.NumberOfBytes); 243 | DEBUG_INFO("Interrupts : %d", deviceContext->interruptsUsed); 244 | } 245 | } 246 | DEBUG_INFO("%s result 0x%x", __FUNCTION__, result); 247 | return result; 248 | } 249 | 250 | NTSTATUS IVSHMEMEvtDeviceReleaseHardware(_In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesTranslated) 251 | { 252 | UNREFERENCED_PARAMETER(ResourcesTranslated); 253 | DEBUG_INFO("%s", __FUNCTION__); 254 | 255 | PDEVICE_CONTEXT deviceContext; 256 | deviceContext = DeviceGetContext(Device); 257 | 258 | if (deviceContext->devRegisters) 259 | { 260 | MmUnmapIoSpace(deviceContext->devRegisters, sizeof(PIVSHMEMDeviceRegisters)); 261 | } 262 | 263 | if (deviceContext->shmemMap) 264 | { 265 | MmUnmapLockedPages(deviceContext->shmemMap, deviceContext->shmemMDL); 266 | deviceContext->shmemMap = NULL; 267 | } 268 | 269 | if (deviceContext->shmemMDL) 270 | { 271 | IoFreeMdl(deviceContext->shmemMDL); 272 | deviceContext->shmemMDL = NULL; 273 | } 274 | 275 | if (deviceContext->interrupts) 276 | { 277 | // WDFINTERRUPT objects are deleted by the framework 278 | 279 | ExFreePoolWithTag(deviceContext->interrupts, 'sQRI'); 280 | 281 | deviceContext->interruptCount = 0; 282 | deviceContext->interruptsUsed = 0; 283 | deviceContext->interrupts = NULL; 284 | } 285 | 286 | KIRQL oldIRQL; 287 | KeAcquireSpinLock(&deviceContext->eventListLock, &oldIRQL); 288 | PLIST_ENTRY entry = deviceContext->eventList.Flink; 289 | while (entry != &deviceContext->eventList) 290 | { 291 | _Analysis_assume_(entry != NULL); 292 | PIVSHMEMEventListEntry event = CONTAINING_RECORD(entry, IVSHMEMEventListEntry, ListEntry); 293 | if (event->event) 294 | { 295 | ObDereferenceObject(event->event); 296 | } 297 | event->owner = NULL; 298 | event->event = NULL; 299 | event->vector = 0; 300 | 301 | entry = entry->Flink; 302 | } 303 | InitializeListHead(&deviceContext->eventList); 304 | deviceContext->eventBufferUsed = 0; 305 | KeReleaseSpinLock(&deviceContext->eventListLock, oldIRQL); 306 | 307 | return STATUS_SUCCESS; 308 | } 309 | 310 | NTSTATUS IVSHMEMEvtD0Entry(_In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState) 311 | { 312 | UNREFERENCED_PARAMETER(Device); 313 | UNREFERENCED_PARAMETER(PreviousState); 314 | DEBUG_INFO("%s", __FUNCTION__); 315 | return STATUS_SUCCESS; 316 | } 317 | 318 | NTSTATUS IVSHMEMEvtD0Exit(_In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState) 319 | { 320 | UNREFERENCED_PARAMETER(Device); 321 | UNREFERENCED_PARAMETER(PreviousState); 322 | PAGED_CODE(); 323 | DEBUG_INFO("%s", __FUNCTION__); 324 | return STATUS_SUCCESS; 325 | } 326 | 327 | BOOLEAN IVSHMEMInterruptISR(_In_ WDFINTERRUPT Interrupt, _In_ ULONG MessageID) 328 | { 329 | WDFDEVICE device; 330 | PDEVICE_CONTEXT deviceContext; 331 | 332 | // out of range. if you have this many you're doing it wrong anyway 333 | if (MessageID > 64) 334 | return TRUE; 335 | 336 | device = WdfInterruptGetDevice(Interrupt); 337 | deviceContext = DeviceGetContext(device); 338 | 339 | if (!InterlockedOr64(&deviceContext->pendingISR, 1ULL << MessageID)) 340 | WdfInterruptQueueDpcForIsr(Interrupt); 341 | 342 | return TRUE; 343 | } 344 | 345 | void IVSHMEMInterruptDPC(_In_ WDFINTERRUPT Interrupt, _In_ WDFOBJECT AssociatedObject) 346 | { 347 | UNREFERENCED_PARAMETER(AssociatedObject); 348 | 349 | WDFDEVICE device; 350 | PDEVICE_CONTEXT deviceContext; 351 | UINT64 pending; 352 | 353 | device = WdfInterruptGetDevice(Interrupt); 354 | deviceContext = DeviceGetContext(device); 355 | 356 | pending = InterlockedExchange64(&deviceContext->pendingISR, 0); 357 | if (!pending) 358 | return; 359 | 360 | KeAcquireSpinLockAtDpcLevel(&deviceContext->eventListLock); 361 | PLIST_ENTRY entry = deviceContext->eventList.Flink; 362 | while (entry != &deviceContext->eventList) 363 | { 364 | PIVSHMEMEventListEntry event = CONTAINING_RECORD(entry, IVSHMEMEventListEntry, ListEntry); 365 | PLIST_ENTRY next = entry->Flink; 366 | if (pending & ((LONG64)1 << event->vector)) 367 | { 368 | _Analysis_assume_(event->event != NULL); 369 | KeSetEvent(event->event, 0, FALSE); 370 | if (event->singleShot) 371 | { 372 | RemoveEntryList(entry); 373 | ObDereferenceObjectDeferDelete(event->event); 374 | event->owner = NULL; 375 | event->event = NULL; 376 | event->vector = 0; 377 | --deviceContext->eventBufferUsed; 378 | } 379 | } 380 | entry = next; 381 | } 382 | KeReleaseSpinLockFromDpcLevel(&deviceContext->eventListLock); 383 | } 384 | -------------------------------------------------------------------------------- /kernel/windows/Device.h: -------------------------------------------------------------------------------- 1 | #include "public.h" 2 | 3 | EXTERN_C_START 4 | 5 | #define MAX_EVENTS 32 6 | 7 | #pragma align(push,4) 8 | typedef struct IVSHMEMDeviceRegisters 9 | { 10 | volatile ULONG irqMask; 11 | volatile ULONG irqStatus; 12 | volatile LONG ivProvision; 13 | volatile ULONG doorbell; 14 | volatile UCHAR reserved[240]; 15 | } 16 | IVSHMEMDeviceRegisters, *PIVSHMEMDeviceRegisters; 17 | #pragma align(pop) 18 | 19 | typedef struct IVSHMEMEventListEntry 20 | { 21 | WDFFILEOBJECT owner; 22 | UINT16 vector; 23 | PRKEVENT event; 24 | BOOLEAN singleShot; 25 | LIST_ENTRY ListEntry; 26 | } 27 | IVSHMEMEventListEntry, *PIVSHMEMEventListEntry; 28 | 29 | #if (NTDDI_VERSION < NTDDI_WIN8) 30 | typedef struct _MM_PHYSICAL_ADDRESS_LIST { 31 | PHYSICAL_ADDRESS PhysicalAddress; 32 | PVOID VirtualAddress; 33 | SIZE_T NumberOfBytes; 34 | } MM_PHYSICAL_ADDRESS_LIST, *PMM_PHYSICAL_ADDRESS_LIST; 35 | #endif 36 | 37 | typedef struct _DEVICE_CONTEXT 38 | { 39 | PIVSHMEMDeviceRegisters devRegisters; // the device registers (BAR0) 40 | 41 | MM_PHYSICAL_ADDRESS_LIST shmemAddr; // physical address of the shared memory (BAR2) 42 | PMDL shmemMDL; // memory discriptor list of the shared memory 43 | PVOID shmemMap; // memory mapping of the shared memory 44 | WDFFILEOBJECT owner; // the file object that currently owns the mapping 45 | UINT16 interruptCount; // the number of interrupt entries allocated 46 | UINT16 interruptsUsed; // the number of interrupt entries used 47 | WDFINTERRUPT *interrupts; // interrupts for this device 48 | LONG64 pendingISR; // flags for ISRs pending processing 49 | 50 | KSPIN_LOCK eventListLock; // spinlock for the below event list 51 | IVSHMEMEventListEntry eventBuffer[MAX_EVENTS]; // buffer of pre-allocated events 52 | UINT16 eventBufferUsed; // number of events currenty in use 53 | LIST_ENTRY eventList; // pending events to fire 54 | } 55 | DEVICE_CONTEXT, *PDEVICE_CONTEXT; 56 | 57 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext) 58 | 59 | NTSTATUS IVSHMEMCreateDevice(_Inout_ PWDFDEVICE_INIT DeviceInit); 60 | 61 | EVT_WDF_DEVICE_PREPARE_HARDWARE IVSHMEMEvtDevicePrepareHardware; 62 | EVT_WDF_DEVICE_RELEASE_HARDWARE IVSHMEMEvtDeviceReleaseHardware; 63 | EVT_WDF_DEVICE_D0_ENTRY IVSHMEMEvtD0Entry; 64 | EVT_WDF_DEVICE_D0_EXIT IVSHMEMEvtD0Exit; 65 | EVT_WDF_INTERRUPT_ISR IVSHMEMInterruptISR; 66 | EVT_WDF_INTERRUPT_DPC IVSHMEMInterruptDPC; 67 | 68 | EXTERN_C_END 69 | -------------------------------------------------------------------------------- /kernel/windows/Driver.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | #ifdef ALLOC_PRAGMA 4 | #pragma alloc_text (INIT, DriverEntry) 5 | #pragma alloc_text (PAGE, IVSHMEMEvtDeviceAdd) 6 | #pragma alloc_text (PAGE, IVSHMEMEvtDriverContextCleanup) 7 | #endif 8 | 9 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) 10 | { 11 | WDF_DRIVER_CONFIG config; 12 | NTSTATUS status; 13 | WDF_OBJECT_ATTRIBUTES attributes; 14 | 15 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 16 | WDF_DRIVER_CONFIG_INIT(&config, IVSHMEMEvtDeviceAdd); 17 | 18 | status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, WDF_NO_HANDLE); 19 | 20 | return status; 21 | } 22 | 23 | NTSTATUS IVSHMEMEvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) 24 | { 25 | NTSTATUS status; 26 | UNREFERENCED_PARAMETER(Driver); 27 | PAGED_CODE(); 28 | 29 | status = IVSHMEMCreateDevice(DeviceInit); 30 | return status; 31 | } -------------------------------------------------------------------------------- /kernel/windows/Driver.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if (NTDOI_VERSION >= NTDOI_WIN8) 6 | #define IVSHMEM_NONPAGED_POOL NonPagedPoolNx 7 | #else 8 | #define IVSHMEM_NONPAGED_POOL NonPagedPool 9 | #endif 10 | 11 | #include "device.h" 12 | #include "queue.h" 13 | 14 | // using error levels to avoid the debug print filter 15 | #define DEBUG_ERROR(fmt, ...) do { KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[E:IVSHMEM] " fmt "\n", ## __VA_ARGS__)); } while (0) 16 | #define DEBUG_INFO(fmt, ...) do { KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[I:IVSHMEM] " fmt "\n", ## __VA_ARGS__)); } while (0) 17 | 18 | EXTERN_C_START 19 | 20 | // 21 | // WDFDRIVER Events 22 | // 23 | 24 | DRIVER_INITIALIZE DriverEntry; 25 | EVT_WDF_DRIVER_DEVICE_ADD IVSHMEMEvtDeviceAdd; 26 | EVT_WDF_OBJECT_CONTEXT_CLEANUP IVSHMEMEvtDriverContextCleanup; 27 | 28 | EXTERN_C_END 29 | -------------------------------------------------------------------------------- /kernel/windows/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017-2022 Geoffrey McRae 2 | Copyright 2017-2022 Red Hat, Inc. and/or its affiliates. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /kernel/windows/Public.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | DEFINE_GUID (GUID_DEVINTERFACE_IVSHMEM, 4 | 0xdf576976,0x569d,0x4672,0x95,0xa0,0xf5,0x7e,0x4e,0xa0,0xb2,0x10); 5 | // {df576976-569d-4672-95a0-f57e4ea0b210} 6 | 7 | typedef UINT16 IVSHMEM_PEERID; 8 | typedef UINT64 IVSHMEM_SIZE; 9 | 10 | #define IVSHMEM_CACHE_NONCACHED 0 11 | #define IVSHMEM_CACHE_CACHED 1 12 | #define IVSHMEM_CACHE_WRITECOMBINED 2 13 | 14 | /* 15 | This structure is for use with the IOCTL_IVSHMEM_REQUEST_MMAP IOCTL 16 | */ 17 | typedef struct IVSHMEM_MMAP_CONFIG 18 | { 19 | UINT8 cacheMode; // the caching mode of the mapping, see IVSHMEM_CACHE_* for options 20 | } 21 | IVSHMEM_MMAP_CONFIG, *PIVSHMEM_MMAP_CONFIG; 22 | 23 | /* 24 | This structure is for use with the IOCTL_IVSHMEM_REQUEST_MMAP IOCTL 25 | */ 26 | typedef struct IVSHMEM_MMAP 27 | { 28 | IVSHMEM_PEERID peerID; // our peer id 29 | IVSHMEM_SIZE size; // the size of the memory region 30 | PVOID ptr; // pointer to the memory region 31 | UINT16 vectors; // the number of vectors available 32 | } 33 | IVSHMEM_MMAP, *PIVSHMEM_MMAP; 34 | 35 | /* 36 | This structure is for use with the IOCTL_IVSHMEM_RING_DOORBELL IOCTL 37 | */ 38 | typedef struct IVSHMEM_RING 39 | { 40 | IVSHMEM_PEERID peerID; // the id of the peer to ring 41 | UINT16 vector; // the doorbell to ring 42 | } 43 | IVSHMEM_RING, *PIVSHMEM_RING; 44 | 45 | /* 46 | This structure is for use with the IOCTL_IVSHMEM_REGISTER_EVENT IOCTL 47 | 48 | Please Note: 49 | - The IVSHMEM driver has a hard limit of 32 events. 50 | - Events that are singleShot are released after they have been set. 51 | - At this time repeating events are only released when the driver device 52 | handle is closed, closing the event handle doesn't release it from the 53 | drivers list. While this won't cause a problem in the driver, it will 54 | cause you to run out of event slots. 55 | */ 56 | typedef struct IVSHMEM_EVENT 57 | { 58 | UINT16 vector; // the vector that triggers the event 59 | HANDLE event; // the event to trigger 60 | BOOLEAN singleShot; // set to TRUE if you want the driver to only trigger this event once 61 | } 62 | IVSHMEM_EVENT, *PIVSHMEM_EVENT; 63 | 64 | #define IOCTL_IVSHMEM_REQUEST_PEERID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) 65 | #define IOCTL_IVSHMEM_REQUEST_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 66 | #define IOCTL_IVSHMEM_REQUEST_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) 67 | #define IOCTL_IVSHMEM_RELEASE_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 68 | #define IOCTL_IVSHMEM_RING_DOORBELL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) 69 | #define IOCTL_IVSHMEM_REGISTER_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) 70 | #define IOCTL_IVSHMEM_REQUEST_KMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) 71 | -------------------------------------------------------------------------------- /kernel/windows/Queue.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | #ifdef ALLOC_PRAGMA 4 | #pragma alloc_text (PAGE, IVSHMEMQueueInitialize) 5 | #endif 6 | 7 | #ifdef _WIN64 8 | // 32bit struct for when a 32bit application sends IOCTL codes 9 | typedef struct IVSHMEM_MMAP32 10 | { 11 | IVSHMEM_PEERID peerID; // our peer id 12 | IVSHMEM_SIZE size; // the size of the memory region 13 | UINT32 ptr; // pointer to the memory region 14 | UINT16 vectors; // the number of vectors available 15 | } 16 | IVSHMEM_MMAP32, *PIVSHMEM_MMAP32; 17 | #endif 18 | 19 | // Forwards 20 | static NTSTATUS ioctl_request_peerid( 21 | const PDEVICE_CONTEXT DeviceContext, 22 | const size_t OutputBufferLength, 23 | const WDFREQUEST Request, 24 | size_t * BytesReturned 25 | ); 26 | 27 | static NTSTATUS ioctl_request_size( 28 | const PDEVICE_CONTEXT DeviceContext, 29 | const size_t OutputBufferLength, 30 | const WDFREQUEST Request, 31 | size_t * BytesReturned 32 | ); 33 | 34 | static NTSTATUS ioctl_request_mmap( 35 | const PDEVICE_CONTEXT DeviceContext, 36 | const size_t InputBufferLength, 37 | const size_t OutputBufferLength, 38 | const WDFREQUEST Request, 39 | size_t * BytesReturned, 40 | BOOLEAN ForKernel 41 | ); 42 | 43 | static NTSTATUS ioctl_release_mmap( 44 | const PDEVICE_CONTEXT DeviceContext, 45 | const WDFREQUEST Request, 46 | size_t * BytesReturned 47 | ); 48 | 49 | static NTSTATUS ioctl_ring_doorbell( 50 | const PDEVICE_CONTEXT DeviceContext, 51 | const size_t InputBufferLength, 52 | const WDFREQUEST Request, 53 | size_t * BytesReturned 54 | ); 55 | 56 | static NTSTATUS ioctl_register_event( 57 | const PDEVICE_CONTEXT DeviceContext, 58 | const size_t InputBufferLength, 59 | const WDFREQUEST Request, 60 | size_t * BytesReturned 61 | ); 62 | 63 | NTSTATUS IVSHMEMQueueInitialize(_In_ WDFDEVICE Device) 64 | { 65 | WDFQUEUE queue; 66 | NTSTATUS status; 67 | WDF_IO_QUEUE_CONFIG queueConfig; 68 | 69 | PAGED_CODE(); 70 | 71 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential); 72 | queueConfig.EvtIoDeviceControl = IVSHMEMEvtIoDeviceControl; 73 | queueConfig.EvtIoStop = IVSHMEMEvtIoStop; 74 | 75 | status = WdfIoQueueCreate(Device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue); 76 | return status; 77 | } 78 | 79 | VOID 80 | IVSHMEMEvtIoDeviceControl( 81 | _In_ WDFQUEUE Queue, 82 | _In_ WDFREQUEST Request, 83 | _In_ size_t OutputBufferLength, 84 | _In_ size_t InputBufferLength, 85 | _In_ ULONG IoControlCode 86 | ) 87 | { 88 | WDFDEVICE hDevice = WdfIoQueueGetDevice(Queue); 89 | PDEVICE_CONTEXT deviceContext = DeviceGetContext(hDevice); 90 | size_t bytesReturned = 0; 91 | 92 | // revision 0 devices have to wait until the shared memory has been provided to the vm 93 | if (deviceContext->devRegisters->ivProvision < 0) 94 | { 95 | DEBUG_INFO("Device not ready yet, ivProvision = %d", deviceContext->devRegisters->ivProvision); 96 | WdfRequestCompleteWithInformation(Request, STATUS_DEVICE_NOT_READY, 0); 97 | return; 98 | } 99 | 100 | NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; 101 | switch (IoControlCode) 102 | { 103 | case IOCTL_IVSHMEM_REQUEST_PEERID: 104 | status = ioctl_request_peerid(deviceContext, OutputBufferLength, Request, &bytesReturned); 105 | break; 106 | 107 | case IOCTL_IVSHMEM_REQUEST_SIZE: 108 | status = ioctl_request_size(deviceContext, OutputBufferLength, Request, &bytesReturned); 109 | break; 110 | 111 | case IOCTL_IVSHMEM_REQUEST_MMAP: 112 | status = ioctl_request_mmap(deviceContext, InputBufferLength, OutputBufferLength, Request, &bytesReturned, FALSE); 113 | break; 114 | case IOCTL_IVSHMEM_REQUEST_KMAP: 115 | status = ioctl_request_mmap(deviceContext, InputBufferLength, OutputBufferLength, Request, &bytesReturned, TRUE); 116 | break; 117 | case IOCTL_IVSHMEM_RELEASE_MMAP: 118 | status = ioctl_release_mmap(deviceContext, Request, &bytesReturned); 119 | break; 120 | 121 | case IOCTL_IVSHMEM_RING_DOORBELL: 122 | status = ioctl_ring_doorbell(deviceContext, InputBufferLength, Request, &bytesReturned); 123 | break; 124 | 125 | case IOCTL_IVSHMEM_REGISTER_EVENT: 126 | status = ioctl_register_event(deviceContext, InputBufferLength, Request, &bytesReturned); 127 | break; 128 | } 129 | 130 | WdfRequestCompleteWithInformation(Request, status, bytesReturned); 131 | } 132 | 133 | VOID 134 | IVSHMEMEvtIoStop( 135 | _In_ WDFQUEUE Queue, 136 | _In_ WDFREQUEST Request, 137 | _In_ ULONG ActionFlags 138 | ) 139 | { 140 | UNREFERENCED_PARAMETER(Queue); 141 | UNREFERENCED_PARAMETER(ActionFlags); 142 | WdfRequestStopAcknowledge(Request, TRUE); 143 | return; 144 | } 145 | 146 | VOID IVSHMEMEvtDeviceFileCleanup(_In_ WDFFILEOBJECT FileObject) 147 | { 148 | PDEVICE_CONTEXT deviceContext = DeviceGetContext(WdfFileObjectGetDevice(FileObject)); 149 | 150 | // remove queued events that belonged to the session 151 | KIRQL oldIRQL; 152 | KeAcquireSpinLock(&deviceContext->eventListLock, &oldIRQL); 153 | PLIST_ENTRY entry = deviceContext->eventList.Flink; 154 | while (entry != &deviceContext->eventList) 155 | { 156 | _Analysis_assume_(entry != NULL); 157 | PIVSHMEMEventListEntry event = CONTAINING_RECORD(entry, IVSHMEMEventListEntry, ListEntry); 158 | if (event->owner != FileObject) 159 | { 160 | entry = entry->Flink; 161 | continue; 162 | } 163 | 164 | PLIST_ENTRY next = entry->Flink; 165 | RemoveEntryList(entry); 166 | ObDereferenceObject(event->event); 167 | event->owner = NULL; 168 | event->event = NULL; 169 | event->vector = 0; 170 | --deviceContext->eventBufferUsed; 171 | entry = next; 172 | } 173 | KeReleaseSpinLock(&deviceContext->eventListLock, oldIRQL); 174 | 175 | if (!deviceContext->shmemMap) 176 | return; 177 | 178 | if (deviceContext->owner != FileObject) 179 | return; 180 | 181 | MmUnmapLockedPages(deviceContext->shmemMap, deviceContext->shmemMDL); 182 | deviceContext->shmemMap = NULL; 183 | deviceContext->owner = NULL; 184 | } 185 | 186 | static NTSTATUS ioctl_request_peerid( 187 | const PDEVICE_CONTEXT DeviceContext, 188 | const size_t OutputBufferLength, 189 | const WDFREQUEST Request, 190 | size_t * BytesReturned 191 | ) 192 | { 193 | if (OutputBufferLength != sizeof(IVSHMEM_PEERID)) 194 | { 195 | DEBUG_ERROR("IOCTL_IVSHMEM_REQUEST_PEERID: Invalid size, expected %u but got %u", sizeof(IVSHMEM_PEERID), OutputBufferLength); 196 | return STATUS_INVALID_BUFFER_SIZE; 197 | } 198 | 199 | IVSHMEM_PEERID *out = NULL; 200 | if (!NT_SUCCESS(WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, (PVOID *)&out, NULL))) 201 | { 202 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REQUEST_PEERID: Failed to retrieve the output buffer"); 203 | return STATUS_INVALID_USER_BUFFER; 204 | } 205 | 206 | *out = (IVSHMEM_PEERID)DeviceContext->devRegisters->ivProvision; 207 | *BytesReturned = sizeof(IVSHMEM_PEERID); 208 | return STATUS_SUCCESS; 209 | } 210 | 211 | static NTSTATUS ioctl_request_size( 212 | const PDEVICE_CONTEXT DeviceContext, 213 | const size_t OutputBufferLength, 214 | const WDFREQUEST Request, 215 | size_t * BytesReturned 216 | ) 217 | { 218 | if (OutputBufferLength != sizeof(IVSHMEM_SIZE)) 219 | { 220 | DEBUG_ERROR("IOCTL_IVSHMEM_REQUEST_SIZE: Invalid size, expected %u but got %u", sizeof(IVSHMEM_SIZE), OutputBufferLength); 221 | return STATUS_INVALID_BUFFER_SIZE; 222 | } 223 | 224 | IVSHMEM_SIZE *out = NULL; 225 | if (!NT_SUCCESS(WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, (PVOID *)&out, NULL))) 226 | { 227 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REQUEST_SIZE: Failed to retrieve the output buffer"); 228 | return STATUS_INVALID_USER_BUFFER; 229 | } 230 | 231 | *out = DeviceContext->shmemAddr.NumberOfBytes; 232 | *BytesReturned = sizeof(IVSHMEM_SIZE); 233 | return STATUS_SUCCESS; 234 | } 235 | 236 | static NTSTATUS ioctl_request_mmap( 237 | const PDEVICE_CONTEXT DeviceContext, 238 | const size_t InputBufferLength, 239 | const size_t OutputBufferLength, 240 | const WDFREQUEST Request, 241 | size_t * BytesReturned, 242 | BOOLEAN ForKernel 243 | ) 244 | { 245 | // only one mapping at a time is allowed 246 | // if (DeviceContext->shmemMap) 247 | // return STATUS_DEVICE_ALREADY_ATTACHED; 248 | 249 | if (InputBufferLength != sizeof(IVSHMEM_MMAP_CONFIG)) 250 | { 251 | DEBUG_ERROR("IOCTL_IVSHMEM_MMAP: Invalid input size, expected %u but got %u", sizeof(IVSHMEM_MMAP_CONFIG), InputBufferLength); 252 | return STATUS_INVALID_BUFFER_SIZE; 253 | } 254 | 255 | PIVSHMEM_MMAP_CONFIG in; 256 | if (!NT_SUCCESS(WdfRequestRetrieveInputBuffer(Request, InputBufferLength, (PVOID)&in, NULL))) 257 | { 258 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_MMAP: Failed to retrieve the input buffer"); 259 | return STATUS_INVALID_USER_BUFFER; 260 | } 261 | 262 | MEMORY_CACHING_TYPE cacheType; 263 | switch (in->cacheMode) 264 | { 265 | case IVSHMEM_CACHE_NONCACHED : cacheType = MmNonCached ; break; 266 | case IVSHMEM_CACHE_CACHED : cacheType = MmCached ; break; 267 | case IVSHMEM_CACHE_WRITECOMBINED: cacheType = MmWriteCombined; break; 268 | default: 269 | DEBUG_ERROR("IOCTL_IVSHMEM_MMAP: Invalid cache mode: %u", in->cacheMode); 270 | return STATUS_INVALID_PARAMETER; 271 | } 272 | 273 | #ifdef _WIN64 274 | PIRP irp = WdfRequestWdmGetIrp(Request); 275 | const BOOLEAN is32Bit = IoIs32bitProcess(irp); 276 | const size_t bufferLen = is32Bit ? sizeof(IVSHMEM_MMAP32) : sizeof(IVSHMEM_MMAP); 277 | #else 278 | const size_t bufferLen = sizeof(IVSHMEM_MMAP); 279 | #endif 280 | PVOID buffer; 281 | 282 | if (OutputBufferLength != bufferLen) 283 | { 284 | DEBUG_ERROR("IOCTL_IVSHMEM_REQUEST_MMAP: Invalid size, expected %u but got %u", bufferLen, OutputBufferLength); 285 | return STATUS_INVALID_BUFFER_SIZE; 286 | } 287 | 288 | if (!NT_SUCCESS(WdfRequestRetrieveOutputBuffer(Request, bufferLen, (PVOID *)&buffer, NULL))) 289 | { 290 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REQUEST_MMAP: Failed to retrieve the output buffer"); 291 | return STATUS_INVALID_USER_BUFFER; 292 | } 293 | 294 | __try 295 | { 296 | DeviceContext->shmemMap = MmMapLockedPagesSpecifyCache( 297 | DeviceContext->shmemMDL, 298 | ForKernel ? KernelMode : UserMode, 299 | cacheType, 300 | NULL, 301 | FALSE, 302 | NormalPagePriority | MdlMappingNoExecute 303 | ); 304 | } 305 | __except (EXCEPTION_EXECUTE_HANDLER) 306 | { 307 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REQUEST_MMAP: Exception trying to map pages"); 308 | return STATUS_DRIVER_INTERNAL_ERROR; 309 | } 310 | 311 | if (!DeviceContext->shmemMap) 312 | { 313 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REQUEST_MMAP: shmemMap is NULL"); 314 | return STATUS_DRIVER_INTERNAL_ERROR; 315 | } 316 | 317 | DeviceContext->owner = WdfRequestGetFileObject(Request); 318 | #ifdef _WIN64 319 | if (is32Bit) 320 | { 321 | PIVSHMEM_MMAP32 out = (PIVSHMEM_MMAP32)buffer; 322 | out->peerID = (UINT16)DeviceContext->devRegisters->ivProvision; 323 | out->size = (UINT64)DeviceContext->shmemAddr.NumberOfBytes; 324 | out->ptr = PtrToUint(DeviceContext->shmemMap); 325 | out->vectors = DeviceContext->interruptsUsed; 326 | } 327 | else 328 | #endif 329 | { 330 | PIVSHMEM_MMAP out = (PIVSHMEM_MMAP)buffer; 331 | out->peerID = (UINT16)DeviceContext->devRegisters->ivProvision; 332 | out->size = (UINT64)DeviceContext->shmemAddr.NumberOfBytes; 333 | out->ptr = DeviceContext->shmemMap; 334 | out->vectors = DeviceContext->interruptsUsed; 335 | } 336 | 337 | *BytesReturned = bufferLen; 338 | return STATUS_SUCCESS; 339 | } 340 | 341 | static NTSTATUS ioctl_release_mmap( 342 | const PDEVICE_CONTEXT DeviceContext, 343 | const WDFREQUEST Request, 344 | size_t * BytesReturned 345 | ) 346 | { 347 | // ensure the mapping exists 348 | if (!DeviceContext->shmemMap) 349 | { 350 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_RELEASE_MMAP: not mapped"); 351 | return STATUS_INVALID_DEVICE_REQUEST; 352 | } 353 | 354 | // ensure someone else other then the owner doesn't attempt to release the mapping 355 | if (DeviceContext->owner != WdfRequestGetFileObject(Request)) 356 | { 357 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_RELEASE_MMAP: Invalid owner"); 358 | return STATUS_INVALID_HANDLE; 359 | } 360 | 361 | MmUnmapLockedPages(DeviceContext->shmemMap, DeviceContext->shmemMDL); 362 | DeviceContext->shmemMap = NULL; 363 | DeviceContext->owner = NULL; 364 | *BytesReturned = 0; 365 | return STATUS_SUCCESS; 366 | } 367 | 368 | static NTSTATUS ioctl_ring_doorbell( 369 | const PDEVICE_CONTEXT DeviceContext, 370 | const size_t InputBufferLength, 371 | const WDFREQUEST Request, 372 | size_t * BytesReturned 373 | ) 374 | { 375 | // ensure someone else other then the owner doesn't attempt to trigger IRQs 376 | if (DeviceContext->owner != WdfRequestGetFileObject(Request)) 377 | { 378 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_RING_DOORBELL: Invalid owner"); 379 | return STATUS_INVALID_HANDLE; 380 | } 381 | 382 | if (InputBufferLength != sizeof(IVSHMEM_RING)) 383 | { 384 | DEBUG_ERROR("IOCTL_IVSHMEM_RING_DOORBELL: Invalid size, expected %u but got %u", sizeof(IVSHMEM_RING), InputBufferLength); 385 | return STATUS_INVALID_BUFFER_SIZE; 386 | } 387 | 388 | PIVSHMEM_RING in; 389 | if (!NT_SUCCESS(WdfRequestRetrieveInputBuffer(Request, InputBufferLength, (PVOID)&in, NULL))) 390 | { 391 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_RING_DOORBELL: Failed to retrieve the input buffer"); 392 | return STATUS_INVALID_USER_BUFFER; 393 | } 394 | 395 | WRITE_REGISTER_ULONG( 396 | &DeviceContext->devRegisters->doorbell, 397 | (ULONG)in->vector | ((ULONG)in->peerID << 16)); 398 | 399 | *BytesReturned = 0; 400 | return STATUS_SUCCESS; 401 | } 402 | 403 | static NTSTATUS ioctl_register_event( 404 | const PDEVICE_CONTEXT DeviceContext, 405 | const size_t InputBufferLength, 406 | const WDFREQUEST Request, 407 | size_t * BytesReturned 408 | ) 409 | { 410 | // ensure someone else other then the owner isn't attempting to register events 411 | if (DeviceContext->owner != WdfRequestGetFileObject(Request)) 412 | { 413 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REGISTER_EVENT: Invalid owner"); 414 | return STATUS_INVALID_HANDLE; 415 | } 416 | 417 | if (InputBufferLength != sizeof(IVSHMEM_EVENT)) 418 | { 419 | DEBUG_ERROR("IOCTL_IVSHMEM_REGISTER_EVENT: Invalid size, expected %u but got %u", sizeof(PIVSHMEM_EVENT), InputBufferLength); 420 | return STATUS_INVALID_BUFFER_SIZE; 421 | } 422 | 423 | // early non locked quick check to see if we are out of event space 424 | if (DeviceContext->eventBufferUsed == MAX_EVENTS) 425 | { 426 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REGISTER_EVENT: Event buffer full"); 427 | return STATUS_INSUFFICIENT_RESOURCES; 428 | } 429 | 430 | PIVSHMEM_EVENT in; 431 | if (!NT_SUCCESS(WdfRequestRetrieveInputBuffer(Request, InputBufferLength, (PVOID)&in, NULL))) 432 | { 433 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REGISTER_EVENT: Failed to retrieve the input buffer"); 434 | return STATUS_INVALID_USER_BUFFER; 435 | } 436 | 437 | PRKEVENT hObject; 438 | if (!NT_SUCCESS(ObReferenceObjectByHandle( 439 | in->event, 440 | SYNCHRONIZE | EVENT_MODIFY_STATE, 441 | *ExEventObjectType, 442 | UserMode, 443 | &hObject, 444 | NULL))) 445 | { 446 | DEBUG_ERROR("%s", "Unable to reference user-mode event object"); 447 | return STATUS_INVALID_HANDLE; 448 | } 449 | 450 | // clear the event in case the caller didn't think to 451 | KeClearEvent(hObject); 452 | 453 | // lock the event list so we can push the new entry into it 454 | KIRQL oldIRQL; 455 | KeAcquireSpinLock(&DeviceContext->eventListLock, &oldIRQL); 456 | { 457 | // check again if there is space before we search as we now hold the lock 458 | if (DeviceContext->eventBufferUsed == MAX_EVENTS) 459 | { 460 | KeReleaseSpinLock(&DeviceContext->eventListLock, oldIRQL); 461 | 462 | DEBUG_ERROR("%s", "IOCTL_IVSHMEM_REGISTER_EVENT: Event buffer full"); 463 | ObDereferenceObject(hObject); 464 | return STATUS_INSUFFICIENT_RESOURCES; 465 | } 466 | 467 | // look for a free slot 468 | BOOLEAN done = FALSE; 469 | for (UINT16 i = 0; i < MAX_EVENTS; ++i) 470 | { 471 | PIVSHMEMEventListEntry event = &DeviceContext->eventBuffer[i]; 472 | if (event->event != NULL) 473 | continue; 474 | 475 | // found one, assign the event to it and add it to the list 476 | event->owner = WdfRequestGetFileObject(Request); 477 | event->event = hObject; 478 | event->vector = in->vector; 479 | event->singleShot = in->singleShot; 480 | ++DeviceContext->eventBufferUsed; 481 | InsertTailList(&DeviceContext->eventList, &event->ListEntry); 482 | done = TRUE; 483 | break; 484 | } 485 | 486 | // this should never occur, if it does it indicates memory corruption 487 | if (!done) 488 | { 489 | DEBUG_ERROR( 490 | "IOCTL_IVSHMEM_REGISTER_EVENT: deviceContext->eventBufferUsed (%u) < MAX_EVENTS (%u) but no slots found!", 491 | DeviceContext->eventBufferUsed, MAX_EVENTS); 492 | KeBugCheckEx(CRITICAL_STRUCTURE_CORRUPTION, 0, 0, 0, 0x1C); 493 | } 494 | } 495 | KeReleaseSpinLock(&DeviceContext->eventListLock, oldIRQL); 496 | 497 | *BytesReturned = 0; 498 | return STATUS_SUCCESS; 499 | } 500 | -------------------------------------------------------------------------------- /kernel/windows/Queue.h: -------------------------------------------------------------------------------- 1 | EXTERN_C_START 2 | 3 | NTSTATUS IVSHMEMQueueInitialize(_In_ WDFDEVICE Device); 4 | 5 | EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL IVSHMEMEvtIoDeviceControl; 6 | EVT_WDF_IO_QUEUE_IO_STOP IVSHMEMEvtIoStop; 7 | EVT_WDF_FILE_CLEANUP IVSHMEMEvtDeviceFileCleanup; 8 | 9 | EXTERN_C_END 10 | -------------------------------------------------------------------------------- /kernel/windows/findwdk/FindWdk.cmake: -------------------------------------------------------------------------------- 1 | # Redistribution and use is allowed under the OSI-approved 3-clause BSD license. 2 | # Copyright (c) 2018 Sergey Podobry (sergey.podobry at gmail.com). All rights reserved. 3 | 4 | #.rst: 5 | # FindWDK 6 | # ---------- 7 | # 8 | # This module searches for the installed Windows Development Kit (WDK) and 9 | # exposes commands for creating kernel drivers and kernel libraries. 10 | # 11 | # Output variables: 12 | # - `WDK_FOUND` -- if false, do not try to use WDK 13 | # - `WDK_ROOT` -- where WDK is installed 14 | # - `WDK_VERSION` -- the version of the selected WDK 15 | # - `WDK_WINVER` -- the WINVER used for kernel drivers and libraries 16 | # (default value is `0x0601` and can be changed per target or globally) 17 | # - `WDK_NTDDI_VERSION` -- the NTDDI_VERSION used for kernel drivers and libraries, 18 | # if not set, the value will be automatically calculated by WINVER 19 | # (default value is left blank and can be changed per target or globally) 20 | # 21 | # Example usage: 22 | # 23 | # find_package(WDK REQUIRED) 24 | # 25 | # wdk_add_library(KmdfCppLib STATIC KMDF 1.15 26 | # KmdfCppLib.h 27 | # KmdfCppLib.cpp 28 | # ) 29 | # target_include_directories(KmdfCppLib INTERFACE .) 30 | # 31 | # wdk_add_driver(KmdfCppDriver KMDF 1.15 32 | # Main.cpp 33 | # ) 34 | # target_link_libraries(KmdfCppDriver KmdfCppLib) 35 | # 36 | 37 | if(DEFINED ENV{WDKContentRoot}) 38 | file(GLOB WDK_NTDDK_FILES 39 | "$ENV{WDKContentRoot}/Include/*/km/ntddk.h" # WDK 10 40 | "$ENV{WDKContentRoot}/Include/km/ntddk.h" # WDK 8.0, 8.1 41 | ) 42 | else() 43 | file(GLOB WDK_NTDDK_FILES 44 | "C:/Program Files*/Windows Kits/*/Include/*/km/ntddk.h" # WDK 10 45 | "C:/Program Files*/Windows Kits/*/Include/km/ntddk.h" # WDK 8.0, 8.1 46 | ) 47 | endif() 48 | 49 | if(WDK_NTDDK_FILES) 50 | if (NOT CMAKE_VERSION VERSION_LESS 3.18.0) 51 | list(SORT WDK_NTDDK_FILES COMPARE NATURAL) # sort to use the latest available WDK 52 | endif() 53 | list(GET WDK_NTDDK_FILES -1 WDK_LATEST_NTDDK_FILE) 54 | endif() 55 | 56 | include(FindPackageHandleStandardArgs) 57 | find_package_handle_standard_args(WDK REQUIRED_VARS WDK_LATEST_NTDDK_FILE) 58 | 59 | if (NOT WDK_LATEST_NTDDK_FILE) 60 | return() 61 | endif() 62 | 63 | get_filename_component(WDK_ROOT ${WDK_LATEST_NTDDK_FILE} DIRECTORY) 64 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) 65 | get_filename_component(WDK_VERSION ${WDK_ROOT} NAME) 66 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) 67 | if (NOT WDK_ROOT MATCHES ".*/[0-9][0-9.]*$") # WDK 10 has a deeper nesting level 68 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) # go up once more 69 | set(WDK_LIB_VERSION "${WDK_VERSION}") 70 | set(WDK_INC_VERSION "${WDK_VERSION}") 71 | else() # WDK 8.0, 8.1 72 | set(WDK_INC_VERSION "") 73 | foreach(VERSION winv6.3 win8 win7) 74 | if (EXISTS "${WDK_ROOT}/Lib/${VERSION}/") 75 | set(WDK_LIB_VERSION "${VERSION}") 76 | break() 77 | endif() 78 | endforeach() 79 | set(WDK_VERSION "${WDK_LIB_VERSION}") 80 | endif() 81 | 82 | message(STATUS "WDK_ROOT: " ${WDK_ROOT}) 83 | message(STATUS "WDK_VERSION: " ${WDK_VERSION}) 84 | 85 | set(WDK_WINVER "0x0601" CACHE STRING "Default WINVER for WDK targets") 86 | set(WDK_NTDDI_VERSION "" CACHE STRING "Specified NTDDI_VERSION for WDK targets if needed") 87 | 88 | set(WDK_ADDITIONAL_FLAGS_FILE "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/wdkflags.h") 89 | file(WRITE ${WDK_ADDITIONAL_FLAGS_FILE} "#pragma runtime_checks(\"suc\", off)") 90 | 91 | set(WDK_COMPILE_FLAGS 92 | "/Zp8" # set struct alignment 93 | "/GF" # enable string pooling 94 | "/GR-" # disable RTTI 95 | "/Gz" # __stdcall by default 96 | "/kernel" # create kernel mode binary 97 | "/FIwarning.h" # disable warnings in WDK headers 98 | "/FI${WDK_ADDITIONAL_FLAGS_FILE}" # include file to disable RTC 99 | ) 100 | 101 | set(WDK_COMPILE_DEFINITIONS "WINNT=1") 102 | set(WDK_COMPILE_DEFINITIONS_DEBUG "MSC_NOOPT;DEPRECATE_DDK_FUNCTIONS=1;DBG=1") 103 | 104 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 105 | list(APPEND WDK_COMPILE_DEFINITIONS "_X86_=1;i386=1;STD_CALL") 106 | set(WDK_PLATFORM "x86") 107 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 108 | list(APPEND WDK_COMPILE_DEFINITIONS "_WIN64;_AMD64_;AMD64") 109 | set(WDK_PLATFORM "x64") 110 | else() 111 | message(FATAL_ERROR "Unsupported architecture") 112 | endif() 113 | 114 | string(CONCAT WDK_LINK_FLAGS 115 | "/MANIFEST:NO " # 116 | "/DRIVER " # 117 | "/OPT:REF " # 118 | "/INCREMENTAL:NO " # 119 | "/OPT:ICF " # 120 | "/SUBSYSTEM:NATIVE " # 121 | "/MERGE:_TEXT=.text;_PAGE=PAGE " # 122 | "/NODEFAULTLIB " # do not link default CRT 123 | "/SECTION:INIT,d " # 124 | "/VERSION:10.0 " # 125 | ) 126 | 127 | # Generate imported targets for WDK lib files 128 | file(GLOB WDK_LIBRARIES "${WDK_ROOT}/Lib/${WDK_LIB_VERSION}/km/${WDK_PLATFORM}/*.lib") 129 | foreach(LIBRARY IN LISTS WDK_LIBRARIES) 130 | get_filename_component(LIBRARY_NAME ${LIBRARY} NAME_WE) 131 | string(TOUPPER ${LIBRARY_NAME} LIBRARY_NAME) 132 | add_library(WDK::${LIBRARY_NAME} INTERFACE IMPORTED) 133 | set_property(TARGET WDK::${LIBRARY_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBRARY}) 134 | endforeach(LIBRARY) 135 | unset(WDK_LIBRARIES) 136 | 137 | function(wdk_add_driver _target) 138 | cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN}) 139 | 140 | add_executable(${_target} ${WDK_UNPARSED_ARGUMENTS}) 141 | 142 | set_target_properties(${_target} PROPERTIES SUFFIX ".sys") 143 | set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}") 144 | set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS 145 | "${WDK_COMPILE_DEFINITIONS};$<$:${WDK_COMPILE_DEFINITIONS_DEBUG}>;_WIN32_WINNT=${WDK_WINVER}" 146 | ) 147 | set_target_properties(${_target} PROPERTIES LINK_FLAGS "${WDK_LINK_FLAGS}") 148 | if(WDK_NTDDI_VERSION) 149 | target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION}) 150 | endif() 151 | 152 | target_include_directories(${_target} SYSTEM PRIVATE 153 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared" 154 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km" 155 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt" 156 | ) 157 | 158 | target_link_libraries(${_target} WDK::NTOSKRNL WDK::HAL WDK::BUFFEROVERFLOWK WDK::WMILIB) 159 | 160 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 161 | target_link_libraries(${_target} WDK::MEMCMP) 162 | endif() 163 | 164 | if(DEFINED WDK_KMDF) 165 | target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}") 166 | target_link_libraries(${_target} 167 | "${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfDriverEntry.lib" 168 | "${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfLdr.lib" 169 | ) 170 | 171 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 172 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry@8") 173 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 174 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry") 175 | endif() 176 | else() 177 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 178 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry@8") 179 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 180 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry") 181 | endif() 182 | endif() 183 | endfunction() 184 | 185 | function(wdk_add_library _target) 186 | cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN}) 187 | 188 | add_library(${_target} ${WDK_UNPARSED_ARGUMENTS}) 189 | 190 | set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}") 191 | set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS 192 | "${WDK_COMPILE_DEFINITIONS};$<$:${WDK_COMPILE_DEFINITIONS_DEBUG};>_WIN32_WINNT=${WDK_WINVER}" 193 | ) 194 | if(WDK_NTDDI_VERSION) 195 | target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION}) 196 | endif() 197 | 198 | target_include_directories(${_target} SYSTEM PRIVATE 199 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared" 200 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km" 201 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt" 202 | ) 203 | 204 | if(DEFINED WDK_KMDF) 205 | target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}") 206 | endif() 207 | endfunction() -------------------------------------------------------------------------------- /kernel/windows/findwdk/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Sergey Podobry (sergey.podobry at gmail.com). All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | Neither the name of the {organization} nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /scripts/kcertify.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | IF %1.==. GOTO defaultarg 4 | @set os_provided=%1 5 | GOTO certify 6 | :defaultarg 7 | @set os_provided="10_X64" 8 | 9 | :certify 10 | makecert -r -pe -ss PrivateCertStore -n CN=ksgldrv ksgldrv.cer 11 | Inf2cat.exe /driver:.\ /os:%os_provided% 12 | Signtool sign /v /fd sha256 /s PrivateCertStore /n ksgldrv /a /t http://timestamp.digicert.com ksgldrv.cat 13 | CertMgr.exe /add ksgldrv.cer /s /r localMachine root 14 | CertMgr.exe /add ksgldrv.cer /s /r localMachine trustedpublisher -------------------------------------------------------------------------------- /scripts/ksgldrv.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ;Copyright (c) 2017-2021 Red Hat Inc. 4 | ;Copyright (c) 2023 dmaivel 5 | ; 6 | ;Module Name: 7 | ; KSGLDRV.inf 8 | ; 9 | ;Abstract: 10 | ; 11 | ;Installation Notes: 12 | ; Using Devcon: Type "devcon install ksgldrv.inf PCI\VEN_1AF4&DEV_1110&SUBSYS_11001AF4&REV_01" to install 13 | ; 14 | ;--*/ 15 | 16 | [Version] 17 | Signature="$WINDOWS NT$" 18 | Class=System 19 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 20 | Provider=%VENDOR% 21 | CatalogFile=KSGLDRV.cat 22 | DriverVer = 09/04/2023,100.10.100.10001 23 | PnpLockDown=1 24 | 25 | [DestinationDirs] 26 | DefaultDestDir = 12 27 | KSGLDRV_Device_CoInstaller_CopyFiles = 11 28 | 29 | ; ================= Class section ===================== 30 | 31 | [SourceDisksNames] 32 | 1 = %DiskName%,,,"" 33 | 34 | [SourceDisksFiles] 35 | KSGLDRV.sys = 1,, 36 | ; 37 | 38 | 39 | ;***************************************** 40 | ; Install Section 41 | ;***************************************** 42 | 43 | [Manufacturer] 44 | %VENDOR%=Standard,NTamd64.10.0 45 | 46 | [Standard.NTamd64.10.0] 47 | %KSGLDRV.DeviceDesc%=KSGLDRV_Device, PCI\VEN_1AF4&DEV_1110&SUBSYS_11001AF4&REV_01, PCI\VEN_1AF4&DEV_1110 48 | 49 | [KSGLDRV_Device.NT] 50 | CopyFiles=Drivers_Dir 51 | 52 | [KSGLDRV_Device.NT.Interfaces] 53 | AddInterface={df576976-569d-4672-95a0-f57e4ea0b210} 54 | 55 | [KSGLDRV_Device.NT.HW] 56 | AddReg = KSGLDRV_AddReg 57 | 58 | [KSGLDRV_AddReg] 59 | HKR,Interrupt Management,,0x00000010 60 | HKR,Interrupt Management\MessageSignaledInterruptProperties,,0x00000010 61 | HKR,Interrupt Management\MessageSignaledInterruptProperties,MSISupported,0x00010001,1 62 | 63 | [Drivers_Dir] 64 | KSGLDRV.sys 65 | 66 | ;-------------- Service installation 67 | [KSGLDRV_Device.NT.Services] 68 | AddService = KSGLDRV,%SPSVCINST_ASSOCSERVICE%, KSGLDRV_Service_Inst 69 | 70 | ; -------------- KSGLDRV driver install sections 71 | [KSGLDRV_Service_Inst] 72 | DisplayName = %KSGLDRV.SVCDESC% 73 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 74 | StartType = 3 ; SERVICE_DEMAND_START 75 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 76 | ServiceBinary = %12%\ksgldrv.sys 77 | 78 | ; 79 | ;--- KSGLDRV_Device Coinstaller installation ------ 80 | ; 81 | 82 | [KSGLDRV_Device.NT.CoInstallers] 83 | AddReg=KSGLDRV_Device_CoInstaller_AddReg 84 | CopyFiles=KSGLDRV_Device_CoInstaller_CopyFiles 85 | 86 | [KSGLDRV_Device_CoInstaller_AddReg] 87 | ; 88 | 89 | 90 | [KSGLDRV_Device_CoInstaller_CopyFiles] 91 | ; 92 | 93 | 94 | [KSGLDRV_Device.NT.Wdf] 95 | KmdfService = KSGLDRV, KSGLDRV_wdfsect 96 | 97 | [KSGLDRV_wdfsect] 98 | KmdfLibraryVersion = 1.15 99 | 100 | [Strings] 101 | SPSVCINST_ASSOCSERVICE= 0x00000002 102 | VENDOR = "dmaivel" 103 | DiskName = "SharedGL Installation Disk" 104 | KSGLDRV.DeviceDesc = "SharedGL Device" 105 | KSGLDRV.SVCDESC = "SharedGL Service" 106 | -------------------------------------------------------------------------------- /scripts/wininstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @cd /d "%~dp0" 3 | @set "ERRORLEVEL=" 4 | @CMD /C EXIT 0 5 | @"%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" >nul 2>&1 6 | @if NOT "%ERRORLEVEL%"=="0" ( 7 | @IF "%*"=="" powershell -Command Start-Process """%0""" -Verb runAs 2>nul 8 | @IF NOT "%*"=="" powershell -Command Start-Process """%0""" """%*""" -Verb runAs 2>nul 9 | @GOTO exit 10 | ) 11 | 12 | @set regglkey="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" 13 | @set regglwowkey="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" 14 | 15 | @set CD= 16 | @set curloc=%CD% 17 | @IF %curloc:~0,1%%curloc:~-1%=="" set curloc=%curloc:~1,-1% 18 | @IF "%curloc:~-1%"=="\" set curloc=%curloc:~0,-1% 19 | 20 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%curloc%\sharedgl32.dll" copy "%curloc%\sharedgl32.dll" "%windir%\SysWOW64\sharedgl.dll" 21 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%curloc%\sharedgl64.dll" copy "%curloc%\sharedgl64.dll" "%windir%\System32\sharedgl.dll" 22 | @IF /I %PROCESSOR_ARCHITECTURE%==X86 IF EXIST "%curloc%\sharedgl32.dll" copy "%curloc%\sharedgl32.dll" "%windir%\SysWOW64\sharedgl.dll" 23 | 24 | @IF EXIST "%windir%\System32\sharedgl.dll" REG ADD %regglkey% /v DLL /t REG_SZ /d sharedgl.dll /f 25 | @IF EXIST "%windir%\System32\sharedgl.dll" REG ADD %regglkey% /v DriverVersion /t REG_DWORD /d 1 /f 26 | @IF EXIST "%windir%\System32\sharedgl.dll" REG ADD %regglkey% /v Flags /t REG_DWORD /d 1 /f 27 | @IF EXIST "%windir%\System32\sharedgl.dll" REG ADD %regglkey% /v Version /t REG_DWORD /d 2 /f 28 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%windir%\SysWOW64\sharedgl.dll" REG ADD %regglwowkey% /v DLL /t REG_SZ /d sharedgl.dll /f 29 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%windir%\SysWOW64\sharedgl.dll" REG ADD %regglwowkey% /v DriverVersion /t REG_DWORD /d 1 /f 30 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%windir%\SysWOW64\sharedgl.dll" REG ADD %regglwowkey% /v Flags /t REG_DWORD /d 1 /f 31 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 IF EXIST "%windir%\SysWOW64\sharedgl.dll" REG ADD %regglwowkey% /v Version /t REG_DWORD /d 2 /f 32 | 33 | @echo Installed SharedGL! 34 | 35 | :exit -------------------------------------------------------------------------------- /scripts/winuninstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @cd /d "%~dp0" 3 | @set "ERRORLEVEL=" 4 | @CMD /C EXIT 0 5 | @"%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" >nul 2>&1 6 | @if NOT "%ERRORLEVEL%"=="0" ( 7 | @IF "%*"=="" powershell -Command Start-Process """%0""" -Verb runAs 2>nul 8 | @IF NOT "%*"=="" powershell -Command Start-Process """%0""" """%*""" -Verb runAs 2>nul 9 | @GOTO exit 10 | ) 11 | 12 | @IF EXIST "%windir%\System32\sharedgl.dll" del "%windir%\System32\sharedgl.dll" 13 | @IF EXIST "%windir%\SysWOW64\sharedgl.dll" del "%windir%\SysWOW64\sharedgl.dll" 14 | 15 | @set "ERRORLEVEL=" 16 | @CMD /C EXIT 0 17 | @REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /d /f sharedgl.dll >nul 2>&1 18 | @if "%ERRORLEVEL%"=="0" REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /f 19 | @CMD /C EXIT 0 20 | @IF /I %PROCESSOR_ARCHITECTURE%==AMD64 REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /d /f sharedgl.dll >nul 2>&1 21 | @if "%ERRORLEVEL%"=="0" IF /I %PROCESSOR_ARCHITECTURE%==AMD64 REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /f 22 | @CMD /C EXIT 0 23 | 24 | @echo Uninstalled SharedGL! 25 | 26 | :exit -------------------------------------------------------------------------------- /src/client/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef _WIN32 4 | #include 5 | #endif 6 | 7 | void __attribute__((constructor)) sharedgl_entry(void) 8 | { 9 | glimpl_init(); 10 | #ifndef _WIN32 11 | glximpl_init(); 12 | #endif 13 | } 14 | 15 | void __attribute__((destructor)) sharedgl_goodbye(void) 16 | { 17 | glimpl_goodbye(); 18 | } -------------------------------------------------------------------------------- /src/client/memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * this pertains to memory detection within Linux VMs 3 | */ 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int sgl_detect_device_memory(const char *path) 16 | { 17 | DIR *directory; 18 | struct dirent *entry = NULL; 19 | 20 | directory = opendir(path); 21 | if (directory == NULL) 22 | return -1; 23 | 24 | while ((entry = readdir(directory)) != NULL) { 25 | char full_name[256] = { 0 }; 26 | snprintf(full_name, 100, "%s/%s", path, entry->d_name); 27 | 28 | if (entry->d_type == DT_DIR) { 29 | if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { 30 | int fd = sgl_detect_device_memory(full_name); 31 | if (fd != -1) 32 | return fd; 33 | } 34 | } else { 35 | if (strstr(full_name, "bar2") != NULL) 36 | return open(full_name, O_RDWR, S_IRWXU); 37 | } 38 | } 39 | 40 | closedir(directory); 41 | return -1; 42 | } -------------------------------------------------------------------------------- /src/client/pb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #ifndef _WIN32 8 | #define __USE_GNU 9 | #define _GNU_SOURCE 10 | #include 11 | #else 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #pragma comment (lib, "Setupapi.lib") 21 | 22 | DEFINE_GUID(GUID_DEVINTERFACE_IVSHMEM, 23 | 0xdf576976, 0x569d, 0x4672, 0x95, 0xa0, 0xf5, 0x7e, 0x4e, 0xa0, 0xb2, 0x10); 24 | 25 | #define IVSHMEM_CACHE_NONCACHED 0 26 | #define IVSHMEM_CACHE_CACHED 1 27 | #define IVSHMEM_CACHE_WRITECOMBINED 2 28 | 29 | #define IOCTL_IVSHMEM_REQUEST_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 30 | #define IOCTL_IVSHMEM_REQUEST_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) 31 | #define IOCTL_IVSHMEM_RELEASE_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 32 | 33 | struct ivshmem_mmap_config { 34 | BYTE cache_mode; 35 | }; 36 | 37 | struct ivshmem_mmap { 38 | WORD peer_id; 39 | DWORD64 size; 40 | PVOID pointer; 41 | WORD vectors; 42 | }; 43 | 44 | static HANDLE ivshmem_handle; 45 | #endif 46 | 47 | static void *ptr; 48 | static void *base; 49 | static int *cur; 50 | 51 | static void *in_base; 52 | static int *in_cur; 53 | 54 | static bool using_direct_access = false; 55 | 56 | static struct pb_net_hooks net_hooks = { NULL }; 57 | 58 | #ifndef _WIN32 59 | void pb_set(int fd, bool direct_access) 60 | { 61 | uintptr_t alloc_size; 62 | 63 | ptr = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 64 | alloc_size = *(uintptr_t*)(ptr + SGL_OFFSET_REGISTER_MEMSIZE); 65 | 66 | munmap(ptr, 0x1000); 67 | ptr = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 68 | 69 | base = ptr + 0x1000; 70 | 71 | if (direct_access) { 72 | using_direct_access = true; 73 | in_base = base; 74 | in_cur = base; 75 | } 76 | else { 77 | in_base = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 78 | in_cur = in_base; 79 | } 80 | } 81 | #else 82 | void pb_set(bool direct_access) 83 | { 84 | HDEVINFO device_info; 85 | PSP_DEVICE_INTERFACE_DETAIL_DATA inf_data; 86 | SP_DEVICE_INTERFACE_DATA dev_data; 87 | DWORD64 size; 88 | struct ivshmem_mmap_config config; 89 | struct ivshmem_mmap map; 90 | DWORD request_size; 91 | 92 | device_info = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE); 93 | ZeroMemory(&dev_data, sizeof(SP_DEVICE_INTERFACE_DATA)); 94 | dev_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 95 | 96 | if (SetupDiEnumDeviceInterfaces(device_info, NULL, &GUID_DEVINTERFACE_IVSHMEM, 0, &dev_data) == FALSE) 97 | return; 98 | 99 | SetupDiGetDeviceInterfaceDetail(device_info, &dev_data, NULL, 0, &request_size, NULL); 100 | if (!request_size) 101 | return; 102 | 103 | inf_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(request_size)); 104 | ZeroMemory(inf_data, request_size); 105 | inf_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); 106 | if (!SetupDiGetDeviceInterfaceDetail(device_info, &dev_data, inf_data, request_size, NULL, NULL)) 107 | return; 108 | 109 | ivshmem_handle = CreateFile(inf_data->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0); 110 | if (ivshmem_handle == INVALID_HANDLE_VALUE) 111 | return; 112 | 113 | if (inf_data) 114 | free(inf_data); 115 | SetupDiDestroyDeviceInfoList(device_info); 116 | 117 | if (!DeviceIoControl(ivshmem_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(UINT64), NULL, NULL)) 118 | return; 119 | 120 | config.cache_mode = IVSHMEM_CACHE_WRITECOMBINED; 121 | ZeroMemory(&map, sizeof(struct ivshmem_mmap)); 122 | if (!DeviceIoControl(ivshmem_handle, IOCTL_IVSHMEM_REQUEST_MMAP, &config, sizeof(struct ivshmem_mmap_config), &map, sizeof(struct ivshmem_mmap), NULL, NULL)) 123 | return; 124 | 125 | ptr = map.pointer; 126 | base = (PVOID)((DWORD64)map.pointer + (DWORD64)0x1000); 127 | 128 | if (direct_access) { 129 | in_base = base; 130 | in_cur = in_base; 131 | } 132 | else { 133 | in_base = VirtualAlloc(NULL, map.size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 134 | in_cur = in_base; 135 | } 136 | } 137 | 138 | void pb_unset(void) 139 | { 140 | DeviceIoControl(ivshmem_handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL); 141 | CloseHandle(ivshmem_handle); 142 | } 143 | #endif 144 | 145 | void pb_set_net(struct pb_net_hooks hooks, size_t internal_alloc_size) 146 | { 147 | net_hooks = hooks; 148 | 149 | #ifndef _WIN32 150 | in_base = mmap(NULL, internal_alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 151 | in_cur = in_base; 152 | #else 153 | in_base = VirtualAlloc(NULL, internal_alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 154 | in_cur = in_base; 155 | #endif 156 | } 157 | 158 | void pb_reset() 159 | { 160 | cur = base; 161 | in_cur = in_base; 162 | } 163 | 164 | void pb_push(int c) 165 | { 166 | *in_cur++ = c; 167 | } 168 | 169 | void pb_pushf(float c) 170 | { 171 | *in_cur++ = *(int*)&c; 172 | } 173 | 174 | int pb_read(int s) 175 | { 176 | if (net_hooks._pb_read) 177 | return net_hooks._pb_read(s); 178 | return *(int*)((size_t)ptr + s); 179 | } 180 | 181 | int64_t pb_read64(int s) 182 | { 183 | if (net_hooks._pb_read64) 184 | return net_hooks._pb_read64(s); 185 | return *(int64_t*)((size_t)ptr + s); 186 | } 187 | 188 | void pb_write(int s, int c) 189 | { 190 | *(int*)((size_t)ptr + s) = c; 191 | } 192 | 193 | /* 194 | * // equivalent to 195 | * int *pdata = (int*)data; 196 | * for (int i = 0; i < length / 4; i++) 197 | * pb_push(*pdata++); 198 | */ 199 | void pb_memcpy(const void *src, size_t length) 200 | { 201 | // length = length - (length % 4); 202 | memcpy(in_cur, src, length); 203 | in_cur += CEIL_DIV(length, 4); 204 | } 205 | 206 | void pb_memcpy_unaligned(const void *src, size_t length) 207 | { 208 | // length = length - (length % 4); 209 | memcpy(in_cur, src, length); 210 | in_cur = (int*)((char*)in_cur + length); 211 | } 212 | 213 | static inline uintptr_t align_to_4(uintptr_t ptr) 214 | { 215 | return (ptr + 3) & ~3; 216 | } 217 | 218 | void pb_realign() 219 | { 220 | in_cur = (int*)align_to_4((uintptr_t)in_cur); 221 | } 222 | 223 | void *pb_ptr(size_t offs) 224 | { 225 | if (net_hooks._pb_ptr) 226 | return net_hooks._pb_ptr(offs); 227 | return (void*)((size_t)ptr + offs); 228 | } 229 | 230 | void *pb_iptr(size_t offs) 231 | { 232 | return (void*)((size_t)in_base + offs); 233 | } 234 | 235 | size_t pb_size() 236 | { 237 | return (size_t)in_cur - (size_t)in_base; 238 | } 239 | 240 | void pb_copy_to_shared() 241 | { 242 | if (!using_direct_access) 243 | memcpy(base, in_base, (size_t)in_cur - (size_t)in_base); 244 | } -------------------------------------------------------------------------------- /src/client/platform/egl.c: -------------------------------------------------------------------------------- 1 | // stub -------------------------------------------------------------------------------- /src/client/platform/glx.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | static Window win = -1; 18 | static const char *glx_extensions = "GLX_ARB_create_context GLX_ARB_create_context_no_error GLX_ARB_create_context_profile GLX_ARB_create_context_robustness GLX_ARB_get_proc_address GLX_EXT_create_context_es2_profile GLX_EXT_create_context_es_profile GLX_EXT_visual_info"; 19 | 20 | static int glx_major = 1; 21 | static int glx_minor = 4; 22 | static const char *glx_majmin_string = "1.4"; 23 | 24 | static int max_width, max_height, real_width, real_height; 25 | 26 | static void *swap_sync_lock; 27 | 28 | ICD_SET_MAX_DIMENSIONS_DEFINITION(max_width, max_height, real_width, real_height); 29 | ICD_RESIZE_DEFINITION(real_width, real_height); 30 | 31 | struct glx_swap_data { 32 | XVisualInfo vinfo; 33 | XVisualInfo *visual_list; 34 | XVisualInfo visual_template; 35 | int nxvisuals; 36 | Window parent; 37 | 38 | int width, height; 39 | XImage *ximage; 40 | XEvent event; 41 | 42 | XGCValues gcv; 43 | GC gc; 44 | 45 | bool initialized; 46 | }; 47 | 48 | struct glx_fb_config { 49 | int render_type, 50 | drawable_type, 51 | double_buffer, 52 | red_size, 53 | green_size, 54 | blue_size, 55 | alpha_size, 56 | stencil_size, 57 | depth_size, 58 | accum_red_size, 59 | accum_green_size, 60 | accum_blue_size, 61 | accum_alpha_size, 62 | accum_stencil_size, 63 | renderable, 64 | visual_type; 65 | // to-do: add more like stereo 66 | }; 67 | 68 | static int n_valid_fb_configs; 69 | 70 | static struct glx_fb_config fb_configs[1729] = { 0 }; 71 | 72 | static int fb_valid_color_sizes[] = { 73 | 0, 1, 8, 16, 24, 32 74 | }; 75 | 76 | static int fb_valid_render_types[] = { 77 | GLX_RGBA_BIT, GLX_COLOR_INDEX_BIT 78 | }; 79 | 80 | static int fb_valid_doublebuffer_types[] = { 81 | False, True 82 | }; 83 | 84 | static int fb_valid_drawable_types[] = { 85 | GLX_WINDOW_BIT 86 | }; 87 | 88 | static int fb_valid_visual_types[] = { 89 | GLX_TRUE_COLOR, GLX_DIRECT_COLOR, GLX_PSEUDO_COLOR, GLX_STATIC_COLOR, GLX_GRAY_SCALE, GLX_STATIC_GRAY 90 | }; 91 | 92 | #define ARR_SIZE(x) (sizeof(x) / sizeof(*x)) 93 | static void glx_generate_fb_configs() 94 | { 95 | int idx = 0; 96 | for (int a = 0; a < ARR_SIZE(fb_valid_color_sizes); a++) { // varying color size 97 | for (int b = 0; b < ARR_SIZE(fb_valid_render_types); b++) { // varying render types 98 | for (int c = 0; c < ARR_SIZE(fb_valid_doublebuffer_types); c++) { // varying double buffer 99 | for (int d = 0; d < ARR_SIZE(fb_valid_drawable_types); d++) { // varying drawable type 100 | for (int e = 0; e < ARR_SIZE(fb_valid_doublebuffer_types); e++) { // varying renderable 101 | for (int f = 0; f < ARR_SIZE(fb_valid_visual_types); f++) { // varying visual type 102 | for (int g = 0; g < ARR_SIZE(fb_valid_color_sizes); g++) { // varying depth 103 | fb_configs[idx].red_size = fb_valid_color_sizes[a]; 104 | fb_configs[idx].green_size = fb_valid_color_sizes[a]; 105 | fb_configs[idx].blue_size = fb_valid_color_sizes[a]; 106 | fb_configs[idx].alpha_size = fb_valid_color_sizes[a]; 107 | fb_configs[idx].accum_red_size = fb_valid_color_sizes[a]; 108 | fb_configs[idx].accum_green_size = fb_valid_color_sizes[a]; 109 | fb_configs[idx].accum_blue_size = fb_valid_color_sizes[a]; 110 | fb_configs[idx].accum_alpha_size = fb_valid_color_sizes[a]; 111 | 112 | fb_configs[idx].stencil_size = -1; // fb_valid_color_sizes[a]; 113 | fb_configs[idx].depth_size = fb_valid_color_sizes[g]; 114 | 115 | fb_configs[idx].render_type = fb_valid_render_types[b]; 116 | fb_configs[idx].double_buffer = fb_valid_doublebuffer_types[c]; 117 | fb_configs[idx].drawable_type = fb_valid_drawable_types[d]; 118 | 119 | fb_configs[idx].renderable = fb_valid_doublebuffer_types[e]; 120 | fb_configs[idx].visual_type = fb_valid_visual_types[f]; 121 | 122 | idx++; 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | n_valid_fb_configs = idx; 132 | } 133 | #undef ARR_SIZE 134 | 135 | static const char *glximpl_name_to_string(int name) 136 | { 137 | switch (name) { 138 | case GLX_VENDOR: return "SharedGL"; 139 | case GLX_VERSION: return glx_majmin_string; 140 | case GLX_EXTENSIONS: return glx_extensions; 141 | } 142 | return "?"; 143 | } 144 | 145 | GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext share_list, Bool direct) 146 | { 147 | return (GLXContext)1; 148 | } 149 | 150 | GLXContext glXGetCurrentContext( void ) 151 | { 152 | return (GLXContext)1; 153 | } 154 | 155 | void glXDestroyContext(Display *dpy, GLXContext ctx) 156 | { 157 | 158 | } 159 | 160 | Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx) 161 | { 162 | return True; 163 | } 164 | 165 | Bool glXQueryExtension(Display *dpy, int *errorb, int *event) 166 | { 167 | return True; 168 | } 169 | 170 | void glXQueryDrawable(Display *dpy, GLXDrawable draw, int attribute, unsigned int *value) 171 | { 172 | 173 | } 174 | 175 | const char *glXQueryExtensionsString(Display *dpy, int screen) 176 | { 177 | return glx_extensions; 178 | } 179 | 180 | XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attrib_list) 181 | { 182 | XVisualInfo *vinfo = malloc(sizeof(XVisualInfo)); 183 | XMatchVisualInfo(dpy, XDefaultScreen(dpy), 24, TrueColor, vinfo); 184 | return vinfo; 185 | } 186 | 187 | GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct) 188 | { 189 | return (GLXContext)1; 190 | } 191 | 192 | Display *glXGetCurrentDisplay(void) 193 | { 194 | return XOpenDisplay(NULL); 195 | } 196 | 197 | Bool glXQueryVersion(Display *dpy, int *maj, int *min) 198 | { 199 | *maj = glx_major; 200 | *min = glx_minor; 201 | return True; 202 | } 203 | 204 | const char *glXGetClientString(Display *dpy, int name) 205 | { 206 | return glximpl_name_to_string(name); 207 | } 208 | 209 | GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, const int *attrib_list) 210 | { 211 | return win; 212 | } 213 | 214 | void glXDestroyWindow(Display *dpy, GLXWindow win) 215 | { 216 | 217 | } 218 | 219 | Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) 220 | { 221 | win = drawable; 222 | return true; 223 | } 224 | 225 | int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config, int attribute, int *value) 226 | { 227 | unsigned int index = (int)(size_t)config; 228 | if (index > n_valid_fb_configs) { 229 | fprintf(stderr, "glXGetFBConfigAttrib : attempted access on config %u, only %u exist\n", index, n_valid_fb_configs); 230 | return Success; 231 | } 232 | 233 | // fprintf(stderr, "glXGetFBConfigAttrib : access on config %u\n", index); 234 | 235 | struct glx_fb_config fb_config = fb_configs[index]; 236 | 237 | switch (attribute) { 238 | case GLX_FBCONFIG_ID: 239 | *value = index; 240 | break; 241 | case GLX_RENDER_TYPE: 242 | *value |= fb_config.render_type; // GLX_RGBA_BIT; 243 | break; 244 | case GLX_VISUAL_ID: 245 | *value = XDefaultVisual(dpy, 0)->visualid; // fb_config.visual_type; 246 | break; 247 | case GLX_BUFFER_SIZE: 248 | *value = 1; 249 | break; 250 | case GLX_SAMPLES: 251 | *value = 32; 252 | break; 253 | case GLX_SAMPLE_BUFFERS: 254 | *value = 1; 255 | break; 256 | case GLX_DRAWABLE_TYPE: 257 | *value |= fb_config.drawable_type; // GLX_WINDOW_BIT; 258 | break; 259 | case GLX_DOUBLEBUFFER: 260 | *value = fb_config.double_buffer; 261 | break; 262 | case GLX_RED_SIZE: 263 | *value = fb_config.red_size; 264 | break; 265 | case GLX_GREEN_SIZE: 266 | *value = fb_config.green_size; 267 | break; 268 | case GLX_BLUE_SIZE: 269 | *value = fb_config.blue_size; 270 | break; 271 | case GLX_ALPHA_SIZE: 272 | *value = fb_config.alpha_size; 273 | break; 274 | case GLX_STENCIL_SIZE: 275 | *value = fb_config.stencil_size; 276 | break; 277 | case GLX_ACCUM_RED_SIZE: 278 | *value = fb_config.accum_red_size; 279 | break; 280 | case GLX_ACCUM_GREEN_SIZE: 281 | *value = fb_config.accum_green_size; 282 | break; 283 | case GLX_ACCUM_BLUE_SIZE: 284 | *value = fb_config.accum_blue_size; 285 | break; 286 | case GLX_ACCUM_ALPHA_SIZE: 287 | *value = fb_config.accum_alpha_size; // 8; 288 | break; 289 | case GLX_DEPTH_SIZE: 290 | *value = fb_config.depth_size; // 24; 291 | break; 292 | case GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB: 293 | *value = 1; 294 | break; 295 | } 296 | 297 | return Success; 298 | } 299 | 300 | GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements) 301 | { 302 | GLXFBConfig *fb_config = calloc(1, sizeof(GLXFBConfig) * n_valid_fb_configs); 303 | for (int i = 0; i < n_valid_fb_configs; i++) 304 | fb_config[i] = (GLXFBConfig)((size_t)i); 305 | *nelements = n_valid_fb_configs; 306 | return fb_config; 307 | } 308 | 309 | XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config) 310 | { 311 | XVisualInfo *vinfo = malloc(sizeof(XVisualInfo)); 312 | XMatchVisualInfo(dpy, XDefaultScreen(dpy), 24, TrueColor, vinfo); 313 | return vinfo; 314 | } 315 | 316 | GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list) 317 | { 318 | /* 319 | * probably not needed, stuck around for testing 320 | */ 321 | int *attribs = (int*)attrib_list; 322 | while (*attribs) { 323 | int attrib = *attribs++; 324 | int value = *attribs++; 325 | 326 | if (attrib == GLX_CONTEXT_PROFILE_MASK_ARB && value == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) 327 | return NULL; 328 | } 329 | 330 | return glXCreateContext(dpy, NULL, 0, 0); 331 | } 332 | 333 | int glXGetConfig(Display *dpy, XVisualInfo *visual, int attrib, int *value) 334 | { 335 | return 1; 336 | } 337 | 338 | GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, const int *attrib_list, int *nitems) 339 | { 340 | return glXGetFBConfigs(dpy, screen, nitems); 341 | } 342 | 343 | Bool glXIsDirect(Display *dpy, GLXContext ctx) 344 | { 345 | return True; 346 | } 347 | 348 | const char *glXQueryServerString( Display *dpy, int screen, int name ) 349 | { 350 | return glximpl_name_to_string(name); 351 | } 352 | 353 | void glXCopyContext(Display *dpy, GLXContext src, GLXContext dst, unsigned long mask) 354 | { 355 | 356 | } 357 | 358 | GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *visual, Pixmap pixmap) 359 | { 360 | return (GLXPixmap)1; 361 | } 362 | 363 | void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pixmap) 364 | { 365 | 366 | } 367 | 368 | GLXDrawable glXGetCurrentDrawable(void) 369 | { 370 | return win; 371 | } 372 | 373 | void glXUseXFont(Font font, int first, int count, int list) 374 | { 375 | 376 | } 377 | 378 | void glXWaitGL(void) 379 | { 380 | 381 | } 382 | 383 | void glXWaitX(void) 384 | { 385 | 386 | } 387 | 388 | int glXQueryContext(Display *dpy, GLXContext ctx, int attribute, int *value) 389 | { 390 | return Success; 391 | } 392 | 393 | void glXSwapBuffers(Display* dpy, GLXDrawable drawable) 394 | { 395 | static struct glx_swap_data swap_data = { 0 }; 396 | 397 | if (swap_data.initialized == false) { 398 | swap_sync_lock = pb_ptr(SGL_OFFSET_REGISTER_SWAP_BUFFERS_SYNC); 399 | 400 | XWindowAttributes attr; 401 | XGetWindowAttributes(dpy, drawable, &attr); 402 | 403 | swap_data.parent = XDefaultRootWindow(dpy); 404 | swap_data.nxvisuals = 0; 405 | swap_data.visual_template.screen = DefaultScreen(dpy); 406 | swap_data.visual_list = XGetVisualInfo(dpy, VisualScreenMask, &swap_data.visual_template, &swap_data.nxvisuals); 407 | 408 | XMatchVisualInfo(dpy, XDefaultScreen(dpy), 24, TrueColor, &swap_data.vinfo); 409 | 410 | /* 411 | * create an ximage whose pointer points to our framebuffer 412 | */ 413 | swap_data.ximage = XCreateImage(dpy, swap_data.vinfo.visual, swap_data.vinfo.depth, ZPixmap, 0, glimpl_fb_address(), max_width, max_height, 8, max_width*4); 414 | swap_data.gcv.graphics_exposures = 0; 415 | swap_data.gc = XCreateGC(dpy, swap_data.parent, GCGraphicsExposures, &swap_data.gcv); 416 | swap_data.initialized = true; 417 | } 418 | 419 | /* lock */ 420 | spin_lock(swap_sync_lock); 421 | 422 | /* swap */ 423 | glimpl_swap_buffers(real_width, real_height, 1, GL_BGRA); 424 | 425 | /* display */ 426 | XPutImage(dpy, drawable, swap_data.gc, swap_data.ximage, 0, 0, 0, 0, real_width, real_height); 427 | 428 | /* unlock */ 429 | spin_unlock(swap_sync_lock); 430 | 431 | /* sync */ 432 | XSync(dpy, False); 433 | } 434 | 435 | void* glXGetProcAddressARB(char* s) 436 | { 437 | // char str[64]; 438 | // if (strstr(s, "EXT") || strstr(s, "ARB")) { 439 | // strcpy(str, s); 440 | // str[strlen(str) - 3] = 0; 441 | // return NULL; 442 | // } 443 | 444 | /* to-do: use stripped str? */ 445 | return dlsym(NULL, s); 446 | } 447 | 448 | void *glXGetProcAddress(char *s) 449 | { 450 | return glXGetProcAddressARB(s); 451 | } 452 | 453 | void glximpl_init() 454 | { 455 | char *glx_version_override = getenv("GLX_VERSION_OVERRIDE"); 456 | if (glx_version_override) { 457 | glx_majmin_string = glx_version_override; 458 | glx_major = glx_version_override[0] - '0'; 459 | glx_minor = glx_version_override[2] - '0'; 460 | } 461 | 462 | glx_generate_fb_configs(); 463 | } -------------------------------------------------------------------------------- /src/client/platform/wgl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DISCLAIMER: 3 | * 4 | * This portion of the repository is served as a drop-in replacement for `opengl32.dll` 5 | * Because a proper ICD implementation is provided by `drv.c`, this part of the code base 6 | * has been rendered useless as Window's opengl32 will call upon drvXXXXX functions. This 7 | * also means we don't need to use MinHook to hook onto SwapBuffers, ChoosePixelFormat, 8 | * and SetPixelFormat. Hooks shouldn't have been in place for these functions to begin with 9 | * as there are WGL equivelents, which means this code needs to be rewritten for it to 10 | * function again as MinHook will be removed from the repository. The rewriting is not currently 11 | * a priority, but this note will be updated when such a rewrite comes along. This means even 12 | * if the end-user defines `OVERRIDE_OPENGL32`, this code will not compile. 13 | */ 14 | 15 | #ifdef OVERRIDE_OPENGL32 16 | #ifdef _WIN32 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | HWND Window; 28 | HDC Hdc; 29 | int Width; 30 | int Height; 31 | 32 | BOOL(*SwapBuffersOriginal)(HDC unnamedParam1); 33 | int(*ChoosePixelFormatOriginal)(HDC hdc, const PIXELFORMATDESCRIPTOR *ppfd); 34 | BOOL(*SetPixelFormatOriginal)(HDC hdc, int format, const PIXELFORMATDESCRIPTOR *ppfd); 35 | 36 | GLAPI PROC wglGetProcAddress(LPCSTR unnamedParam1) 37 | { 38 | return GetProcAddress(GetModuleHandleW(NULL), unnamedParam1); 39 | } 40 | 41 | BOOL wglMakeCurrent(HDC unnamedParam1, HGLRC unnamedParam2) 42 | { 43 | Hdc = unnamedParam1; 44 | Window = WindowFromDC(Hdc); 45 | 46 | RECT Rect; 47 | if (GetClientRect(Window, &Rect)) { 48 | Width = Rect.right - Rect.left; 49 | Height = Rect.bottom - Rect.top; 50 | } 51 | 52 | return TRUE; 53 | } 54 | 55 | BOOL wglDeleteContext(HGLRC unnamedParam1) 56 | { 57 | return TRUE; // STUB 58 | } 59 | 60 | HGLRC wglCreateContext(HDC unnamedParam1) 61 | { 62 | return (HGLRC)1; // STUB 63 | } 64 | 65 | HDC wglGetCurrentDC() 66 | { 67 | return Hdc; 68 | } 69 | 70 | GLAPI BOOL SwapBuffersHook(HDC unnamedParam1) 71 | { 72 | static BITMAPINFO bmi = { 73 | .bmiHeader.biSize = sizeof(BITMAPINFO), 74 | .bmiHeader.biPlanes = 1, 75 | .bmiHeader.biBitCount = 32, 76 | .bmiHeader.biCompression = BI_RGB, 77 | .bmiHeader.biSizeImage = 0, 78 | .bmiHeader.biClrUsed = 0, 79 | .bmiHeader.biClrImportant = 0, 80 | .bmiHeader.biXPelsPerMeter = 0, 81 | .bmiHeader.biYPelsPerMeter = 0 82 | }; 83 | 84 | static int Init = 0; 85 | static void *Frame = NULL; 86 | 87 | if (!Init) { 88 | bmi.bmiHeader.biWidth = Width; 89 | bmi.bmiHeader.biHeight = -Height; 90 | 91 | glimpl_report(Width, Height); 92 | 93 | Frame = glimpl_fb_address(); 94 | Init = 1; 95 | } 96 | 97 | glimpl_swap_buffers(Width, Height, 1, GL_BGRA); /* to-do: fix overlay so vflip and -Height won't be needed */ 98 | SetDIBitsToDevice(Hdc, 0, 0, Width, Height, 0, 0, 0, Height, Frame, &bmi, DIB_RGB_COLORS); 99 | // StretchDIBits(Hdc, 0, 0, Width, Height, 0, 0, Width, Height, Frame, &bmi, DIB_RGB_COLORS, SRCCOPY); 100 | 101 | return TRUE; 102 | } 103 | 104 | int ChoosePixelFormatHook(HDC hdc, const PIXELFORMATDESCRIPTOR *ppfd) 105 | { 106 | return TRUE; // STUB 107 | } 108 | 109 | BOOL SetPixelFormatHook(HDC hdc, int format, const PIXELFORMATDESCRIPTOR *ppfd) 110 | { 111 | return TRUE; // STUB 112 | } 113 | 114 | void WglInit() 115 | { 116 | MH_Initialize(); 117 | 118 | MH_CreateHook(SwapBuffers, SwapBuffersHook, (PVOID*)(&SwapBuffersOriginal)); 119 | MH_EnableHook(SwapBuffers); 120 | 121 | MH_CreateHook(ChoosePixelFormat, ChoosePixelFormatHook, (PVOID*)(&ChoosePixelFormatOriginal)); 122 | MH_EnableHook(ChoosePixelFormat); 123 | 124 | MH_CreateHook(SetPixelFormat, SetPixelFormatHook, (PVOID*)(&SetPixelFormatOriginal)); 125 | MH_EnableHook(SetPixelFormat); 126 | } 127 | 128 | #endif 129 | #endif -------------------------------------------------------------------------------- /src/client/platform/windrv.c: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | static PIXELFORMATDESCRIPTOR pfd_table[64] = { 0 }; 18 | static int pfd_count = 0; 19 | 20 | static struct WGLCALLBACKS callbacks; 21 | 22 | static int max_width, max_height, real_width, real_height; 23 | 24 | static void *swap_sync_lock; 25 | 26 | ICD_SET_MAX_DIMENSIONS_DEFINITION(max_width, max_height, real_width, real_height); 27 | ICD_RESIZE_DEFINITION(real_width, real_height); 28 | 29 | typedef HGLRC(WINAPI * wglCreateContext_t )(HDC); 30 | typedef BOOL(WINAPI * wglDeleteContext_t )(HGLRC); 31 | 32 | static wglCreateContext_t g_pfnwglCreateContext = NULL; 33 | static wglDeleteContext_t g_pfnwglDeleteContext = NULL; 34 | 35 | struct pfd_color_info { 36 | int rbits, gbits, bbits, abits; 37 | int rshift, gshift, bshift, ashift; 38 | }; 39 | 40 | struct pfd_depth_info { 41 | int depthbits, stencilbits; 42 | }; 43 | 44 | static struct pfd_color_info pfd_colors[4] = { 45 | { 8, 8, 8, 0, 16, 8, 0, 0 }, 46 | { 8, 8, 8, 0, 8, 16, 24, 0 }, 47 | { 8, 8, 8, 8, 16, 8, 0, 24 }, 48 | { 8, 8, 8, 8, 8, 16, 24, 0 } 49 | }; 50 | 51 | static struct pfd_depth_info pfd_depths[4] = { 52 | { 32, 0 }, 53 | { 24, 0 }, 54 | { 16, 0 }, 55 | { 24, 8 } 56 | }; 57 | 58 | struct wgl_extension_entry { 59 | const char *name; 60 | PROC proc; 61 | }; 62 | 63 | static HMODULE module_handle = 0; 64 | static BOOL do_vflip = TRUE; 65 | 66 | void windrv_set_module_address(HMODULE module) 67 | { 68 | module_handle = module; 69 | } 70 | 71 | void windrv_set_vflip(BOOL flip) 72 | { 73 | do_vflip = flip; 74 | } 75 | 76 | // removed WGL_ARB_pixel_format 77 | static const char *wgl_extensions = "WGL_ARB_create_context WGL_ARB_create_context_profile WGL_ARB_extensions_string WGL_ARB_framebuffer_sRGB"; 78 | 79 | static HGLRC wgl_create_context(HDC hdc) 80 | { 81 | if (g_pfnwglCreateContext == NULL) 82 | g_pfnwglCreateContext = (wglCreateContext_t)GetProcAddress(GetModuleHandleA("opengl32.dll"), "wglCreateContext"); 83 | 84 | return g_pfnwglCreateContext(hdc); 85 | } 86 | 87 | static BOOL wgl_delete_context(HGLRC hglrc) 88 | { 89 | if (g_pfnwglDeleteContext == NULL) 90 | g_pfnwglDeleteContext = (wglDeleteContext_t)GetProcAddress(GetModuleHandleA("opengl32.dll"), "wglDeleteContext"); 91 | 92 | return g_pfnwglDeleteContext(hglrc); 93 | } 94 | 95 | const char* wglGetExtensionsStringARB(HDC hdc) 96 | { 97 | return wgl_extensions; 98 | } 99 | 100 | HGLRC wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList) 101 | { 102 | return wgl_create_context(hDC); 103 | } 104 | 105 | BOOL wglGetPixelFormatAttribivARB(HDC hdc, 106 | int iPixelFormat, 107 | int iLayerPlane, 108 | UINT nAttributes, 109 | const int *piAttributes, 110 | int *piValues) 111 | { 112 | return TRUE; 113 | } 114 | 115 | BOOL wglGetPixelFormatAttribfvARB(HDC hdc, 116 | int iPixelFormat, 117 | int iLayerPlane, 118 | UINT nAttributes, 119 | const int *piAttributes, 120 | FLOAT *pfValues) 121 | { 122 | return TRUE; 123 | } 124 | 125 | BOOL wglChoosePixelFormatARB(HDC hdc, 126 | const int *piAttribIList, 127 | const FLOAT *pfAttribFList, 128 | UINT nMaxFormats, 129 | int *piFormats, 130 | UINT *nNumFormats) 131 | { 132 | *piFormats = 1; 133 | *nNumFormats = 1; 134 | return TRUE; 135 | } 136 | 137 | #define WGL_EXTENSION_ENTRY(P) { #P, (PROC) P } 138 | 139 | static const struct wgl_extension_entry wgl_extension_entries[] = { 140 | 141 | /* WGL_ARB_extensions_string */ 142 | WGL_EXTENSION_ENTRY( wglGetExtensionsStringARB ), 143 | 144 | /* WGL_ARB_pixel_format */ 145 | // WGL_EXTENSION_ENTRY( wglChoosePixelFormatARB ), 146 | // WGL_EXTENSION_ENTRY( wglGetPixelFormatAttribfvARB ), 147 | // WGL_EXTENSION_ENTRY( wglGetPixelFormatAttribivARB ), 148 | 149 | /* WGL_ARB_create_context */ 150 | WGL_EXTENSION_ENTRY( wglCreateContextAttribsARB ), 151 | 152 | { NULL, NULL } 153 | }; 154 | 155 | static void pfd_add( 156 | bool doublebuffer, bool gdi, unsigned int accum, 157 | int rbits, int gbits, int bbits, int abits, 158 | int rshift, int gshift, int bshift, int ashift, 159 | int depthbits, int stencilbits) 160 | { 161 | pfd_table[pfd_count].nSize = sizeof(pfd_table[pfd_count]); 162 | pfd_table[pfd_count].nVersion = 1; 163 | pfd_table[pfd_count].dwFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION | PFD_DRAW_TO_WINDOW; 164 | 165 | if (doublebuffer) 166 | pfd_table[pfd_count].dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE; 167 | 168 | if (gdi) 169 | pfd_table[pfd_count].dwFlags |= PFD_SUPPORT_GDI; 170 | 171 | pfd_table[pfd_count].iPixelType = PFD_TYPE_RGBA; 172 | pfd_table[pfd_count].iLayerType = PFD_MAIN_PLANE; 173 | 174 | pfd_table[pfd_count].cColorBits = rbits + gbits + bbits + abits; 175 | pfd_table[pfd_count].cRedBits = rbits; 176 | pfd_table[pfd_count].cRedShift = rshift; 177 | pfd_table[pfd_count].cGreenBits = gbits; 178 | pfd_table[pfd_count].cGreenShift = gshift; 179 | pfd_table[pfd_count].cBlueBits = bbits; 180 | pfd_table[pfd_count].cBlueShift = bshift; 181 | pfd_table[pfd_count].cAlphaBits = abits; 182 | pfd_table[pfd_count].cAlphaShift = ashift; 183 | pfd_table[pfd_count].cAccumBits = 4*accum; 184 | pfd_table[pfd_count].cAccumRedBits = accum; 185 | pfd_table[pfd_count].cAccumGreenBits = accum; 186 | pfd_table[pfd_count].cAccumBlueBits = accum; 187 | pfd_table[pfd_count].cAccumAlphaBits = accum; 188 | pfd_table[pfd_count].cDepthBits = depthbits; 189 | pfd_table[pfd_count].cStencilBits = stencilbits; 190 | pfd_table[pfd_count].cAuxBuffers = 0; 191 | pfd_table[pfd_count].iLayerType = 0; 192 | pfd_table[pfd_count].bReserved = 0; 193 | pfd_table[pfd_count].dwLayerMask = 0; 194 | pfd_table[pfd_count].dwVisibleMask = 0; 195 | pfd_table[pfd_count].dwDamageMask = 0; 196 | 197 | pfd_count++; 198 | } 199 | 200 | /* 201 | * accounts for accum 202 | */ 203 | static void pfd_add2( 204 | bool doublebuffer, bool gdi, unsigned int accum, 205 | int rbits, int gbits, int bbits, int abits, 206 | int rshift, int gshift, int bshift, int ashift, 207 | int depthbits, int stencilbits) 208 | { 209 | for (int i = 0; i < 2; i++) 210 | pfd_add(doublebuffer, gdi, i * accum, rbits, gbits, bbits, abits, rshift, gshift, bshift, ashift, depthbits, stencilbits); 211 | } 212 | 213 | static void pfd_init() 214 | { 215 | /* 216 | * optional doublebuffer 217 | * no gdi 218 | */ 219 | for (int i = 0; i < 2; i++) { 220 | for (int color = 0; color < 4; color++) 221 | for (int depth = 0; depth < 4; depth++) 222 | pfd_add2(i, false, 16, 223 | pfd_colors[color].rbits, pfd_colors[color].gbits, pfd_colors[color].bbits, pfd_colors[color].abits, 224 | pfd_colors[color].rshift, pfd_colors[color].gshift, pfd_colors[color].bshift, pfd_colors[color].ashift, 225 | pfd_depths[depth].depthbits, pfd_depths[depth].stencilbits); 226 | } 227 | } 228 | 229 | DHGLRC APIENTRY DrvCreateContext(HDC hdc) 230 | { 231 | return (DHGLRC)1; 232 | } 233 | 234 | DHGLRC APIENTRY DrvCreateLayerContext(HDC hdc, INT iLayerPlane) 235 | { 236 | return (DHGLRC)1; 237 | } 238 | 239 | BOOL APIENTRY DrvDeleteContext(DHGLRC dhglrc) 240 | { 241 | return wgl_delete_context(dhglrc); 242 | } 243 | 244 | BOOL APIENTRY DrvCopyContext(DHGLRC dhrcSource, DHGLRC dhrcDest, UINT fuMask) 245 | { 246 | return TRUE; 247 | } 248 | 249 | PGLCLTPROCTABLE APIENTRY DrvSetContext(HDC hdc, DHGLRC dhglrc, PFN_SETPROCTABLE pfnSetProcTable) 250 | { 251 | return glimpl_GetProcTable(); 252 | } 253 | 254 | BOOL APIENTRY DrvReleaseContext(DHGLRC dhglrc) 255 | { 256 | return TRUE; 257 | } 258 | 259 | BOOL APIENTRY DrvValidateVersion(ULONG ulVersion) 260 | { 261 | return TRUE; 262 | } 263 | 264 | BOOL APIENTRY DrvShareLists(DHGLRC dhglrc1, DHGLRC dhglrc2) 265 | { 266 | return TRUE; 267 | } 268 | 269 | PROC APIENTRY DrvGetProcAddress(LPCSTR lpszProc) 270 | { 271 | if (lpszProc[0] == 'g' && lpszProc[1] == 'l') 272 | return GetProcAddress(module_handle, lpszProc); 273 | 274 | if (lpszProc[0] == 'w' && lpszProc[1] == 'g' && lpszProc[2] == 'l') 275 | for (struct wgl_extension_entry *entry = wgl_extension_entries; entry->name; entry++) 276 | if (strcmp(lpszProc, entry->name) == 0) 277 | return entry->proc; 278 | 279 | return NULL; 280 | } 281 | 282 | void APIENTRY DrvSetCallbackProcs(INT nProcs, PROC *pProcs) 283 | { 284 | size_t size = MIN(nProcs * sizeof(*pProcs), sizeof(callbacks)); 285 | memcpy(&callbacks, pProcs, size); 286 | 287 | return; 288 | } 289 | 290 | BOOL APIENTRY DrvDescribeLayerPlane(HDC hdc, INT iPixelFormat, INT iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd) 291 | { 292 | return FALSE; 293 | } 294 | 295 | int APIENTRY DrvGetLayerPaletteEntries(HDC hdc, INT iLayerPlane, INT iStart, INT cEntries, COLORREF *pcr) 296 | { 297 | return 0; 298 | } 299 | 300 | int APIENTRY DrvSetLayerPaletteEntries(HDC hdc, INT iLayerPlane, INT iStart, INT cEntries, CONST COLORREF *pcr) 301 | { 302 | return 0; 303 | } 304 | 305 | BOOL APIENTRY DrvRealizeLayerPalette(HDC hdc, INT iLayerPlane, BOOL bRealize) 306 | { 307 | return FALSE; 308 | } 309 | 310 | BOOL APIENTRY DrvSwapBuffers(HDC hdc) 311 | { 312 | static BITMAPINFO bmi = { 313 | .bmiHeader.biSize = sizeof(BITMAPINFO), 314 | .bmiHeader.biPlanes = 1, 315 | .bmiHeader.biBitCount = 32, 316 | .bmiHeader.biCompression = BI_RGB, 317 | .bmiHeader.biSizeImage = 0, 318 | .bmiHeader.biClrUsed = 0, 319 | .bmiHeader.biClrImportant = 0, 320 | .bmiHeader.biXPelsPerMeter = 0, 321 | .bmiHeader.biYPelsPerMeter = 0 322 | }; 323 | 324 | static int init = 0; 325 | static void *framebuffer = NULL; 326 | 327 | if (!init) { 328 | bmi.bmiHeader.biWidth = max_width; 329 | bmi.bmiHeader.biHeight = -max_height; 330 | 331 | swap_sync_lock = pb_ptr(SGL_OFFSET_REGISTER_SWAP_BUFFERS_SYNC); 332 | framebuffer = glimpl_fb_address(); 333 | init = 1; 334 | } 335 | 336 | spin_lock(swap_sync_lock); 337 | 338 | glimpl_swap_buffers(real_width, real_height, do_vflip, GL_BGRA); /* to-do: fix overlay so vflip and -Height won't be needed */ 339 | SetDIBitsToDevice(hdc, 0, 0, real_width, real_height, 0, 0, 0, real_height, framebuffer, &bmi, DIB_RGB_COLORS); 340 | // StretchDIBits(hdc, 0, 0, real_width, real_height, 0, 0, real_width, real_height, framebuffer, &bmi, DIB_RGB_COLORS, SRCCOPY); 341 | 342 | spin_unlock(swap_sync_lock); 343 | 344 | return TRUE; 345 | } 346 | 347 | BOOL APIENTRY DrvPresentBuffers(HDC hdc, LPPRESENTBUFFERS data) 348 | { 349 | return TRUE; 350 | } 351 | 352 | BOOL APIENTRY DrvSwapLayerBuffers(HDC hdc, UINT fuPlanes) 353 | { 354 | if (fuPlanes & WGL_SWAP_MAIN_PLANE) 355 | return DrvSwapBuffers(hdc); 356 | 357 | return FALSE; 358 | } 359 | 360 | LONG APIENTRY DrvDescribePixelFormat(HDC hdc, INT iPixelFormat, ULONG cjpfd, PIXELFORMATDESCRIPTOR *ppfd) 361 | { 362 | if (!pfd_count) 363 | pfd_init(); 364 | 365 | --iPixelFormat; 366 | 367 | if (iPixelFormat >= pfd_count || iPixelFormat < 0 || cjpfd != sizeof(PIXELFORMATDESCRIPTOR)) 368 | return pfd_count; 369 | 370 | if (ppfd != NULL) 371 | memcpy(ppfd, &pfd_table[iPixelFormat], sizeof(PIXELFORMATDESCRIPTOR)); 372 | 373 | return pfd_count; 374 | } 375 | 376 | BOOL APIENTRY DrvSetPixelFormat(HDC hdc, LONG iPixelFormat) 377 | { 378 | if (GetPixelFormat(hdc) == 0) 379 | SetPixelFormat(hdc, iPixelFormat, NULL); 380 | 381 | return TRUE; 382 | } 383 | 384 | // BOOL APIENTRY DrvMakeCurrent(HDC hDC, HGLRC hRC) 385 | // { 386 | // return TRUE; 387 | // } 388 | 389 | #endif -------------------------------------------------------------------------------- /src/client/scratch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN32 5 | #include 6 | #else 7 | #define __USE_GNU 8 | #define _GNU_SOURCE 9 | #include 10 | #include 11 | #include 12 | #endif 13 | 14 | static void *address = NULL; 15 | static size_t current_size = 0; 16 | 17 | static inline uintptr_t align_to_4kb(uintptr_t ptr) 18 | { 19 | return (ptr + 4095) & ~4095; 20 | } 21 | 22 | #ifdef _WIN32 23 | static void *windows_mremap(void *old_address, size_t old_size, size_t new_size) 24 | { 25 | MEMORY_BASIC_INFORMATION mbi; 26 | void *new_address; 27 | 28 | /* 29 | * check to see if we can extend the current allocation 30 | */ 31 | if (VirtualQuery((char*)old_address + old_size, &mbi, sizeof(mbi)) == sizeof(mbi)) 32 | if (mbi.State == MEM_FREE && mbi.RegionSize >= (new_size - old_size)) 33 | if (VirtualAlloc((char*)old_address + old_size, new_size - old_size, MEM_COMMIT, PAGE_READWRITE)) 34 | return old_address; 35 | 36 | /* 37 | * otherwise, allocate a new region, copy, free 38 | * this can be expensive, but will rarely be performed 39 | */ 40 | new_address = VirtualAlloc(NULL, new_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 41 | if (new_address) { 42 | memcpy(new_address, old_address, old_size); 43 | VirtualFree(old_address, 0, MEM_RELEASE); 44 | return new_address; 45 | } 46 | 47 | return NULL; 48 | } 49 | #endif 50 | 51 | void *scratch_buffer_get(size_t size) 52 | { 53 | if (!current_size) { 54 | current_size = align_to_4kb(size); 55 | #ifdef _WIN32 56 | address = VirtualAlloc(NULL, current_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 57 | #else 58 | address = mmap(NULL, current_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 59 | #endif 60 | return address; 61 | } 62 | else { 63 | size_t aligned_size = align_to_4kb(size); 64 | if (current_size < aligned_size) { 65 | #ifdef _WIN32 66 | address = windows_mremap(address, current_size, aligned_size); 67 | #else 68 | address = mremap(address, current_size, aligned_size, MREMAP_MAYMOVE); 69 | #endif 70 | current_size = aligned_size; 71 | return address; 72 | } 73 | 74 | return address; 75 | } 76 | } -------------------------------------------------------------------------------- /src/client/spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) 3 | #include 4 | #else 5 | // #warning Non-x86 platform detected, assuming ARM. 6 | #define _mm_pause() asm volatile("yield"); 7 | #endif 8 | 9 | #ifdef _WIN32 10 | #include 11 | #endif 12 | 13 | void spin_lock(int *lock) 14 | { 15 | #ifndef _WIN32 16 | while (!__sync_bool_compare_and_swap(lock, 0, 1)) 17 | _mm_pause(); 18 | #else 19 | while (InterlockedCompareExchange(lock, 1, 0)) 20 | _mm_pause(); 21 | #endif 22 | } 23 | 24 | void spin_unlock(int volatile *lock) 25 | { 26 | #ifndef _WIN32 27 | asm volatile ("":::"memory"); 28 | #endif 29 | *lock = 0; 30 | } -------------------------------------------------------------------------------- /src/client/winmain.c: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 /* globbed */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static char env_value[16]; 9 | 10 | BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) 11 | { 12 | if (reason == DLL_PROCESS_ATTACH) { 13 | DWORD result; 14 | 15 | /* 16 | * some weird hack that can speed up processes, reducing apparent lag; 17 | * by setting the priority of the program to "low", we give the kernel 18 | * more CPU time, which is crucial because the kernel driver is how data 19 | * between the VM and host move. 20 | */ 21 | result = GetEnvironmentVariableA("SGL_RUN_WITH_LOW_PRIORITY", env_value, 16); 22 | if (strcmp(env_value, "true") == 0) 23 | SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); 24 | 25 | /* 26 | * if running a directx application via WineD3D, we don't need to perform a 27 | * vertical flip as the library appears to perform this action for us 28 | */ 29 | result = GetEnvironmentVariableA("SGL_WINED3D_DONT_VFLIP", env_value, 16); 30 | if (strcmp(env_value, "true") == 0) 31 | windrv_set_vflip(FALSE); 32 | 33 | windrv_set_module_address(module); 34 | glimpl_init(); 35 | } 36 | if (reason == DLL_PROCESS_DETACH) 37 | glimpl_goodbye(); 38 | 39 | return TRUE; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/server/context.c: -------------------------------------------------------------------------------- 1 | #define SHAREDGL_HOST 2 | #include 3 | #include 4 | #include 5 | 6 | static bool is_vid_init = false; 7 | static int mw = 1920; 8 | static int mh = 1080; 9 | static bool is_overlay_string_init = false; 10 | 11 | void sgl_set_max_resolution(int width, int height) 12 | { 13 | mw = width; 14 | mh = height; 15 | } 16 | 17 | void sgl_get_max_resolution(int *width, int *height) 18 | { 19 | *width = mw; 20 | *height = mh; 21 | } 22 | 23 | struct sgl_host_context *sgl_context_create() 24 | { 25 | struct sgl_host_context *context = (struct sgl_host_context *)malloc(sizeof(struct sgl_host_context)); 26 | 27 | if (!is_vid_init) { 28 | SDL_Init(SDL_INIT_VIDEO); 29 | is_vid_init = true; 30 | } 31 | 32 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 33 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 34 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 35 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); 36 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 37 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 38 | 39 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 40 | SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); 41 | // SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 42 | // SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 43 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); 44 | 45 | context->window = SDL_CreateWindow( 46 | "SDL Offscreen Window", 47 | SDL_WINDOWPOS_CENTERED, 48 | SDL_WINDOWPOS_CENTERED, 49 | mw, mh, 50 | SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); 51 | if (context->window == NULL) { 52 | fprintf(stderr, "%s: Failed to create window\n", __func__); 53 | SDL_Quit(); 54 | exit(1); 55 | } 56 | 57 | context->gl_context = SDL_GL_CreateContext(context->window); 58 | if (context->gl_context == NULL) { 59 | fprintf(stderr, "%s: Failed to create GL context\n", __func__); 60 | SDL_DestroyWindow(context->window); 61 | SDL_Quit(); 62 | exit(1); 63 | } 64 | 65 | sgl_set_current(context); 66 | 67 | if (!is_overlay_string_init) { 68 | overlay_set_renderer_string((char*)glGetString(GL_RENDERER)); 69 | is_overlay_string_init = true; 70 | } 71 | 72 | return context; 73 | } 74 | 75 | void sgl_context_destroy(struct sgl_host_context *ctx) 76 | { 77 | sgl_set_current(NULL); 78 | SDL_DestroyWindow(ctx->window); 79 | SDL_GL_DeleteContext(ctx->gl_context); 80 | free(ctx); 81 | } 82 | 83 | #ifdef SGL_DEBUG_EMIT_FRAMES 84 | SDL_Window *window; 85 | #endif 86 | 87 | void sgl_set_current(struct sgl_host_context *ctx) 88 | { 89 | if (ctx == NULL) 90 | SDL_GL_MakeCurrent(NULL, NULL); 91 | else 92 | SDL_GL_MakeCurrent(ctx->window, ctx->gl_context); 93 | 94 | #ifdef SGL_DEBUG_EMIT_FRAMES 95 | if (ctx) 96 | window = ctx->window; 97 | #endif 98 | } 99 | 100 | void *sgl_read_pixels(unsigned int width, unsigned int height, void *data, int vflip, int format, size_t mem_usage) 101 | { 102 | static struct overlay_context overlay_ctx = { 0 }; 103 | 104 | overlay_stage1(&overlay_ctx); 105 | 106 | glReadPixels(0, 0, mw, height, format, GL_UNSIGNED_BYTE, data); // GL_BGRA 107 | int *pdata = data; 108 | 109 | if (vflip) { 110 | for (int y = 0; y < height / 2; y++) { 111 | for (int x = 0; x < mw; x++) { 112 | int *ptop = &pdata[y * mw + x]; 113 | int *pbottom = &pdata[(height - y - 1) * mw + x]; 114 | 115 | int vtop = *ptop; 116 | int vbottom = *pbottom; 117 | 118 | *ptop = vbottom; 119 | *pbottom = vtop; 120 | } 121 | } 122 | } 123 | 124 | overlay_stage2(&overlay_ctx, data, mw, mem_usage); 125 | 126 | #ifdef SGL_DEBUG_EMIT_FRAMES 127 | SDL_GL_SwapWindow(window); 128 | #endif 129 | 130 | return data; 131 | } -------------------------------------------------------------------------------- /src/server/dynarr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void *dynarr_alloc(void **root, size_t next_offset, size_t size) 5 | { 6 | /* 7 | * if list hasn't started, then start the dam list 8 | */ 9 | if (*root == NULL) { 10 | *root = calloc(1, size); 11 | return *root; 12 | } 13 | 14 | /* 15 | * otherwise, iterate through the list until we find the next spot to allocate to 16 | */ 17 | void *next; 18 | 19 | /* 20 | * iterate through root until next = NULL 21 | */ 22 | for (next = *root; *(void**)(next + next_offset); next = *(void**)(next + next_offset)); 23 | 24 | /* 25 | * allocation 26 | */ 27 | *(void**)(next + next_offset) = calloc(1, size); 28 | 29 | return *(void**)(next + next_offset); 30 | } 31 | 32 | void dynarr_free_element(void **root, size_t next_offset, dynarr_match_fn matcher, void *data) 33 | { 34 | void *prev = NULL; 35 | 36 | for (void *elem = *root; elem;) { 37 | void *next = *(void**)(elem + next_offset); 38 | 39 | if (matcher(elem, data)) { 40 | /* 41 | * check if element is first, otherwise doesn't matter 42 | */ 43 | if (prev == NULL) 44 | *root = next; 45 | else 46 | *(void**)(prev + next_offset) = next; 47 | 48 | free(elem); 49 | } 50 | else 51 | prev = elem; 52 | 53 | elem = next; 54 | } 55 | } 56 | 57 | void dynarr_free(void **root, size_t next_offset) 58 | { 59 | /* 60 | * recursively call up until the last element 61 | * (elements need to be freed in reverse order) 62 | */ 63 | if (*(void**)(root)) { 64 | dynarr_free(*(void**)(root + next_offset), next_offset); 65 | free(*root); 66 | } 67 | } -------------------------------------------------------------------------------- /src/server/main.c: -------------------------------------------------------------------------------- 1 | #define SHAREDGL_HOST 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | static void *shm_ptr; 22 | static size_t shm_size; 23 | 24 | static int *internal_cmd_ptr; 25 | 26 | static const char *usage = 27 | "usage: sglrenderer [-h] [-v] [-o] [-n] [-x] [-g MAJOR.MINOR] [-r WIDTHxHEIGHT] [-m SIZE] [-p PORT]\n" 28 | "\n" 29 | "options:\n" 30 | " -h display help information\n" 31 | " -v display virtual machine arguments\n" 32 | " -o enables fps overlay on clients\n" 33 | " -n enable network server instead of using shared memory\n" 34 | " -x remove shared memory file\n" 35 | " -g [MAJOR.MINOR] report specific opengl version (default: %d.%d)\n" 36 | " -r [WIDTHxHEIGHT] set max resolution (default: 1920x1080)\n" 37 | " -m [SIZE] max amount of megabytes program may allocate (default: 32mib)\n" 38 | " -p [PORT] if networking is enabled, specify which port to use (default: 3000)\n"; 39 | 40 | static void generate_virtual_machine_arguments(size_t m) 41 | { 42 | static const char *libvirt_string = 43 | "\n" 44 | " \n" 45 | " %ld\n" 46 | "\n"; 47 | 48 | static const char *qemu_string = 49 | "-object memory-backend-file,size=%ldM,share,mem-path=/dev/shm/" SGL_SHARED_MEMORY_NAME ",id=" SGL_SHARED_MEMORY_NAME "\n"; 50 | 51 | fprintf(stderr, "\nlibvirt:\n"); 52 | fprintf(stderr, libvirt_string, m); 53 | fprintf(stderr, "\nqemu:\n"); 54 | fprintf(stderr, qemu_string, m); 55 | fprintf(stderr, "\n"); 56 | } 57 | 58 | static void term_handler(int sig) 59 | { 60 | munmap(shm_ptr, shm_size); 61 | int icmd = *internal_cmd_ptr; 62 | 63 | switch (sig) { 64 | case SIGINT: 65 | break; 66 | case SIGSEGV: 67 | PRINT_LOG("server stopped! segmentation fault on %s (%d)\n", sgl_cmd2str(icmd), icmd); 68 | break; 69 | // shouldn't ever reach here 70 | case SIGPIPE: 71 | PRINT_LOG("server stopped! socket unexpectedly closed\n"); 72 | break; 73 | } 74 | 75 | exit(1); 76 | } 77 | 78 | static void arg_parser_protector(int sig) 79 | { 80 | PRINT_LOG("expected second argument\n"); 81 | exit(1); 82 | } 83 | 84 | int main(int argc, char **argv) 85 | { 86 | bool print_virtual_machine_arguments = false; 87 | 88 | bool network_over_shared = false; 89 | int port = 3000; 90 | 91 | int major = SGL_DEFAULT_MAJOR; 92 | int minor = SGL_DEFAULT_MINOR; 93 | 94 | shm_size = 32; 95 | 96 | signal(SIGSEGV, arg_parser_protector); 97 | 98 | for (int i = 1; i < argc; i++) { 99 | switch (argv[i][1]) { 100 | case 'h': 101 | fprintf(stderr, usage, SGL_DEFAULT_MAJOR, SGL_DEFAULT_MINOR); 102 | return 0; 103 | case 'v': 104 | print_virtual_machine_arguments = true; 105 | break; 106 | case 'n': 107 | network_over_shared = true; 108 | break; 109 | case 'o': 110 | overlay_enable(); 111 | break; 112 | case 'x': 113 | shm_unlink(SGL_SHARED_MEMORY_NAME); 114 | PRINT_LOG("unlinked shared memory '%s'\n", SGL_SHARED_MEMORY_NAME); 115 | return 0; 116 | case 'g': 117 | major = argv[i + 1][0] - '0'; 118 | minor = argv[i + 1][2] - '0'; 119 | i++; 120 | break; 121 | case 'r': { 122 | int width, height, j; 123 | for (j = 0; j < strlen(argv[i + 1]); j++) 124 | if (argv[i + 1][j] == 'x') 125 | break; 126 | sgl_set_max_resolution( 127 | atoi(argv[i + 1]), 128 | atoi(&argv[i + 1][j + 1]) 129 | ); 130 | i++; 131 | break; 132 | } 133 | case 'm': 134 | shm_size = atoi(argv[i + 1]); 135 | i++; 136 | break; 137 | case 'p': 138 | port = atoi(argv[i + 1]); 139 | i++; 140 | break; 141 | default: 142 | PRINT_LOG("unrecognized command-line option '%s'\n", argv[i]); 143 | } 144 | } 145 | 146 | signal(SIGINT, term_handler); 147 | signal(SIGSEGV, term_handler); 148 | signal(SIGPIPE, SIG_IGN); 149 | 150 | PRINT_LOG("press CTRL+C to terminate server\n"); 151 | 152 | if (print_virtual_machine_arguments) { 153 | if (!network_over_shared) 154 | generate_virtual_machine_arguments(shm_size); 155 | else 156 | PRINT_LOG("command line argument '-v' ignored as networking is enabled\n"); 157 | } 158 | 159 | /* 160 | * allocate memory, only create a shared memory file if using shared memory 161 | */ 162 | shm_size *= 1024 * 1024; 163 | if (!network_over_shared) { 164 | int shm_fd = shm_open(SGL_SHARED_MEMORY_NAME, O_CREAT | O_RDWR, S_IRWXU); 165 | if (shm_fd == -1) { 166 | PRINT_LOG("failed to open shared memory '%s'\n", SGL_SHARED_MEMORY_NAME); 167 | return -1; 168 | } 169 | 170 | if (ftruncate(shm_fd, shm_size) == -1) { 171 | PRINT_LOG("failed to truncate shared memory\n"); 172 | return -2; 173 | } 174 | 175 | shm_ptr = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 176 | } 177 | else { 178 | shm_ptr = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); 179 | } 180 | 181 | PRINT_LOG("reserved %ld MiB of memory\n", shm_size / 1024 / 1024); 182 | 183 | struct sgl_cmd_processor_args args = { 184 | .base_address = shm_ptr, 185 | .memory_size = shm_size, 186 | 187 | .network_over_shared = network_over_shared, 188 | .port = port, 189 | 190 | .gl_major = major, 191 | .gl_minor = minor, 192 | 193 | .internal_cmd_ptr = &internal_cmd_ptr, 194 | }; 195 | 196 | int mw, mh; 197 | sgl_get_max_resolution(&mw, &mh); 198 | PRINT_LOG("maximum resolution set to %dx%d\n", mw, mh); 199 | PRINT_LOG("reporting gl version %d.%d\n", major, minor); 200 | 201 | sgl_cmd_processor_start(args); 202 | } -------------------------------------------------------------------------------- /src/server/overlay.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static void overlay_draw_char(int *display, int width, char c, int x, int y, unsigned int fg) 9 | { 10 | int mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 11 | const unsigned char *gylph = IBM + (int)c * CHAR_HEIGHT; 12 | 13 | unsigned char *color; 14 | 15 | for (int cy = 0; cy < CHAR_HEIGHT; cy++) 16 | for (int cx = 0; cx < CHAR_WIDTH; cx++) { 17 | /* 18 | * darken pixels 19 | */ 20 | color = (unsigned char*)&display[(y + cy) * width + (x + ((CHAR_WIDTH - 1) - cx))]; 21 | color[0] = color[0] * 120 / 255; 22 | color[1] = color[1] * 120 / 255; 23 | color[2] = color[2] * 120 / 255; 24 | color[3] = color[3] * 120 / 255; 25 | 26 | if (gylph[cy] & mask[cx]) 27 | display[(y + cy) * width + (x + ((CHAR_WIDTH - 1) - cx))] = fg; 28 | } 29 | } 30 | 31 | static void overlay_draw_text(int *display, int width, char *text, int x, int y, unsigned int fg) 32 | { 33 | char* c = text; 34 | for (int i = x; *c; i += CHAR_WIDTH) 35 | overlay_draw_char( 36 | display, 37 | width, 38 | *c++, 39 | i, 40 | y, 41 | fg 42 | ); 43 | } 44 | 45 | static bool overlay_enabled = false; 46 | static char overlay_string[256] = "SharedGL using "; 47 | 48 | void overlay_set_renderer_string(char *string) 49 | { 50 | strcpy(overlay_string + 15, string); 51 | } 52 | 53 | void overlay_enable() 54 | { 55 | overlay_enabled = true; 56 | } 57 | 58 | void overlay_stage1(struct overlay_context *ctx) 59 | { 60 | if (!overlay_enabled) 61 | return; 62 | 63 | ctx->delta_ticks = clock() - ctx->current_ticks; 64 | if (ctx->current_ticks && ctx->delta_ticks != 0) 65 | ctx->fps = CLOCKS_PER_SEC / ctx->delta_ticks; 66 | } 67 | 68 | void overlay_stage2(struct overlay_context *ctx, int *frame, int width, size_t mem_usage) 69 | { 70 | if (!overlay_enabled) 71 | return; 72 | 73 | double usage = mem_usage; 74 | bool is_mb = false; 75 | 76 | if (mem_usage > 0x100000) { 77 | usage /= 0x100000; 78 | is_mb = true; 79 | } 80 | else { 81 | usage /= 0x1000; 82 | } 83 | 84 | if (ctx->current_ticks) { 85 | char str[12]; 86 | char mem[24]; 87 | sprintf(str, "FPS: %ld", ctx->fps); 88 | sprintf(mem, "MEM: %.2f %s", usage, is_mb ? "MB" : "KB"); 89 | 90 | overlay_draw_text(frame, width, overlay_string, 0, CHAR_HEIGHT * 0, 0xffffff); 91 | overlay_draw_text(frame, width, mem, 0, CHAR_HEIGHT * 1, 0xffffff); 92 | overlay_draw_text(frame, width, str, 0, CHAR_HEIGHT * 2, 0xffffff); 93 | } 94 | 95 | ctx->current_ticks = clock(); 96 | } --------------------------------------------------------------------------------