Initial commit
This commit is contained in:
commit
4602228be9
13 changed files with 451 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
result
|
||||
.direnv/
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "muvm"]
|
||||
path = muvm
|
||||
url = https://github.com/valpackett/muvm
|
||||
[submodule "libkrun"]
|
||||
path = libkrun
|
||||
url = https://github.com/valpackett/libkrun
|
||||
18
LICENSE.md
Normal file
18
LICENSE.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
Copyright 2025 Invisible Things Lab, Clan contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
24
README.md
Normal file
24
README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# munix
|
||||
|
||||
WIP: A microVM runner for NixOS systems with desktop integration, powered by muvm/libkrun.
|
||||
|
||||
## Development
|
||||
|
||||
Building an example closure:
|
||||
|
||||
```
|
||||
nix build '.#nixosConfigurations.x86_64-linux.testvm.config.system.build.toplevel'
|
||||
```
|
||||
|
||||
Running the nix build:
|
||||
|
||||
```
|
||||
nix run '.#packages.x86_64-linux.munix' $(readlink result)
|
||||
```
|
||||
|
||||
Working on muvm & munix locally (not built into the nix store):
|
||||
|
||||
```
|
||||
cd muvm && cargo build --locked --release
|
||||
PATH=$PWD/muvm/target/release:$PATH ./munix $(readlink result)
|
||||
```
|
||||
123
flake.lock
generated
Normal file
123
flake.lock
generated
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1758078198,
|
||||
"narHash": "sha256-60ojlXp42UZYTOAgsiKPZUab1Aa8pXTIo+rz0zoaynI=",
|
||||
"ref": "val/tsvwswkqrrsr",
|
||||
"rev": "1f0fc70eb049852a18a5203af2204bd9f5729f29",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/nixpkgs"
|
||||
},
|
||||
"original": {
|
||||
"ref": "val/tsvwswkqrrsr",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/nixpkgs"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"virtwl": "virtwl"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"virtwl": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758075582,
|
||||
"narHash": "sha256-o2lpXQLaM9QcZVr+sAxvh83CqJW1QkFhfja6K40ndmA=",
|
||||
"ref": "wip",
|
||||
"rev": "5a5df73a11b2f6bf671a8fc89926ac993e0fbb78",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/wayland-proxy-virtwl"
|
||||
},
|
||||
"original": {
|
||||
"ref": "wip",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/wayland-proxy-virtwl"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
167
flake.nix
Normal file
167
flake.nix
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
{
|
||||
inputs = {
|
||||
self.submodules = true;
|
||||
# nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
# https://github.com/NixOS/nixpkgs/pull/444133
|
||||
nixpkgs.url = "git+https://github.com/valpackett/nixpkgs?shallow=1&submodules=1&ref=val/tsvwswkqrrsr";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip";
|
||||
virtwl.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = {self, nixpkgs, flake-utils, virtwl, ...}:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
in {
|
||||
|
||||
packages.libkrunfw = pkgs.libkrunfw;
|
||||
# packages.libkrunfw = (pkgs.libkrunfw.overrideAttrs {
|
||||
# version = "4.10.0";
|
||||
# src = pkgs.fetchFromGitHub {
|
||||
# owner = "containers";
|
||||
# repo = "libkrunfw";
|
||||
# tag = "v4.10.0";
|
||||
# hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk=";
|
||||
# };
|
||||
# kernelSrc = pkgs.fetchurl {
|
||||
# url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.34.tar.xz";
|
||||
# hash = "sha256-p/P+OB9n7KQXLptj77YaFL1/nhJ44DYD0P9ak/Jwwk0=";
|
||||
# };
|
||||
# cargoHash = "";
|
||||
# });
|
||||
|
||||
packages.libkrun = (pkgs.libkrun.override {
|
||||
withBlk = true;
|
||||
withGpu = true;
|
||||
withSound = true;
|
||||
withNet = true;
|
||||
libkrunfw = self.packages.${system}.libkrunfw;
|
||||
}).overrideAttrs (old: {
|
||||
src = ./libkrun;
|
||||
cargoDeps = pkgs.rustPlatform.importCargoLock {
|
||||
lockFile = ./libkrun/Cargo.lock;
|
||||
};
|
||||
# mesonFlags = [ (pkgs.lib.mesonOption "decoders" "gles,vulkan,composer") ]; # no magma(?)
|
||||
});
|
||||
|
||||
packages.muvm = (pkgs.muvm.override {
|
||||
libkrun = self.packages.${system}.libkrun;
|
||||
}).overrideAttrs (old: {
|
||||
postPatch = ""; # no more sysctl; udevd now takes the var anyway; XXX: fex
|
||||
MUVM_UDEVD_PATH = "${pkgs.systemd}/lib/systemd/systemd-udevd";
|
||||
src = ./muvm;
|
||||
cargoDeps = pkgs.rustPlatform.importCargoLock {
|
||||
lockFile = ./muvm/Cargo.lock;
|
||||
};
|
||||
});
|
||||
|
||||
packages.munix = let
|
||||
munixScript = (pkgs.writeScriptBin "munix" (builtins.readFile ./munix)).overrideAttrs(old: {
|
||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
||||
});
|
||||
munixInitRootHook = (pkgs.writeScriptBin "munix-init-root" (builtins.readFile ./munix-init-root)).overrideAttrs(old: {
|
||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
||||
});
|
||||
munixInitUserHook = (pkgs.writeScriptBin "munix-init-user" (builtins.readFile ./munix-init-user)).overrideAttrs(old: {
|
||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
||||
});
|
||||
in pkgs.symlinkJoin {
|
||||
name = "munix";
|
||||
paths = [ munixScript munixInitRootHook munixInitUserHook self.packages.${system}.muvm pkgs.passt pkgs.bubblewrap ];
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/munix --prefix PATH : $out/bin
|
||||
'';
|
||||
};
|
||||
|
||||
devShells.default = let
|
||||
projects = with self.packages.${system}; [ libkrun muvm ];
|
||||
in pkgs.mkShell {
|
||||
MUVM_UDEVD_PATH = "${pkgs.systemd}/lib/systemd/systemd-udevd";
|
||||
nativeBuildInputs = pkgs.lib.concatMap (pkg: pkg.nativeBuildInputs) projects;
|
||||
buildInputs = (pkgs.lib.concatMap (pkg: pkg.buildInputs) projects) ++ (with self.packages.${system}; [
|
||||
# virglrenderer
|
||||
]) ++ (with pkgs; [
|
||||
cargo
|
||||
rust-analyzer
|
||||
rustfmt
|
||||
passt
|
||||
bubblewrap
|
||||
]);
|
||||
};
|
||||
|
||||
packages.mesa = (pkgs.mesa.override {
|
||||
vulkanDrivers = [
|
||||
"amd"
|
||||
"intel"
|
||||
"microsoft-experimental" # removing this breaks the build
|
||||
"nouveau"
|
||||
"swrast"
|
||||
"virtio"
|
||||
"gfxstream" # probably not going to use this though
|
||||
];
|
||||
}).overrideAttrs (new: old: {
|
||||
mesonFlags = old.mesonFlags ++ [ (pkgs.lib.mesonBool "amdgpu-virtio" true) ];
|
||||
patches = old.patches ++ [ ./radvmmio.patch ]; # already merged to git
|
||||
});
|
||||
|
||||
nixosConfigurations.testvm = nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
modules = [
|
||||
{
|
||||
system.stateVersion = "25.11";
|
||||
fileSystems."/".device = pkgs.lib.mkDefault "/dev/sda";
|
||||
boot.isContainer = true;
|
||||
|
||||
users.mutableUsers = false;
|
||||
users.users.appvm = {
|
||||
uid = 1001;
|
||||
isNormalUser = true;
|
||||
home = "/home/appvm";
|
||||
description = "microVM User";
|
||||
extraGroups = [ "wheel" "video" "input" ];
|
||||
};
|
||||
users.groups.appvm.gid = 1001;
|
||||
users.allowNoPasswordLogin = true;
|
||||
|
||||
hardware.graphics.enable = true;
|
||||
hardware.graphics.package = self.packages.${system}.mesa;
|
||||
system.replaceDependencies.replacements = [
|
||||
{
|
||||
original = pkgs.mesa;
|
||||
replacement = self.packages.${system}.mesa;
|
||||
}
|
||||
];
|
||||
environment.systemPackages = [
|
||||
pkgs.fastfetch
|
||||
pkgs.htop
|
||||
pkgs.radeontop
|
||||
virtwl.packages.x86_64-linux.proxy
|
||||
pkgs.wayland-utils
|
||||
pkgs.weston
|
||||
pkgs.waycheck
|
||||
pkgs.vulkan-tools
|
||||
pkgs.glxinfo
|
||||
pkgs.glmark2
|
||||
pkgs.mesa-demos
|
||||
pkgs.xorg.xeyes
|
||||
pkgs.xterm
|
||||
pkgs.vkquake
|
||||
pkgs.kdePackages.kate
|
||||
pkgs.adwaita-fonts
|
||||
pkgs.adwaita-icon-theme
|
||||
pkgs.gnome-text-editor
|
||||
pkgs.firefox
|
||||
pkgs.ffmpeg-full
|
||||
pkgs.mpv
|
||||
pkgs.libva-utils
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
1
libkrun
Submodule
1
libkrun
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit bd97a39bfaa46147933beca7e16513b6820bb031
|
||||
35
munix
Executable file
35
munix
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
: "${MICROVM_SHELL:=bash}"
|
||||
SCRIPT_PATH=$(dirname $(realpath -s $0))
|
||||
MUVM_PATH=$(dirname $(which muvm))
|
||||
PASST_PATH=$(dirname $(which passt))
|
||||
export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C
|
||||
unset DISPLAY XAUTHORITY # or: --bind /tmp/.X11-unix /tmp/.X11-unix --bind $XAUTHORITY $XAUTHORITY
|
||||
exec bwrap --unshare-all --share-net \
|
||||
--uid 1001 --gid 1001 \
|
||||
--tmpfs / \
|
||||
--dir /run --dir /var --symlink /run /var/run --dir /tmp \
|
||||
--proc /proc --ro-bind /sys /sys \
|
||||
--dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm --dev-bind /dev/dri /dev/dri \
|
||||
--ro-bind "$MUVM_PATH" /run/munix/muvm \
|
||||
--ro-bind "$PASST_PATH" /run/munix/passt \
|
||||
--ro-bind "$1/sw/bin/env" /usr/bin/env \
|
||||
--ro-bind "$SCRIPT_PATH/munix-init-root" /usr/bin/munix-init-root \
|
||||
--ro-bind "$SCRIPT_PATH/munix-init-user" /usr/bin/munix-init-user \
|
||||
--ro-bind /nix/store /nix/store \
|
||||
--ro-bind /run/opengl-driver /run/opengl-driver \
|
||||
--ro-bind /run/systemd/resolve /run/systemd/resolve \
|
||||
--ro-bind /etc/resolv.conf /etc/resolv.conf \
|
||||
--ro-bind /etc/group /etc/group \
|
||||
--ro-bind /etc/passwd /etc/passwd \
|
||||
--dir "$XDG_RUNTIME_DIR" \
|
||||
--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" \
|
||||
--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0" \
|
||||
--bind $HOME/Downloads/baseq1 $HOME/Downloads/baseq1 \
|
||||
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
|
||||
--setenv PATH "/run/munix/muvm:/run/munix/passt:$1/sw/bin" \
|
||||
muvm \
|
||||
-x /usr/bin/munix-init-root -X /usr/bin/munix-init-user --udevd-path="$1/sw/bin/true" \
|
||||
-e WAYLAND_DISPLAY=wayland-1 \
|
||||
-e MICROVM_CLOSURE="$1" \
|
||||
-i -t "$1/sw/bin/$MICROVM_SHELL"
|
||||
27
munix-init-root
Executable file
27
munix-init-root
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
unset LANGUAGE LC_ALL LC_CTYPE LC_NUMERIC LC_COLLATE LC_TIME LC_MESSAGES LC_MONETARY LC_ADDRESS LC_IDENTIFICATION LC_MEASUREMENT LC_PAPER LC_TELEPHONE LC_NAME LANG 2>/dev/null # perl, calm down
|
||||
PATH=$MICROVM_CLOSURE/sw/bin
|
||||
|
||||
echo "=> Initializing microVM environment"
|
||||
|
||||
mkdir /run/log
|
||||
|
||||
# Prepare mounts for paths that activation writes to
|
||||
mount -t tmpfs tmpfs /etc
|
||||
cp /run/muvm-host/etc/resolv.conf /etc/resolv.conf
|
||||
mount -t tmpfs tmpfs /usr/bin
|
||||
cp /run/muvm-host/usr/bin/munix-init-user /usr/bin/munix-init-user
|
||||
mount -t tmpfs tmpfs /dev/shm # tries to remount, fails on virtiofs due to unexpected opts
|
||||
|
||||
$MICROVM_CLOSURE/activate >/run/log/activate.spam 2>&1
|
||||
|
||||
umount /dev/shm # restore the original virtiofs dax shm though
|
||||
|
||||
chown 1001:1001 /run /dev # avoid "Detected unsafe path transition"
|
||||
systemd-tmpfiles --create >/run/log/tmpfiles.spam 2>&1
|
||||
|
||||
systemd-machine-id-setup >/dev/null 2>&1
|
||||
|
||||
$MICROVM_CLOSURE/sw/lib/systemd/systemd-udevd >/run/log/udevd.spam 2>&1 &
|
||||
|
||||
echo "=> microVM environment ready!"
|
||||
4
munix-init-user
Executable file
4
munix-init-user
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
PATH=$MICROVM_CLOSURE/sw/bin
|
||||
mkdir -p ~/.var/log
|
||||
wayland-proxy-virtwl --virtio-gpu >~/.var/log/wayland-proxy.log 2>&1 &
|
||||
1
muvm
Submodule
1
muvm
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 70badbc44d421c49f82130321e35b949f8b4ed14
|
||||
42
radvmmio.patch
Normal file
42
radvmmio.patch
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
From c2fd030644cf2074f9d2ffd155839b2e943473d0 Mon Sep 17 00:00:00 2001
|
||||
From: Val Packett <val@packett.cool>
|
||||
Date: Wed, 10 Sep 2025 15:44:41 -0300
|
||||
Subject: [PATCH] radv: detect platform:virtio-mmio devices for virtgpu native
|
||||
context
|
||||
|
||||
VirtIO devices can be configured as platform devices instead of PCI,
|
||||
which is especially common in microVM projects like libkrun.
|
||||
|
||||
Let's allow RADV to probe MMIO virtgpu devices.
|
||||
|
||||
Signed-off-by: Val Packett <val@invisiblethingslab.com>
|
||||
---
|
||||
src/amd/vulkan/radv_physical_device.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/amd/vulkan/radv_physical_device.c b/src/amd/vulkan/radv_physical_device.c
|
||||
index 07b5b000b3ae..cd6f4c3488a1 100644
|
||||
--- a/src/amd/vulkan/radv_physical_device.c
|
||||
+++ b/src/amd/vulkan/radv_physical_device.c
|
||||
@@ -2507,14 +2507,15 @@ create_drm_physical_device(struct vk_instance *vk_instance, struct _drmDevice *d
|
||||
#ifndef _WIN32
|
||||
bool supported_device = false;
|
||||
|
||||
- if (!(device->available_nodes & (1 << DRM_NODE_RENDER)) || device->bustype != DRM_BUS_PCI)
|
||||
+ if (!(device->available_nodes & (1 << DRM_NODE_RENDER)))
|
||||
return VK_ERROR_INCOMPATIBLE_DRIVER;
|
||||
|
||||
#ifdef HAVE_AMDGPU_VIRTIO
|
||||
- supported_device |= device->deviceinfo.pci->vendor_id == VIRTGPU_PCI_VENDOR_ID;
|
||||
+ supported_device |= device->bustype == DRM_BUS_PCI && device->deviceinfo.pci->vendor_id == VIRTGPU_PCI_VENDOR_ID;
|
||||
+ supported_device |= device->bustype == DRM_BUS_PLATFORM; /* virtio-mmio */
|
||||
#endif
|
||||
|
||||
- supported_device |= device->deviceinfo.pci->vendor_id == ATI_VENDOR_ID;
|
||||
+ supported_device |= device->bustype == DRM_BUS_PCI && device->deviceinfo.pci->vendor_id == ATI_VENDOR_ID;
|
||||
|
||||
if (!supported_device)
|
||||
return VK_ERROR_INCOMPATIBLE_DRIVER;
|
||||
--
|
||||
2.50.1
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue