├── .github └── workflows │ ├── publish.yml │ └── tests.yml ├── Formula ├── libangle.rb ├── libepoxy-angle.rb ├── qemu-virgl.rb └── virglrenderer.rb ├── Patches ├── libepoxy-v01.diff ├── libepoxy-v02.diff ├── qemu-edid-v01.diff ├── qemu-hexagon-v01.diff ├── qemu-hexagon-v02.diff ├── qemu-libusb-v01.diff ├── qemu-v01.diff ├── qemu-v02.diff ├── qemu-v03.diff ├── qemu-v04.diff ├── qemu-v05.diff ├── qemu-version-v01.diff ├── virglrenderer-v01.diff ├── virglrenderer-v02.diff ├── virglrenderer-v03.diff └── virglrenderer-v04.diff └── README.md /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: brew pr-pull 2 | on: 3 | pull_request_target: 4 | types: 5 | - labeled 6 | jobs: 7 | pr-pull: 8 | if: contains(github.event.pull_request.labels.*.name, 'pr-pull') 9 | runs-on: macos-11 10 | steps: 11 | - name: Set up Homebrew 12 | uses: Homebrew/actions/setup-homebrew@master 13 | 14 | - name: Set up git 15 | uses: Homebrew/actions/git-user-config@master 16 | 17 | - name: Pull bottles 18 | env: 19 | HOMEBREW_GITHUB_API_TOKEN: ${{ github.token }} 20 | PULL_REQUEST: ${{ github.event.pull_request.number }} 21 | run: brew pr-pull --debug --tap=$GITHUB_REPOSITORY $PULL_REQUEST 22 | 23 | - name: Push commits 24 | uses: Homebrew/actions/git-try-push@master 25 | with: 26 | token: ${{ github.token }} 27 | branch: master 28 | 29 | - name: Delete branch 30 | if: github.event.pull_request.head.repo.fork == false 31 | env: 32 | BRANCH: ${{ github.event.pull_request.head.ref }} 33 | run: git push --delete origin $BRANCH 34 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: brew test-bot 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | jobs: 8 | test-bot: 9 | strategy: 10 | matrix: 11 | os: [macos-11] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Set up Homebrew 15 | id: set-up-homebrew 16 | uses: Homebrew/actions/setup-homebrew@master 17 | 18 | - name: Cache Homebrew Bundler RubyGems 19 | id: cache 20 | uses: actions/cache@v1 21 | with: 22 | path: ${{ steps.set-up-homebrew.outputs.gems-path }} 23 | key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} 24 | restore-keys: ${{ runner.os }}-rubygems- 25 | 26 | - name: Install Homebrew Bundler RubyGems 27 | if: steps.cache.outputs.cache-hit != 'true' 28 | run: brew install-bundler-gems 29 | 30 | - run: brew test-bot --only-cleanup-before 31 | 32 | - run: brew test-bot --only-setup 33 | 34 | - run: brew test-bot --only-tap-syntax 35 | 36 | - run: brew test-bot --only-formulae 37 | if: github.event_name == 'pull_request' 38 | 39 | - name: Upload bottles as artifact 40 | if: always() && github.event_name == 'pull_request' 41 | uses: actions/upload-artifact@main 42 | with: 43 | name: bottles 44 | path: '*.bottle.*' 45 | -------------------------------------------------------------------------------- /Formula/libangle.rb: -------------------------------------------------------------------------------- 1 | class Libangle < Formula 2 | desc "Conformant OpenGL ES implementation for Windows, Mac, Linux, iOS and Android" 3 | homepage "https://github.com/google/angle" 4 | url "https://github.com/google/angle.git", using: :git, revision: "df0f7133799ca6aa0d31802b22d919c6197051cf" 5 | version "20211212.1" 6 | license "BSD-3-Clause" 7 | 8 | bottle do 9 | root_url "https://github.com/knazarov/homebrew-qemu-virgl/releases/download/libangle-20211212.1" 10 | sha256 cellar: :any, arm64_big_sur: "6e776fc996fa02df211ee7e79512d4996558447bde65a63d2c7578ed1f63f660" 11 | sha256 cellar: :any, big_sur: "1c201f77bb6d877f2404ec761e47e13b97a3d61dff7ddfc484caa3deae4e5c1b" 12 | end 13 | 14 | depends_on "meson" => :build 15 | depends_on "ninja" => :build 16 | 17 | resource "depot_tools" do 18 | url "https://chromium.googlesource.com/chromium/tools/depot_tools.git", revision: "dc86a4b9044f9243886ca0da0c1753820ac51f45" 19 | end 20 | 21 | def install 22 | mkdir "build" do 23 | resource("depot_tools").stage do 24 | path = PATH.new(ENV["PATH"], Dir.pwd) 25 | with_env(PATH: path) do 26 | Dir.chdir(buildpath) 27 | 28 | system "python2", "scripts/bootstrap.py" 29 | system "gclient", "sync" 30 | if Hardware::CPU.arm? 31 | system "gn", "gen", \ 32 | "--args=use_custom_libcxx=false target_cpu=\"arm64\" treat_warnings_as_errors=false", \ 33 | "./angle_build" 34 | else 35 | system "gn", "gen", "--args=use_custom_libcxx=false treat_warnings_as_errors=false", "./angle_build" 36 | end 37 | system "ninja", "-C", "angle_build" 38 | lib.install "angle_build/libabsl.dylib" 39 | lib.install "angle_build/libEGL.dylib" 40 | lib.install "angle_build/libGLESv2.dylib" 41 | lib.install "angle_build/libchrome_zlib.dylib" 42 | include.install Pathname.glob("include/*") 43 | end 44 | end 45 | end 46 | end 47 | 48 | test do 49 | # `test do` will create, run in and delete a temporary directory. 50 | # 51 | # This test will fail and we won't accept that! For Homebrew/homebrew-core 52 | # this will need to be a test that verifies the functionality of the 53 | # software. Run the test with `brew test libangle`. Options passed 54 | # to `brew install` such as `--HEAD` also need to be provided to `brew test`. 55 | # 56 | # The installed folder is not in the path, so use the entire path to any 57 | # executables being tested: `system "#{bin}/program", "do", "something"`. 58 | system "true" 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /Formula/libepoxy-angle.rb: -------------------------------------------------------------------------------- 1 | class LibepoxyAngle < Formula 2 | desc "Library for handling OpenGL function pointer management" 3 | homepage "https://github.com/anholt/libepoxy" 4 | url "https://github.com/anholt/libepoxy.git", using: :git, revision: "de08cf3479ca06ff921c584eeee6280e5a135f99" 5 | version "20210315.1" 6 | license "MIT" 7 | 8 | depends_on "meson" => :build 9 | depends_on "ninja" => :build 10 | depends_on "pkg-config" => :build 11 | depends_on "python@3.9" => :build 12 | depends_on "knazarov/qemu-virgl/libangle" 13 | 14 | # waiting for upstreaming of https://github.com/akihikodaki/libepoxy/tree/macos 15 | patch :p1 do 16 | url "https://raw.githubusercontent.com/knazarov/homebrew-qemu-virgl/8bab5791b5af446204dea93d36943e00329032bf/Patches/libepoxy-v02.diff" 17 | sha256 "8ce3a33be6ccab5482e77261d0ca98d0a6aeff9d6dfc32b0e75cd323f87dccee" 18 | end 19 | 20 | def install 21 | mkdir "build" do 22 | system "meson", *std_meson_args, "-Dc_args=-I#{Formula["libangle"].opt_prefix}/include", 23 | "-Dc_link_args=-L#{Formula["libangle"].opt_prefix}/lib", "-Degl=yes", "-Dx11=false", 24 | "-Dfallback-libdir=#{HOMEBREW_PREFIX}/lib", ".." 25 | system "ninja", "-v" 26 | system "ninja", "install", "-v" 27 | end 28 | end 29 | 30 | test do 31 | (testpath/"test.c").write <<~EOS 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | int main() 38 | { 39 | CGLPixelFormatAttribute attribs[] = {0}; 40 | CGLPixelFormatObj pix; 41 | int npix; 42 | CGLContextObj ctx; 43 | 44 | CGLChoosePixelFormat( attribs, &pix, &npix ); 45 | CGLCreateContext(pix, (void*)0, &ctx); 46 | 47 | glClear(GL_COLOR_BUFFER_BIT); 48 | CGLReleasePixelFormat(pix); 49 | CGLReleaseContext(pix); 50 | return 0; 51 | } 52 | EOS 53 | system ENV.cc, "test.c", "-L#{lib}", "-lepoxy", "-framework", "OpenGL", "-o", "test" 54 | system "ls", "-lh", "test" 55 | system "file", "test" 56 | system "./test" 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /Formula/qemu-virgl.rb: -------------------------------------------------------------------------------- 1 | class QemuVirgl < Formula 2 | desc "Emulator for x86 and PowerPC" 3 | homepage "https://www.qemu.org/" 4 | url "https://github.com/qemu/qemu.git", using: :git, revision: "99fc08366b06282614daeda989d2fde6ab8a707f" 5 | version "20211212.1" 6 | license "GPL-2.0-only" 7 | 8 | depends_on "libtool" => :build 9 | depends_on "meson" => :build 10 | depends_on "ninja" => :build 11 | depends_on "pkg-config" => :build 12 | 13 | depends_on "glib" 14 | depends_on "gnutls" 15 | depends_on "jpeg" 16 | depends_on "knazarov/qemu-virgl/libangle" 17 | depends_on "knazarov/qemu-virgl/libepoxy-angle" 18 | depends_on "knazarov/qemu-virgl/virglrenderer" 19 | depends_on "libpng" 20 | depends_on "libssh" 21 | depends_on "libusb" 22 | depends_on "lzo" 23 | depends_on "ncurses" 24 | depends_on "nettle" 25 | depends_on "pixman" 26 | depends_on "snappy" 27 | depends_on "spice-protocol" 28 | depends_on "vde" 29 | 30 | # 820KB floppy disk image file of FreeDOS 1.2, used to test QEMU 31 | resource "test-image" do 32 | url "https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/1.2/FD12FLOPPY.zip" 33 | sha256 "81237c7b42dc0ffc8b32a2f5734e3480a3f9a470c50c14a9c4576a2561a35807" 34 | end 35 | 36 | # waiting for upstreaming of https://github.com/akihikodaki/qemu/tree/macos 37 | patch :p1 do 38 | url "https://raw.githubusercontent.com/knazarov/homebrew-qemu-virgl/87072b7ccc07f5087bf0848fa8920f8b3f8d5a47/Patches/qemu-v05.diff" 39 | sha256 "6d27699ba454b5ecb7411822a745b89dce3dea5fccabfb56c84ad698f3222dd4" 40 | end 41 | 42 | def install 43 | ENV["LIBTOOL"] = "glibtool" 44 | 45 | args = %W[ 46 | --prefix=#{prefix} 47 | --cc=#{ENV.cc} 48 | --host-cc=#{ENV.cc} 49 | --disable-bsd-user 50 | --disable-guest-agent 51 | --enable-curses 52 | --enable-libssh 53 | --enable-vde 54 | --extra-cflags=-DNCURSES_WIDECHAR=1 55 | --extra-cflags=-I#{Formula["libangle"].opt_prefix}/include 56 | --extra-cflags=-I#{Formula["libepoxy-angle"].opt_prefix}/include 57 | --extra-cflags=-I#{Formula["virglrenderer"].opt_prefix}/include 58 | --extra-cflags=-I#{Formula["spice-protocol"].opt_prefix}/include/spice-1 59 | --extra-ldflags=-L#{Formula["libangle"].opt_prefix}/lib 60 | --extra-ldflags=-L#{Formula["libepoxy-angle"].opt_prefix}/lib 61 | --extra-ldflags=-L#{Formula["virglrenderer"].opt_prefix}/lib 62 | --extra-ldflags=-L#{Formula["spice-protocol"].opt_prefix}/lib 63 | --disable-sdl 64 | --disable-gtk 65 | ] 66 | # Sharing Samba directories in QEMU requires the samba.org smbd which is 67 | # incompatible with the macOS-provided version. This will lead to 68 | # silent runtime failures, so we set it to a Homebrew path in order to 69 | # obtain sensible runtime errors. This will also be compatible with 70 | # Samba installations from external taps. 71 | args << "--smbd=#{HOMEBREW_PREFIX}/sbin/samba-dot-org-smbd" 72 | 73 | args << "--enable-cocoa" if OS.mac? 74 | 75 | system "./configure", *args 76 | system "make", "V=1", "install" 77 | end 78 | 79 | test do 80 | expected = "QEMU Project" 81 | assert_match expected, shell_output("#{bin}/qemu-system-aarch64 --version") 82 | assert_match expected, shell_output("#{bin}/qemu-system-alpha --version") 83 | assert_match expected, shell_output("#{bin}/qemu-system-arm --version") 84 | assert_match expected, shell_output("#{bin}/qemu-system-cris --version") 85 | assert_match expected, shell_output("#{bin}/qemu-system-hppa --version") 86 | assert_match expected, shell_output("#{bin}/qemu-system-i386 --version") 87 | assert_match expected, shell_output("#{bin}/qemu-system-m68k --version") 88 | assert_match expected, shell_output("#{bin}/qemu-system-microblaze --version") 89 | assert_match expected, shell_output("#{bin}/qemu-system-microblazeel --version") 90 | assert_match expected, shell_output("#{bin}/qemu-system-mips --version") 91 | assert_match expected, shell_output("#{bin}/qemu-system-mips64 --version") 92 | assert_match expected, shell_output("#{bin}/qemu-system-mips64el --version") 93 | assert_match expected, shell_output("#{bin}/qemu-system-mipsel --version") 94 | assert_match expected, shell_output("#{bin}/qemu-system-nios2 --version") 95 | assert_match expected, shell_output("#{bin}/qemu-system-or1k --version") 96 | assert_match expected, shell_output("#{bin}/qemu-system-ppc --version") 97 | assert_match expected, shell_output("#{bin}/qemu-system-ppc64 --version") 98 | assert_match expected, shell_output("#{bin}/qemu-system-riscv32 --version") 99 | assert_match expected, shell_output("#{bin}/qemu-system-riscv64 --version") 100 | assert_match expected, shell_output("#{bin}/qemu-system-rx --version") 101 | assert_match expected, shell_output("#{bin}/qemu-system-s390x --version") 102 | assert_match expected, shell_output("#{bin}/qemu-system-sh4 --version") 103 | assert_match expected, shell_output("#{bin}/qemu-system-sh4eb --version") 104 | assert_match expected, shell_output("#{bin}/qemu-system-sparc --version") 105 | assert_match expected, shell_output("#{bin}/qemu-system-sparc64 --version") 106 | assert_match expected, shell_output("#{bin}/qemu-system-tricore --version") 107 | assert_match expected, shell_output("#{bin}/qemu-system-x86_64 --version") 108 | assert_match expected, shell_output("#{bin}/qemu-system-xtensa --version") 109 | assert_match expected, shell_output("#{bin}/qemu-system-xtensaeb --version") 110 | resource("test-image").stage testpath 111 | assert_match "file format: raw", shell_output("#{bin}/qemu-img info FLOPPY.img") 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /Formula/virglrenderer.rb: -------------------------------------------------------------------------------- 1 | class Virglrenderer < Formula 2 | desc "VirGL virtual OpenGL renderer" 3 | homepage "https://gitlab.freedesktop.org/virgl/virglrenderer" 4 | url "https://gitlab.freedesktop.org/virgl/virglrenderer.git", revision: "453017e32ace65fa2f9c908bd5a9721f65fbf2a2" 5 | version "20211212.1" 6 | license "MIT" 7 | 8 | depends_on "meson" => :build 9 | depends_on "ninja" => :build 10 | depends_on "pkg-config" => :build 11 | depends_on "knazarov/qemu-virgl/libangle" 12 | depends_on "knazarov/qemu-virgl/libepoxy-angle" 13 | 14 | # waiting for upstreaming of https://github.com/akihikodaki/virglrenderer/tree/macos 15 | patch :p1 do 16 | url "https://raw.githubusercontent.com/knazarov/homebrew-qemu-virgl/d8e807a58717d551ecb73a6e721e49559cec1a3d/Patches/virglrenderer-v04.diff" 17 | sha256 "cb9e2ea4d73cd99375bd9fc9a008f4d7e53249a6259d63ff8f367a08c4fd8b9c" 18 | end 19 | 20 | def install 21 | mkdir "build" do 22 | system "meson", *std_meson_args, "-Dc_args=-I#{Formula["libepoxy-angle"].opt_prefix}/include", 23 | "-Dc_link_args=-L#{Formula["libepoxy-angle"].opt_prefix}/lib", ".." 24 | system "ninja", "-v" 25 | system "ninja", "install", "-v" 26 | end 27 | end 28 | 29 | test do 30 | system "true" 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /Patches/libepoxy-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index ca37e80..5fd7144 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -165,6 +165,9 @@ endif 6 | dl_dep = cc.find_library('dl', required: false) 7 | gl_dep = dependency('gl', required: false) 8 | egl_dep = dependency('egl', required: false) 9 | +if not egl_dep.found() 10 | + egl_dep = cc.find_library('EGL', required: false) 11 | +endif 12 | 13 | # Optional dependencies for tests 14 | x11_dep = dependency('x11', required: false) 15 | @@ -174,12 +177,12 @@ x11_dep = dependency('x11', required: false) 16 | # if we fail 17 | gles2_dep = dependency('glesv2', required: false) 18 | if not gles2_dep.found() 19 | - gles2_dep = cc.find_library('libGLESv2', required: false) 20 | + gles2_dep = cc.find_library('GLESv2', required: false) 21 | endif 22 | 23 | gles1_dep = dependency('glesv1_cm', required: false) 24 | if not gles1_dep.found() 25 | - gles1_dep = cc.find_library('libGLESv1_CM', required: false) 26 | + gles1_dep = cc.find_library('GLESv1_CM', required: false) 27 | endif 28 | 29 | # On windows, the DLL has to have all of its functions 30 | diff --git a/src/dispatch_common.c b/src/dispatch_common.c 31 | index 62b7134..b82938a 100644 32 | --- a/src/dispatch_common.c 33 | +++ b/src/dispatch_common.c 34 | @@ -175,9 +175,10 @@ 35 | 36 | #if defined(__APPLE__) 37 | #define GLX_LIB "/opt/X11/lib/libGL.1.dylib" 38 | +#define EGL_LIB "libEGL.dylib" 39 | #define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" 40 | -#define GLES1_LIB "libGLESv1_CM.so" 41 | -#define GLES2_LIB "libGLESv2.so" 42 | +#define GLES1_LIB "libGLESv1_CM.dylib" 43 | +#define GLES2_LIB "libGLESv2.dylib" 44 | #elif defined(__ANDROID__) 45 | #define GLX_LIB "libGLESv2.so" 46 | #define EGL_LIB "libEGL.so" 47 | diff --git a/src/dispatch_common.h b/src/dispatch_common.h 48 | index a136943..55388a8 100644 49 | --- a/src/dispatch_common.h 50 | +++ b/src/dispatch_common.h 51 | @@ -28,7 +28,7 @@ 52 | #define PLATFORM_HAS_GLX ENABLE_GLX 53 | #define PLATFORM_HAS_WGL 1 54 | #elif defined(__APPLE__) 55 | -#define PLATFORM_HAS_EGL 0 56 | +#define PLATFORM_HAS_EGL ENABLE_EGL 57 | #define PLATFORM_HAS_GLX ENABLE_GLX 58 | #define PLATFORM_HAS_WGL 0 59 | #elif defined(ANDROID) 60 | -------------------------------------------------------------------------------- /Patches/libepoxy-v02.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index ca37e80..fd9b578 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -48,6 +48,12 @@ else 6 | build_egl = enable_egl == 'yes' 7 | endif 8 | 9 | +fallback_libdir = get_option('fallback-libdir') 10 | + 11 | +if fallback_libdir != '' 12 | + conf.set_quoted('FALLBACK_LIBDIR', fallback_libdir) 13 | +endif 14 | + 15 | enable_x11 = get_option('x11') 16 | if not enable_x11 17 | if enable_glx == 'yes' 18 | @@ -165,6 +171,9 @@ endif 19 | dl_dep = cc.find_library('dl', required: false) 20 | gl_dep = dependency('gl', required: false) 21 | egl_dep = dependency('egl', required: false) 22 | +if not egl_dep.found() 23 | + egl_dep = cc.find_library('EGL', required: false) 24 | +endif 25 | 26 | # Optional dependencies for tests 27 | x11_dep = dependency('x11', required: false) 28 | @@ -174,12 +183,12 @@ x11_dep = dependency('x11', required: false) 29 | # if we fail 30 | gles2_dep = dependency('glesv2', required: false) 31 | if not gles2_dep.found() 32 | - gles2_dep = cc.find_library('libGLESv2', required: false) 33 | + gles2_dep = cc.find_library('GLESv2', required: false) 34 | endif 35 | 36 | gles1_dep = dependency('glesv1_cm', required: false) 37 | if not gles1_dep.found() 38 | - gles1_dep = cc.find_library('libGLESv1_CM', required: false) 39 | + gles1_dep = cc.find_library('GLESv1_CM', required: false) 40 | endif 41 | 42 | # On windows, the DLL has to have all of its functions 43 | diff --git a/meson_options.txt b/meson_options.txt 44 | index dc30e68..0723577 100644 45 | --- a/meson_options.txt 46 | +++ b/meson_options.txt 47 | @@ -11,6 +11,10 @@ option('egl', 48 | choices: [ 'auto', 'yes', 'no' ], 49 | value: 'auto', 50 | description: 'Enable EGL support') 51 | +option('fallback-libdir', 52 | + type: 'string', 53 | + value: '', 54 | + description: 'Fallback path to search EGL in if the default fails') 55 | option('x11', 56 | type: 'boolean', 57 | value: true, 58 | diff --git a/src/dispatch_common.c b/src/dispatch_common.c 59 | index 62b7134..dee52b5 100644 60 | --- a/src/dispatch_common.c 61 | +++ b/src/dispatch_common.c 62 | @@ -175,9 +175,10 @@ 63 | 64 | #if defined(__APPLE__) 65 | #define GLX_LIB "/opt/X11/lib/libGL.1.dylib" 66 | +#define EGL_LIB "libEGL.dylib" 67 | #define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" 68 | -#define GLES1_LIB "libGLESv1_CM.so" 69 | -#define GLES2_LIB "libGLESv2.so" 70 | +#define GLES1_LIB "libGLESv1_CM.dylib" 71 | +#define GLES2_LIB "libGLESv2.dylib" 72 | #elif defined(__ANDROID__) 73 | #define GLX_LIB "libGLESv2.so" 74 | #define EGL_LIB "libEGL.so" 75 | @@ -310,6 +311,8 @@ get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool l 76 | flags |= RTLD_NOLOAD; 77 | 78 | *handle = dlopen(lib_name, flags); 79 | + 80 | +#ifndef FALLBACK_LIBDIR 81 | if (!*handle) { 82 | if (exit_on_fail) { 83 | fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror()); 84 | @@ -318,6 +321,28 @@ get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool l 85 | (void)dlerror(); 86 | } 87 | } 88 | +#else 89 | + if (!*handle) { 90 | + char *first_dlerror = strdup(dlerror()); 91 | + char *fullpath = malloc(strlen(FALLBACK_LIBDIR) + strlen(lib_name) + 2); 92 | + sprintf(fullpath, "%s/%s", FALLBACK_LIBDIR, lib_name); 93 | + 94 | + *handle = dlopen(fullpath, flags); 95 | + 96 | + if (!*handle) { 97 | + if (exit_on_fail) { 98 | + fprintf(stderr, "Couldn't open %s: %s\n", lib_name, first_dlerror); 99 | + fprintf(stderr, "Couldn't open fallback library %s: %s\n", fullpath, dlerror()); 100 | + abort(); 101 | + } else { 102 | + (void)dlerror(); 103 | + } 104 | + } 105 | + 106 | + free(first_dlerror); 107 | + free(fullpath); 108 | + } 109 | +#endif 110 | } 111 | pthread_mutex_unlock(&api.mutex); 112 | #endif 113 | diff --git a/src/dispatch_common.h b/src/dispatch_common.h 114 | index a136943..55388a8 100644 115 | --- a/src/dispatch_common.h 116 | +++ b/src/dispatch_common.h 117 | @@ -28,7 +28,7 @@ 118 | #define PLATFORM_HAS_GLX ENABLE_GLX 119 | #define PLATFORM_HAS_WGL 1 120 | #elif defined(__APPLE__) 121 | -#define PLATFORM_HAS_EGL 0 122 | +#define PLATFORM_HAS_EGL ENABLE_EGL 123 | #define PLATFORM_HAS_GLX ENABLE_GLX 124 | #define PLATFORM_HAS_WGL 0 125 | #elif defined(ANDROID) 126 | -------------------------------------------------------------------------------- /Patches/qemu-edid-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c 2 | index b0ce583d436..e2c478e5042 100644 3 | --- a/hw/display/edid-generate.c 4 | +++ b/hw/display/edid-generate.c 5 | @@ -44,6 +44,35 @@ static const struct edid_mode { 6 | { .xres = 640, .yres = 480, .byte = 35, .bit = 5 }, 7 | }; 8 | 9 | +typedef struct Timings { 10 | + uint32_t xfront; 11 | + uint32_t xsync; 12 | + uint32_t xblank; 13 | + 14 | + uint32_t yfront; 15 | + uint32_t ysync; 16 | + uint32_t yblank; 17 | + 18 | + uint64_t clock; 19 | +} Timings; 20 | + 21 | +static void generate_timings(Timings *timings, uint32_t refresh_rate, 22 | + uint32_t xres, uint32_t yres) 23 | +{ 24 | + /* pull some realistic looking timings out of thin air */ 25 | + timings->xfront = xres * 25 / 100; 26 | + timings->xsync = xres * 3 / 100; 27 | + timings->xblank = xres * 35 / 100; 28 | + 29 | + timings->yfront = yres * 5 / 1000; 30 | + timings->ysync = yres * 5 / 1000; 31 | + timings->yblank = yres * 35 / 1000; 32 | + 33 | + timings->clock = ((uint64_t)refresh_rate * 34 | + (xres + timings->xblank) * 35 | + (yres + timings->yblank)) / 10000000; 36 | +} 37 | + 38 | static void edid_ext_dta(uint8_t *dta) 39 | { 40 | dta[0] = 0x02; 41 | @@ -129,17 +158,17 @@ static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta, 42 | } 43 | } 44 | 45 | -static void edid_checksum(uint8_t *edid) 46 | +static void edid_checksum(uint8_t *edid, size_t len) 47 | { 48 | uint32_t sum = 0; 49 | int i; 50 | 51 | - for (i = 0; i < 127; i++) { 52 | + for (i = 0; i < len; i++) { 53 | sum += edid[i]; 54 | } 55 | sum &= 0xff; 56 | if (sum) { 57 | - edid[127] = 0x100 - sum; 58 | + edid[len] = 0x100 - sum; 59 | } 60 | } 61 | 62 | @@ -180,8 +209,8 @@ static void edid_desc_ranges(uint8_t *desc) 63 | desc[7] = 30; 64 | desc[8] = 160; 65 | 66 | - /* max dot clock (1200 MHz) */ 67 | - desc[9] = 1200 / 10; 68 | + /* max dot clock (2550 MHz) */ 69 | + desc[9] = 2550 / 10; 70 | 71 | /* no extended timing information */ 72 | desc[10] = 0x01; 73 | @@ -207,38 +236,29 @@ static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate, 74 | uint32_t xres, uint32_t yres, 75 | uint32_t xmm, uint32_t ymm) 76 | { 77 | - /* pull some realistic looking timings out of thin air */ 78 | - uint32_t xfront = xres * 25 / 100; 79 | - uint32_t xsync = xres * 3 / 100; 80 | - uint32_t xblank = xres * 35 / 100; 81 | - 82 | - uint32_t yfront = yres * 5 / 1000; 83 | - uint32_t ysync = yres * 5 / 1000; 84 | - uint32_t yblank = yres * 35 / 1000; 85 | - 86 | - uint64_t clock = (uint64_t)refresh_rate * (xres + xblank) * (yres + yblank); 87 | - 88 | - stl_le_p(desc, clock / 10000000); 89 | + Timings timings; 90 | + generate_timings(&timings, refresh_rate, xres, yres); 91 | + stl_le_p(desc, timings.clock); 92 | 93 | desc[2] = xres & 0xff; 94 | - desc[3] = xblank & 0xff; 95 | + desc[3] = timings.xblank & 0xff; 96 | desc[4] = (((xres & 0xf00) >> 4) | 97 | - ((xblank & 0xf00) >> 8)); 98 | + ((timings.xblank & 0xf00) >> 8)); 99 | 100 | desc[5] = yres & 0xff; 101 | - desc[6] = yblank & 0xff; 102 | + desc[6] = timings.yblank & 0xff; 103 | desc[7] = (((yres & 0xf00) >> 4) | 104 | - ((yblank & 0xf00) >> 8)); 105 | + ((timings.yblank & 0xf00) >> 8)); 106 | 107 | - desc[8] = xfront & 0xff; 108 | - desc[9] = xsync & 0xff; 109 | + desc[8] = timings.xfront & 0xff; 110 | + desc[9] = timings.xsync & 0xff; 111 | 112 | - desc[10] = (((yfront & 0x00f) << 4) | 113 | - ((ysync & 0x00f) << 0)); 114 | - desc[11] = (((xfront & 0x300) >> 2) | 115 | - ((xsync & 0x300) >> 4) | 116 | - ((yfront & 0x030) >> 2) | 117 | - ((ysync & 0x030) >> 4)); 118 | + desc[10] = (((timings.yfront & 0x00f) << 4) | 119 | + ((timings.ysync & 0x00f) << 0)); 120 | + desc[11] = (((timings.xfront & 0x300) >> 2) | 121 | + ((timings.xsync & 0x300) >> 4) | 122 | + ((timings.yfront & 0x030) >> 2) | 123 | + ((timings.ysync & 0x030) >> 4)); 124 | 125 | desc[12] = xmm & 0xff; 126 | desc[13] = ymm & 0xff; 127 | @@ -296,15 +316,61 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res) 128 | return res * 254 / 10 / dpi; 129 | } 130 | 131 | +static void init_displayid(uint8_t *did) 132 | +{ 133 | + did[0] = 0x70; /* display id extension */ 134 | + did[1] = 0x13; /* version 1.3 */ 135 | + did[2] = 4; /* length */ 136 | + did[3] = 0x03; /* product type (0x03 == standalone display device) */ 137 | + edid_checksum(did + 1, did[2] + 4); 138 | +} 139 | + 140 | +static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate, 141 | + uint32_t xres, uint32_t yres, 142 | + uint32_t xmm, uint32_t ymm) 143 | +{ 144 | + Timings timings; 145 | + generate_timings(&timings, refresh_rate, xres, yres); 146 | + 147 | + did[0] = 0x70; /* display id extension */ 148 | + did[1] = 0x13; /* version 1.3 */ 149 | + did[2] = 23; /* length */ 150 | + did[3] = 0x03; /* product type (0x03 == standalone display device) */ 151 | + 152 | + did[5] = 0x03; /* Detailed Timings Data Block */ 153 | + did[6] = 0x00; /* revision */ 154 | + did[7] = 0x14; /* block length */ 155 | + 156 | + did[8] = timings.clock & 0xff; 157 | + did[9] = (timings.clock & 0xff00) >> 8; 158 | + did[10] = (timings.clock & 0xff0000) >> 16; 159 | + 160 | + did[11] = 0x88; /* leave aspect ratio undefined */ 161 | + 162 | + stw_le_p(did + 12, 0xffff & (xres - 1)); 163 | + stw_le_p(did + 14, 0xffff & (timings.xblank - 1)); 164 | + stw_le_p(did + 16, 0xffff & (timings.xfront - 1)); 165 | + stw_le_p(did + 18, 0xffff & (timings.xsync - 1)); 166 | + 167 | + stw_le_p(did + 20, 0xffff & (yres - 1)); 168 | + stw_le_p(did + 22, 0xffff & (timings.yblank - 1)); 169 | + stw_le_p(did + 24, 0xffff & (timings.yfront - 1)); 170 | + stw_le_p(did + 26, 0xffff & (timings.ysync - 1)); 171 | + 172 | + edid_checksum(did + 1, did[2] + 4); 173 | +} 174 | + 175 | void qemu_edid_generate(uint8_t *edid, size_t size, 176 | qemu_edid_info *info) 177 | { 178 | uint32_t desc = 54; 179 | uint8_t *xtra3 = NULL; 180 | uint8_t *dta = NULL; 181 | + uint8_t *did = NULL; 182 | uint32_t width_mm, height_mm; 183 | uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000; 184 | uint32_t dpi = 100; /* if no width_mm/height_mm */ 185 | + uint32_t large_screen = 0; 186 | 187 | /* =============== set defaults =============== */ 188 | 189 | @@ -320,6 +386,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size, 190 | if (!info->prefy) { 191 | info->prefy = 768; 192 | } 193 | + if (info->prefx >= 4096 || info->prefy >= 4096) { 194 | + large_screen = 1; 195 | + } 196 | if (info->width_mm && info->height_mm) { 197 | width_mm = info->width_mm; 198 | height_mm = info->height_mm; 199 | @@ -337,6 +406,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size, 200 | edid_ext_dta(dta); 201 | } 202 | 203 | + if (size >= 384) { 204 | + did = edid + 256; 205 | + init_displayid(did); 206 | + edid[126]++; 207 | + } 208 | + 209 | /* =============== header information =============== */ 210 | 211 | /* fixed */ 212 | @@ -401,9 +476,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size, 213 | 214 | /* =============== descriptor blocks =============== */ 215 | 216 | - edid_desc_timing(edid + desc, refresh_rate, info->prefx, info->prefy, 217 | - width_mm, height_mm); 218 | - desc += 18; 219 | + /* The DTD section has only 12 bits to store the resolution */ 220 | + if (!large_screen) { 221 | + edid_desc_timing(edid + desc, refresh_rate, info->prefx, info->prefy, 222 | + width_mm, height_mm); 223 | + desc += 18; 224 | + } 225 | 226 | edid_desc_ranges(edid + desc); 227 | desc += 18; 228 | @@ -429,12 +507,22 @@ void qemu_edid_generate(uint8_t *edid, size_t size, 229 | desc += 18; 230 | } 231 | 232 | + /* =============== display id extensions =============== */ 233 | + 234 | + if (size >= 384 && large_screen) { 235 | + qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy, 236 | + width_mm, height_mm); 237 | + } 238 | + 239 | /* =============== finish up =============== */ 240 | 241 | edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); 242 | - edid_checksum(edid); 243 | + edid_checksum(edid, 127); 244 | if (dta) { 245 | - edid_checksum(dta); 246 | + edid_checksum(dta, 127); 247 | + } 248 | + if (did) { 249 | + edid_checksum(did, 127); 250 | } 251 | } 252 | 253 | diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c 254 | index 48d29630ab7..62fb5c38c1f 100644 255 | --- a/hw/display/vga-pci.c 256 | +++ b/hw/display/vga-pci.c 257 | @@ -49,7 +49,7 @@ struct PCIVGAState { 258 | qemu_edid_info edid_info; 259 | MemoryRegion mmio; 260 | MemoryRegion mrs[4]; 261 | - uint8_t edid[256]; 262 | + uint8_t edid[384]; 263 | }; 264 | 265 | #define TYPE_PCI_VGA "pci-vga" 266 | diff --git a/qemu-edid.c b/qemu-edid.c 267 | index 1cd6a951723..028f2d181a1 100644 268 | --- a/qemu-edid.c 269 | +++ b/qemu-edid.c 270 | @@ -41,7 +41,7 @@ static void usage(FILE *out) 271 | int main(int argc, char *argv[]) 272 | { 273 | FILE *outfile = NULL; 274 | - uint8_t blob[256]; 275 | + uint8_t blob[384]; 276 | uint32_t dpi = 100; 277 | int rc; 278 | 279 | -------------------------------------------------------------------------------- /Patches/qemu-hexagon-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build 2 | index 5dd68907b1..bb0b4fb621 100644 3 | --- a/target/hexagon/meson.build 4 | +++ b/target/hexagon/meson.build 5 | @@ -53,90 +53,81 @@ hexagon_ss.add(semantics_generated) 6 | shortcode_generated = custom_target( 7 | 'shortcode_generated.h.inc', 8 | output: 'shortcode_generated.h.inc', 9 | - input: 'gen_shortcode.py', 10 | depends: [semantics_generated], 11 | depend_files: [hex_common_py, attribs_def], 12 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 13 | + command: [python, files('gen_shortcode.py'), semantics_generated, attribs_def, '@OUTPUT@'], 14 | ) 15 | hexagon_ss.add(shortcode_generated) 16 | 17 | helper_protos_generated = custom_target( 18 | 'helper_protos_generated.h.inc', 19 | output: 'helper_protos_generated.h.inc', 20 | - input: 'gen_helper_protos.py', 21 | depends: [semantics_generated], 22 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 23 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 24 | + command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 25 | ) 26 | hexagon_ss.add(helper_protos_generated) 27 | 28 | tcg_funcs_generated = custom_target( 29 | 'tcg_funcs_generated.c.inc', 30 | output: 'tcg_funcs_generated.c.inc', 31 | - input: 'gen_tcg_funcs.py', 32 | depends: [semantics_generated], 33 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 34 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 35 | + command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 36 | ) 37 | hexagon_ss.add(tcg_funcs_generated) 38 | 39 | tcg_func_table_generated = custom_target( 40 | 'tcg_func_table_generated.c.inc', 41 | output: 'tcg_func_table_generated.c.inc', 42 | - input: 'gen_tcg_func_table.py', 43 | depends: [semantics_generated], 44 | depend_files: [hex_common_py, attribs_def], 45 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 46 | + command: [python, files('gen_tcg_func_table.py'), semantics_generated, attribs_def, '@OUTPUT@'], 47 | ) 48 | hexagon_ss.add(tcg_func_table_generated) 49 | 50 | helper_funcs_generated = custom_target( 51 | 'helper_funcs_generated.c.inc', 52 | output: 'helper_funcs_generated.c.inc', 53 | - input: 'gen_helper_funcs.py', 54 | depends: [semantics_generated], 55 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 56 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 57 | + command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 58 | ) 59 | hexagon_ss.add(helper_funcs_generated) 60 | 61 | printinsn_generated = custom_target( 62 | 'printinsn_generated.h.inc', 63 | output: 'printinsn_generated.h.inc', 64 | - input: 'gen_printinsn.py', 65 | depends: [semantics_generated], 66 | depend_files: [hex_common_py, attribs_def], 67 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 68 | + command: [python, files('gen_printinsn.py'), semantics_generated, attribs_def, '@OUTPUT@'], 69 | ) 70 | hexagon_ss.add(printinsn_generated) 71 | 72 | op_regs_generated = custom_target( 73 | 'op_regs_generated.h.inc', 74 | output: 'op_regs_generated.h.inc', 75 | - input: 'gen_op_regs.py', 76 | depends: [semantics_generated], 77 | depend_files: [hex_common_py, attribs_def], 78 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 79 | + command: [python, files('gen_op_regs.py'), semantics_generated, attribs_def, '@OUTPUT@'], 80 | ) 81 | hexagon_ss.add(op_regs_generated) 82 | 83 | op_attribs_generated = custom_target( 84 | 'op_attribs_generated.h.inc', 85 | output: 'op_attribs_generated.h.inc', 86 | - input: 'gen_op_attribs.py', 87 | depends: [semantics_generated], 88 | depend_files: [hex_common_py, attribs_def], 89 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 90 | + command: [python, files('gen_op_attribs.py'), semantics_generated, attribs_def, '@OUTPUT@'], 91 | ) 92 | hexagon_ss.add(op_attribs_generated) 93 | 94 | opcodes_def_generated = custom_target( 95 | 'opcodes_def_generated.h.inc', 96 | output: 'opcodes_def_generated.h.inc', 97 | - input: 'gen_opcodes_def.py', 98 | depends: [semantics_generated], 99 | depend_files: [hex_common_py, attribs_def], 100 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 101 | + command: [python, files('gen_opcodes_def.py'), semantics_generated, attribs_def, '@OUTPUT@'], 102 | ) 103 | hexagon_ss.add(opcodes_def_generated) 104 | 105 | @@ -164,9 +155,8 @@ hexagon_ss.add(iset_py) 106 | dectree_generated = custom_target( 107 | 'dectree_generated.h.inc', 108 | output: 'dectree_generated.h.inc', 109 | - input: 'dectree.py', 110 | depends: [iset_py], 111 | - command: ['PYTHONPATH=' + meson.current_build_dir(), '@INPUT@', '@OUTPUT@'], 112 | + command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'], 113 | ) 114 | hexagon_ss.add(dectree_generated) 115 | 116 | -------------------------------------------------------------------------------- /Patches/qemu-hexagon-v02.diff: -------------------------------------------------------------------------------- 1 | diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build 2 | index 15318a6fa7..bb0b4fb621 100644 3 | --- a/target/hexagon/meson.build 4 | +++ b/target/hexagon/meson.build 5 | @@ -33,8 +33,7 @@ gen_semantics = executable( 6 | semantics_generated = custom_target( 7 | 'semantics_generated.pyinc', 8 | output: 'semantics_generated.pyinc', 9 | - input: gen_semantics, 10 | - command: ['@INPUT@', '@OUTPUT@'], 11 | + command: [gen_semantics, '@OUTPUT@'], 12 | ) 13 | hexagon_ss.add(semantics_generated) 14 | 15 | @@ -54,90 +53,81 @@ hexagon_ss.add(semantics_generated) 16 | shortcode_generated = custom_target( 17 | 'shortcode_generated.h.inc', 18 | output: 'shortcode_generated.h.inc', 19 | - input: 'gen_shortcode.py', 20 | depends: [semantics_generated], 21 | depend_files: [hex_common_py, attribs_def], 22 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 23 | + command: [python, files('gen_shortcode.py'), semantics_generated, attribs_def, '@OUTPUT@'], 24 | ) 25 | hexagon_ss.add(shortcode_generated) 26 | 27 | helper_protos_generated = custom_target( 28 | 'helper_protos_generated.h.inc', 29 | output: 'helper_protos_generated.h.inc', 30 | - input: 'gen_helper_protos.py', 31 | depends: [semantics_generated], 32 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 33 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 34 | + command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 35 | ) 36 | hexagon_ss.add(helper_protos_generated) 37 | 38 | tcg_funcs_generated = custom_target( 39 | 'tcg_funcs_generated.c.inc', 40 | output: 'tcg_funcs_generated.c.inc', 41 | - input: 'gen_tcg_funcs.py', 42 | depends: [semantics_generated], 43 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 44 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 45 | + command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 46 | ) 47 | hexagon_ss.add(tcg_funcs_generated) 48 | 49 | tcg_func_table_generated = custom_target( 50 | 'tcg_func_table_generated.c.inc', 51 | output: 'tcg_func_table_generated.c.inc', 52 | - input: 'gen_tcg_func_table.py', 53 | depends: [semantics_generated], 54 | depend_files: [hex_common_py, attribs_def], 55 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 56 | + command: [python, files('gen_tcg_func_table.py'), semantics_generated, attribs_def, '@OUTPUT@'], 57 | ) 58 | hexagon_ss.add(tcg_func_table_generated) 59 | 60 | helper_funcs_generated = custom_target( 61 | 'helper_funcs_generated.c.inc', 62 | output: 'helper_funcs_generated.c.inc', 63 | - input: 'gen_helper_funcs.py', 64 | depends: [semantics_generated], 65 | depend_files: [hex_common_py, attribs_def, gen_tcg_h], 66 | - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 67 | + command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], 68 | ) 69 | hexagon_ss.add(helper_funcs_generated) 70 | 71 | printinsn_generated = custom_target( 72 | 'printinsn_generated.h.inc', 73 | output: 'printinsn_generated.h.inc', 74 | - input: 'gen_printinsn.py', 75 | depends: [semantics_generated], 76 | depend_files: [hex_common_py, attribs_def], 77 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 78 | + command: [python, files('gen_printinsn.py'), semantics_generated, attribs_def, '@OUTPUT@'], 79 | ) 80 | hexagon_ss.add(printinsn_generated) 81 | 82 | op_regs_generated = custom_target( 83 | 'op_regs_generated.h.inc', 84 | output: 'op_regs_generated.h.inc', 85 | - input: 'gen_op_regs.py', 86 | depends: [semantics_generated], 87 | depend_files: [hex_common_py, attribs_def], 88 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 89 | + command: [python, files('gen_op_regs.py'), semantics_generated, attribs_def, '@OUTPUT@'], 90 | ) 91 | hexagon_ss.add(op_regs_generated) 92 | 93 | op_attribs_generated = custom_target( 94 | 'op_attribs_generated.h.inc', 95 | output: 'op_attribs_generated.h.inc', 96 | - input: 'gen_op_attribs.py', 97 | depends: [semantics_generated], 98 | depend_files: [hex_common_py, attribs_def], 99 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 100 | + command: [python, files('gen_op_attribs.py'), semantics_generated, attribs_def, '@OUTPUT@'], 101 | ) 102 | hexagon_ss.add(op_attribs_generated) 103 | 104 | opcodes_def_generated = custom_target( 105 | 'opcodes_def_generated.h.inc', 106 | output: 'opcodes_def_generated.h.inc', 107 | - input: 'gen_opcodes_def.py', 108 | depends: [semantics_generated], 109 | depend_files: [hex_common_py, attribs_def], 110 | - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], 111 | + command: [python, files('gen_opcodes_def.py'), semantics_generated, attribs_def, '@OUTPUT@'], 112 | ) 113 | hexagon_ss.add(opcodes_def_generated) 114 | 115 | @@ -154,8 +144,7 @@ gen_dectree_import = executable( 116 | iset_py = custom_target( 117 | 'iset.py', 118 | output: 'iset.py', 119 | - input: gen_dectree_import, 120 | - command: ['@INPUT@', '@OUTPUT@'], 121 | + command: [gen_dectree_import, '@OUTPUT@'], 122 | ) 123 | hexagon_ss.add(iset_py) 124 | 125 | @@ -166,9 +155,8 @@ hexagon_ss.add(iset_py) 126 | dectree_generated = custom_target( 127 | 'dectree_generated.h.inc', 128 | output: 'dectree_generated.h.inc', 129 | - input: 'dectree.py', 130 | depends: [iset_py], 131 | - command: ['PYTHONPATH=' + meson.current_build_dir(), '@INPUT@', '@OUTPUT@'], 132 | + command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'], 133 | ) 134 | hexagon_ss.add(dectree_generated) 135 | 136 | -------------------------------------------------------------------------------- /Patches/qemu-libusb-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/hw/usb/meson.build b/hw/usb/meson.build 2 | index 3ca6127937..de853d780d 100644 3 | --- a/hw/usb/meson.build 4 | +++ b/hw/usb/meson.build 5 | @@ -72,7 +72,7 @@ if usbredir.found() 6 | endif 7 | 8 | # usb pass-through 9 | -if config_host.has_key('CONFIG_USB_LIBUSB') 10 | +if libusb.found() 11 | usbhost_ss = ss.source_set() 12 | usbhost_ss.add(when: ['CONFIG_USB', libusb], 13 | if_true: files('host-libusb.c')) 14 | -------------------------------------------------------------------------------- /Patches/qemu-version-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index bcbbec71a1..8b75085fa5 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -85,7 +85,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs) 6 | endif 7 | 8 | # 1. ensure config-host.mak is up-to-date 9 | -config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION 10 | +config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/QEMU_VERSION 11 | @echo config-host.mak is out-of-date, running configure 12 | @if test -f meson-private/coredata.dat; then \ 13 | ./config.status --skip-meson; \ 14 | @@ -204,7 +204,7 @@ clean: recurse-clean 15 | rm -f TAGS cscope.* *.pod *~ */*~ 16 | rm -f fsdev/*.pod scsi/*.pod 17 | 18 | -VERSION = $(shell cat $(SRC_PATH)/VERSION) 19 | +VERSION = $(shell cat $(SRC_PATH)/QEMU_VERSION) 20 | 21 | dist: qemu-$(VERSION).tar.bz2 22 | 23 | diff --git a/QEMU_VERSION b/QEMU_VERSION 24 | new file mode 100644 25 | index 0000000000..5214c0b8b9 26 | --- /dev/null 27 | +++ b/QEMU_VERSION 28 | @@ -0,0 +1 @@ 29 | +5.2.50 30 | diff --git a/VERSION b/VERSION 31 | deleted file mode 100644 32 | index 5214c0b8b9..0000000000 33 | --- a/VERSION 34 | +++ /dev/null 35 | @@ -1 +0,0 @@ 36 | -5.2.50 37 | diff --git a/meson.build b/meson.build 38 | index 2dc66ae930..a8f8a02b3f 100644 39 | --- a/meson.build 40 | +++ b/meson.build 41 | @@ -1,7 +1,7 @@ 42 | project('qemu', ['c'], meson_version: '>=0.55.0', 43 | default_options: ['warning_level=1', 'c_std=gnu99', 'cpp_std=gnu++11', 'b_colorout=auto'] + 44 | (meson.version().version_compare('>=0.56.0') ? [ 'b_staticpic=false' ] : []), 45 | - version: run_command('head', meson.source_root() / 'VERSION').stdout().strip()) 46 | + version: run_command('head', meson.source_root() / 'QEMU_VERSION').stdout().strip()) 47 | 48 | not_found = dependency('', required: false) 49 | if meson.version().version_compare('>=0.56.0') 50 | -------------------------------------------------------------------------------- /Patches/virglrenderer-v01.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index 333dd74..ec9e8e0 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -74,7 +74,6 @@ endforeach 6 | 7 | prog_python = import('python').find_installation('python3') 8 | 9 | -libdrm_dep = dependency('libdrm', version : '>=2.4.50') 10 | thread_dep = dependency('threads') 11 | epoxy_dep = dependency('epoxy', version: '>= 1.5.4') 12 | m_dep = cc.find_library('m') 13 | @@ -154,9 +153,12 @@ endif 14 | 15 | if with_egl 16 | if cc.has_header('epoxy/egl.h', dependencies: epoxy_dep) and epoxy_dep.get_pkgconfig_variable('epoxy_has_egl') == '1' 17 | + libdrm_dep = dependency('libdrm', required: require_egl, version : '>=2.4.50') 18 | gbm_dep = dependency('gbm', version: '>= ' + _gbm_ver, required: require_egl) 19 | - have_egl = gbm_dep.found() 20 | - conf_data.set('HAVE_EPOXY_EGL_H', 1) 21 | + have_egl = libdrm_dep.found() and gbm_dep.found() 22 | + if have_egl 23 | + conf_data.set('HAVE_EPOXY_EGL_H', 1) 24 | + endif 25 | else 26 | assert(not require_egl, 27 | 'egl was explicitely requested but it is not supported by epoxy') 28 | diff --git a/src/meson.build b/src/meson.build 29 | index 257d7dc..4df732a 100644 30 | --- a/src/meson.build 31 | +++ b/src/meson.build 32 | @@ -77,7 +77,6 @@ vrend_winsys_glx_sources = [ 33 | virgl_depends = [ 34 | gallium_dep, 35 | epoxy_dep, 36 | - libdrm_dep, 37 | thread_dep, 38 | m_dep, 39 | ] 40 | @@ -94,7 +93,7 @@ virgl_sources += vrend_sources 41 | 42 | if have_egl 43 | virgl_sources += vrend_winsys_egl_sources 44 | - virgl_depends += [gbm_dep] 45 | + virgl_depends += [libdrm_dep, gbm_dep] 46 | endif 47 | 48 | if have_glx 49 | diff --git a/src/virglrenderer.c b/src/virglrenderer.c 50 | index 0730a1d..9f63ec7 100644 51 | --- a/src/virglrenderer.c 52 | +++ b/src/virglrenderer.c 53 | @@ -424,8 +424,8 @@ void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 54 | ctx->detach_resource(ctx, res); 55 | } 56 | 57 | -int virgl_renderer_resource_get_info(int res_handle, 58 | - struct virgl_renderer_resource_info *info) 59 | +int virgl_renderer_borrow_texture_for_scanout(int res_handle, 60 | + struct virgl_renderer_texture_info *info) 61 | { 62 | TRACE_FUNC(); 63 | struct virgl_resource *res = virgl_resource_lookup(res_handle); 64 | @@ -435,8 +435,8 @@ int virgl_renderer_resource_get_info(int res_handle, 65 | if (!info) 66 | return EINVAL; 67 | 68 | - vrend_renderer_resource_get_info(res->pipe_resource, 69 | - (struct vrend_renderer_resource_info *)info); 70 | + vrend_renderer_borrow_texture_for_scanout(res->pipe_resource, 71 | + (struct vrend_renderer_texture_info *)info); 72 | info->handle = res_handle; 73 | 74 | if (state.winsys_initialized) { 75 | diff --git a/src/virglrenderer.h b/src/virglrenderer.h 76 | index d56b5dc..716d0a4 100644 77 | --- a/src/virglrenderer.h 78 | +++ b/src/virglrenderer.h 79 | @@ -232,9 +232,9 @@ VIRGL_EXPORT void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 80 | 81 | VIRGL_EXPORT virgl_debug_callback_type virgl_set_debug_callback(virgl_debug_callback_type cb); 82 | 83 | -/* return information about a resource */ 84 | +/* borrow a texture for scanout */ 85 | 86 | -struct virgl_renderer_resource_info { 87 | +struct virgl_renderer_texture_info { 88 | uint32_t handle; 89 | uint32_t virgl_format; 90 | uint32_t width; 91 | @@ -246,8 +246,8 @@ struct virgl_renderer_resource_info { 92 | int drm_fourcc; 93 | }; 94 | 95 | -VIRGL_EXPORT int virgl_renderer_resource_get_info(int res_handle, 96 | - struct virgl_renderer_resource_info *info); 97 | +VIRGL_EXPORT int virgl_renderer_borrow_texture_for_scanout(int res_handle, 98 | + struct virgl_renderer_texture_info *info); 99 | 100 | VIRGL_EXPORT void virgl_renderer_cleanup(void *cookie); 101 | 102 | diff --git a/src/vrend_blitter.h b/src/vrend_blitter.h 103 | index c4a7adb..94b5a45 100644 104 | --- a/src/vrend_blitter.h 105 | +++ b/src/vrend_blitter.h 106 | @@ -31,12 +31,12 @@ 107 | "// Blitter\n" \ 108 | 109 | #define HEADER_GLES \ 110 | - "#version 310 es\n" \ 111 | + "#version 300 es\n" \ 112 | "// Blitter\n" \ 113 | "precision mediump float;\n" \ 114 | 115 | #define HEADER_GLES_MS_ARRAY \ 116 | - "#version 310 es\n" \ 117 | + "#version 300 es\n" \ 118 | "// Blitter\n" \ 119 | "#extension GL_OES_texture_storage_multisample_2d_array: require\n" \ 120 | "precision mediump float;\n" \ 121 | diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c 122 | index 15474d2..62ebe9f 100644 123 | --- a/src/vrend_renderer.c 124 | +++ b/src/vrend_renderer.c 125 | @@ -10639,21 +10639,43 @@ void vrend_context_set_debug_flags(struct vrend_context *ctx, const char *flagst 126 | } 127 | } 128 | 129 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 130 | - struct vrend_renderer_resource_info *info) 131 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 132 | + struct vrend_renderer_texture_info *info) 133 | { 134 | - struct vrend_resource *res = (struct vrend_resource *)pres; 135 | + struct vrend_texture *tex = (struct vrend_texture *)pres; 136 | + struct vrend_format_table *tex_conv = tex_conv_table + tex->base.base.format; 137 | int elsize; 138 | 139 | - elsize = util_format_get_blocksize(res->base.format); 140 | + assert(tex->base.target == GL_TEXTURE_2D); 141 | + assert(!util_format_is_depth_or_stencil(tex->base.base.format)); 142 | + 143 | + elsize = util_format_get_blocksize(tex->base.base.format); 144 | + 145 | + glBindTexture(GL_TEXTURE_2D, tex->base.id); 146 | + 147 | + for (unsigned i = 0; i < ARRAY_SIZE(tex->cur_swizzle); ++i) { 148 | + GLint next_swizzle = to_gl_swizzle(tex_conv->swizzle[i]); 149 | + if (tex->cur_swizzle[i] != next_swizzle) { 150 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R + i, next_swizzle); 151 | + tex->cur_swizzle[i] = next_swizzle; 152 | + } 153 | + } 154 | + 155 | + if (tex->cur_srgb_decode != GL_DECODE_EXT && util_format_is_srgb(tex->base.base.format)) { 156 | + if (has_feature(feat_texture_srgb_decode)) { 157 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, 158 | + GL_DECODE_EXT); 159 | + tex->cur_srgb_decode = GL_DECODE_EXT; 160 | + } 161 | + } 162 | 163 | - info->tex_id = res->id; 164 | - info->width = res->base.width0; 165 | - info->height = res->base.height0; 166 | - info->depth = res->base.depth0; 167 | - info->format = res->base.format; 168 | - info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 169 | - info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; 170 | + info->tex_id = tex->base.id; 171 | + info->width = tex->base.base.width0; 172 | + info->height = tex->base.base.height0; 173 | + info->depth = tex->base.base.depth0; 174 | + info->format = tex->base.base.format; 175 | + info->flags = tex->base.y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 176 | + info->stride = util_format_get_nblocksx(tex->base.base.format, u_minify(tex->base.base.width0, 0)) * elsize; 177 | } 178 | 179 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 180 | diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h 181 | index 297fc5c..8d9be22 100644 182 | --- a/src/vrend_renderer.h 183 | +++ b/src/vrend_renderer.h 184 | @@ -430,7 +430,7 @@ void vrend_renderer_detach_res_ctx(struct vrend_context *ctx, 185 | 186 | struct vrend_context_tweaks *vrend_get_context_tweaks(struct vrend_context *ctx); 187 | 188 | -struct vrend_renderer_resource_info { 189 | +struct vrend_renderer_texture_info { 190 | uint32_t handle; 191 | uint32_t format; 192 | uint32_t width; 193 | @@ -441,8 +441,8 @@ struct vrend_renderer_resource_info { 194 | uint32_t stride; 195 | }; 196 | 197 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 198 | - struct vrend_renderer_resource_info *info); 199 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 200 | + struct vrend_renderer_texture_info *info); 201 | 202 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 203 | uint32_t *max_size); 204 | diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c 205 | index 43f2e4e..6fa52af 100644 206 | --- a/src/vrend_winsys.c 207 | +++ b/src/vrend_winsys.c 208 | @@ -22,6 +22,7 @@ 209 | * 210 | **************************************************************************/ 211 | 212 | +#include "vrend_debug.h" 213 | #include "vrend_winsys.h" 214 | 215 | #ifdef HAVE_EPOXY_GLX_H 216 | diff --git a/src/vrend_winsys_gbm.h b/src/vrend_winsys_gbm.h 217 | index dd5ce36..e909296 100644 218 | --- a/src/vrend_winsys_gbm.h 219 | +++ b/src/vrend_winsys_gbm.h 220 | @@ -25,7 +25,9 @@ 221 | #ifndef VIRGL_GBM_H 222 | #define VIRGL_GBM_H 223 | 224 | +#ifdef HAVE_EPOXY_EGL_H 225 | #include 226 | +#endif 227 | #include "vrend_iov.h" 228 | #include "virglrenderer.h" 229 | 230 | @@ -66,6 +68,8 @@ struct virgl_gbm { 231 | struct gbm_device *device; 232 | }; 233 | 234 | +#ifdef HAVE_EPOXY_EGL_H 235 | + 236 | struct virgl_gbm *virgl_gbm_init(int fd); 237 | 238 | void virgl_gbm_fini(struct virgl_gbm *gbm); 239 | @@ -89,3 +93,5 @@ bool virgl_gbm_external_allocation_preferred(uint32_t flags); 240 | bool virgl_gbm_gpu_import_required(uint32_t flags); 241 | 242 | #endif 243 | + 244 | +#endif 245 | -------------------------------------------------------------------------------- /Patches/virglrenderer-v02.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index 333dd74..ec9e8e0 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -74,7 +74,6 @@ endforeach 6 | 7 | prog_python = import('python').find_installation('python3') 8 | 9 | -libdrm_dep = dependency('libdrm', version : '>=2.4.50') 10 | thread_dep = dependency('threads') 11 | epoxy_dep = dependency('epoxy', version: '>= 1.5.4') 12 | m_dep = cc.find_library('m') 13 | @@ -154,9 +153,12 @@ endif 14 | 15 | if with_egl 16 | if cc.has_header('epoxy/egl.h', dependencies: epoxy_dep) and epoxy_dep.get_pkgconfig_variable('epoxy_has_egl') == '1' 17 | + libdrm_dep = dependency('libdrm', required: require_egl, version : '>=2.4.50') 18 | gbm_dep = dependency('gbm', version: '>= ' + _gbm_ver, required: require_egl) 19 | - have_egl = gbm_dep.found() 20 | - conf_data.set('HAVE_EPOXY_EGL_H', 1) 21 | + have_egl = libdrm_dep.found() and gbm_dep.found() 22 | + if have_egl 23 | + conf_data.set('HAVE_EPOXY_EGL_H', 1) 24 | + endif 25 | else 26 | assert(not require_egl, 27 | 'egl was explicitely requested but it is not supported by epoxy') 28 | diff --git a/src/meson.build b/src/meson.build 29 | index 257d7dc..4df732a 100644 30 | --- a/src/meson.build 31 | +++ b/src/meson.build 32 | @@ -77,7 +77,6 @@ vrend_winsys_glx_sources = [ 33 | virgl_depends = [ 34 | gallium_dep, 35 | epoxy_dep, 36 | - libdrm_dep, 37 | thread_dep, 38 | m_dep, 39 | ] 40 | @@ -94,7 +93,7 @@ virgl_sources += vrend_sources 41 | 42 | if have_egl 43 | virgl_sources += vrend_winsys_egl_sources 44 | - virgl_depends += [gbm_dep] 45 | + virgl_depends += [libdrm_dep, gbm_dep] 46 | endif 47 | 48 | if have_glx 49 | diff --git a/src/virglrenderer.c b/src/virglrenderer.c 50 | index 0730a1d..9f63ec7 100644 51 | --- a/src/virglrenderer.c 52 | +++ b/src/virglrenderer.c 53 | @@ -424,8 +424,8 @@ void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 54 | ctx->detach_resource(ctx, res); 55 | } 56 | 57 | -int virgl_renderer_resource_get_info(int res_handle, 58 | - struct virgl_renderer_resource_info *info) 59 | +int virgl_renderer_borrow_texture_for_scanout(int res_handle, 60 | + struct virgl_renderer_texture_info *info) 61 | { 62 | TRACE_FUNC(); 63 | struct virgl_resource *res = virgl_resource_lookup(res_handle); 64 | @@ -435,8 +435,8 @@ int virgl_renderer_resource_get_info(int res_handle, 65 | if (!info) 66 | return EINVAL; 67 | 68 | - vrend_renderer_resource_get_info(res->pipe_resource, 69 | - (struct vrend_renderer_resource_info *)info); 70 | + vrend_renderer_borrow_texture_for_scanout(res->pipe_resource, 71 | + (struct vrend_renderer_texture_info *)info); 72 | info->handle = res_handle; 73 | 74 | if (state.winsys_initialized) { 75 | diff --git a/src/virglrenderer.h b/src/virglrenderer.h 76 | index d56b5dc..716d0a4 100644 77 | --- a/src/virglrenderer.h 78 | +++ b/src/virglrenderer.h 79 | @@ -232,9 +232,9 @@ VIRGL_EXPORT void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 80 | 81 | VIRGL_EXPORT virgl_debug_callback_type virgl_set_debug_callback(virgl_debug_callback_type cb); 82 | 83 | -/* return information about a resource */ 84 | +/* borrow a texture for scanout */ 85 | 86 | -struct virgl_renderer_resource_info { 87 | +struct virgl_renderer_texture_info { 88 | uint32_t handle; 89 | uint32_t virgl_format; 90 | uint32_t width; 91 | @@ -246,8 +246,8 @@ struct virgl_renderer_resource_info { 92 | int drm_fourcc; 93 | }; 94 | 95 | -VIRGL_EXPORT int virgl_renderer_resource_get_info(int res_handle, 96 | - struct virgl_renderer_resource_info *info); 97 | +VIRGL_EXPORT int virgl_renderer_borrow_texture_for_scanout(int res_handle, 98 | + struct virgl_renderer_texture_info *info); 99 | 100 | VIRGL_EXPORT void virgl_renderer_cleanup(void *cookie); 101 | 102 | diff --git a/src/vrend_blitter.h b/src/vrend_blitter.h 103 | index c4a7adb..94b5a45 100644 104 | --- a/src/vrend_blitter.h 105 | +++ b/src/vrend_blitter.h 106 | @@ -31,12 +31,12 @@ 107 | "// Blitter\n" \ 108 | 109 | #define HEADER_GLES \ 110 | - "#version 310 es\n" \ 111 | + "#version 300 es\n" \ 112 | "// Blitter\n" \ 113 | "precision mediump float;\n" \ 114 | 115 | #define HEADER_GLES_MS_ARRAY \ 116 | - "#version 310 es\n" \ 117 | + "#version 300 es\n" \ 118 | "// Blitter\n" \ 119 | "#extension GL_OES_texture_storage_multisample_2d_array: require\n" \ 120 | "precision mediump float;\n" \ 121 | diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c 122 | index 15474d2..2ed6144 100644 123 | --- a/src/vrend_renderer.c 124 | +++ b/src/vrend_renderer.c 125 | @@ -10639,21 +10639,46 @@ void vrend_context_set_debug_flags(struct vrend_context *ctx, const char *flagst 126 | } 127 | } 128 | 129 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 130 | - struct vrend_renderer_resource_info *info) 131 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 132 | + struct vrend_renderer_texture_info *info) 133 | { 134 | - struct vrend_resource *res = (struct vrend_resource *)pres; 135 | + struct vrend_texture *tex = (struct vrend_texture *)pres; 136 | + const struct vrend_format_table *tex_conv = 137 | + vrend_get_format_table_entry_with_emulation(tex->base.base.bind, tex->base.base.format); 138 | int elsize; 139 | 140 | - elsize = util_format_get_blocksize(res->base.format); 141 | + assert(tex->base.target == GL_TEXTURE_2D); 142 | + assert(!util_format_is_depth_or_stencil(tex->base.base.format)); 143 | + 144 | + elsize = util_format_get_blocksize(tex->base.base.format); 145 | + 146 | + glBindTexture(GL_TEXTURE_2D, tex->base.id); 147 | + 148 | + if (tex_conv->flags & VIRGL_TEXTURE_NEED_SWIZZLE) { 149 | + for (unsigned i = 0; i < ARRAY_SIZE(tex->cur_swizzle); ++i) { 150 | + GLint next_swizzle = to_gl_swizzle(tex_conv->swizzle[i]); 151 | + if (tex->cur_swizzle[i] != next_swizzle) { 152 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R + i, next_swizzle); 153 | + tex->cur_swizzle[i] = next_swizzle; 154 | + } 155 | + } 156 | + } 157 | + 158 | + if (tex->cur_srgb_decode != GL_DECODE_EXT && util_format_is_srgb(tex->base.base.format)) { 159 | + if (has_feature(feat_texture_srgb_decode)) { 160 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, 161 | + GL_DECODE_EXT); 162 | + tex->cur_srgb_decode = GL_DECODE_EXT; 163 | + } 164 | + } 165 | 166 | - info->tex_id = res->id; 167 | - info->width = res->base.width0; 168 | - info->height = res->base.height0; 169 | - info->depth = res->base.depth0; 170 | - info->format = res->base.format; 171 | - info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 172 | - info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; 173 | + info->tex_id = tex->base.id; 174 | + info->width = tex->base.base.width0; 175 | + info->height = tex->base.base.height0; 176 | + info->depth = tex->base.base.depth0; 177 | + info->format = tex->base.base.format; 178 | + info->flags = tex->base.y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 179 | + info->stride = util_format_get_nblocksx(tex->base.base.format, u_minify(tex->base.base.width0, 0)) * elsize; 180 | } 181 | 182 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 183 | diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h 184 | index 297fc5c..8d9be22 100644 185 | --- a/src/vrend_renderer.h 186 | +++ b/src/vrend_renderer.h 187 | @@ -430,7 +430,7 @@ void vrend_renderer_detach_res_ctx(struct vrend_context *ctx, 188 | 189 | struct vrend_context_tweaks *vrend_get_context_tweaks(struct vrend_context *ctx); 190 | 191 | -struct vrend_renderer_resource_info { 192 | +struct vrend_renderer_texture_info { 193 | uint32_t handle; 194 | uint32_t format; 195 | uint32_t width; 196 | @@ -441,8 +441,8 @@ struct vrend_renderer_resource_info { 197 | uint32_t stride; 198 | }; 199 | 200 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 201 | - struct vrend_renderer_resource_info *info); 202 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 203 | + struct vrend_renderer_texture_info *info); 204 | 205 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 206 | uint32_t *max_size); 207 | diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c 208 | index 43f2e4e..6fa52af 100644 209 | --- a/src/vrend_winsys.c 210 | +++ b/src/vrend_winsys.c 211 | @@ -22,6 +22,7 @@ 212 | * 213 | **************************************************************************/ 214 | 215 | +#include "vrend_debug.h" 216 | #include "vrend_winsys.h" 217 | 218 | #ifdef HAVE_EPOXY_GLX_H 219 | diff --git a/src/vrend_winsys_gbm.h b/src/vrend_winsys_gbm.h 220 | index dd5ce36..e909296 100644 221 | --- a/src/vrend_winsys_gbm.h 222 | +++ b/src/vrend_winsys_gbm.h 223 | @@ -25,7 +25,9 @@ 224 | #ifndef VIRGL_GBM_H 225 | #define VIRGL_GBM_H 226 | 227 | +#ifdef HAVE_EPOXY_EGL_H 228 | #include 229 | +#endif 230 | #include "vrend_iov.h" 231 | #include "virglrenderer.h" 232 | 233 | @@ -66,6 +68,8 @@ struct virgl_gbm { 234 | struct gbm_device *device; 235 | }; 236 | 237 | +#ifdef HAVE_EPOXY_EGL_H 238 | + 239 | struct virgl_gbm *virgl_gbm_init(int fd); 240 | 241 | void virgl_gbm_fini(struct virgl_gbm *gbm); 242 | @@ -89,3 +93,5 @@ bool virgl_gbm_external_allocation_preferred(uint32_t flags); 243 | bool virgl_gbm_gpu_import_required(uint32_t flags); 244 | 245 | #endif 246 | + 247 | +#endif 248 | -------------------------------------------------------------------------------- /Patches/virglrenderer-v03.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index 2ccc20a..5aca90f 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -74,7 +74,6 @@ endforeach 6 | 7 | prog_python = import('python').find_installation('python3') 8 | 9 | -libdrm_dep = dependency('libdrm', version : '>=2.4.50') 10 | thread_dep = dependency('threads') 11 | epoxy_dep = dependency('epoxy', version: '>= 1.5.4') 12 | m_dep = cc.find_library('m') 13 | @@ -182,9 +181,12 @@ endif 14 | 15 | if with_egl 16 | if cc.has_header('epoxy/egl.h', dependencies: epoxy_dep) and epoxy_dep.get_pkgconfig_variable('epoxy_has_egl') == '1' 17 | + libdrm_dep = dependency('libdrm', required: require_egl, version : '>=2.4.50') 18 | gbm_dep = dependency('gbm', version: '>= ' + _gbm_ver, required: require_egl) 19 | - have_egl = gbm_dep.found() 20 | - conf_data.set('HAVE_EPOXY_EGL_H', 1) 21 | + have_egl = libdrm_dep.found() and gbm_dep.found() 22 | + if have_egl 23 | + conf_data.set('HAVE_EPOXY_EGL_H', 1) 24 | + endif 25 | else 26 | assert(not require_egl, 27 | 'egl was explicitely requested but it is not supported by epoxy') 28 | diff --git a/src/meson.build b/src/meson.build 29 | index 575b7a3..118024b 100644 30 | --- a/src/meson.build 31 | +++ b/src/meson.build 32 | @@ -89,7 +89,6 @@ venus_sources = [ 33 | virgl_depends = [ 34 | gallium_dep, 35 | epoxy_dep, 36 | - libdrm_dep, 37 | thread_dep, 38 | m_dep, 39 | ] 40 | @@ -106,7 +105,7 @@ virgl_sources += vrend_sources 41 | 42 | if have_egl 43 | virgl_sources += vrend_winsys_egl_sources 44 | - virgl_depends += [gbm_dep] 45 | + virgl_depends += [libdrm_dep, gbm_dep] 46 | endif 47 | 48 | if have_glx 49 | diff --git a/src/virglrenderer.c b/src/virglrenderer.c 50 | index 900818c..de32e79 100644 51 | --- a/src/virglrenderer.c 52 | +++ b/src/virglrenderer.c 53 | @@ -446,8 +446,8 @@ void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 54 | ctx->detach_resource(ctx, res); 55 | } 56 | 57 | -int virgl_renderer_resource_get_info(int res_handle, 58 | - struct virgl_renderer_resource_info *info) 59 | +int virgl_renderer_borrow_texture_for_scanout(int res_handle, 60 | + struct virgl_renderer_texture_info *info) 61 | { 62 | TRACE_FUNC(); 63 | struct virgl_resource *res = virgl_resource_lookup(res_handle); 64 | @@ -457,8 +457,8 @@ int virgl_renderer_resource_get_info(int res_handle, 65 | if (!info) 66 | return EINVAL; 67 | 68 | - vrend_renderer_resource_get_info(res->pipe_resource, 69 | - (struct vrend_renderer_resource_info *)info); 70 | + vrend_renderer_borrow_texture_for_scanout(res->pipe_resource, 71 | + (struct vrend_renderer_texture_info *)info); 72 | info->handle = res_handle; 73 | 74 | if (state.winsys_initialized) { 75 | diff --git a/src/virglrenderer.h b/src/virglrenderer.h 76 | index 2fe43aa..35cd25d 100644 77 | --- a/src/virglrenderer.h 78 | +++ b/src/virglrenderer.h 79 | @@ -240,9 +240,9 @@ VIRGL_EXPORT void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 80 | 81 | VIRGL_EXPORT virgl_debug_callback_type virgl_set_debug_callback(virgl_debug_callback_type cb); 82 | 83 | -/* return information about a resource */ 84 | +/* borrow a texture for scanout */ 85 | 86 | -struct virgl_renderer_resource_info { 87 | +struct virgl_renderer_texture_info { 88 | uint32_t handle; 89 | uint32_t virgl_format; 90 | uint32_t width; 91 | @@ -254,8 +254,8 @@ struct virgl_renderer_resource_info { 92 | int drm_fourcc; 93 | }; 94 | 95 | -VIRGL_EXPORT int virgl_renderer_resource_get_info(int res_handle, 96 | - struct virgl_renderer_resource_info *info); 97 | +VIRGL_EXPORT int virgl_renderer_borrow_texture_for_scanout(int res_handle, 98 | + struct virgl_renderer_texture_info *info); 99 | 100 | VIRGL_EXPORT void virgl_renderer_cleanup(void *cookie); 101 | 102 | diff --git a/src/vrend_blitter.h b/src/vrend_blitter.h 103 | index c4a7adb..94b5a45 100644 104 | --- a/src/vrend_blitter.h 105 | +++ b/src/vrend_blitter.h 106 | @@ -31,12 +31,12 @@ 107 | "// Blitter\n" \ 108 | 109 | #define HEADER_GLES \ 110 | - "#version 310 es\n" \ 111 | + "#version 300 es\n" \ 112 | "// Blitter\n" \ 113 | "precision mediump float;\n" \ 114 | 115 | #define HEADER_GLES_MS_ARRAY \ 116 | - "#version 310 es\n" \ 117 | + "#version 300 es\n" \ 118 | "// Blitter\n" \ 119 | "#extension GL_OES_texture_storage_multisample_2d_array: require\n" \ 120 | "precision mediump float;\n" \ 121 | diff --git a/src/vrend_formats.c b/src/vrend_formats.c 122 | index 6aeb2d4..df86efc 100644 123 | --- a/src/vrend_formats.c 124 | +++ b/src/vrend_formats.c 125 | @@ -332,6 +332,8 @@ static struct vrend_format_table gl_bgra_formats[] = { 126 | static struct vrend_format_table gles_bgra_formats[] = { 127 | { VIRGL_FORMAT_B8G8R8X8_UNORM, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, 128 | { VIRGL_FORMAT_B8G8R8A8_UNORM, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NO_SWIZZLE }, 129 | + { VIRGL_FORMAT_B8G8R8X8_SRGB, GL_SRGB8_ALPHA8, GL_BGRA_EXT, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, 130 | + { VIRGL_FORMAT_B8G8R8A8_SRGB, GL_SRGB8_ALPHA8, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NO_SWIZZLE }, 131 | }; 132 | 133 | static struct vrend_format_table gles_bgra_formats_emulation[] = { 134 | @@ -614,24 +616,30 @@ void vrend_build_format_list_gl(void) 135 | 136 | void vrend_build_format_list_gles(void) 137 | { 138 | - /* The BGR[A|X] formats is required but OpenGL ES does not 139 | - * support rendering to it. Try to use GL_BGRA_EXT from the 140 | - * GL_EXT_texture_format_BGRA8888 extension. But the 141 | - * GL_BGRA_EXT format is not supported by OpenGL Desktop. 142 | - */ 143 | - add_formats(gles_bgra_formats); 144 | + /* The Z32 format is required, but OpenGL ES does not support 145 | + * using it as a depth buffer. We just fake support with Z24 146 | + * and hope nobody notices. 147 | + */ 148 | + add_formats(gles_z32_format); 149 | + add_formats(gles_bit10_formats); 150 | +} 151 | 152 | - /* The Z32 format is required, but OpenGL ES does not support 153 | - * using it as a depth buffer. We just fake support with Z24 154 | - * and hope nobody notices. 155 | - */ 156 | - add_formats(gles_z32_format); 157 | - add_formats(gles_bit10_formats); 158 | +void vrend_build_format_list_gles_bgra(void) 159 | +{ 160 | + /* OpenGL ES only supports BGR[A|X] texture formats if the 161 | + * GL_EXT_texture_format_BGRA8888 extension is available and 162 | + * the internal format and pixel transfer format are both 163 | + * GL_BGRA_EXT. But the GL_BGRA_EXT format is not supported 164 | + * by OpenGL Desktop, so we only add these formats for GLES 165 | + * hosts. 166 | + */ 167 | + add_formats(gles_bgra_formats); 168 | } 169 | 170 | void vrend_build_emulated_format_list_gles(void) 171 | { 172 | - add_formats(gles_bgra_formats_emulation); 173 | + assert(0); 174 | + add_formats(gles_bgra_formats_emulation); 175 | } 176 | 177 | /* glTexStorage may not support all that is supported by glTexImage, 178 | diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c 179 | index b8b2a36..1d5e2e5 100644 180 | --- a/src/vrend_renderer.c 181 | +++ b/src/vrend_renderer.c 182 | @@ -202,6 +202,7 @@ enum features_id 183 | feat_txqs, 184 | feat_ubo, 185 | feat_viewport_array, 186 | + feat_gles_bgra, 187 | feat_last, 188 | }; 189 | 190 | @@ -302,6 +303,7 @@ static const struct { 191 | FEAT(txqs, 45, UNAVAIL, "GL_ARB_shader_texture_image_samples" ), 192 | FEAT(ubo, 31, 30, "GL_ARB_uniform_buffer_object" ), 193 | FEAT(viewport_array, 41, UNAVAIL, "GL_ARB_viewport_array", "GL_OES_viewport_array"), 194 | + FEAT(gles_bgra, UNAVAIL, 20, "GL_EXT_texture_format_BGRA8888"), 195 | }; 196 | 197 | struct global_renderer_state { 198 | @@ -1191,6 +1193,7 @@ static inline enum virgl_formats 199 | vrend_format_replace_emulated(uint32_t bind, enum virgl_formats format) 200 | { 201 | enum virgl_formats retval = format; 202 | + return format; 203 | 204 | if (vrend_state.use_gles && (bind & VIRGL_BIND_PREFER_EMULATED_BGRA)) { 205 | VREND_DEBUG(dbg_tweak, vrend_state.current_ctx, "Check tweak for format %s", util_format_name(format)); 206 | @@ -2492,6 +2495,7 @@ static void vrend_hw_emit_framebuffer_state(struct vrend_sub_context *sub_ctx) 207 | sub_ctx->framebuffer_srgb_enabled = use_srgb; 208 | } 209 | 210 | +#if 0 // XXX ryanneph 211 | if (vrend_state.use_gles && 212 | vrend_get_tweak_is_active(&sub_ctx->tweaks, virgl_tweak_gles_brga_apply_dest_swizzle)) { 213 | sub_ctx->swizzle_output_rgb_to_bgr = 0; 214 | @@ -2504,8 +2508,8 @@ static void vrend_hw_emit_framebuffer_state(struct vrend_sub_context *sub_ctx) 215 | } 216 | } 217 | } 218 | - 219 | } 220 | +#endif 221 | 222 | glDrawBuffers(sub_ctx->nr_cbufs, buffers); 223 | } 224 | @@ -6249,6 +6253,13 @@ int vrend_renderer_init(const struct vrend_if_cbs *cbs, uint32_t flags) 225 | 226 | if (vrend_state.use_gles) { 227 | vrend_build_format_list_gles(); 228 | + 229 | + if (has_feature(feat_gles_bgra)) { 230 | + vrend_build_format_list_gles_bgra(); 231 | + } else { 232 | + // TODO(ryanneph): add an emulation path for GLES hosts that require BGRA emulation 233 | + vrend_printf("WARNING: BGRA textures aren't natively supported on this GLES host (missing GL_EXT_texture_format_BGRA8888)\n"); 234 | + } 235 | } else { 236 | vrend_build_format_list_gl(); 237 | } 238 | @@ -6919,6 +6930,7 @@ static enum virgl_formats vrend_resource_fixup_emulated_bgra(struct vrend_resour 239 | const enum virgl_formats format = pr->format; 240 | const bool format_can_texture_storage = has_feature(feat_texture_storage) && 241 | (tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_TEXTURE_STORAGE); 242 | + return format; // XXX ryanneph 243 | 244 | /* On GLES there is no support for glTexImage*DMultisample and 245 | * BGRA surfaces are also unlikely to support glTexStorage2DMultisample 246 | @@ -10703,21 +10715,46 @@ void vrend_context_set_debug_flags(struct vrend_context *ctx, const char *flagst 247 | } 248 | } 249 | 250 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 251 | - struct vrend_renderer_resource_info *info) 252 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 253 | + struct vrend_renderer_texture_info *info) 254 | { 255 | - struct vrend_resource *res = (struct vrend_resource *)pres; 256 | + struct vrend_texture *tex = (struct vrend_texture *)pres; 257 | + const struct vrend_format_table *tex_conv = 258 | + vrend_get_format_table_entry_with_emulation(tex->base.base.bind, tex->base.base.format); 259 | int elsize; 260 | 261 | - elsize = util_format_get_blocksize(res->base.format); 262 | + assert(tex->base.target == GL_TEXTURE_2D); 263 | + assert(!util_format_is_depth_or_stencil(tex->base.base.format)); 264 | + 265 | + elsize = util_format_get_blocksize(tex->base.base.format); 266 | + 267 | + glBindTexture(GL_TEXTURE_2D, tex->base.id); 268 | + 269 | + if (tex_conv->flags & VIRGL_TEXTURE_NEED_SWIZZLE) { 270 | + for (unsigned i = 0; i < ARRAY_SIZE(tex->cur_swizzle); ++i) { 271 | + GLint next_swizzle = to_gl_swizzle(tex_conv->swizzle[i]); 272 | + if (tex->cur_swizzle[i] != next_swizzle) { 273 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R + i, next_swizzle); 274 | + tex->cur_swizzle[i] = next_swizzle; 275 | + } 276 | + } 277 | + } 278 | + 279 | + if (tex->cur_srgb_decode != GL_DECODE_EXT && util_format_is_srgb(tex->base.base.format)) { 280 | + if (has_feature(feat_texture_srgb_decode)) { 281 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, 282 | + GL_DECODE_EXT); 283 | + tex->cur_srgb_decode = GL_DECODE_EXT; 284 | + } 285 | + } 286 | 287 | - info->tex_id = res->id; 288 | - info->width = res->base.width0; 289 | - info->height = res->base.height0; 290 | - info->depth = res->base.depth0; 291 | - info->format = res->base.format; 292 | - info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 293 | - info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; 294 | + info->tex_id = tex->base.id; 295 | + info->width = tex->base.base.width0; 296 | + info->height = tex->base.base.height0; 297 | + info->depth = tex->base.base.depth0; 298 | + info->format = tex->base.base.format; 299 | + info->flags = tex->base.y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 300 | + info->stride = util_format_get_nblocksx(tex->base.base.format, u_minify(tex->base.base.width0, 0)) * elsize; 301 | } 302 | 303 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 304 | diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h 305 | index 55d6b94..e442f62 100644 306 | --- a/src/vrend_renderer.h 307 | +++ b/src/vrend_renderer.h 308 | @@ -401,6 +401,7 @@ GLint64 vrend_renderer_get_timestamp(void); 309 | void vrend_build_format_list_common(void); 310 | void vrend_build_format_list_gl(void); 311 | void vrend_build_format_list_gles(void); 312 | +void vrend_build_format_list_gles_bgra(void); 313 | void vrend_build_emulated_format_list_gles(void); 314 | void vrend_check_texture_storage(struct vrend_format_table *table); 315 | 316 | @@ -430,7 +431,7 @@ void vrend_renderer_detach_res_ctx(struct vrend_context *ctx, 317 | 318 | struct vrend_context_tweaks *vrend_get_context_tweaks(struct vrend_context *ctx); 319 | 320 | -struct vrend_renderer_resource_info { 321 | +struct vrend_renderer_texture_info { 322 | uint32_t handle; 323 | uint32_t format; 324 | uint32_t width; 325 | @@ -441,8 +442,8 @@ struct vrend_renderer_resource_info { 326 | uint32_t stride; 327 | }; 328 | 329 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 330 | - struct vrend_renderer_resource_info *info); 331 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 332 | + struct vrend_renderer_texture_info *info); 333 | 334 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 335 | uint32_t *max_size); 336 | diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c 337 | index bf2d9ef..9863b57 100644 338 | --- a/src/vrend_winsys.c 339 | +++ b/src/vrend_winsys.c 340 | @@ -22,6 +22,7 @@ 341 | * 342 | **************************************************************************/ 343 | 344 | +#include "vrend_debug.h" 345 | #include "vrend_winsys.h" 346 | 347 | #ifdef HAVE_EPOXY_GLX_H 348 | diff --git a/src/vrend_winsys_gbm.h b/src/vrend_winsys_gbm.h 349 | index 84943fb..52b1544 100644 350 | --- a/src/vrend_winsys_gbm.h 351 | +++ b/src/vrend_winsys_gbm.h 352 | @@ -25,7 +25,9 @@ 353 | #ifndef VIRGL_GBM_H 354 | #define VIRGL_GBM_H 355 | 356 | +#ifdef HAVE_EPOXY_EGL_H 357 | #include 358 | +#endif 359 | #include "vrend_iov.h" 360 | #include "virglrenderer.h" 361 | 362 | @@ -101,6 +103,8 @@ struct virgl_gbm { 363 | struct gbm_device *device; 364 | }; 365 | 366 | +#ifdef HAVE_EPOXY_EGL_H 367 | + 368 | struct virgl_gbm *virgl_gbm_init(int fd); 369 | 370 | void virgl_gbm_fini(struct virgl_gbm *gbm); 371 | @@ -124,3 +128,5 @@ bool virgl_gbm_external_allocation_preferred(uint32_t flags); 372 | bool virgl_gbm_gpu_import_required(uint32_t flags); 373 | 374 | #endif 375 | + 376 | +#endif 377 | diff --git a/vtest/vtest_renderer.c b/vtest/vtest_renderer.c 378 | index da314c6..40ed80a 100644 379 | --- a/vtest/vtest_renderer.c 380 | +++ b/vtest/vtest_renderer.c 381 | @@ -1051,6 +1051,14 @@ static int vtest_create_resource_internal(struct vtest_context *ctx, 382 | } 383 | } 384 | 385 | + if (args->format == PIPE_FORMAT_B8G8R8A8_UNORM || 386 | + args->format == PIPE_FORMAT_B8G8R8X8_UNORM || 387 | + args->format == PIPE_FORMAT_B8G8R8A8_SRGB || 388 | + args->format == PIPE_FORMAT_B8G8R8X8_SRGB) 389 | + { 390 | + args->bind |= VIRGL_BIND_PREFER_EMULATED_BGRA; 391 | + } 392 | + 393 | res = vtest_new_resource(args->handle); 394 | if (!res) 395 | return -ENOMEM; 396 | -------------------------------------------------------------------------------- /Patches/virglrenderer-v04.diff: -------------------------------------------------------------------------------- 1 | diff --git a/meson.build b/meson.build 2 | index f6ed468..488ee5a 100644 3 | --- a/meson.build 4 | +++ b/meson.build 5 | @@ -74,7 +74,6 @@ endforeach 6 | 7 | prog_python = import('python').find_installation('python3') 8 | 9 | -libdrm_dep = dependency('libdrm', version : '>=2.4.50') 10 | thread_dep = dependency('threads') 11 | epoxy_dep = dependency('epoxy', version: '>= 1.5.4') 12 | m_dep = cc.find_library('m') 13 | @@ -210,8 +209,9 @@ endif 14 | 15 | if with_egl 16 | if cc.has_header('epoxy/egl.h', dependencies: epoxy_dep) and epoxy_dep.get_pkgconfig_variable('epoxy_has_egl') == '1' 17 | + libdrm_dep = dependency('libdrm', required: require_egl, version : '>=2.4.50') 18 | gbm_dep = dependency('gbm', version: '>= ' + _gbm_ver, required: require_egl) 19 | - have_egl = gbm_dep.found() 20 | + have_egl = libdrm_dep.found() and gbm_dep.found() 21 | if (have_egl) 22 | conf_data.set('HAVE_EPOXY_EGL_H', 1) 23 | else 24 | diff --git a/src/meson.build b/src/meson.build 25 | index 16c645d..9ba99d3 100644 26 | --- a/src/meson.build 27 | +++ b/src/meson.build 28 | @@ -136,7 +136,6 @@ venus_codegen = custom_target( 29 | virgl_depends = [ 30 | gallium_dep, 31 | epoxy_dep, 32 | - libdrm_dep, 33 | thread_dep, 34 | m_dep, 35 | ] 36 | @@ -153,7 +152,7 @@ virgl_sources += vrend_sources 37 | 38 | if have_egl 39 | virgl_sources += vrend_winsys_egl_sources 40 | - virgl_depends += [gbm_dep] 41 | + virgl_depends += [libdrm_dep, gbm_dep] 42 | endif 43 | 44 | if have_glx 45 | diff --git a/src/virglrenderer.c b/src/virglrenderer.c 46 | index 44982d7..7da6c37 100644 47 | --- a/src/virglrenderer.c 48 | +++ b/src/virglrenderer.c 49 | @@ -447,8 +447,8 @@ void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 50 | ctx->detach_resource(ctx, res); 51 | } 52 | 53 | -int virgl_renderer_resource_get_info(int res_handle, 54 | - struct virgl_renderer_resource_info *info) 55 | +int virgl_renderer_borrow_texture_for_scanout(int res_handle, 56 | + struct virgl_renderer_texture_info *info) 57 | { 58 | TRACE_FUNC(); 59 | struct virgl_resource *res = virgl_resource_lookup(res_handle); 60 | @@ -458,8 +458,8 @@ int virgl_renderer_resource_get_info(int res_handle, 61 | if (!info) 62 | return EINVAL; 63 | 64 | - vrend_renderer_resource_get_info(res->pipe_resource, 65 | - (struct vrend_renderer_resource_info *)info); 66 | + vrend_renderer_borrow_texture_for_scanout(res->pipe_resource, 67 | + (struct vrend_renderer_texture_info *)info); 68 | info->handle = res_handle; 69 | 70 | if (state.winsys_initialized) { 71 | diff --git a/src/virglrenderer.h b/src/virglrenderer.h 72 | index a1c06ff..cb439f5 100644 73 | --- a/src/virglrenderer.h 74 | +++ b/src/virglrenderer.h 75 | @@ -247,9 +247,9 @@ VIRGL_EXPORT void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) 76 | 77 | VIRGL_EXPORT virgl_debug_callback_type virgl_set_debug_callback(virgl_debug_callback_type cb); 78 | 79 | -/* return information about a resource */ 80 | +/* borrow a texture for scanout */ 81 | 82 | -struct virgl_renderer_resource_info { 83 | +struct virgl_renderer_texture_info { 84 | uint32_t handle; 85 | uint32_t virgl_format; 86 | uint32_t width; 87 | @@ -261,8 +261,8 @@ struct virgl_renderer_resource_info { 88 | int drm_fourcc; 89 | }; 90 | 91 | -VIRGL_EXPORT int virgl_renderer_resource_get_info(int res_handle, 92 | - struct virgl_renderer_resource_info *info); 93 | +VIRGL_EXPORT int virgl_renderer_borrow_texture_for_scanout(int res_handle, 94 | + struct virgl_renderer_texture_info *info); 95 | 96 | VIRGL_EXPORT void virgl_renderer_cleanup(void *cookie); 97 | 98 | diff --git a/src/vrend_blitter.h b/src/vrend_blitter.h 99 | index 3da5823..d929ca9 100644 100 | --- a/src/vrend_blitter.h 101 | +++ b/src/vrend_blitter.h 102 | @@ -52,12 +52,12 @@ 103 | "// Blitter\n" \ 104 | 105 | #define HEADER_GLES \ 106 | - "#version 310 es\n" \ 107 | + "#version 300 es\n" \ 108 | "// Blitter\n" \ 109 | "precision mediump float;\n" \ 110 | 111 | #define HEADER_GLES_MS_ARRAY \ 112 | - "#version 310 es\n" \ 113 | + "#version 300 es\n" \ 114 | "// Blitter\n" \ 115 | "#extension GL_OES_texture_storage_multisample_2d_array: require\n" \ 116 | "precision mediump float;\n" \ 117 | diff --git a/src/vrend_formats.c b/src/vrend_formats.c 118 | index af652bb..987e610 100644 119 | --- a/src/vrend_formats.c 120 | +++ b/src/vrend_formats.c 121 | @@ -536,8 +536,8 @@ static void vrend_add_formats(struct vrend_format_table *table, int num_entries) 122 | formats that are supported as destination formats by glReadPixels. */ 123 | if (is_desktop_gl || 124 | (status == GL_FRAMEBUFFER_COMPLETE && 125 | - ((is_depth && depth_stencil_formats_can_readback(table[i].format)) || 126 | - color_format_can_readback(&table[i], gles_ver)))) 127 | + (is_depth ? depth_stencil_formats_can_readback(table[i].format) : 128 | + color_format_can_readback(&table[i], gles_ver)))) 129 | flags |= VIRGL_TEXTURE_CAN_READBACK; 130 | 131 | glDeleteTextures(1, &tex_id); 132 | diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c 133 | index ffb1abc..da55fd0 100644 134 | --- a/src/vrend_renderer.c 135 | +++ b/src/vrend_renderer.c 136 | @@ -11117,21 +11117,45 @@ void vrend_context_set_debug_flags(struct vrend_context *ctx, const char *flagst 137 | } 138 | } 139 | 140 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 141 | - struct vrend_renderer_resource_info *info) 142 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 143 | + struct vrend_renderer_texture_info *info) 144 | { 145 | - struct vrend_resource *res = (struct vrend_resource *)pres; 146 | + struct vrend_texture *tex = (struct vrend_texture *)pres; 147 | + struct vrend_format_table *tex_conv = &tex_conv_table[tex->base.base.format]; 148 | int elsize; 149 | 150 | - elsize = util_format_get_blocksize(res->base.format); 151 | + assert(tex->base.target == GL_TEXTURE_2D); 152 | + assert(!util_format_is_depth_or_stencil(tex->base.base.format)); 153 | + 154 | + elsize = util_format_get_blocksize(tex->base.base.format); 155 | + 156 | + glBindTexture(GL_TEXTURE_2D, tex->base.id); 157 | + 158 | + if (tex_conv->flags & VIRGL_TEXTURE_NEED_SWIZZLE) { 159 | + for (unsigned i = 0; i < ARRAY_SIZE(tex->cur_swizzle); ++i) { 160 | + GLint next_swizzle = to_gl_swizzle(tex_conv->swizzle[i]); 161 | + if (tex->cur_swizzle[i] != next_swizzle) { 162 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R + i, next_swizzle); 163 | + tex->cur_swizzle[i] = next_swizzle; 164 | + } 165 | + } 166 | + } 167 | + 168 | + if (tex->cur_srgb_decode != GL_DECODE_EXT && util_format_is_srgb(tex->base.base.format)) { 169 | + if (has_feature(feat_texture_srgb_decode)) { 170 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, 171 | + GL_DECODE_EXT); 172 | + tex->cur_srgb_decode = GL_DECODE_EXT; 173 | + } 174 | + } 175 | 176 | - info->tex_id = res->id; 177 | - info->width = res->base.width0; 178 | - info->height = res->base.height0; 179 | - info->depth = res->base.depth0; 180 | - info->format = res->base.format; 181 | - info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 182 | - info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; 183 | + info->tex_id = tex->base.id; 184 | + info->width = tex->base.base.width0; 185 | + info->height = tex->base.base.height0; 186 | + info->depth = tex->base.base.depth0; 187 | + info->format = tex->base.base.format; 188 | + info->flags = tex->base.y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; 189 | + info->stride = util_format_get_nblocksx(tex->base.base.format, u_minify(tex->base.base.width0, 0)) * elsize; 190 | } 191 | 192 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 193 | diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h 194 | index e6f84cc..89e394a 100644 195 | --- a/src/vrend_renderer.h 196 | +++ b/src/vrend_renderer.h 197 | @@ -436,7 +436,7 @@ void vrend_renderer_detach_res_ctx(struct vrend_context *ctx, 198 | 199 | struct vrend_context_tweaks *vrend_get_context_tweaks(struct vrend_context *ctx); 200 | 201 | -struct vrend_renderer_resource_info { 202 | +struct vrend_renderer_texture_info { 203 | uint32_t handle; 204 | uint32_t format; 205 | uint32_t width; 206 | @@ -460,8 +460,8 @@ struct vrend_blit_info { 207 | bool has_srgb_write_control; 208 | }; 209 | 210 | -void vrend_renderer_resource_get_info(struct pipe_resource *pres, 211 | - struct vrend_renderer_resource_info *info); 212 | +void vrend_renderer_borrow_texture_for_scanout(struct pipe_resource *pres, 213 | + struct vrend_renderer_texture_info *info); 214 | 215 | void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, 216 | uint32_t *max_size); 217 | diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c 218 | index 669af81..c6d682f 100644 219 | --- a/src/vrend_winsys.c 220 | +++ b/src/vrend_winsys.c 221 | @@ -22,6 +22,7 @@ 222 | * 223 | **************************************************************************/ 224 | 225 | +#include "vrend_debug.h" 226 | #include "vrend_winsys.h" 227 | 228 | #ifdef HAVE_EPOXY_GLX_H 229 | @@ -30,6 +31,8 @@ 230 | 231 | #include 232 | 233 | +#include "util/macros.h" 234 | + 235 | enum { 236 | CONTEXT_NONE, 237 | CONTEXT_EGL, 238 | @@ -113,7 +116,7 @@ void vrend_winsys_cleanup(void) 239 | #endif 240 | } 241 | 242 | -virgl_renderer_gl_context vrend_winsys_create_context(struct virgl_gl_ctx_param *param) 243 | +virgl_renderer_gl_context vrend_winsys_create_context(UNUSED struct virgl_gl_ctx_param *param) 244 | { 245 | #ifdef HAVE_EPOXY_EGL_H 246 | if (use_context == CONTEXT_EGL) 247 | @@ -126,7 +129,7 @@ virgl_renderer_gl_context vrend_winsys_create_context(struct virgl_gl_ctx_param 248 | return NULL; 249 | } 250 | 251 | -void vrend_winsys_destroy_context(virgl_renderer_gl_context ctx) 252 | +void vrend_winsys_destroy_context(UNUSED virgl_renderer_gl_context ctx) 253 | { 254 | #ifdef HAVE_EPOXY_EGL_H 255 | if (use_context == CONTEXT_EGL) { 256 | @@ -142,7 +145,7 @@ void vrend_winsys_destroy_context(virgl_renderer_gl_context ctx) 257 | #endif 258 | } 259 | 260 | -int vrend_winsys_make_context_current(virgl_renderer_gl_context ctx) 261 | +int vrend_winsys_make_context_current(UNUSED virgl_renderer_gl_context ctx) 262 | { 263 | #ifdef HAVE_EPOXY_EGL_H 264 | if (use_context == CONTEXT_EGL) 265 | diff --git a/src/vrend_winsys_gbm.h b/src/vrend_winsys_gbm.h 266 | index 84943fb..52b1544 100644 267 | --- a/src/vrend_winsys_gbm.h 268 | +++ b/src/vrend_winsys_gbm.h 269 | @@ -25,7 +25,9 @@ 270 | #ifndef VIRGL_GBM_H 271 | #define VIRGL_GBM_H 272 | 273 | +#ifdef HAVE_EPOXY_EGL_H 274 | #include 275 | +#endif 276 | #include "vrend_iov.h" 277 | #include "virglrenderer.h" 278 | 279 | @@ -101,6 +103,8 @@ struct virgl_gbm { 280 | struct gbm_device *device; 281 | }; 282 | 283 | +#ifdef HAVE_EPOXY_EGL_H 284 | + 285 | struct virgl_gbm *virgl_gbm_init(int fd); 286 | 287 | void virgl_gbm_fini(struct virgl_gbm *gbm); 288 | @@ -124,3 +128,5 @@ bool virgl_gbm_external_allocation_preferred(uint32_t flags); 289 | bool virgl_gbm_gpu_import_required(uint32_t flags); 290 | 291 | #endif 292 | + 293 | +#endif 294 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D accelerated qemu on MacOS 2 | 3 | ![ubuntu](https://user-images.githubusercontent.com/6728841/111193747-90da1a00-85cb-11eb-9517-36c1a19c19be.gif) 4 | 5 | ## What is it for 6 | 7 | If you own a Mac (x86 or ARM) and want to have a full Linux desktop for development or testing, you'll find that having a responsive desktop is a nice thing. The graphical acceleration is possible thanks to [the work](https://gist.github.com/akihikodaki/87df4149e7ca87f18dc56807ec5a1bc5) of [Akihiko Odaki](https://github.com/akihikodaki). I've only packaged it into an easily-installable brew repository while the changes are not yet merged into upstream. 8 | 9 | Features: 10 | 11 | - Support for both ARM and X86 acceleration with Hypervisor.framework (works without root or kernel extensions) 12 | - Support for OpenGL acceleration in the guest (both X11 and Wayland) 13 | - Works on large screens (5k+) 14 | - Dynamically changing guest resolution on window resize 15 | - Properly handle sound output when plugging/unplugging headphones 16 | 17 | ## Installation 18 | 19 | `brew install knazarov/qemu-virgl/qemu-virgl` 20 | 21 | Or `brew tap knazarov/qemu-virgl` and then `brew install qemu-virgl`. 22 | 23 | 24 | ## Usage 25 | 26 | Qemu has many command line options and emulated devices, so the 27 | sections are specific to your CPU (Intel/M1). 28 | 29 | For the best experience, maximize the qemu window when it starts. To 30 | release the mouse, press `Ctrl-Alt-g`. 31 | 32 | ### Usage - M1 Macs 33 | 34 | **Latest release needs virtio-gpu-gl-pci command line option instead of virtio-gpu-pci, otherwise gpu acceleration won't work** 35 | 36 | First, create a disk image you'll run your Linux installation from (tune image size as needed): 37 | 38 | ```sh 39 | qemu-img create hdd.raw 64G 40 | ``` 41 | 42 | Download an ARM based Fedora 35 image: 43 | 44 | ```sh 45 | curl -LO https://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/aarch64/iso/Fedora-Workstation-Live-aarch64-35-1.2.iso 46 | ``` 47 | 48 | Copy the firmware: 49 | 50 | ```sh 51 | cp $(dirname $(which qemu-img))/../share/qemu/edk2-aarch64-code.fd . 52 | cp $(dirname $(which qemu-img))/../share/qemu/edk2-arm-vars.fd . 53 | ``` 54 | 55 | Install the system from the CD image: 56 | 57 | ```sh 58 | qemu-system-aarch64 \ 59 | -machine virt,accel=hvf,highmem=off \ 60 | -cpu cortex-a72 -smp 2 -m 4G \ 61 | -device intel-hda -device hda-output \ 62 | -device qemu-xhci \ 63 | -device virtio-gpu-gl-pci \ 64 | -device usb-kbd \ 65 | -device virtio-net-pci,netdev=net \ 66 | -device virtio-mouse-pci \ 67 | -display cocoa,gl=es \ 68 | -netdev user,id=net,ipv6=off \ 69 | -drive "if=pflash,format=raw,file=./edk2-aarch64-code.fd,readonly=on" \ 70 | -drive "if=pflash,format=raw,file=./edk2-arm-vars.fd,discard=on" \ 71 | -drive "if=virtio,format=raw,file=./hdd.raw,discard=on" \ 72 | -cdrom Fedora-Workstation-Live-aarch64-35-1.2.iso \ 73 | -boot d 74 | ``` 75 | 76 | Run the system without the CD image to boot into the primary partition: 77 | 78 | ```sh 79 | qemu-system-aarch64 \ 80 | -machine virt,accel=hvf,highmem=off \ 81 | -cpu cortex-a72 -smp 2 -m 4G \ 82 | -device intel-hda -device hda-output \ 83 | -device qemu-xhci \ 84 | -device virtio-gpu-gl-pci \ 85 | -device usb-kbd \ 86 | -device virtio-net-pci,netdev=net \ 87 | -device virtio-mouse-pci \ 88 | -display cocoa,gl=es \ 89 | -netdev user,id=net,ipv6=off \ 90 | -drive "if=pflash,format=raw,file=./edk2-aarch64-code.fd,readonly=on" \ 91 | -drive "if=pflash,format=raw,file=./edk2-arm-vars.fd,discard=on" \ 92 | -drive "if=virtio,format=raw,file=./hdd.raw,discard=on" 93 | ``` 94 | 95 | 96 | ### Usage - Intel Macs 97 | 98 | First, create a disk image you'll run your Linux installation from (tune image size as needed): 99 | 100 | ```sh 101 | qemu-img create hdd.raw 64G 102 | ``` 103 | 104 | Download an x86 based Fedora 35 image: 105 | 106 | ```sh 107 | curl -LO https://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso 108 | ``` 109 | 110 | Install the system from the CD image: 111 | 112 | ```sh 113 | qemu-system-x86_64 \ 114 | -machine accel=hvf \ 115 | -cpu Haswell-v4 -smp 2 -m 4G \ 116 | -device intel-hda -device hda-output \ 117 | -device qemu-xhci \ 118 | -device virtio-vga-gl \ 119 | -device usb-kbd \ 120 | -device virtio-net-pci,netdev=net \ 121 | -device virtio-mouse-pci \ 122 | -display cocoa,gl=es \ 123 | -netdev user,id=net,ipv6=off \ 124 | -drive "if=virtio,format=raw,file=hdd.raw,discard=on" \ 125 | -cdrom Fedora-Workstation-Live-x86_64-35-1.2.iso \ 126 | -boot d 127 | ``` 128 | 129 | Run the system without the CD image to boot into the primary partition: 130 | 131 | ```sh 132 | qemu-system-x86_64 \ 133 | -machine accel=hvf \ 134 | -cpu Haswell-v4 -smp 2 -m 4G \ 135 | -device intel-hda -device hda-output \ 136 | -device qemu-xhci \ 137 | -device virtio-vga-gl \ 138 | -device usb-kbd \ 139 | -device virtio-net-pci,netdev=net \ 140 | -device virtio-mouse-pci \ 141 | -display cocoa,gl=es \ 142 | -netdev user,id=net,ipv6=off \ 143 | -drive "if=virtio,format=raw,file=hdd.raw,discard=on" 144 | ``` 145 | 146 | 147 | ## Usage - Advanced 148 | 149 | This section has additional configuration you may want to do to improve your workflow 150 | 151 | 152 | ### Clipboard sharing 153 | 154 | There's now support for sharing clipboard in both directions: from vm->host and host->vm. To enable clibpoard sharing, add this to your command line: 155 | 156 | ``` 157 | -chardev qemu-vdagent,id=spice,name=vdagent,clipboard=on \ 158 | -device virtio-serial-pci \ 159 | -device virtserialport,chardev=spice,name=com.redhat.spice.0 160 | ``` 161 | 162 | ### Mouse integration 163 | 164 | By default, you have mouse pointer capture and have to release mouse pointer from the VM using keyboard shortcut. In order to have seamless mouse configuration, 165 | add the following to your command line instead of `-device virtio-mouse-pci`: 166 | 167 | ``` 168 | -device usb-tablet \ 169 | ``` 170 | 171 | ### MacOS native networking for VMs (vmnet) 172 | 173 | akihikodaki's patch set includes support for vmnet which offers more flexibility than `-netdev user`, and allows higher network throughput. (see https://github.com/akihikodaki/qemu/commit/72a35bb6e0a16bb7d346ba822a6d47293915fc95). 174 | 175 | For instance, to enable bridge mode, replace: 176 | 177 | ``` 178 | -device virtio-net-pci,netdev=net \ 179 | -netdev user,id=net,ipv6=off \ 180 | ``` 181 | 182 | with 183 | 184 | 185 | ``` 186 | -netdev vmnet-macos,id=n1,mode=bridged,ifname=en0 \ 187 | -device virtio-net,netdev=n1 \ 188 | ``` 189 | 190 | vmnet also offers "host" and "shared" networking model: 191 | 192 | ``` 193 | -netdev vmnet-macos,id=str,mode=host|shared[,dhcp_start_address=addr,dhcp_end_address=addr,dhcp_subnet_mask=mask] 194 | ``` 195 | 196 | ***caveats:*** 197 | 198 | 1) vmnet requires running qemu as root, for now. 199 | 2) current vmnet API (Apple) doesn't support setting MAC address, so it will be randomized every time the VM is started. 200 | 201 | To work around 2), for now it's possible to set the MAC address within the VM. 202 | 203 | As root, create a file `/etc/udev/rules.d/75-mac-vmnet.rules` with the following content: 204 | 205 | ``` 206 | ACTION=="add", SUBSYSTEM=="net", KERNEL=="enp0s3", RUN+="/usr/bin/ip link set dev %k address 00:11:22:33:44:55" 207 | ``` 208 | 209 | replace `enp0s3` with the name of your interface and `00:11:22:33:44:55` with the desired MAC address. 210 | 211 | Reboot or issue a `ip link set dev enp0s3 address 00:11:22:33:44:55` to change your MAC address. 212 | --------------------------------------------------------------------------------